From cb3717b4abf5502eed875f0c9b2a01559dcc164c Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 11 Jun 2024 21:35:57 -0400 Subject: [PATCH 0001/1101] SimplePackageTest is a pass on Windows --- .../jpackage/internal/AppImageBundler.java | 10 +- .../jdk/jpackage/internal/Application.java | 226 ++++++++++++ .../jdk/jpackage/internal/Functional.java | 187 ++++++++++ .../jdk/jpackage/internal/Launcher.java | 124 +++++++ .../jpackage/internal/LauncherAsService.java | 7 + .../jdk/jpackage/internal/LauncherData.java | 4 +- .../internal/LauncherJarStartupInfo.java | 31 ++ .../internal/LauncherModularStartupInfo.java | 34 ++ .../internal/LauncherStartupInfo.java | 120 +++++++ .../jdk/jpackage/internal/Package.java | 205 +++++++++++ ...BundlerHelper.java => RuntimeBuilder.java} | 189 +++++----- .../jdk/jpackage/internal/ScriptRunner.java | 33 +- .../jdk/jpackage/internal/Workshop.java | 95 +++++ .../resources/MainResources.properties | 1 + .../jdk/jpackage/internal/WinApplication.java | 63 ++++ .../jdk/jpackage/internal/WinLauncher.java | 66 ++++ .../jdk/jpackage/internal/WinMsiBundler.java | 338 ++++-------------- .../jdk/jpackage/internal/WinMsiPackage.java | 246 +++++++++++++ .../internal/WixAppImageFragmentBuilder.java | 150 +++----- .../jpackage/internal/WixFragmentBuilder.java | 10 +- .../internal/WixLauncherAsService.java | 11 +- .../internal/WixUiFragmentBuilder.java | 47 +-- 22 files changed, 1662 insertions(+), 535 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/Functional.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherModularStartupInfo.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{JLinkBundlerHelper.java => RuntimeBuilder.java} (61%) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java create mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java create mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java create mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java index 68c5685650602..5b95e1674166e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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 @@ -166,10 +166,11 @@ private Path createAppBundle(Map params, Path outputDirectory) throws PackagerException, IOException, ConfigException { + var app = Application.TARGET_APPLICATION.fetchFrom(params); + boolean hasAppImage = PREDEFINED_APP_IMAGE.fetchFrom(params) != null; - boolean hasRuntimeImage = - PREDEFINED_RUNTIME_IMAGE.fetchFrom(params) != null; + boolean hasRuntimeImage = app.predefinedRuntimeImage() != null; Path rootDirectory = hasAppImage ? PREDEFINED_APP_IMAGE.fetchFrom(params) : @@ -178,8 +179,7 @@ private Path createAppBundle(Map params, AbstractAppImageBuilder appBuilder = appImageSupplier.apply(rootDirectory); if (!hasAppImage) { if (!hasRuntimeImage) { - JLinkBundlerHelper.execute(params, - appBuilder.getAppLayout().runtimeHomeDirectory()); + app.runtimeBuilder().execute(appBuilder.getAppLayout().runtimeHomeDirectory()); } else { StandardBundlerParam.copyPredefinedRuntimeImage( params, appBuilder.getAppLayout()); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java new file mode 100644 index 0000000000000..4bd0792aafdb9 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Stream; +import jdk.internal.util.OperatingSystem; +import static jdk.jpackage.internal.Functional.ThrowingBiFunction.toBiFunction; +import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; +import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; +import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; +import static jdk.jpackage.internal.StandardBundlerParam.ICON; +import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; +import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; +import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; +import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; +import static jdk.jpackage.internal.StandardBundlerParam.VERSION; +import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; +import static jdk.jpackage.internal.StandardBundlerParam.isRuntimeInstaller; + +interface Application { + + String name(); + + String description(); + + String version(); + + String vendor(); + + Path predefinedRuntimeImage(); + + RuntimeBuilder runtimeBuilder(); + + default Path appImageDirName() { + switch (OperatingSystem.current()) { + case MACOS -> { + return Path.of(name() + ".app"); + } + default -> { + return Path.of(name()); + } + } + } + + Launcher mainLauncher(); + + List additionalLaunchers(); + + default boolean isService() { + return allLaunchers().stream().filter(Launcher::isService).findAny().isPresent(); + } + + default ApplicationLayout appLayout() { + if (mainLauncher() == null) { + return ApplicationLayout.javaRuntime(); + } else { + return ApplicationLayout.platformAppImage(); + } + } + + default List allLaunchers() { + return Optional.ofNullable(mainLauncher()).map(main -> { + return Stream.concat(Stream.of(main), additionalLaunchers().stream()).toList(); + }).orElse(List.of()); + } + + static record Impl(String name, String description, String version, String vendor, + Path predefinedRuntimeImage, RuntimeBuilder runtimeBuilder, Launcher mainLauncher, + List additionalLaunchers) implements Application { + + } + + static class Proxy implements Application { + + Proxy(Application target) { + this.target = target; + } + + @Override + public String name() { + return target.name(); + } + + @Override + public String description() { + return target.description(); + } + + @Override + public String version() { + return target.version(); + } + + @Override + public String vendor() { + return target.vendor(); + } + + @Override + public Path predefinedRuntimeImage() { + return target.predefinedRuntimeImage(); + } + + @Override + public RuntimeBuilder runtimeBuilder() { + return target.runtimeBuilder(); + } + + @Override + public Launcher mainLauncher() { + return target.mainLauncher(); + } + + @Override + public List additionalLaunchers() { + return target.additionalLaunchers(); + } + + private final Application target; + } + + static Application createFromParams(Map params, + Function, Launcher> launcherSupplier) throws ConfigException { + var name = APP_NAME.fetchFrom(params); + var description = DESCRIPTION.fetchFrom(params); + var version = VERSION.fetchFrom(params); + var vendor = VENDOR.fetchFrom(params); + var predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); + + var predefinedAppImage = getPredefinedAppImage(params); + if (name == null && predefinedAppImage == null) { + // Can happen when no name is given, and using a foreign app-image + throw new ConfigException(I18N.getString("error.no.name"), I18N.getString( + "error.no.name.advice")); + } + + RuntimeBuilder runtimeBuilder; + + Launcher mainLauncher; + List additionalLaunchers; + if (isRuntimeInstaller(params)) { + runtimeBuilder = null; + mainLauncher = null; + additionalLaunchers = List.of(); + } else if (predefinedAppImage != null) { + runtimeBuilder = null; + + AppImageFile appImage = AppImageFile.load(predefinedAppImage); + + version = appImage.getAppVersion(); + + mainLauncher = launcherSupplier.apply(mergeParams(params, Map.of(APP_NAME.getID(), + appImage.getLauncherName(), DESCRIPTION.getID(), description))); + additionalLaunchers = appImage.getAddLaunchers().stream().map(li -> { + return launcherSupplier.apply(mergeParams(params, Map.of(APP_NAME.getID(), li + .getName(), SHORTCUT_HINT.getID(), li.isShortcut(), MENU_HINT.getID(), li + .isMenu(), LAUNCHER_AS_SERVICE.getID(), li.isService()))); + }).toList(); + } else { + var launchers = Optional.ofNullable(ADD_LAUNCHERS.fetchFrom(params)).orElseGet( + Collections::emptyList); + mainLauncher = launcherSupplier.apply(params); + additionalLaunchers = launchers.stream().map(launcherParams -> { + return launcherSupplier.apply(mergeParams(params, launcherParams)); + }).toList(); + + var startupInfos = Stream.concat(Stream.of(mainLauncher), additionalLaunchers.stream()).map( + Launcher::startupInfo).toList(); + runtimeBuilder = RuntimeBuilder.createFromParams(params, startupInfos); + } + + return new Impl(name, description, version, vendor, predefinedRuntimeImage, runtimeBuilder, + mainLauncher, additionalLaunchers); + } + + private static Map mergeParams(Map mainParams, + Map launcherParams) { + if (!launcherParams.containsKey(DESCRIPTION.getID())) { + launcherParams = new HashMap<>(launcherParams); + launcherParams.put(DESCRIPTION.getID(), String.format("%s (%s)", DESCRIPTION.fetchFrom( + mainParams), APP_NAME.fetchFrom(launcherParams))); + } + return AddLauncherArguments.merge(mainParams, launcherParams, ICON.getID(), ADD_LAUNCHERS + .getID(), FILE_ASSOCIATIONS.getID(), PREDEFINED_APP_IMAGE.getID()); + } + + final static String PARAM_ID = "target.application"; + + static final StandardBundlerParam TARGET_APPLICATION = new StandardBundlerParam<>( + PARAM_ID, Application.class, params -> { + return toBiFunction(Application::createFromParams).apply(params, + Launcher::createFromParams); + }, null); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Functional.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Functional.java new file mode 100644 index 0000000000000..0a3e588a6210e --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Functional.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; + +public class Functional { + + @FunctionalInterface + public interface ThrowingConsumer { + + void accept(T t) throws Throwable; + + public static Consumer toConsumer(ThrowingConsumer v) { + return o -> { + try { + v.accept(o); + } catch (Throwable ex) { + throw rethrowUnchecked(ex); + } + }; + } + } + + @FunctionalInterface + public interface ThrowingBiConsumer { + + void accept(T t, U u) throws Throwable; + + public static BiConsumer toBiConsumer(ThrowingBiConsumer v) { + return (t, u) -> { + try { + v.accept(t, u); + } catch (Throwable ex) { + throw rethrowUnchecked(ex); + } + }; + } + } + + @FunctionalInterface + public interface ThrowingSupplier { + + T get() throws Throwable; + + public static Supplier toSupplier(ThrowingSupplier v) { + return () -> { + try { + return v.get(); + } catch (Throwable ex) { + throw rethrowUnchecked(ex); + } + }; + } + } + + @FunctionalInterface + public interface ThrowingFunction { + + R apply(T t) throws Throwable; + + public static Function toFunction(ThrowingFunction v) { + return (t) -> { + try { + return v.apply(t); + } catch (Throwable ex) { + throw rethrowUnchecked(ex); + } + }; + } + } + + @FunctionalInterface + public interface ThrowingBiFunction { + + R apply(T t, U u) throws Throwable; + + public static BiFunction toBiFunction(ThrowingBiFunction v) { + return (t, u) -> { + try { + return v.apply(t, u); + } catch (Throwable ex) { + throw rethrowUnchecked(ex); + } + }; + } + } + + @FunctionalInterface + public interface ThrowingRunnable { + + void run() throws Throwable; + + public static Runnable toRunnable(ThrowingRunnable v) { + return () -> { + try { + v.run(); + } catch (Throwable ex) { + throw rethrowUnchecked(ex); + } + }; + } + } + + public static Supplier identity(Supplier v) { + return v; + } + + public static Consumer identity(Consumer v) { + return v; + } + + public static BiConsumer identity(BiConsumer v) { + return v; + } + + public static Runnable identity(Runnable v) { + return v; + } + + public static BiFunction identityBiFunction(BiFunction v) { + return v; + } + + public static Function identityFunction(Function v) { + return v; + } + + public static Predicate identityPredicate(Predicate v) { + return v; + } + + public static class ExceptionBox extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public ExceptionBox(Throwable throwable) { + super(throwable); + } + } + + public static RuntimeException rethrowUnchecked(Throwable throwable) throws + ExceptionBox { + if (throwable instanceof RuntimeException runtimeThrowable) { + throw runtimeThrowable; + } + + if (throwable instanceof InvocationTargetException) { + throw new ExceptionBox(throwable.getCause()); + } + + throw new ExceptionBox(throwable); + } + + @SuppressWarnings("unchecked") + static > C toCollection(Collection v) { + Collection tmp = v; + return (C) tmp; + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java new file mode 100644 index 0000000000000..161057582e409 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +interface Launcher { + + String name(); + + default Path executableName() { + return Path.of(name()); + } + + LauncherStartupInfo startupInfo(); + + List fileAssociations(); + + boolean isService(); + + String version(); + + String release(); + + String description(); + + /** + * null for the default or resource directory icon empty path for not icon any other value for + * custom icon + */ + Path icon(); + + static record Impl(String name, LauncherStartupInfo startupInfo, + List fileAssociations, boolean isService, String version, + String release, String description, Path icon) implements Launcher { + + } + + static class Proxy implements Launcher { + + Proxy(Launcher target) { + this.target = target; + } + + @Override + public String name() { + return target.name(); + } + + @Override + public LauncherStartupInfo startupInfo() { + return target.startupInfo(); + } + + @Override + public List fileAssociations() { + return target.fileAssociations(); + } + + @Override + public boolean isService() { + return target.isService(); + } + + @Override + public String version() { + return target.version(); + } + + @Override + public String release() { + return target.release(); + } + + @Override + public String description() { + return target.description(); + } + + @Override + public Path icon() { + return target.icon(); + } + + private final Launcher target; + } + + static Launcher createFromParams(Map params) { + var name = StandardBundlerParam.APP_NAME.fetchFrom(params); + var startupInfo = LauncherStartupInfo.createFromParams(params); + var isService = StandardBundlerParam.LAUNCHER_AS_SERVICE.fetchFrom(params); + var version = StandardBundlerParam.VERSION.fetchFrom(params); + var release = StandardBundlerParam.RELEASE.fetchFrom(params); + var description = StandardBundlerParam.DESCRIPTION.fetchFrom(params); + var icon = StandardBundlerParam.ICON.fetchFrom(params); + var fa = FileAssociation.fetchFrom(params); + + return new Impl(name, startupInfo, fa, isService, version, release, description, icon); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java index bf25fc229e52d..cb65781935c8b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java @@ -47,6 +47,13 @@ class LauncherAsService { resource.addSubstitutionDataEntry("SERVICE_DESCRIPTION", description); } + LauncherAsService(Launcher launcher, OverridableResource resource) { + this.name = launcher.name(); + this.description = launcher.description(); + this.resource = resource; + resource.addSubstitutionDataEntry("SERVICE_DESCRIPTION", description); + } + protected OverridableResource getResource() { return resource; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java index ce6813de28b1e..7044f0e4350f9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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 @@ -141,7 +141,7 @@ private static LauncherData createModular(String mainModule, launcherData.modulePath = getModulePath(params); // Try to find module in the specified module path list. - ModuleReference moduleRef = JLinkBundlerHelper.createModuleFinder( + ModuleReference moduleRef = RuntimeBuilder.createModuleFinder( launcherData.modulePath).find(moduleName).orElse(null); if (moduleRef != null) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java new file mode 100644 index 0000000000000..eb9ed36e2e49c --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; + +interface LauncherJarStartupInfo extends LauncherStartupInfo { + Path jarPath(); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherModularStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherModularStartupInfo.java new file mode 100644 index 0000000000000..241e3c3fd26e3 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherModularStartupInfo.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.List; + +interface LauncherModularStartupInfo extends LauncherStartupInfo { + String moduleName(); + + List modulePath(); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java new file mode 100644 index 0000000000000..951cd800adf75 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import static jdk.jpackage.internal.StandardBundlerParam.ARGUMENTS; +import static jdk.jpackage.internal.StandardBundlerParam.JAVA_OPTIONS; + +interface LauncherStartupInfo { + String qualifiedClassName(); + + default String packageName() { + int sepIdx = qualifiedClassName().lastIndexOf('.'); + if (sepIdx < 0) { + return ""; + } + return qualifiedClassName().substring(sepIdx + 1); + } + + List javaOptions(); + + List defaultParameters(); + + List classPath(); + + static LauncherStartupInfo createFromParams(Map params) { + var inputDir = StandardBundlerParam.SOURCE_DIR.fetchFrom(params); + var launcherData = StandardBundlerParam.LAUNCHER_DATA.fetchFrom(params); + var javaOptions = JAVA_OPTIONS.fetchFrom(params); + var arguments = ARGUMENTS.fetchFrom(params); + var classpath = launcherData.classPath().stream().map(p -> { + return inputDir.resolve(p).toAbsolutePath(); + }).toList(); + + if (launcherData.isModular()) { + return new LauncherModularStartupInfo() { + @Override + public String moduleName() { + return launcherData.moduleName(); + } + + @Override + public List modulePath() { + return launcherData.modulePath().stream().map(Path::toAbsolutePath).toList(); + } + + @Override + public String qualifiedClassName() { + return launcherData.qualifiedClassName(); + } + + @Override + public List javaOptions() { + return javaOptions; + } + + @Override + public List defaultParameters() { + return arguments; + } + + @Override + public List classPath() { + return classpath; + } + }; + } else { + return new LauncherJarStartupInfo() { + @Override + public Path jarPath() { + return inputDir.resolve(launcherData.mainJarName()); + } + + @Override + public String qualifiedClassName() { + return launcherData.qualifiedClassName(); + } + + @Override + public List javaOptions() { + return javaOptions; + } + + @Override + public List defaultParameters() { + return arguments; + } + + @Override + public List classPath() { + return classpath; + } + }; + } + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java new file mode 100644 index 0000000000000..058a030211fae --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.Map; +import java.util.Optional; +import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; +import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; +import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; +import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; +import static jdk.jpackage.internal.StandardBundlerParam.VERSION; +import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; + +interface Package { + + enum PackageType { + WinMsi(".msi"), + WinExe(".exe"), + LinuxDeb(".deb"), + LinuxRpm(".rpm"), + MacPkg(".pkg"), + MacDmg(".dmg"); + + PackageType(String suffix) { + this.suffix = suffix; + } + + String suffix() { + return suffix; + } + + private final String suffix; + } + + Application app(); + + PackageType type(); + + /** + * Returns platform-specific package name. + */ + String name(); + + String description(); + + String version(); + + String aboutURL(); + + Path licenseFile(); + + Path predefinedAppImage(); + + default ApplicationLayout appLayout() { + return app().appLayout(); + } + + default Path installerName() { + var type = type(); + switch (type) { + case WinMsi, WinExe -> { + return Path.of(String.format("%s-%s%s", name(), version(), type.suffix())); + } + default -> { + throw new UnsupportedOperationException(); + } + } + } + + default boolean isRuntimeInstaller() { + return app().mainLauncher() == null; + } + + /** + * Returns relative path to the package installation directory. On Windows it should be relative + * to %ProgramFiles% and relative to the system root ('/') on other platforms. + */ + Path relativeInstallDir(); + + static record Impl(Application app, PackageType type, String name, String description, + String version, String aboutURL, Path licenseFile, Path predefinedAppImage, + Path relativeInstallDir) implements Package { + + } + + static class Proxy implements Package { + + Proxy(Package target) { + this.target = target; + } + + @Override + public Application app() { + return target.app(); + } + + @Override + public PackageType type() { + return target.type(); + } + + @Override + public String name() { + return target.name(); + } + + @Override + public String description() { + return target.description(); + } + + @Override + public String version() { + return target.version(); + } + + @Override + public String aboutURL() { + return target.aboutURL(); + } + + @Override + public Path licenseFile() { + return target.licenseFile(); + } + + @Override + public Path predefinedAppImage() { + return target.predefinedAppImage(); + } + + @Override + public Path relativeInstallDir() { + return target.relativeInstallDir(); + } + + private final Package target; + } + + static Package createFromParams(Map params, Application app, + PackageType type) throws ConfigException { + var name = Optional.ofNullable(APP_NAME.fetchFrom(params)).orElseGet(app::name); + var description = Optional.ofNullable(DESCRIPTION.fetchFrom(params)).orElseGet(app::name); + var version = Optional.ofNullable(VERSION.fetchFrom(params)).orElseGet(app::version); + var aboutURL = ABOUT_URL.fetchFrom(params); + var licenseFile = Optional.ofNullable(LICENSE_FILE.fetchFrom(params)).map(Path::of).orElse(null); + var predefinedAppImage = getPredefinedAppImage(params); + + var relativeInstallDir = Optional.ofNullable(INSTALL_DIR.fetchFrom(params)).map(Path::of) + .orElseGet(() -> { + switch (type) { + case WinExe, WinMsi -> { + return Path.of(name); + } + case LinuxDeb, LinuxRpm -> { + return Path.of("/opt").resolve(name); + } + case MacDmg, MacPkg -> { + String root; + if (StandardBundlerParam.isRuntimeInstaller(params)) { + root = "/Library/Java/JavaVirtualMachines"; + } else { + root = "/Applications"; + } + return Path.of(root).resolve(name + ".app"); + } + default -> { + throw new IllegalArgumentException(); + } + } + }); + if (relativeInstallDir.isAbsolute()) { + relativeInstallDir = relativeInstallDir.relativize(Path.of("/")); + } + + return new Impl(app, type, name, description, version, aboutURL, licenseFile, + predefinedAppImage, relativeInstallDir); + } + + final static String PARAM_ID = "target.package"; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkBundlerHelper.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilder.java similarity index 61% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkBundlerHelper.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilder.java index 62ddaa8221984..cdadccdb9d64b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkBundlerHelper.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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,11 +22,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.jpackage.internal; import java.io.File; -import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.module.Configuration; @@ -35,50 +33,119 @@ import java.lang.module.ModuleReference; import java.lang.module.ResolvedModule; import java.nio.file.Path; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.Supplier; import java.util.jar.JarFile; -import java.util.regex.Matcher; import java.util.spi.ToolProvider; import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.module.ModulePath; +import static jdk.jpackage.internal.StandardBundlerParam.ADD_MODULES; +import static jdk.jpackage.internal.StandardBundlerParam.JLINK_OPTIONS; +import static jdk.jpackage.internal.StandardBundlerParam.LIMIT_MODULES; +import static jdk.jpackage.internal.StandardBundlerParam.MODULE_PATH; +final class RuntimeBuilder { -final class JLinkBundlerHelper { + private RuntimeBuilder(List jlinkCmdLine) { + this.jlinkCmdLine = jlinkCmdLine; + } - static void execute(Map params, Path outputDir) - throws IOException, PackagerException { + void execute(Path outputDir) throws PackagerException { + var args = new ArrayList(); + args.add("--output"); + args.add(outputDir.toString()); + args.addAll(jlinkCmdLine); - List modulePath = - StandardBundlerParam.MODULE_PATH.fetchFrom(params); - Set addModules = - StandardBundlerParam.ADD_MODULES.fetchFrom(params); - Set limitModules = - StandardBundlerParam.LIMIT_MODULES.fetchFrom(params); - List options = - StandardBundlerParam.JLINK_OPTIONS.fetchFrom(params); + StringWriter writer = new StringWriter(); + PrintWriter pw = new PrintWriter(writer); - LauncherData launcherData = StandardBundlerParam.LAUNCHER_DATA.fetchFrom( - params); + int retVal = LazyLoad.JLINK_TOOL.run(pw, pw, args.toArray(String[]::new)); + String jlinkOut = writer.toString(); - // Modules - if (!launcherData.isModular() && addModules.isEmpty()) { - addModules.add(ALL_DEFAULT); + args.add(0, "jlink"); + Log.verbose(args, List.of(jlinkOut), retVal, -1); + if (retVal != 0) { + throw new PackagerException("error.jlink.failed", jlinkOut); } + } - Set modules = createModuleList(modulePath, addModules, limitModules); + static ModuleFinder createModuleFinder(Collection modulePath) { + return ModuleFinder.compose( + ModulePath.of(JarFile.runtimeVersion(), true, + modulePath.toArray(Path[]::new)), + ModuleFinder.ofSystem()); + } + + static RuntimeBuilder createFromParams(Map params, + List startupInfos) throws ConfigException { + List modulePath = Optional.ofNullable(MODULE_PATH.fetchFrom(params)).orElseGet( + Collections::emptyList); + Set addModules = Optional.ofNullable(ADD_MODULES.fetchFrom(params)).orElseGet( + Collections::emptySet); + Set limitModules = Optional.ofNullable(LIMIT_MODULES.fetchFrom(params)).orElseGet( + Collections::emptySet); + List options = Optional.ofNullable(JLINK_OPTIONS.fetchFrom(params)).orElseGet( + Collections::emptyList); + + return new RuntimeBuilder(createJLinkCmdline(modulePath, addModules, limitModules, options, + startupInfos)); + } - if (launcherData.isModular()) { - modules.add(launcherData.moduleName()); + private static List createJLinkCmdline(List modulePath, Set addModules, + Set limitModules, List options, List startupInfos) throws ConfigException { + List launcherModules = startupInfos.stream().map(si -> { + if (si instanceof LauncherModularStartupInfo siModular) { + return siModular.moduleName(); + } else { + return (String) null; + } + }).filter(Objects::nonNull).toList(); + + if (launcherModules.isEmpty() && addModules.isEmpty()) { + addModules = Set.of(ALL_DEFAULT); + } + + var modules = createModuleList(modulePath, addModules, limitModules); + + modules.addAll(launcherModules); + + var args = new ArrayList(); + if (!modulePath.isEmpty()) { + args.add("--module-path"); + args.add(getPathList(modulePath)); + } + if (!modules.isEmpty()) { + args.add("--add-modules"); + args.add(getStringList(modules)); + } + if (!limitModules.isEmpty()) { + args.add("--limit-modules"); + args.add(getStringList(limitModules)); + } + + for (String option : options) { + switch (option) { + case "--output", "--add-modules", "--module-path" -> { + throw new ConfigException(MessageFormat.format(I18N.getString( + "error.blocked.option"), option), null); + } + default -> { + args.add(option); + } + } } - runJLink(outputDir, modulePath, modules, limitModules, options); + return args; } /* @@ -91,11 +158,11 @@ private static Set getDefaultModules( // the modules in the run-time image that export an API Stream systemRoots = ModuleFinder.ofSystem().findAll().stream() .map(ModuleReference::descriptor) - .filter(JLinkBundlerHelper::exportsAPI) + .filter(RuntimeBuilder::exportsAPI) .map(ModuleDescriptor::name); Set roots = Stream.concat(systemRoots, - addModules.stream()).collect(Collectors.toSet()); + addModules.stream()).collect(Collectors.toSet()); ModuleFinder finder = createModuleFinder(paths); @@ -116,13 +183,6 @@ private static boolean exportsAPI(ModuleDescriptor descriptor) { .anyMatch(e -> !e.isQualified()); } - static ModuleFinder createModuleFinder(Collection modulePath) { - return ModuleFinder.compose( - ModulePath.of(JarFile.runtimeVersion(), true, - modulePath.toArray(Path[]::new)), - ModuleFinder.ofSystem()); - } - private static Set createModuleList(List paths, Set addModules, Set limitModules) { @@ -131,11 +191,11 @@ private static Set createModuleList(List paths, final Map>> phonyModules = Map.of( ALL_MODULE_PATH, () -> createModuleFinder(paths) - .findAll() - .stream() - .map(ModuleReference::descriptor) - .map(ModuleDescriptor::name) - .collect(Collectors.toSet()), + .findAll() + .stream() + .map(ModuleReference::descriptor) + .map(ModuleDescriptor::name) + .collect(Collectors.toSet()), ALL_DEFAULT, () -> getDefaultModules(paths, modules)); @@ -154,64 +214,18 @@ private static Set createModuleList(List paths, return modules; } - private static void runJLink(Path output, List modulePath, - Set modules, Set limitModules, - List options) - throws PackagerException, IOException { - - ArrayList args = new ArrayList(); - args.add("--output"); - args.add(output.toString()); - if (modulePath != null && !modulePath.isEmpty()) { - args.add("--module-path"); - args.add(getPathList(modulePath)); - } - if (modules != null && !modules.isEmpty()) { - args.add("--add-modules"); - args.add(getStringList(modules)); - } - if (limitModules != null && !limitModules.isEmpty()) { - args.add("--limit-modules"); - args.add(getStringList(limitModules)); - } - if (options != null) { - for (String option : options) { - if (option.startsWith("--output") || - option.startsWith("--add-modules") || - option.startsWith("--module-path")) { - throw new PackagerException("error.blocked.option", option); - } - args.add(option); - } - } - - StringWriter writer = new StringWriter(); - PrintWriter pw = new PrintWriter(writer); - - int retVal = LazyLoad.JLINK_TOOL.run(pw, pw, args.toArray(new String[0])); - String jlinkOut = writer.toString(); - - args.add(0, "jlink"); - Log.verbose(args, List.of(jlinkOut), retVal, -1); - - - if (retVal != 0) { - throw new PackagerException("error.jlink.failed" , jlinkOut); - } - } - private static String getPathList(List pathList) { return pathList.stream() .map(Path::toString) - .map(Matcher::quoteReplacement) .collect(Collectors.joining(File.pathSeparator)); } private static String getStringList(Set strings) { - return Matcher.quoteReplacement(strings.stream().collect( - Collectors.joining(","))); + return strings.stream().collect(Collectors.joining(",")); } + private final List jlinkCmdLine; + // The token for "all modules on the module path". private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; @@ -219,6 +233,7 @@ private static String getStringList(Set strings) { private static final String ALL_DEFAULT = "ALL-DEFAULT"; private static class LazyLoad { + static final ToolProvider JLINK_TOOL = ToolProvider.findFirst( "jlink").orElseThrow(); }; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java index a43a195cd863d..7a1b0c804178c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -33,9 +33,6 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; -import static jdk.jpackage.internal.OverridableResource.createResource; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT; /** * Runs custom script from resource directory. @@ -75,12 +72,11 @@ ScriptRunner setEnvironmentVariable(String envVarName, String envVarValue) { return this; } - public void run(Map params) throws IOException { - String scriptName = String.format("%s-%s%s", APP_NAME.fetchFrom(params), + public void run(Workshop workshop, String name) throws IOException { + String scriptName = String.format("%s-%s%s", name, scriptNameSuffix, scriptSuffix()); - Path scriptPath = CONFIG_ROOT.fetchFrom(params).resolve( - scriptName); - createResource(null, params) + Path scriptPath = workshop.configDir().resolve(scriptName); + workshop.createResource(null) .setCategory(I18N.getString(resourceCategoryId)) .saveToFile(scriptPath); if (!Files.exists(scriptPath)) { @@ -100,6 +96,25 @@ public void run(Map params) throws IOException { Executor.of(pb).executeExpectSuccess(); } + public void run(Map params) throws IOException { + run(new Workshop() { + @Override + public Path buildRoot() { + throw new UnsupportedOperationException(); + } + + @Override + public Path resourceDir() { + return StandardBundlerParam.RESOURCE_DIR.fetchFrom(params); + } + + @Override + public Path configDir() { + return StandardBundlerParam.CONFIG_ROOT.fetchFrom(params); + } + }, StandardBundlerParam.APP_NAME.fetchFrom(params)); + } + private static String shell() { if (OperatingSystem.isWindows()) { return "cscript"; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java new file mode 100644 index 0000000000000..151a3d61cf536 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.Map; +import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; + +interface Workshop { + + Path buildRoot(); + + Path resourceDir(); + + /** + * Returns path to the root folder of application image. When building app image this is the + * path to a root directory where application image is assembled. When building a package this + * is the path to input application image. + */ + default Path appImageRoot() { + return buildRoot().resolve("image"); + } + + default Path configDir() { + return buildRoot().resolve("config"); + } + + default OverridableResource createResource(String defaultName) { + return new OverridableResource(defaultName).setResourceDir(resourceDir()); + } + + static Path appImageDir(Workshop workshop, Application app) { + return workshop.appImageRoot().resolve(app.appImageDirName()); + } + + static Path appImageDir(Workshop workshop, Package pkg) { + return workshop.appImageRoot().resolve(pkg.relativeInstallDir()); + } + + record Impl(Path buildRoot, Path resourceDir) implements Workshop { + + } + + static class Proxy implements Workshop { + + Proxy(Workshop target) { + this.target = target; + } + + @Override + public Path buildRoot() { + return target.buildRoot(); + } + + @Override + public Path resourceDir() { + return target.resourceDir(); + } + + private final Workshop target; + } + + static Workshop createFromParams(Map params) throws ConfigException { + var root = StandardBundlerParam.TEMP_ROOT.fetchFrom(params); + var resourceDir = StandardBundlerParam.RESOURCE_DIR.fetchFrom(params); + return new Impl(root, resourceDir); + } + + static final StandardBundlerParam WORKSHOP = new StandardBundlerParam<>( + "workshop", Workshop.class, params -> { + return toFunction(Workshop::createFromParams).apply(params); + }, null); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index 4c5d51d5bcc65..53f012b0e950e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -75,6 +75,7 @@ error.tool-old-version.advice=Please install {0} {1} or newer error.jlink.failed=jlink failed with: {0} error.blocked.option=jlink option [{0}] is not permitted in --jlink-options error.no.name=Name not specified with --name and cannot infer one from app-image +error.no.name.advice=Specify name with --name warning.no.jdk.modules.found=Warning: No JDK Modules found diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java new file mode 100644 index 0000000000000..04830cdcf3a83 --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.Map; +import java.util.stream.Collectors; +import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; +import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; +import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; +import static jdk.jpackage.internal.WinLauncher.WinShortcut.WinShortcutDesktop; +import static jdk.jpackage.internal.WinLauncher.WinShortcut.WinShortcutStartMenu; +import static jdk.jpackage.internal.WindowsAppImageBuilder.CONSOLE_HINT; + +interface WinApplication extends Application { + + static class Impl extends Application.Proxy implements WinApplication { + + Impl(Application app) { + super(app); + } + } + + static WinApplication createFromParams(Map params) throws ConfigException { + var app = Application.createFromParams(params, launcherParams -> { + var launcher = Launcher.createFromParams(launcherParams); + var isConsole = CONSOLE_HINT.fetchFrom(launcherParams); + var shortcuts = Map.of(WinShortcutDesktop, SHORTCUT_HINT, WinShortcutStartMenu, MENU_HINT) + .entrySet().stream().filter(e -> { + return e.getValue().fetchFrom(launcherParams); + }).map(Map.Entry::getKey).collect(Collectors.toSet()); + + return new WinLauncher.Impl(launcher, isConsole, shortcuts); + }); + return new Impl(app); + } + + static final StandardBundlerParam TARGET_APPLICATION = new StandardBundlerParam<>( + Application.PARAM_ID, WinApplication.class, params -> { + return toFunction(WinApplication::createFromParams).apply(params); + }, null); +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java new file mode 100644 index 0000000000000..63bca1b8842ad --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.Set; + +interface WinLauncher extends Launcher { + + @Override + default Path executableName() { + return Path.of(name() + ".exe"); + } + + boolean isConsole(); + + enum WinShortcut { + WinShortcutDesktop, + WinShortcutStartMenu + } + + Set shortcuts(); + + static class Impl extends Launcher.Proxy implements WinLauncher { + Impl(Launcher launcher, boolean isConsole, Set shortcuts) { + super(launcher); + this.isConsole = isConsole; + this.shortcuts = shortcuts; + } + + @Override + public boolean isConsole() { + return isConsole; + } + + @Override + public Set shortcuts() { + return shortcuts; + } + + private final boolean isConsole; + private final Set shortcuts; + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 894d41d764204..086836494400d 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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,6 @@ import java.io.InputStream; import java.io.Writer; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; @@ -44,7 +43,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.xml.parsers.DocumentBuilder; @@ -54,19 +52,6 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.AppImageFile.LauncherInfo; - -import static jdk.jpackage.internal.OverridableResource.createResource; -import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT; -import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; -import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; -import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; -import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; @@ -134,95 +119,6 @@ */ public class WinMsiBundler extends AbstractBundler { - public static final BundlerParamInfo MSI_IMAGE_DIR = - new StandardBundlerParam<>( - "win.msi.imageDir", - Path.class, - params -> { - Path imagesRoot = IMAGES_ROOT.fetchFrom(params); - if (!Files.exists(imagesRoot)) { - try { - Files.createDirectories(imagesRoot); - } catch (IOException ioe) { - return null; - } - } - return imagesRoot.resolve("win-msi.image"); - }, - (s, p) -> null); - - public static final BundlerParamInfo WIN_APP_IMAGE = - new StandardBundlerParam<>( - "win.app.image", - Path.class, - null, - (s, p) -> null); - - static final StandardBundlerParam SERVICE_INSTALLER - = new StandardBundlerParam<>( - "win.msi.serviceInstaller", - InstallableFile.class, - null, - null - ); - - public static final StandardBundlerParam MSI_SYSTEM_WIDE = - new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_PER_USER_INSTALLATION.getId(), - Boolean.class, - params -> true, // MSIs default to system wide - // valueOf(null) is false, - // and we actually do want null - (s, p) -> (s == null || "null".equalsIgnoreCase(s))? null - : Boolean.valueOf(s) - ); - - public static final StandardBundlerParam PRODUCT_VERSION = - new StandardBundlerParam<>( - "win.msi.productVersion", - String.class, - VERSION::fetchFrom, - (s, p) -> s - ); - - private static final BundlerParamInfo HELP_URL = - new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_HELP_URL.getId(), - String.class, - null, - (s, p) -> s); - - private static final BundlerParamInfo UPDATE_URL = - new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_UPDATE_URL.getId(), - String.class, - null, - (s, p) -> s); - - private static final BundlerParamInfo UPGRADE_UUID = - new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_UPGRADE_UUID.getId(), - String.class, - null, - (s, p) -> s); - - private static final BundlerParamInfo INSTALLER_FILE_NAME = - new StandardBundlerParam<> ( - "win.installerName", - String.class, - params -> { - String nm = INSTALLER_NAME.fetchFrom(params); - if (nm == null) return null; - - String version = VERSION.fetchFrom(params); - if (version == null) { - return nm; - } else { - return nm + "-" + version; - } - }, - (s, p) -> s); - public WinMsiBundler() { appImageBundler = new WinAppBundler().setDependentTask(true); wixFragments = Stream.of( @@ -272,27 +168,6 @@ public boolean isDefault() { return false; } - private static UUID getUpgradeCode(Map params) { - String upgradeCode = UPGRADE_UUID.fetchFrom(params); - if (upgradeCode != null) { - return UUID.fromString(upgradeCode); - } - return createNameUUID("UpgradeCode", params, List.of(VENDOR, APP_NAME)); - } - - private static UUID getProductCode(Map params) { - return createNameUUID("ProductCode", params, List.of(VENDOR, APP_NAME, - VERSION)); - } - - private static UUID createNameUUID(String prefix, - Map params, - List> components) { - String key = Stream.concat(Stream.of(prefix), components.stream().map( - c -> c.fetchFrom(params))).collect(Collectors.joining("/")); - return UUID.nameUUIDFromBytes(key.getBytes(StandardCharsets.UTF_8)); - } - @Override public boolean validate(Map params) throws ConfigException { @@ -303,12 +178,6 @@ public boolean validate(Map params) wixToolset = WixTool.toolset(); } - try { - getUpgradeCode(params); - } catch (IllegalArgumentException ex) { - throw new ConfigException(ex); - } - for (var toolInfo: wixToolset.values()) { Log.verbose(MessageFormat.format(I18N.getString( "message.tool-version"), toolInfo.path.getFileName(), @@ -320,27 +189,8 @@ public boolean validate(Map params) wixFragments.get(0).logWixFeatures(); - /********* validate bundle parameters *************/ - - try { - String version = PRODUCT_VERSION.fetchFrom(params); - MsiVersion.of(version); - } catch (IllegalArgumentException ex) { - throw new ConfigException(ex.getMessage(), I18N.getString( - "error.version-string-wrong-format.advice"), ex); - } - FileAssociation.verify(FileAssociation.fetchFrom(params)); - var serviceInstallerResource = initServiceInstallerResource(params); - if (serviceInstallerResource != null) { - if (!Files.exists(serviceInstallerResource.getExternalPath())) { - throw new ConfigException(I18N.getString( - "error.missing-service-installer"), I18N.getString( - "error.missing-service-installer.advice")); - } - } - return true; } catch (RuntimeException re) { if (re.getCause() instanceof ConfigException) { @@ -353,189 +203,151 @@ public boolean validate(Map params) private void prepareProto(Map params) throws PackagerException, IOException { - Path appImage = StandardBundlerParam.getPredefinedAppImage(params); - String appName = APP_NAME.fetchFrom(params); - Path appDir; - if (appName == null) { - // Can happen when no name is given, and using a foreign app-image - throw new PackagerException("error.no.name"); - } + + var pkg = WinMsiPackage.TARGET_PACKAGE.fetchFrom(params); + var workshop = Workshop.WORKSHOP.fetchFrom(params); + + Path appImage = pkg.predefinedAppImage(); // we either have an application image or need to build one if (appImage != null) { - appDir = MSI_IMAGE_DIR.fetchFrom(params).resolve(appName); - // copy everything from appImage dir into appDir/name - IOUtils.copyRecursive(appImage, appDir); + IOUtils.copyRecursive(appImage, Workshop.appImageDir(workshop, pkg)); } else { - appDir = appImageBundler.execute(params, MSI_IMAGE_DIR.fetchFrom( - params)); + Files.createDirectories(workshop.appImageRoot()); + appImageBundler.execute(params, workshop.appImageRoot()); } + var appImageLayout = pkg.appLayout().resolveAt(Workshop.appImageDir(workshop, pkg)); + // Configure installer icon - if (StandardBundlerParam.isRuntimeInstaller(params)) { + if (pkg.isRuntimeInstaller()) { // Use icon from java launcher. // Assume java.exe exists in Java Runtime being packed. // Ignore custom icon if any as we don't want to copy anything in // Java Runtime image. - installerIcon = ApplicationLayout.javaRuntime() - .resolveAt(appDir) - .runtimeDirectory() - .resolve(Path.of("bin", "java.exe")); + installerIcon = appImageLayout.runtimeDirectory().resolve(Path.of("bin", "java.exe")); } else { - var appLayout = ApplicationLayout.windowsAppImage().resolveAt(appDir); - - installerIcon = appLayout.launchersDirectory() - .resolve(appName + ".exe"); + installerIcon = appImageLayout.launchersDirectory().resolve(pkg.app().mainLauncher() + .executableName()); - new PackageFile(appName).save(appLayout); + new PackageFile(pkg.name()).save(appImageLayout); } installerIcon = installerIcon.toAbsolutePath(); - params.put(WIN_APP_IMAGE.getID(), appDir); - - String licenseFile = LICENSE_FILE.fetchFrom(params); + Path licenseFile = pkg.licenseFile(); if (licenseFile != null) { // need to copy license file to the working directory // and convert to rtf if needed - Path lfile = Path.of(licenseFile); - Path destFile = CONFIG_ROOT.fetchFrom(params) - .resolve(lfile.getFileName()); + Path destFile = workshop.configDir().resolve(licenseFile.getFileName()); - IOUtils.copyFile(lfile, destFile); + IOUtils.copyFile(licenseFile, destFile); destFile.toFile().setWritable(true); ensureByMutationFileIsRTF(destFile); } - - var serviceInstallerResource = initServiceInstallerResource(params); - if (serviceInstallerResource != null) { - var serviceInstallerPath = serviceInstallerResource.getExternalPath(); - params.put(SERVICE_INSTALLER.getID(), new InstallableFile( - serviceInstallerPath, serviceInstallerPath.getFileName())); - } } @Override public Path execute(Map params, Path outputParentDir) throws PackagerException { + var pkg = WinMsiPackage.TARGET_PACKAGE.fetchFrom(params); + var workshop = Workshop.WORKSHOP.fetchFrom(params); + IOUtils.writableOutputDir(outputParentDir); - Path imageDir = MSI_IMAGE_DIR.fetchFrom(params); + Path imageDir = Workshop.appImageDir(workshop, pkg); try { - Files.createDirectories(imageDir); - prepareProto(params); - for (var wixFragment : wixFragments) { - wixFragment.initFromParams(params); + wixFragment.initFromParams(workshop, pkg); wixFragment.addFilesToConfigRoot(); } - Map wixVars = prepareMainProjectFile(params); + Map wixVars = prepareMainProjectFile(workshop, pkg); new ScriptRunner() .setDirectory(imageDir) .setResourceCategoryId("resource.post-app-image-script") .setScriptNameSuffix("post-image") .setEnvironmentVariable("JpAppImageDir", imageDir.toAbsolutePath().toString()) - .run(params); + .run(workshop, pkg.name()); - return buildMSI(params, wixVars, outputParentDir); + return buildMSI(workshop, pkg, wixVars, outputParentDir); } catch (IOException ex) { Log.verbose(ex); throw new PackagerException(ex); } } - private long getAppImageSizeKb(Map params) throws - IOException { - ApplicationLayout appLayout; - if (StandardBundlerParam.isRuntimeInstaller(params)) { - appLayout = ApplicationLayout.javaRuntime(); - } else { - appLayout = ApplicationLayout.windowsAppImage(); - } - appLayout = appLayout.resolveAt(WIN_APP_IMAGE.fetchFrom(params)); - - long size = appLayout.sizeInBytes() >> 10; - - return size; - } - - private Map prepareMainProjectFile( - Map params) throws IOException { + private Map prepareMainProjectFile(Workshop workshop, WinMsiPackage pkg) throws IOException { Map data = new HashMap<>(); - final UUID productCode = getProductCode(params); - final UUID upgradeCode = getUpgradeCode(params); - - data.put("JpProductCode", productCode.toString()); - data.put("JpProductUpgradeCode", upgradeCode.toString()); + data.put("JpProductCode", pkg.productCode().toString()); + data.put("JpProductUpgradeCode", pkg.upgradeCode().toString()); Log.verbose(MessageFormat.format(I18N.getString("message.product-code"), - productCode)); + pkg.productCode())); Log.verbose(MessageFormat.format(I18N.getString("message.upgrade-code"), - upgradeCode)); + pkg.upgradeCode())); data.put("JpAllowUpgrades", "yes"); - if (!StandardBundlerParam.isRuntimeInstaller(params)) { + if (!pkg.isRuntimeInstaller()) { data.put("JpAllowDowngrades", "yes"); } - data.put("JpAppName", APP_NAME.fetchFrom(params)); - data.put("JpAppDescription", DESCRIPTION.fetchFrom(params)); - data.put("JpAppVendor", VENDOR.fetchFrom(params)); - data.put("JpAppVersion", PRODUCT_VERSION.fetchFrom(params)); + data.put("JpAppName", pkg.name()); + data.put("JpAppDescription", pkg.description()); + data.put("JpAppVendor", pkg.app().vendor()); + data.put("JpAppVersion", pkg.version()); if (Files.exists(installerIcon)) { data.put("JpIcon", installerIcon.toString()); } - Optional.ofNullable(HELP_URL.fetchFrom(params)).ifPresent(value -> { + Optional.ofNullable(pkg.helpURL()).ifPresent(value -> { data.put("JpHelpURL", value); }); - Optional.ofNullable(UPDATE_URL.fetchFrom(params)).ifPresent(value -> { + Optional.ofNullable(pkg.updateURL()).ifPresent(value -> { data.put("JpUpdateURL", value); }); - Optional.ofNullable(ABOUT_URL.fetchFrom(params)).ifPresent(value -> { + Optional.ofNullable(pkg.aboutURL()).ifPresent(value -> { data.put("JpAboutURL", value); }); - data.put("JpAppSizeKb", Long.toString(getAppImageSizeKb(params))); - - final Path configDir = CONFIG_ROOT.fetchFrom(params); + data.put("JpAppSizeKb", Long.toString(pkg.appLayout().resolveAt(Workshop.appImageDir( + workshop, pkg)).sizeInBytes() >> 10)); - data.put("JpConfigDir", configDir.toAbsolutePath().toString()); + data.put("JpConfigDir", workshop.configDir().toAbsolutePath().toString()); - if (MSI_SYSTEM_WIDE.fetchFrom(params)) { + if (pkg.isSystemWideInstall()) { data.put("JpIsSystemWide", "yes"); } // Copy standard l10n files. for (String loc : Arrays.asList("de", "en", "ja", "zh_CN")) { String fname = "MsiInstallerStrings_" + loc + ".wxl"; - createResource(fname, params) + workshop.createResource(fname) .setCategory(I18N.getString("resource.wxl-file")) - .saveToFile(configDir.resolve(fname)); + .saveToFile(workshop.configDir().resolve(fname)); } - createResource("main.wxs", params) + workshop.createResource("main.wxs") .setCategory(I18N.getString("resource.main-wix-file")) - .saveToFile(configDir.resolve("main.wxs")); + .saveToFile(workshop.configDir().resolve("main.wxs")); - createResource("overrides.wxi", params) + workshop.createResource("overrides.wxi") .setCategory(I18N.getString("resource.overrides-wix-file")) - .saveToFile(configDir.resolve("overrides.wxi")); + .saveToFile(workshop.configDir().resolve("overrides.wxi")); return data; } - private Path buildMSI(Map params, + private Path buildMSI(Workshop workshop, WinMsiPackage pkg, Map wixVars, Path outdir) throws IOException { - Path msiOut = outdir.resolve(INSTALLER_FILE_NAME.fetchFrom(params) + ".msi"); + Path msiOut = outdir.resolve(pkg.installerName()); Log.verbose(MessageFormat.format(I18N.getString( "message.preparing-msi-config"), msiOut.toAbsolutePath() @@ -546,9 +358,9 @@ private Path buildMSI(Map params, Collectors.toMap( entry -> entry.getKey(), entry -> entry.getValue().path))) - .setWixObjDir(TEMP_ROOT.fetchFrom(params).resolve("wixobj")) - .setWorkDir(WIN_APP_IMAGE.fetchFrom(params)) - .addSource(CONFIG_ROOT.fetchFrom(params).resolve("main.wxs"), wixVars); + .setWixObjDir(workshop.buildRoot().resolve("wixobj")) + .setWorkDir(Workshop.appImageDir(workshop, pkg)) + .addSource(workshop.configDir().resolve("main.wxs"), wixVars); for (var wixFragment : wixFragments) { wixFragment.configureWixPipeline(wixPipeline); @@ -559,15 +371,15 @@ private Path buildMSI(Map params, wixPipeline.addLightOptions("-sice:ICE27"); - if (!MSI_SYSTEM_WIDE.fetchFrom(params)) { + if (!pkg.isSystemWideInstall()) { wixPipeline.addLightOptions("-sice:ICE91"); } // Filter out custom l10n files that were already used to // override primary l10n files. Ignore case filename comparison, // both lists are expected to be short. - List primaryWxlFiles = getWxlFilesFromDir(params, CONFIG_ROOT); - List customWxlFiles = getWxlFilesFromDir(params, RESOURCE_DIR).stream() + List primaryWxlFiles = getWxlFilesFromDir(workshop.configDir()); + List customWxlFiles = getWxlFilesFromDir(workshop.resourceDir()).stream() .filter(custom -> primaryWxlFiles.stream().noneMatch(primary -> primary.getFileName().toString().equalsIgnoreCase( custom.getFileName().toString()))) @@ -591,7 +403,7 @@ private Path buildMSI(Map params, } // Append a primary culture bases on runtime locale. - final Path primaryWxlFile = CONFIG_ROOT.fetchFrom(params).resolve( + final Path primaryWxlFile = workshop.configDir().resolve( I18N.getString("resource.wxl-file-name")); cultures.add(getCultureFromWxlFile(primaryWxlFile)); @@ -606,9 +418,7 @@ private Path buildMSI(Map params, return msiOut; } - private static List getWxlFilesFromDir(Map params, - StandardBundlerParam pathParam) throws IOException { - Path dir = pathParam.fetchFrom(params); + private static List getWxlFilesFromDir(Path dir) throws IOException { if (dir == null) { return Collections.emptyList(); } @@ -720,34 +530,6 @@ private static void ensureByMutationFileIsRTF(Path f) { } catch (IOException e) { Log.verbose(e); } - - } - - private static OverridableResource initServiceInstallerResource( - Map params) { - if (StandardBundlerParam.isRuntimeInstaller(params)) { - // Runtime installer doesn't install launchers, - // service installer not needed - return null; - } - - if (!AppImageFile.getLaunchers( - StandardBundlerParam.getPredefinedAppImage(params), params).stream().anyMatch( - LauncherInfo::isService)) { - // Not a single launcher is requested to be installed as a service, - // service installer not needed - return null; - } - - var result = createResource(null, params) - .setPublicName("service-installer.exe") - .setSourceOrder(OverridableResource.Source.External); - if (result.getResourceDir() == null) { - return null; - } - - return result.setExternal(result.getResourceDir().resolve( - result.getPublicName())); } private Path installerIcon; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java new file mode 100644 index 0000000000000..3ec47c031cb77 --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java @@ -0,0 +1,246 @@ + +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; +import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; + +interface WinMsiPackage extends Package { + + boolean withInstallDirChooser(); + + boolean withShortcutPrompt(); + + String helpURL(); + + String updateURL(); + + String startMenuGroupName(); + + boolean isSystemWideInstall(); + + default UUID upgradeCode() { + return createNameUUID("UpgradeCode", app().vendor(), name()); + } + + default UUID productCode() { + return createNameUUID("ProductCode", app().vendor(), name(), version()); + } + + Path serviceInstaller(); + + static class Impl extends Package.Proxy implements WinMsiPackage { + + Impl(Package pkg, boolean withInstallDirChooser, boolean withShortcutPrompt, String helpURL, + String updateURL, String startMenuGroupName, boolean isSystemWideInstall, + UUID upgradeCode, Path serviceInstaller) { + super(pkg); + this.withInstallDirChooser = withInstallDirChooser; + this.withShortcutPrompt = withShortcutPrompt; + this.helpURL = helpURL; + this.updateURL = updateURL; + this.startMenuGroupName = startMenuGroupName; + this.isSystemWideInstall = isSystemWideInstall; + this.upgradeCode = upgradeCode; + this.serviceInstaller = serviceInstaller; + } + + @Override + public boolean withInstallDirChooser() { + return withInstallDirChooser; + } + + @Override + public boolean withShortcutPrompt() { + return withShortcutPrompt; + } + + @Override + public String helpURL() { + return helpURL; + } + + @Override + public String updateURL() { + return updateURL; + } + + @Override + public String startMenuGroupName() { + return startMenuGroupName; + } + + @Override + public boolean isSystemWideInstall() { + return isSystemWideInstall; + } + + @Override + public UUID upgradeCode() { + if (upgradeCode == null) { + return WinMsiPackage.super.upgradeCode(); + } else { + return upgradeCode; + } + } + + @Override + public Path serviceInstaller() { + return serviceInstaller; + } + + private final boolean withInstallDirChooser; + private final boolean withShortcutPrompt; + private final String helpURL; + private final String updateURL; + private final String startMenuGroupName; + private final boolean isSystemWideInstall; + private final UUID upgradeCode; + private final Path serviceInstaller; + } + + private static WinMsiPackage createFromParams(Map params) throws ConfigException { + var pkg = Package.createFromParams(params, WinApplication.createFromParams(params), + PackageType.WinMsi); + var withInstallDirChooser = Internal.INSTALLDIR_CHOOSER.fetchFrom(params); + var withShortcutPrompt = Internal.SHORTCUT_PROMPT.fetchFrom(params); + var helpURL = Internal.HELP_URL.fetchFrom(params); + var updateURL = Internal.UPDATE_URL.fetchFrom(params); + var startMenuGroupName = Internal.MENU_GROUP.fetchFrom(params); + var isSystemWideInstall = Internal.MSI_SYSTEM_WIDE.fetchFrom(params); + var upgradeCode = getUpgradeCode(params); + + try { + MsiVersion.of(pkg.version()); + } catch (IllegalArgumentException ex) { + throw new ConfigException(ex.getMessage(), I18N.getString( + "error.version-string-wrong-format.advice"), ex); + } + + Path serviceInstaller = null; + if (!pkg.app().isService()) { + serviceInstaller = null; + } else { + Path resourceDir = RESOURCE_DIR.fetchFrom(params); + if (resourceDir != null) { + serviceInstaller = resourceDir.resolve("service-installer.exe"); + if (Files.exists(serviceInstaller)) { + throw new ConfigException(I18N.getString( + "error.missing-service-installer"), I18N.getString( + "error.missing-service-installer.advice")); + } + } + } + + return new Impl(pkg, withInstallDirChooser, withShortcutPrompt, helpURL, updateURL, + startMenuGroupName, isSystemWideInstall, upgradeCode, serviceInstaller); + } + + private static UUID getUpgradeCode(Map params) throws ConfigException { + try { + return Optional.ofNullable(Internal.UPGRADE_UUID.fetchFrom(params)) + .map(UUID::fromString).orElse( + null); + } catch (IllegalArgumentException ex) { + throw new ConfigException(ex); + } + } + + private static UUID createNameUUID(String... components) { + String key = String.join("/", components); + return UUID.nameUUIDFromBytes(key.getBytes(StandardCharsets.UTF_8)); + } + + static class Internal { + + private static final BundlerParamInfo INSTALLDIR_CHOOSER + = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_DIR_CHOOSER.getId(), + Boolean.class, + params -> false, + (s, p) -> Boolean.valueOf(s) + ); + + private static final StandardBundlerParam SHORTCUT_PROMPT + = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_SHORTCUT_PROMPT.getId(), + Boolean.class, + params -> false, + (s, p) -> Boolean.valueOf(s) + ); + + private static final StandardBundlerParam MENU_GROUP + = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_MENU_GROUP.getId(), + String.class, + params -> I18N.getString("param.menu-group.default"), + (s, p) -> s + ); + + private static final StandardBundlerParam MSI_SYSTEM_WIDE + = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_PER_USER_INSTALLATION.getId(), + Boolean.class, + params -> true, // MSIs default to system wide + // valueOf(null) is false, + // and we actually do want null + (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? null + : Boolean.valueOf(s) + ); + + private static final BundlerParamInfo HELP_URL + = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_HELP_URL.getId(), + String.class, + null, + (s, p) -> s); + + private static final BundlerParamInfo UPDATE_URL + = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_UPDATE_URL.getId(), + String.class, + null, + (s, p) -> s); + + private static final BundlerParamInfo UPGRADE_UUID + = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_UPGRADE_UUID.getId(), + String.class, + null, + (s, p) -> s); + } + + static final StandardBundlerParam TARGET_PACKAGE = new StandardBundlerParam<>( + Package.PARAM_ID, WinMsiPackage.class, params -> { + return toFunction(WinMsiPackage::createFromParams).apply(params); + }, null); +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index cf7338f7d0b48..54a3d1adf87e6 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -29,10 +29,8 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Files; -import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; @@ -55,48 +53,34 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.AppImageFile.LauncherInfo; +import static jdk.jpackage.internal.Functional.toCollection; import jdk.jpackage.internal.IOUtils.XmlConsumer; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.WinMsiBundler.MSI_SYSTEM_WIDE; -import static jdk.jpackage.internal.WinMsiBundler.SERVICE_INSTALLER; -import static jdk.jpackage.internal.WinMsiBundler.WIN_APP_IMAGE; +import jdk.jpackage.internal.WinLauncher.WinShortcut; import org.w3c.dom.NodeList; /** * Creates WiX fragment with components for contents of app image. */ -class WixAppImageFragmentBuilder extends WixFragmentBuilder { +final class WixAppImageFragmentBuilder extends WixFragmentBuilder { @Override - void initFromParams(Map params) { - super.initFromParams(params); + void initFromParams(Workshop workshop, WinMsiPackage pkg) { + super.initFromParams(workshop, pkg); - Path appImageRoot = WIN_APP_IMAGE.fetchFrom(params); + Path appImageRoot = Workshop.appImageDir(workshop, pkg); - Supplier appImageSupplier = () -> { - if (StandardBundlerParam.isRuntimeInstaller(params)) { - return ApplicationLayout.javaRuntime(); - } else { - return ApplicationLayout.platformAppImage(); - } - }; - - systemWide = MSI_SYSTEM_WIDE.fetchFrom(params); + systemWide = pkg.isSystemWideInstall(); registryKeyPath = Path.of("Software", - VENDOR.fetchFrom(params), - APP_NAME.fetchFrom(params), - VERSION.fetchFrom(params)).toString(); + pkg.app().vendor(), + pkg.app().name(), + pkg.app().version()).toString(); - installDir = (systemWide ? PROGRAM_FILES : LOCAL_PROGRAM_FILES).resolve( - WINDOWS_INSTALL_DIR.fetchFrom(params)); + installDir = (systemWide ? PROGRAM_FILES : LOCAL_PROGRAM_FILES).resolve(pkg. + relativeInstallDir()); do { - ApplicationLayout layout = appImageSupplier.get(); + ApplicationLayout layout = pkg.appLayout(); // Don't want AppImageFile.FILENAME in installed application. new InstallableFile(AppImageFile.getPathInAppImage(Path.of("")), null).excludeFromApplicationLayout(layout); @@ -107,42 +91,33 @@ void initFromParams(Map params) { appImage = layout.resolveAt(appImageRoot.toAbsolutePath().normalize()); } while (false); - installedAppImage = appImageSupplier.get().resolveAt(INSTALLDIR); + installedAppImage = pkg.appLayout().resolveAt(INSTALLDIR); - shortcutFolders = Stream.of(ShortcutsFolder.values()).filter( - shortcutFolder -> shortcutFolder.requested(params)).collect( - Collectors.toSet()); + launchers = toCollection(pkg.app().allLaunchers()); - if (StandardBundlerParam.isRuntimeInstaller(params)) { - launchers = Collections.emptyList(); - } else { - launchers = AppImageFile.getLaunchers(appImageRoot, params); - } + shortcutFolders = ShortcutsFolder.getForPackage(pkg); launchersAsServices = launchers.stream() - .filter(LauncherInfo::isService) + .filter(Launcher::isService) .map(launcher -> { - var launcherPath = addExeSuffixToPath( - installedAppImage.launchersDirectory().resolve( - launcher.getName())); + var launcherPath = installedAppImage.launchersDirectory().resolve(launcher.executableName()); var id = Id.File.of(launcherPath); - return new WixLauncherAsService(launcher.getName(), params) + return new WixLauncherAsService(launcher, workshop::createResource) .setLauncherInstallPath(toWixPath(launcherPath)) .setLauncherInstallPathId(id); }).toList(); if (!launchersAsServices.isEmpty()) { - serviceInstaller = SERVICE_INSTALLER.fetchFrom(params); // Service installer tool will be installed in launchers directory serviceInstaller = new InstallableFile( - serviceInstaller.srcPath().toAbsolutePath().normalize(), + pkg.serviceInstaller(), installedAppImage.launchersDirectory().resolve( serviceInstaller.installPath())); } - programMenuFolderName = MENU_GROUP.fetchFrom(params); + programMenuFolderName = pkg.startMenuGroupName(); - initFileAssociations(params); + initFileAssociations(pkg); } @Override @@ -199,8 +174,10 @@ private Path getInstalledFaIcoPath(FileAssociation fa) { return installedAppImage.destktopIntegrationDirectory().resolve(fname); } - private void initFileAssociations(Map params) { - associations = FileAssociation.fetchFrom(params).stream() + private void initFileAssociations(WinMsiPackage pkg) { + var allFileAssociations = pkg.app().allLaunchers().stream().map(Launcher::fileAssociations) + .flatMap(List::stream).toList(); + associations = allFileAssociations.stream() .peek(this::normalizeFileAssociation) // Filter out file associations without extensions. .filter(fa -> !fa.extensions.isEmpty()) @@ -445,14 +422,10 @@ private void addShortcutComponentGroup(XMLStreamWriter xml) throws Set defineShortcutFolders = new HashSet<>(); for (var launcher : launchers) { for (var folder : shortcutFolders) { - Path launcherPath = addExeSuffixToPath(installedAppImage - .launchersDirectory().resolve(launcher.getName())); - - if ((launcher.isMenu() && - (folder.equals(ShortcutsFolder.ProgramMenu))) || - (launcher.isShortcut() && - (folder.equals(ShortcutsFolder.Desktop)))) { + Path launcherPath = installedAppImage.launchersDirectory().resolve(launcher + .executableName()); + if (folder.isRequestedFor(launcher)) { String componentId = addShortcutComponent(xml, launcherPath, folder); @@ -858,22 +831,15 @@ private static IllegalArgumentException throwInvalidPathException(Path v) { } enum ShortcutsFolder { - ProgramMenu(PROGRAM_MENU_PATH, Arguments.CLIOptions.WIN_MENU_HINT, + ProgramMenu(PROGRAM_MENU_PATH, WinShortcut.WinShortcutDesktop, "JP_INSTALL_STARTMENU_SHORTCUT", "JpStartMenuShortcutPrompt"), - Desktop(DESKTOP_PATH, Arguments.CLIOptions.WIN_SHORTCUT_HINT, + Desktop(DESKTOP_PATH, WinShortcut.WinShortcutStartMenu, "JP_INSTALL_DESKTOP_SHORTCUT", "JpDesktopShortcutPrompt"); - private ShortcutsFolder(Path root, Arguments.CLIOptions cliOption, + private ShortcutsFolder(Path root, WinShortcut shortcutId, String property, String wixVariableName) { this.root = root; - this.bundlerParam = new StandardBundlerParam<>( - cliOption.getId(), - Boolean.class, - params -> false, - // valueOf(null) is false, - // and we actually do want null in some cases - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s) - ); + this.shortcutId = shortcutId; this.wixVariableName = wixVariableName; this.property = property; } @@ -885,18 +851,26 @@ Path getPath(WixAppImageFragmentBuilder outer) { return root; } - boolean requested(Map params) { - return bundlerParam.fetchFrom(params); + boolean isRequestedFor(WinLauncher launcher) { + return launcher.shortcuts().contains(shortcutId); } String getWixVariableName() { return wixVariableName; } + static Set getForPackage(WinMsiPackage pkg) { + return pkg.app().allLaunchers().stream().map(launcher -> { + return Stream.of(ShortcutsFolder.values()).filter(shortcutsFolder -> { + return shortcutsFolder.isRequestedFor((WinLauncher)launcher); + }); + }).flatMap(Function.identity()).collect(Collectors.toSet()); + } + private final Path root; private final String property; private final String wixVariableName; - private final StandardBundlerParam bundlerParam; + private final WinShortcut shortcutId; } private boolean systemWide; @@ -911,7 +885,7 @@ String getWixVariableName() { private Set shortcutFolders; - private List launchers; + private List launchers; private List launchersAsServices; @@ -947,38 +921,4 @@ String getWixVariableName() { private static final Set USER_PROFILE_DIRS = Set.of(LOCAL_PROGRAM_FILES, PROGRAM_MENU_PATH, DESKTOP_PATH); - - private static final StandardBundlerParam MENU_GROUP = - new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_MENU_GROUP.getId(), - String.class, - params -> I18N.getString("param.menu-group.default"), - (s, p) -> s - ); - - private static final BundlerParamInfo WINDOWS_INSTALL_DIR = - new StandardBundlerParam<>( - "windows-install-dir", - String.class, - params -> { - String dir = INSTALL_DIR.fetchFrom(params); - if (dir != null) { - if (dir.contains(":") || dir.contains("..")) { - Log.error(MessageFormat.format(I18N.getString( - "message.invalid.install.dir"), dir, - APP_NAME.fetchFrom(params))); - } else { - if (dir.startsWith("\\")) { - dir = dir.substring(1); - } - if (dir.endsWith("\\")) { - dir = dir.substring(0, dir.length() - 1); - } - return dir; - } - } - return APP_NAME.fetchFrom(params); // Default to app name - }, - (s, p) -> s - ); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java index bc98899c65985..b618cebd707db 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java @@ -33,15 +33,12 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.stream.XMLStreamWriter; import jdk.jpackage.internal.IOUtils.XmlConsumer; import jdk.jpackage.internal.OverridableResource.Source; -import static jdk.jpackage.internal.OverridableResource.createResource; -import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT; import jdk.internal.util.Architecture; /** @@ -57,12 +54,11 @@ void setOutputFileName(String v) { outputFileName = v; } - void initFromParams(Map params) { + void initFromParams(Workshop workshop, WinMsiPackage pkg) { wixVariables = null; additionalResources = null; - configRoot = CONFIG_ROOT.fetchFrom(params); - fragmentResource = createResource(outputFileName, params).setSourceOrder( - Source.ResourceDir); + configRoot = workshop.configDir(); + fragmentResource = workshop.createResource(outputFileName).setSourceOrder(Source.ResourceDir); } void logWixFeatures() { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java index 9b737c8e1a4b6..54e6f3311fe82 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java @@ -29,7 +29,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Map; +import java.util.function.Function; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import javax.xml.transform.Source; @@ -38,7 +38,6 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import static jdk.jpackage.internal.OverridableResource.createResource; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -46,12 +45,12 @@ class WixLauncherAsService extends LauncherAsService { - WixLauncherAsService(String name, Map mainParams) { - super(name, mainParams, - createResource("service-install.wxi", mainParams).setCategory( + WixLauncherAsService(WinLauncher launcher, Function createResource) { + super(launcher, + createResource.apply("service-install.wxi").setCategory( I18N.getString("resource.launcher-as-service-wix-file"))); - serviceConfigResource = createResource("service-config.wxi", mainParams).setCategory( + serviceConfigResource = createResource.apply("service-config.wxi").setCategory( I18N.getString("resource.launcher-as-service-wix-file")); addSubstitutionDataEntry("SERVICE_NAME", getName()); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java index 8d20d6432bf3a..219e2ab7dd766 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, 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 @@ -36,12 +36,9 @@ import java.util.Objects; import java.util.function.Function; import java.util.function.Supplier; -import java.util.stream.Stream; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import jdk.jpackage.internal.IOUtils.XmlConsumer; -import static jdk.jpackage.internal.OverridableResource.createResource; -import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; import jdk.jpackage.internal.WixAppImageFragmentBuilder.ShortcutsFolder; /** @@ -50,31 +47,27 @@ final class WixUiFragmentBuilder extends WixFragmentBuilder { @Override - void initFromParams(Map params) { - super.initFromParams(params); + void initFromParams(Workshop workshop, WinMsiPackage pkg) { + super.initFromParams(workshop, pkg); - String licenseFile = LICENSE_FILE.fetchFrom(params); + Path licenseFile = pkg.licenseFile(); withLicenseDlg = licenseFile != null; if (withLicenseDlg) { - Path licenseFileName = IOUtils.getFileName(Path.of(licenseFile)); + Path licenseFileName = IOUtils.getFileName(licenseFile); Path destFile = getConfigRoot().resolve(licenseFileName); setWixVariable("JpLicenseRtf", destFile.toAbsolutePath().toString()); } - withInstallDirChooserDlg = INSTALLDIR_CHOOSER.fetchFrom(params); + withInstallDirChooserDlg = pkg.withInstallDirChooser(); - List shortcutFolders = Stream.of( - ShortcutsFolder.values()).filter(shortcutFolder -> { - return shortcutFolder.requested(params) - && SHORTCUT_PROMPT.fetchFrom(params); - }).toList(); + var shortcutFolders = ShortcutsFolder.getForPackage(pkg); withShortcutPromptDlg = !shortcutFolders.isEmpty(); customDialogs = new ArrayList<>(); if (withShortcutPromptDlg) { - CustomDialog dialog = new CustomDialog(params, I18N.getString( + CustomDialog dialog = new CustomDialog(workshop::createResource, I18N.getString( "resource.shortcutpromptdlg-wix-file"), "ShortcutPromptDlg.wxs"); for (var shortcutFolder : shortcutFolders) { @@ -85,7 +78,7 @@ void initFromParams(Map params) { } if (withInstallDirChooserDlg) { - CustomDialog dialog = new CustomDialog(params, I18N.getString( + CustomDialog dialog = new CustomDialog(workshop::createResource, I18N.getString( "resource.installdirnotemptydlg-wix-file"), "InstallDirNotEmptyDlg.wxs"); List dialogIds = getUI().dialogIdsSupplier.apply(this); @@ -458,14 +451,12 @@ private static void writePublishDialogPair(XMLStreamWriter xml, private final class CustomDialog { - CustomDialog(Map params, String category, + CustomDialog(Function createResource, String category, String wxsFileName) { this.wxsFileName = wxsFileName; this.wixVariables = new WixVariables(); - addResource( - createResource(wxsFileName, params).setCategory(category), - wxsFileName); + addResource(createResource.apply(wxsFileName).setCategory(category), wxsFileName); } void addToWixPipeline(WixPipeline wixPipeline) { @@ -482,20 +473,4 @@ void addToWixPipeline(WixPipeline wixPipeline) { private boolean withLicenseDlg; private boolean withCustomActionsDll = true; private List customDialogs; - - private static final BundlerParamInfo INSTALLDIR_CHOOSER - = new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_DIR_CHOOSER.getId(), - Boolean.class, - params -> false, - (s, p) -> Boolean.valueOf(s) - ); - - private static final StandardBundlerParam SHORTCUT_PROMPT - = new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_SHORTCUT_PROMPT.getId(), - Boolean.class, - params -> false, - (s, p) -> Boolean.valueOf(s) - ); } From 8bff511d5e5dc4779bd1169a86033ab63bd2ac64 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 12 Jun 2024 23:35:56 -0400 Subject: [PATCH 0002/1101] Bugfix. All unpack tests pass --- .../jdk/jpackage/internal/Application.java | 3 +- .../jdk/jpackage/internal/Arguments.java | 4 +- .../jdk/jpackage/internal/Launcher.java | 27 +++++++---- .../jdk/jpackage/internal/Package.java | 29 +++++++++--- .../jdk/jpackage/internal/Workshop.java | 46 +++++++++++++------ .../jdk/jpackage/internal/WinApplication.java | 38 +++++++++++++-- .../jdk/jpackage/internal/WinMsiBundler.java | 18 ++++---- .../jdk/jpackage/internal/WinMsiPackage.java | 10 ++-- .../internal/WixAppImageFragmentBuilder.java | 11 ++--- 9 files changed, 132 insertions(+), 54 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java index 4bd0792aafdb9..2560af5fb95d1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java @@ -41,7 +41,6 @@ import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; @@ -213,7 +212,7 @@ static Application createFromParams(Map params, mainParams), APP_NAME.fetchFrom(launcherParams))); } return AddLauncherArguments.merge(mainParams, launcherParams, ICON.getID(), ADD_LAUNCHERS - .getID(), FILE_ASSOCIATIONS.getID(), PREDEFINED_APP_IMAGE.getID()); + .getID(), FILE_ASSOCIATIONS.getID()); } final static String PARAM_ID = "target.application"; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java index 16cd89d9d52d0..65c88da658963 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java @@ -143,7 +143,9 @@ public Arguments(String[] args) { // CLIOptions is public for DeployParamsTest public enum CLIOptions { PACKAGE_TYPE("type", "t", OptionCategories.PROPERTY, () -> { - context().deployParams.setTargetFormat(popArg()); + var type = popArg(); + context().deployParams.setTargetFormat(type); + setOptionValue("type", type); }), INPUT ("input", "i", OptionCategories.PROPERTY, () -> { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java index 161057582e409..57d1a02116878 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java @@ -27,6 +27,12 @@ import java.nio.file.Path; import java.util.List; import java.util.Map; +import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; +import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; +import static jdk.jpackage.internal.StandardBundlerParam.RELEASE; +import static jdk.jpackage.internal.StandardBundlerParam.VERSION; interface Launcher { @@ -49,8 +55,8 @@ default Path executableName() { String description(); /** - * null for the default or resource directory icon empty path for not icon any other value for - * custom icon + * Null for the default or resource directory icon, empty path for no icon, other value for + * custom icon. */ Path icon(); @@ -110,12 +116,17 @@ public Path icon() { } static Launcher createFromParams(Map params) { - var name = StandardBundlerParam.APP_NAME.fetchFrom(params); - var startupInfo = LauncherStartupInfo.createFromParams(params); - var isService = StandardBundlerParam.LAUNCHER_AS_SERVICE.fetchFrom(params); - var version = StandardBundlerParam.VERSION.fetchFrom(params); - var release = StandardBundlerParam.RELEASE.fetchFrom(params); - var description = StandardBundlerParam.DESCRIPTION.fetchFrom(params); + var name = APP_NAME.fetchFrom(params); + + LauncherStartupInfo startupInfo = null; + if (PREDEFINED_APP_IMAGE.fetchFrom(params) == null) { + startupInfo = LauncherStartupInfo.createFromParams(params); + } + + var isService = LAUNCHER_AS_SERVICE.fetchFrom(params); + var version = VERSION.fetchFrom(params); + var release = RELEASE.fetchFrom(params); + var description = DESCRIPTION.fetchFrom(params); var icon = StandardBundlerParam.ICON.fetchFrom(params); var fa = FileAssociation.fetchFrom(params); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index 058a030211fae..98da34e53df9c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -27,9 +27,11 @@ import java.nio.file.Path; import java.util.Map; import java.util.Optional; +import java.util.stream.Stream; +import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; +import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; @@ -53,6 +55,12 @@ String suffix() { return suffix; } + static PackageType fromCmdLineType(String type) { + return Stream.of(values()).filter(pt -> { + return pt.suffix().substring(1).equals(type); + }).findAny().get(); + } + private final String suffix; } @@ -163,7 +171,7 @@ public Path relativeInstallDir() { static Package createFromParams(Map params, Application app, PackageType type) throws ConfigException { - var name = Optional.ofNullable(APP_NAME.fetchFrom(params)).orElseGet(app::name); + var name = Optional.ofNullable(INSTALLER_NAME.fetchFrom(params)).orElseGet(app::name); var description = Optional.ofNullable(DESCRIPTION.fetchFrom(params)).orElseGet(app::name); var version = Optional.ofNullable(VERSION.fetchFrom(params)).orElseGet(app::version); var aboutURL = ABOUT_URL.fetchFrom(params); @@ -174,10 +182,10 @@ static Package createFromParams(Map params, Application .orElseGet(() -> { switch (type) { case WinExe, WinMsi -> { - return Path.of(name); + return app.appImageDirName(); } case LinuxDeb, LinuxRpm -> { - return Path.of("/opt").resolve(name); + return Path.of("/opt").resolve(app.appImageDirName()); } case MacDmg, MacPkg -> { String root; @@ -186,7 +194,7 @@ static Package createFromParams(Map params, Application } else { root = "/Applications"; } - return Path.of(root).resolve(name + ".app"); + return Path.of(root).resolve(app.appImageDirName()); } default -> { throw new IllegalArgumentException(); @@ -200,6 +208,15 @@ static Package createFromParams(Map params, Application return new Impl(app, type, name, description, version, aboutURL, licenseFile, predefinedAppImage, relativeInstallDir); } - + final static String PARAM_ID = "target.package"; + + static final StandardBundlerParam TARGET_PACKAGE = new StandardBundlerParam<>( + PARAM_ID, Package.class, params -> { + return toSupplier(() -> { + return Package.createFromParams(params, Application.TARGET_APPLICATION + .fetchFrom(params), PackageType.fromCmdLineType(Workshop.PACKAGE_TYPE + .fetchFrom(params))); + }).get(); + }, null); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java index 151a3d61cf536..ffc9a415ffe39 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java @@ -26,6 +26,7 @@ import java.nio.file.Path; import java.util.Map; +import jdk.internal.util.OperatingSystem; import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; interface Workshop { @@ -35,11 +36,11 @@ interface Workshop { Path resourceDir(); /** - * Returns path to the root folder of application image. When building app image this is the - * path to a root directory where application image is assembled. When building a package this - * is the path to input application image. + * Returns path to application image directory. When building app image this is the path to a + * directory where it is assembled. When building a package this is the path to the source app + * image. */ - default Path appImageRoot() { + default Path appImageDir() { return buildRoot().resolve("image"); } @@ -51,14 +52,6 @@ default OverridableResource createResource(String defaultName) { return new OverridableResource(defaultName).setResourceDir(resourceDir()); } - static Path appImageDir(Workshop workshop, Application app) { - return workshop.appImageRoot().resolve(app.appImageDirName()); - } - - static Path appImageDir(Workshop workshop, Package pkg) { - return workshop.appImageRoot().resolve(pkg.relativeInstallDir()); - } - record Impl(Path buildRoot, Path resourceDir) implements Workshop { } @@ -85,11 +78,38 @@ public Path resourceDir() { static Workshop createFromParams(Map params) throws ConfigException { var root = StandardBundlerParam.TEMP_ROOT.fetchFrom(params); var resourceDir = StandardBundlerParam.RESOURCE_DIR.fetchFrom(params); - return new Impl(root, resourceDir); + + var defaultWorkshop = new Impl(root, resourceDir); + + Path appImageDir; + if (StandardBundlerParam.isRuntimeInstaller(params)) { + appImageDir = StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); + } else if (StandardBundlerParam.hasPredefinedAppImage(params)) { + appImageDir = StandardBundlerParam.getPredefinedAppImage(params); + } else { + Path dir; + if (PACKAGE_TYPE.fetchFrom(params).equals("app-image") || OperatingSystem.isWindows()) { + dir = Application.TARGET_APPLICATION.fetchFrom(params).appImageDirName(); + } else { + dir = Package.TARGET_PACKAGE.fetchFrom(params).relativeInstallDir(); + } + + appImageDir = defaultWorkshop.buildRoot().resolve("image").resolve(dir); + } + + return new Proxy(defaultWorkshop) { + @Override + public Path appImageDir() { + return appImageDir; + } + }; } static final StandardBundlerParam WORKSHOP = new StandardBundlerParam<>( "workshop", Workshop.class, params -> { return toFunction(Workshop::createFromParams).apply(params); }, null); + + static final StandardBundlerParam PACKAGE_TYPE = new StandardBundlerParam<>( + Arguments.CLIOptions.PACKAGE_TYPE.getId(), String.class, null, null); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java index 04830cdcf3a83..18100f4659d4c 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java @@ -24,8 +24,11 @@ */ package jdk.jpackage.internal; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import static jdk.jpackage.internal.Arguments.CLIOptions.WIN_MENU_HINT; +import static jdk.jpackage.internal.Arguments.CLIOptions.WIN_SHORTCUT_HINT; import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; @@ -45,11 +48,17 @@ static class Impl extends Application.Proxy implements WinApplication { static WinApplication createFromParams(Map params) throws ConfigException { var app = Application.createFromParams(params, launcherParams -> { var launcher = Launcher.createFromParams(launcherParams); - var isConsole = CONSOLE_HINT.fetchFrom(launcherParams); - var shortcuts = Map.of(WinShortcutDesktop, SHORTCUT_HINT, WinShortcutStartMenu, MENU_HINT) - .entrySet().stream().filter(e -> { - return e.getValue().fetchFrom(launcherParams); - }).map(Map.Entry::getKey).collect(Collectors.toSet()); + boolean isConsole = CONSOLE_HINT.fetchFrom(launcherParams); + + var shortcuts = Map.of(WinShortcutDesktop, List.of(SHORTCUT_HINT, + Internal.WIN_SHORTCUT_HINT_PARAM), WinShortcutStartMenu, + List.of(MENU_HINT, Internal.WIN_MENU_HINT_PARAM)).entrySet().stream().filter( + e -> { + return e.getValue().stream().allMatch(param -> { + return param.fetchFrom(launcherParams); + }); + }).map( + Map.Entry::getKey).collect(Collectors.toSet()); return new WinLauncher.Impl(launcher, isConsole, shortcuts); }); @@ -60,4 +69,23 @@ static WinApplication createFromParams(Map params) throw Application.PARAM_ID, WinApplication.class, params -> { return toFunction(WinApplication::createFromParams).apply(params); }, null); + + static final class Internal { + + private static final StandardBundlerParam WIN_MENU_HINT_PARAM = new StandardBundlerParam<>( + WIN_MENU_HINT.getId(), + Boolean.class, + p -> false, + // valueOf(null) is false, + // and we actually do want null in some cases + (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); + + private static final StandardBundlerParam WIN_SHORTCUT_HINT_PARAM = new StandardBundlerParam<>( + WIN_SHORTCUT_HINT.getId(), + Boolean.class, + p -> false, + // valueOf(null) is false, + // and we actually do want null in some cases + (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); + } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 086836494400d..49f89e9f57aa8 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -204,6 +204,7 @@ public boolean validate(Map params) private void prepareProto(Map params) throws PackagerException, IOException { + // Order is important! var pkg = WinMsiPackage.TARGET_PACKAGE.fetchFrom(params); var workshop = Workshop.WORKSHOP.fetchFrom(params); @@ -211,13 +212,13 @@ private void prepareProto(Map params) // we either have an application image or need to build one if (appImage != null) { - IOUtils.copyRecursive(appImage, Workshop.appImageDir(workshop, pkg)); + IOUtils.copyRecursive(appImage, workshop.appImageDir()); } else { - Files.createDirectories(workshop.appImageRoot()); - appImageBundler.execute(params, workshop.appImageRoot()); + Files.createDirectories(workshop.appImageDir().getParent()); + appImageBundler.execute(params, workshop.appImageDir().getParent()); } - var appImageLayout = pkg.appLayout().resolveAt(Workshop.appImageDir(workshop, pkg)); + var appImageLayout = pkg.appLayout().resolveAt(workshop.appImageDir()); // Configure installer icon if (pkg.isRuntimeInstaller()) { @@ -250,12 +251,13 @@ private void prepareProto(Map params) public Path execute(Map params, Path outputParentDir) throws PackagerException { + // Order is important! var pkg = WinMsiPackage.TARGET_PACKAGE.fetchFrom(params); var workshop = Workshop.WORKSHOP.fetchFrom(params); IOUtils.writableOutputDir(outputParentDir); - Path imageDir = Workshop.appImageDir(workshop, pkg); + Path imageDir = workshop.appImageDir(); try { prepareProto(params); for (var wixFragment : wixFragments) { @@ -315,8 +317,8 @@ private Map prepareMainProjectFile(Workshop workshop, WinMsiPack data.put("JpAboutURL", value); }); - data.put("JpAppSizeKb", Long.toString(pkg.appLayout().resolveAt(Workshop.appImageDir( - workshop, pkg)).sizeInBytes() >> 10)); + data.put("JpAppSizeKb", Long.toString(pkg.appLayout().resolveAt(workshop.appImageDir()) + .sizeInBytes() >> 10)); data.put("JpConfigDir", workshop.configDir().toAbsolutePath().toString()); @@ -359,7 +361,7 @@ private Path buildMSI(Workshop workshop, WinMsiPackage pkg, entry -> entry.getKey(), entry -> entry.getValue().path))) .setWixObjDir(workshop.buildRoot().resolve("wixobj")) - .setWorkDir(Workshop.appImageDir(workshop, pkg)) + .setWorkDir(workshop.appImageDir()) .addSource(workshop.configDir().resolve("main.wxs"), wixVars); for (var wixFragment : wixFragments) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java index 3ec47c031cb77..a9f22bf83a294 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java @@ -49,11 +49,11 @@ interface WinMsiPackage extends Package { boolean isSystemWideInstall(); default UUID upgradeCode() { - return createNameUUID("UpgradeCode", app().vendor(), name()); + return createNameUUID("UpgradeCode", app().vendor(), app().name()); } default UUID productCode() { - return createNameUUID("ProductCode", app().vendor(), name(), version()); + return createNameUUID("ProductCode", app().vendor(), app().name(), version()); } Path serviceInstaller(); @@ -153,7 +153,7 @@ private static WinMsiPackage createFromParams(Map params Path resourceDir = RESOURCE_DIR.fetchFrom(params); if (resourceDir != null) { serviceInstaller = resourceDir.resolve("service-installer.exe"); - if (Files.exists(serviceInstaller)) { + if (!Files.exists(serviceInstaller)) { throw new ConfigException(I18N.getString( "error.missing-service-installer"), I18N.getString( "error.missing-service-installer.advice")); @@ -180,7 +180,7 @@ private static UUID createNameUUID(String... components) { return UUID.nameUUIDFromBytes(key.getBytes(StandardCharsets.UTF_8)); } - static class Internal { + final static class Internal { private static final BundlerParamInfo INSTALLDIR_CHOOSER = new StandardBundlerParam<>( @@ -241,6 +241,6 @@ static class Internal { static final StandardBundlerParam TARGET_PACKAGE = new StandardBundlerParam<>( Package.PARAM_ID, WinMsiPackage.class, params -> { - return toFunction(WinMsiPackage::createFromParams).apply(params); + return toFunction(WinMsiPackage::createFromParams).apply(params); }, null); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index 54a3d1adf87e6..3d79959c28f44 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -67,14 +67,14 @@ final class WixAppImageFragmentBuilder extends WixFragmentBuilder { void initFromParams(Workshop workshop, WinMsiPackage pkg) { super.initFromParams(workshop, pkg); - Path appImageRoot = Workshop.appImageDir(workshop, pkg); + Path appImageRoot = workshop.appImageDir(); systemWide = pkg.isSystemWideInstall(); registryKeyPath = Path.of("Software", pkg.app().vendor(), pkg.app().name(), - pkg.app().version()).toString(); + pkg.version()).toString(); installDir = (systemWide ? PROGRAM_FILES : LOCAL_PROGRAM_FILES).resolve(pkg. relativeInstallDir()); @@ -109,10 +109,9 @@ void initFromParams(Workshop workshop, WinMsiPackage pkg) { if (!launchersAsServices.isEmpty()) { // Service installer tool will be installed in launchers directory - serviceInstaller = new InstallableFile( - pkg.serviceInstaller(), - installedAppImage.launchersDirectory().resolve( - serviceInstaller.installPath())); + serviceInstaller = new InstallableFile(pkg.serviceInstaller().toAbsolutePath() + .normalize(), installedAppImage.launchersDirectory().resolve(pkg + .serviceInstaller().getFileName())); } programMenuFolderName = pkg.startMenuGroupName(); From 2c24edde1a211ee330147eb9bbc0600ab2e21a4a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Jun 2024 00:00:26 -0400 Subject: [PATCH 0003/1101] Fix merge compilation errors --- .../jdk/jpackage/internal/WinMsiBundler.java | 21 +++++++++---------- .../internal/WixAppImageFragmentBuilder.java | 1 + .../jpackage/internal/WixFragmentBuilder.java | 2 +- .../internal/WixUiFragmentBuilder.java | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index f76d4f52d0286..77847d60b59a6 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -343,10 +343,9 @@ private Path buildMSI(Workshop workshop, WinMsiPackage pkg, WixPipeline wixPipeline = new WixPipeline() .setToolset(wixToolset) - .setWixObjDir(TEMP_ROOT.fetchFrom(params).resolve("wixobj")) - .setWorkDir(WIN_APP_IMAGE.fetchFrom(params)) - .addSource(CONFIG_ROOT.fetchFrom(params).resolve("main.wxs"), - wixVars); + .setWixObjDir(workshop.buildRoot().resolve("wixobj")) + .setWorkDir(workshop.appImageDir()) + .addSource(workshop.configDir().resolve("main.wxs"), wixVars); for (var wixFragment : wixFragments) { wixFragment.configureWixPipeline(wixPipeline); @@ -359,7 +358,7 @@ private Path buildMSI(Workshop workshop, WinMsiPackage pkg, case Wix3 -> { wixPipeline.addLightOptions("-sice:ICE27"); - if (!MSI_SYSTEM_WIDE.fetchFrom(params)) { + if (!pkg.isSystemWideInstall()) { wixPipeline.addLightOptions("-sice:ICE91"); } } @@ -370,7 +369,7 @@ private Path buildMSI(Workshop workshop, WinMsiPackage pkg, } } - final Path configDir = CONFIG_ROOT.fetchFrom(params); + final Path configDir = workshop.configDir(); var primaryWxlFiles = Stream.of("de", "en", "ja", "zh_CN").map(loc -> { return configDir.resolve("MsiInstallerStrings_" + loc + ".wxl"); @@ -381,21 +380,21 @@ private Path buildMSI(Workshop workshop, WinMsiPackage pkg, // Copy standard l10n files. for (var path : primaryWxlFiles) { var name = path.getFileName().toString(); - wixResources.addResource(createResource(name, params).setPublicName(name).setCategory( + wixResources.addResource(workshop.createResource(name).setPublicName(name).setCategory( I18N.getString("resource.wxl-file")), path); } - wixResources.addResource(createResource("main.wxs", params).setPublicName("main.wxs"). + wixResources.addResource(workshop.createResource("main.wxs").setPublicName("main.wxs"). setCategory(I18N.getString("resource.main-wix-file")), configDir.resolve("main.wxs")); - wixResources.addResource(createResource("overrides.wxi", params).setPublicName( + wixResources.addResource(workshop.createResource("overrides.wxi").setPublicName( "overrides.wxi").setCategory(I18N.getString("resource.overrides-wix-file")), configDir.resolve("overrides.wxi")); // Filter out custom l10n files that were already used to // override primary l10n files. Ignore case filename comparison, // both lists are expected to be short. - List customWxlFiles = getWxlFilesFromDir(params, RESOURCE_DIR).stream() + List customWxlFiles = getWxlFilesFromDir(workshop.resourceDir()).stream() .filter(custom -> primaryWxlFiles.stream().noneMatch(primary -> primary.getFileName().toString().equalsIgnoreCase( custom.getFileName().toString()))) @@ -408,7 +407,7 @@ private Path buildMSI(Workshop workshop, WinMsiPackage pkg, // Copy custom l10n files. for (var path : customWxlFiles) { var name = path.getFileName().toString(); - wixResources.addResource(createResource(name, params).setPublicName(name). + wixResources.addResource(workshop.createResource(name).setPublicName(name). setSourceOrder(OverridableResource.Source.ResourceDir).setCategory(I18N. getString("resource.wxl-file")), configDir.resolve(name)); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index e5eb47d7f2c19..65dcb381a6214 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -29,6 +29,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Files; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java index f431820f7e6c4..ef1d0e4d2aecd 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java @@ -31,6 +31,7 @@ import java.nio.file.Path; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.regex.Matcher; @@ -39,7 +40,6 @@ import jdk.jpackage.internal.IOUtils.XmlConsumer; import jdk.jpackage.internal.OverridableResource.Source; import jdk.internal.util.Architecture; -import static jdk.jpackage.internal.OverridableResource.createResource; import jdk.jpackage.internal.WixSourceConverter.ResourceGroup; import jdk.jpackage.internal.WixToolset.WixToolsetType; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java index 8b823edf813f4..f6ee0c564c623 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java @@ -507,7 +507,7 @@ private final class CustomDialog { this.wxsFileName = wxsFileName; this.wixVariables = new WixVariables(); - addResource(createResource(wxsFileName, params).setCategory(category).setPublicName( + addResource(createResource.apply(wxsFileName).setCategory(category).setPublicName( wxsFileName), wxsFileName); } From 0e1d9877e61a9e94b2ec1b2e4cbbcb1a04191ac7 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Jun 2024 10:03:35 -0400 Subject: [PATCH 0004/1101] Trailing whitespace removed --- .../share/classes/jdk/jpackage/internal/ScriptRunner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java index 7a1b0c804178c..bff71c81fec0f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java @@ -107,7 +107,7 @@ public Path buildRoot() { public Path resourceDir() { return StandardBundlerParam.RESOURCE_DIR.fetchFrom(params); } - + @Override public Path configDir() { return StandardBundlerParam.CONFIG_ROOT.fetchFrom(params); From 6a60e899620869a8a9bf227c35ee4a0ac431c422 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Jun 2024 11:05:48 -0400 Subject: [PATCH 0005/1101] Fix additional launcher shortcuts --- .../jdk/jpackage/internal/WinApplication.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java index 18100f4659d4c..eccfd39f1cb6e 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java @@ -54,11 +54,14 @@ static WinApplication createFromParams(Map params) throw Internal.WIN_SHORTCUT_HINT_PARAM), WinShortcutStartMenu, List.of(MENU_HINT, Internal.WIN_MENU_HINT_PARAM)).entrySet().stream().filter( e -> { - return e.getValue().stream().allMatch(param -> { - return param.fetchFrom(launcherParams); - }); - }).map( - Map.Entry::getKey).collect(Collectors.toSet()); + var shortcutParams = e.getValue(); + if (launcherParams.containsKey(shortcutParams.get(0).getID())) { + // This is an explicit shortcut configuration for an addition launcher + return shortcutParams.get(0).fetchFrom(launcherParams); + } else { + return shortcutParams.get(1).fetchFrom(launcherParams); + } + }).map(Map.Entry::getKey).collect(Collectors.toSet()); return new WinLauncher.Impl(launcher, isConsole, shortcuts); }); From 5157cb51a2ee3517b75db4653f14a83d2e6d10d3 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 21 Jun 2024 18:47:42 -0400 Subject: [PATCH 0006/1101] Move common code for proxy classes in ProxyBase. Remove Launcher#version() and Launcher#release(). Turn Package.PackageType into interface and add Package.StandardPackageType enum for known packaging types. This is to allow adding custom packaging types at runtime --- .../jdk/jpackage/internal/Application.java | 14 +- .../jdk/jpackage/internal/Functional.java | 21 +++ .../jdk/jpackage/internal/Launcher.java | 31 +--- .../jdk/jpackage/internal/Package.java | 157 ++++++++++++------ .../jdk/jpackage/internal/ProxyBase.java | 33 ++++ .../jdk/jpackage/internal/WinApplication.java | 14 +- .../jdk/jpackage/internal/WinLauncher.java | 2 +- .../jdk/jpackage/internal/WinMsiBundler.java | 8 +- .../jdk/jpackage/internal/WinMsiPackage.java | 4 +- 9 files changed, 188 insertions(+), 96 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/ProxyBase.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java index 2560af5fb95d1..a72f64cc62e9d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java @@ -75,6 +75,10 @@ default Path appImageDirName() { Launcher mainLauncher(); + default boolean isRuntime() { + return mainLauncher() == null; + } + List additionalLaunchers(); default boolean isService() { @@ -82,7 +86,7 @@ default boolean isService() { } default ApplicationLayout appLayout() { - if (mainLauncher() == null) { + if (isRuntime()) { return ApplicationLayout.javaRuntime(); } else { return ApplicationLayout.platformAppImage(); @@ -101,10 +105,10 @@ static record Impl(String name, String description, String version, String vendo } - static class Proxy implements Application { + static class Proxy extends ProxyBase implements Application { - Proxy(Application target) { - this.target = target; + Proxy(T target) { + super(target); } @Override @@ -146,8 +150,6 @@ public Launcher mainLauncher() { public List additionalLaunchers() { return target.additionalLaunchers(); } - - private final Application target; } static Application createFromParams(Map params, diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Functional.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Functional.java index 0a3e588a6210e..d33d16ac7a989 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Functional.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Functional.java @@ -30,6 +30,7 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; +import java.util.function.UnaryOperator; public class Functional { @@ -113,6 +114,22 @@ public static BiFunction toBiFunction(ThrowingBiFunction { + + T apply(T t) throws Throwable; + + public static UnaryOperator toUnaryOperator(ThrowingUnaryOperator v) { + return (t) -> { + try { + return v.apply(t); + } catch (Throwable ex) { + throw rethrowUnchecked(ex); + } + }; + } + } + @FunctionalInterface public interface ThrowingRunnable { @@ -153,6 +170,10 @@ public static Function identityFunction(Function v) { return v; } + public static UnaryOperator identityUnaryOperator(UnaryOperator v) { + return v; + } + public static Predicate identityPredicate(Predicate v) { return v; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java index 57d1a02116878..cf24065aed4cc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java @@ -31,8 +31,6 @@ import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.RELEASE; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; interface Launcher { @@ -48,10 +46,6 @@ default Path executableName() { boolean isService(); - String version(); - - String release(); - String description(); /** @@ -61,15 +55,14 @@ default Path executableName() { Path icon(); static record Impl(String name, LauncherStartupInfo startupInfo, - List fileAssociations, boolean isService, String version, - String release, String description, Path icon) implements Launcher { + List fileAssociations, boolean isService, String description, Path icon) implements Launcher { } - static class Proxy implements Launcher { + static class Proxy extends ProxyBase implements Launcher { - Proxy(Launcher target) { - this.target = target; + Proxy(T target) { + super(target); } @Override @@ -92,16 +85,6 @@ public boolean isService() { return target.isService(); } - @Override - public String version() { - return target.version(); - } - - @Override - public String release() { - return target.release(); - } - @Override public String description() { return target.description(); @@ -111,8 +94,6 @@ public String description() { public Path icon() { return target.icon(); } - - private final Launcher target; } static Launcher createFromParams(Map params) { @@ -124,12 +105,10 @@ static Launcher createFromParams(Map params) { } var isService = LAUNCHER_AS_SERVICE.fetchFrom(params); - var version = VERSION.fetchFrom(params); - var release = RELEASE.fetchFrom(params); var description = DESCRIPTION.fetchFrom(params); var icon = StandardBundlerParam.ICON.fetchFrom(params); var fa = FileAssociation.fetchFrom(params); - return new Impl(name, startupInfo, fa, isService, version, release, description, icon); + return new Impl(name, startupInfo, fa, isService, description, icon); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index 98da34e53df9c..8f72eefc5ae5d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal; import java.nio.file.Path; +import java.text.MessageFormat; import java.util.Map; import java.util.Optional; import java.util.stream.Stream; @@ -39,7 +40,10 @@ interface Package { - enum PackageType { + interface PackageType { + } + + enum StandardPackageType implements PackageType { WinMsi(".msi"), WinExe(".exe"), LinuxDeb(".deb"), @@ -47,7 +51,7 @@ enum PackageType { MacPkg(".pkg"), MacDmg(".dmg"); - PackageType(String suffix) { + StandardPackageType(String suffix) { this.suffix = suffix; } @@ -55,7 +59,7 @@ String suffix() { return suffix; } - static PackageType fromCmdLineType(String type) { + static StandardPackageType fromCmdLineType(String type) { return Stream.of(values()).filter(pt -> { return pt.suffix().substring(1).equals(type); }).findAny().get(); @@ -68,10 +72,18 @@ static PackageType fromCmdLineType(String type) { PackageType type(); + default StandardPackageType asStandardPackageType() { + if (type() instanceof StandardPackageType stdType) { + return stdType; + } else { + return null; + } + } + /** * Returns platform-specific package name. */ - String name(); + String packageName(); String description(); @@ -87,20 +99,27 @@ default ApplicationLayout appLayout() { return app().appLayout(); } - default Path installerName() { - var type = type(); - switch (type) { - case WinMsi, WinExe -> { - return Path.of(String.format("%s-%s%s", name(), version(), type.suffix())); - } - default -> { - throw new UnsupportedOperationException(); + /** + * Returns package file name. + */ + default Path packageFileName() { + if (type() instanceof StandardPackageType type) { + switch (type) { + case WinMsi, WinExe -> { + return Path + .of(String.format("%s-%s%s", packageName(), version(), type.suffix())); + } + default -> { + throw new UnsupportedOperationException(); + } } + } else { + throw new UnsupportedOperationException(); } } default boolean isRuntimeInstaller() { - return app().mainLauncher() == null; + return app().isRuntime(); } /** @@ -109,16 +128,16 @@ default boolean isRuntimeInstaller() { */ Path relativeInstallDir(); - static record Impl(Application app, PackageType type, String name, String description, + static record Impl(Application app, PackageType type, String packageName, String description, String version, String aboutURL, Path licenseFile, Path predefinedAppImage, Path relativeInstallDir) implements Package { } - static class Proxy implements Package { + static class Proxy extends ProxyBase implements Package { - Proxy(Package target) { - this.target = target; + Proxy(T target) { + super(target); } @Override @@ -132,8 +151,8 @@ public PackageType type() { } @Override - public String name() { - return target.name(); + public String packageName() { + return target.packageName(); } @Override @@ -165,58 +184,98 @@ public Path predefinedAppImage() { public Path relativeInstallDir() { return target.relativeInstallDir(); } - - private final Package target; } static Package createFromParams(Map params, Application app, - PackageType type) throws ConfigException { - var name = Optional.ofNullable(INSTALLER_NAME.fetchFrom(params)).orElseGet(app::name); + PackageType pkgType) throws ConfigException { + var packageName = Optional.ofNullable(INSTALLER_NAME.fetchFrom(params)).orElseGet(app::name); var description = Optional.ofNullable(DESCRIPTION.fetchFrom(params)).orElseGet(app::name); var version = Optional.ofNullable(VERSION.fetchFrom(params)).orElseGet(app::version); var aboutURL = ABOUT_URL.fetchFrom(params); var licenseFile = Optional.ofNullable(LICENSE_FILE.fetchFrom(params)).map(Path::of).orElse(null); var predefinedAppImage = getPredefinedAppImage(params); - var relativeInstallDir = Optional.ofNullable(INSTALL_DIR.fetchFrom(params)).map(Path::of) - .orElseGet(() -> { - switch (type) { - case WinExe, WinMsi -> { - return app.appImageDirName(); - } - case LinuxDeb, LinuxRpm -> { - return Path.of("/opt").resolve(app.appImageDirName()); - } - case MacDmg, MacPkg -> { - String root; - if (StandardBundlerParam.isRuntimeInstaller(params)) { - root = "/Library/Java/JavaVirtualMachines"; - } else { - root = "/Applications"; - } - return Path.of(root).resolve(app.appImageDirName()); - } - default -> { - throw new IllegalArgumentException(); - } - } - }); + var relativeInstallDir = Optional.ofNullable(INSTALL_DIR.fetchFrom(params)).map(v -> { + return toSupplier(() -> mapInstallDir(Path.of(v), pkgType)).get(); + }).orElseGet(() -> { + if (pkgType instanceof StandardPackageType stdPkgType) { + return defaultInstallDir(app, stdPkgType); + } else { + return app.appImageDirName(); + } + }); if (relativeInstallDir.isAbsolute()) { relativeInstallDir = relativeInstallDir.relativize(Path.of("/")); } - return new Impl(app, type, name, description, version, aboutURL, licenseFile, + return new Impl(app, pkgType, packageName, description, version, aboutURL, licenseFile, predefinedAppImage, relativeInstallDir); } + private static Path defaultInstallDir(Application app, StandardPackageType type) { + switch (type) { + case WinExe, WinMsi -> { + return app.appImageDirName(); + } + case LinuxDeb, LinuxRpm -> { + return Path.of("/opt").resolve(app.appImageDirName()); + } + case MacDmg, MacPkg -> { + String root; + if (app.isRuntime()) { + root = "/Library/Java/JavaVirtualMachines"; + } else { + root = "/Applications"; + } + return Path.of(root).resolve(app.appImageDirName()); + } + default -> { + throw new IllegalArgumentException(); + } + } + } + + private static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigException { + var ex = new ConfigException(MessageFormat.format(I18N.getString("error.invalid-install-dir"), + installDir), null); + + if (installDir.getFileName().equals(Path.of(""))) { + // Trailing '/' or '\\'. Strip them away. + installDir = installDir.getParent(); + } + + if (installDir.toString().isEmpty()) { + throw ex; + } + + if (pkgType instanceof StandardPackageType stdPkgType) { + switch (stdPkgType) { + case WinExe, WinMsi -> { + if (installDir.isAbsolute()) { + throw ex; + } + } + } + } else if (!installDir.isAbsolute()) { + throw ex; + } + + if (!installDir.normalize().toString().equals(installDir.toString())) { + // Don't allow '..' or '.' in path components + throw ex; + } + + return installDir; + } + final static String PARAM_ID = "target.package"; static final StandardBundlerParam TARGET_PACKAGE = new StandardBundlerParam<>( PARAM_ID, Package.class, params -> { return toSupplier(() -> { return Package.createFromParams(params, Application.TARGET_APPLICATION - .fetchFrom(params), PackageType.fromCmdLineType(Workshop.PACKAGE_TYPE - .fetchFrom(params))); + .fetchFrom(params), StandardPackageType.fromCmdLineType( + Workshop.PACKAGE_TYPE.fetchFrom(params))); }).get(); }, null); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ProxyBase.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ProxyBase.java new file mode 100644 index 0000000000000..4f11954377048 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ProxyBase.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +abstract class ProxyBase { + ProxyBase(T target) { + this.target = target; + } + + protected final T target; +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java index eccfd39f1cb6e..62dc71dbdf6d7 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java @@ -27,8 +27,6 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import static jdk.jpackage.internal.Arguments.CLIOptions.WIN_MENU_HINT; -import static jdk.jpackage.internal.Arguments.CLIOptions.WIN_SHORTCUT_HINT; import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; @@ -51,8 +49,8 @@ static WinApplication createFromParams(Map params) throw boolean isConsole = CONSOLE_HINT.fetchFrom(launcherParams); var shortcuts = Map.of(WinShortcutDesktop, List.of(SHORTCUT_HINT, - Internal.WIN_SHORTCUT_HINT_PARAM), WinShortcutStartMenu, - List.of(MENU_HINT, Internal.WIN_MENU_HINT_PARAM)).entrySet().stream().filter( + Internal.WIN_SHORTCUT_HINT), WinShortcutStartMenu, + List.of(MENU_HINT, Internal.WIN_MENU_HINT)).entrySet().stream().filter( e -> { var shortcutParams = e.getValue(); if (launcherParams.containsKey(shortcutParams.get(0).getID())) { @@ -75,16 +73,16 @@ static WinApplication createFromParams(Map params) throw static final class Internal { - private static final StandardBundlerParam WIN_MENU_HINT_PARAM = new StandardBundlerParam<>( - WIN_MENU_HINT.getId(), + private static final StandardBundlerParam WIN_MENU_HINT = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_MENU_HINT.getId(), Boolean.class, p -> false, // valueOf(null) is false, // and we actually do want null in some cases (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); - private static final StandardBundlerParam WIN_SHORTCUT_HINT_PARAM = new StandardBundlerParam<>( - WIN_SHORTCUT_HINT.getId(), + private static final StandardBundlerParam WIN_SHORTCUT_HINT = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_SHORTCUT_HINT.getId(), Boolean.class, p -> false, // valueOf(null) is false, diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java index 63bca1b8842ad..18ae547f16995 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java @@ -43,7 +43,7 @@ enum WinShortcut { Set shortcuts(); - static class Impl extends Launcher.Proxy implements WinLauncher { + static class Impl extends Launcher.Proxy implements WinLauncher { Impl(Launcher launcher, boolean isConsole, Set shortcuts) { super(launcher); this.isConsole = isConsole; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 77847d60b59a6..8e6ea3495471e 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -233,7 +233,7 @@ private void prepareProto(Map params) installerIcon = appImageLayout.launchersDirectory().resolve(pkg.app().mainLauncher() .executableName()); - new PackageFile(pkg.name()).save(appImageLayout); + new PackageFile(pkg.packageName()).save(appImageLayout); } installerIcon = installerIcon.toAbsolutePath(); @@ -274,7 +274,7 @@ public Path execute(Map params, .setResourceCategoryId("resource.post-app-image-script") .setScriptNameSuffix("post-image") .setEnvironmentVariable("JpAppImageDir", imageDir.toAbsolutePath().toString()) - .run(workshop, pkg.name()); + .run(workshop, pkg.packageName()); return buildMSI(workshop, pkg, wixVars, outputParentDir); } catch (IOException ex) { @@ -299,7 +299,7 @@ private Map prepareMainProjectFile(Workshop workshop, WinMsiPack data.put("JpAllowDowngrades", "yes"); } - data.put("JpAppName", pkg.name()); + data.put("JpAppName", pkg.packageName()); data.put("JpAppDescription", pkg.description()); data.put("JpAppVendor", pkg.app().vendor()); data.put("JpAppVersion", pkg.version()); @@ -335,7 +335,7 @@ private Path buildMSI(Workshop workshop, WinMsiPackage pkg, Map wixVars, Path outdir) throws IOException { - Path msiOut = outdir.resolve(pkg.installerName()); + Path msiOut = outdir.resolve(pkg.packageFileName()); Log.verbose(MessageFormat.format(I18N.getString( "message.preparing-msi-config"), msiOut.toAbsolutePath() diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java index a9f22bf83a294..5a5e931b4ed27 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java @@ -58,7 +58,7 @@ default UUID productCode() { Path serviceInstaller(); - static class Impl extends Package.Proxy implements WinMsiPackage { + static class Impl extends Package.Proxy implements WinMsiPackage { Impl(Package pkg, boolean withInstallDirChooser, boolean withShortcutPrompt, String helpURL, String updateURL, String startMenuGroupName, boolean isSystemWideInstall, @@ -130,7 +130,7 @@ public Path serviceInstaller() { private static WinMsiPackage createFromParams(Map params) throws ConfigException { var pkg = Package.createFromParams(params, WinApplication.createFromParams(params), - PackageType.WinMsi); + StandardPackageType.WinMsi); var withInstallDirChooser = Internal.INSTALLDIR_CHOOSER.fetchFrom(params); var withShortcutPrompt = Internal.SHORTCUT_PROMPT.fetchFrom(params); var helpURL = Internal.HELP_URL.fetchFrom(params); From 7870e806cfe3ce86d2046baa29e8101c5cb7dd97 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 21 Jun 2024 19:18:17 -0400 Subject: [PATCH 0007/1101] Current state of Linux port of "no params" project --- .../jpackage/internal/LinuxApplication.java | 73 ++++++ .../jpackage/internal/LinuxDebBundler.java | 80 +----- .../jpackage/internal/LinuxDebPackage.java | 75 ++++++ .../jdk/jpackage/internal/LinuxLauncher.java | 45 ++++ .../jdk/jpackage/internal/LinuxPackage.java | 235 ++++++++++++++++++ .../jpackage/internal/LinuxPackageArch.java | 105 ++++++++ .../internal/LinuxPackageBundler.java | 204 ++++----------- .../jpackage/internal/LinuxRpmBundler.java | 43 +--- .../jpackage/internal/LinuxRpmPackage.java | 71 ++++++ .../resources/LinuxResources.properties | 2 + .../jpackage/internal/LauncherAsService.java | 23 +- .../internal/ShellCustomActionFactory.java | 4 +- .../internal/UnixLaunchersAsServices.java | 21 +- 13 files changed, 671 insertions(+), 310 deletions(-) create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplication.java create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplication.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplication.java new file mode 100644 index 0000000000000..80e36fa42a31e --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplication.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import java.util.Map; +import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; +import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; + +interface LinuxApplication extends Application { + static class Impl extends Application.Proxy implements LinuxApplication { + + Impl(Application app) { + super(app); + } + } + + static LinuxApplication createFromParams(Map params) throws ConfigException { + var app = Application.createFromParams(params, launcherParams -> { + var launcher = Launcher.createFromParams(launcherParams); + + boolean shortcut; + if (launcherParams.containsKey(SHORTCUT_HINT.getID())) { + // This is an explicit shortcut configuration for an addition launcher + shortcut = SHORTCUT_HINT.fetchFrom(launcherParams); + } else { + shortcut = Internal.LINUX_SHORTCUT_HINT.fetchFrom(launcherParams); + } + + return new LinuxLauncher.Impl(launcher, shortcut); + }); + return new Impl(app); + } + + static final StandardBundlerParam TARGET_APPLICATION = new StandardBundlerParam<>( + Application.PARAM_ID, LinuxApplication.class, params -> { + return toFunction(LinuxApplication::createFromParams).apply(params); + }, null); + + static final class Internal { + + private static final StandardBundlerParam LINUX_SHORTCUT_HINT = + new StandardBundlerParam<>( + Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(), + Boolean.class, + params -> false, + (s, p) -> (s == null || "null".equalsIgnoreCase(s)) + ? false : Boolean.valueOf(s) + ); + } +} \ No newline at end of file diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index 478ec07879740..35305e372972c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -58,86 +58,10 @@ public class LinuxDebBundler extends LinuxPackageBundler { - // Debian rules for package naming are used here - // https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Source - // - // Package names must consist only of lower case letters (a-z), - // digits (0-9), plus (+) and minus (-) signs, and periods (.). - // They must be at least two characters long and - // must start with an alphanumeric character. - // - private static final Pattern DEB_PACKAGE_NAME_PATTERN = - Pattern.compile("^[a-z][a-z\\d\\+\\-\\.]+"); - - private static final BundlerParamInfo PACKAGE_NAME = - new StandardBundlerParam<> ( - Arguments.CLIOptions.LINUX_BUNDLE_NAME.getId(), - String.class, - params -> { - String nm = INSTALLER_NAME.fetchFrom(params); - if (nm == null) return null; - - // make sure to lower case and spaces/underscores become dashes - nm = nm.toLowerCase().replaceAll("[ _]", "-"); - return nm; - }, - (s, p) -> { - if (!DEB_PACKAGE_NAME_PATTERN.matcher(s).matches()) { - throw new IllegalArgumentException(new ConfigException( - MessageFormat.format(I18N.getString( - "error.invalid-value-for-package-name"), s), - I18N.getString( - "error.invalid-value-for-package-name.advice"))); - } - - return s; - }); - private static final String TOOL_DPKG_DEB = "dpkg-deb"; private static final String TOOL_DPKG = "dpkg"; private static final String TOOL_FAKEROOT = "fakeroot"; - private static final String DEB_ARCH; - static { - String debArch; - try { - debArch = Executor.of(TOOL_DPKG, "--print-architecture").saveOutput( - true).executeExpectSuccess().getOutput().get(0); - } catch (IOException ex) { - debArch = null; - } - DEB_ARCH = debArch; - } - - private static final String releaseSuffix(Map params) { - return Optional.ofNullable(RELEASE.fetchFrom(params, false)).map( - rel -> "-" + rel).orElse(""); - } - - private static final BundlerParamInfo FULL_PACKAGE_NAME = - new StandardBundlerParam<>( - "linux.deb.fullPackageName", String.class, params -> { - return PACKAGE_NAME.fetchFrom(params) - + "_" + VERSION.fetchFrom(params) - + releaseSuffix(params) - + "_" + DEB_ARCH; - }, (s, p) -> s); - - private static final BundlerParamInfo EMAIL = - new StandardBundlerParam<> ( - Arguments.CLIOptions.LINUX_DEB_MAINTAINER.getId(), - String.class, - params -> "Unknown", - (s, p) -> s); - - private static final BundlerParamInfo MAINTAINER = - new StandardBundlerParam<> ( - Arguments.CLIOptions.LINUX_DEB_MAINTAINER.getId() + ".internal", - String.class, - params -> VENDOR.fetchFrom(params) + " <" - + EMAIL.fetchFrom(params) + ">", - (s, p) -> s); - private static final BundlerParamInfo SECTION = new StandardBundlerParam<>( Arguments.CLIOptions.LINUX_CATEGORY.getId(), @@ -197,9 +121,7 @@ protected Path buildPackageBundle( private static final Pattern PACKAGE_NAME_REGEX = Pattern.compile("^(^\\S+):"); @Override - protected void initLibProvidersLookup( - Map params, - LibProvidersLookup libProvidersLookup) { + protected void initLibProvidersLookup(LibProvidersLookup libProvidersLookup) { libProvidersLookup.setPackageLookup(file -> { Path realPath = file.toRealPath(); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java new file mode 100644 index 0000000000000..b9ca6d9438c23 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.Map; +import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; + +interface LinuxDebPackage extends LinuxPackage { + + String maintainerEmail(); + + default String maintainer() { + return String.format("%s <%s>", app().vendor(), maintainerEmail()); + } + + static class Impl extends LinuxPackage.Proxy implements LinuxDebPackage { + + public Impl(LinuxPackage target, String maintainerEmail) { + super(target); + this.maintainerEmail = maintainerEmail; + } + + @Override + public String maintainerEmail() { + return maintainerEmail; + } + + private final String maintainerEmail; + } + + private static LinuxDebPackage createFromParams(Map params) throws ConfigException { + var pkg = LinuxPackage.createFromParams(params, StandardPackageType.LinuxDeb); + + var maintainerEmail = Internal.MAINTAINER_EMAIL.fetchFrom(params); + + return new Impl(pkg, maintainerEmail); + } + + final static class Internal { + + private static final BundlerParamInfo MAINTAINER_EMAIL + = new StandardBundlerParam<>( + Arguments.CLIOptions.LINUX_DEB_MAINTAINER.getId(), + String.class, + params -> "Unknown", + (s, p) -> s); + } + + static final StandardBundlerParam TARGET_PACKAGE = new StandardBundlerParam<>( + Package.PARAM_ID, LinuxDebPackage.class, params -> { + return toFunction(LinuxDebPackage::createFromParams).apply(params); + }, null); +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java new file mode 100644 index 0000000000000..38dd21133c5d8 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +interface LinuxLauncher extends Launcher { + + boolean shortcut(); + + static class Impl extends Launcher.Proxy implements LinuxLauncher { + + Impl(Launcher launcher, boolean shortcut) { + super(launcher); + this.shortcut = shortcut; + } + + @Override + public boolean shortcut() { + return shortcut; + } + + private final boolean shortcut; + } +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java new file mode 100644 index 0000000000000..213ddd0feae04 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.text.MessageFormat; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +interface LinuxPackage extends Package { + + String menuGroupName(); + + String category(); + + String additionalDependencies(); + + String release(); + + @Override + default ApplicationLayout appLayout() { + if (isInstallDirInUsrTree()) { + return ApplicationLayout.linuxUsrTreePackageImage(relativeInstallDir(), packageName()); + } else { + return Package.super.appLayout(); + } + } + + default boolean isInstallDirInUsrTree() { + return Set.of(Path.of("usr/local"), Path.of("usr")).contains(relativeInstallDir()); + } + + static class Impl extends Package.Proxy implements LinuxPackage { + + public Impl(Package target, String menuGroupName, String category, + String additionalDependencies, String release) { + super(target); + this.menuGroupName = menuGroupName; + this.category = category; + this.additionalDependencies = additionalDependencies; + this.release = release; + } + + @Override + public String menuGroupName() { + return menuGroupName; + } + + @Override + public String category() { + return category; + } + + @Override + public String additionalDependencies() { + return additionalDependencies; + } + + @Override + public String release() { + return release; + } + + private final String menuGroupName; + private final String category; + private final String additionalDependencies; + private final String release; + } + + static class Proxy extends Package.Proxy implements LinuxPackage { + + public Proxy(T target) { + super(target); + } + + @Override + public String menuGroupName() { + return target.menuGroupName(); + } + + @Override + public String category() { + return target.category(); + } + + @Override + public String additionalDependencies() { + return target.additionalDependencies(); + } + + @Override + public String release() { + return target.release(); + } + } + + static LinuxPackage createFromParams(Map params, + StandardPackageType pkgType) throws ConfigException { + var pkg = Package.createFromParams(params, LinuxApplication.createFromParams(params), pkgType); + var menuGroupName = Internal.LINUX_MENU_GROUP.fetchFrom(params); + var category = Internal.LINUX_CATEGORY.fetchFrom(params); + var additionalDependencies = Internal.LINUX_PACKAGE_DEPENDENCIES.fetchFrom(params); + var release = Internal.RELEASE.fetchFrom(params); + + var packageName = mapPackageName(pkg.packageName(), pkgType); + var arch = LinuxPackageArch.getValue(pkgType); + + return new Impl(pkg, menuGroupName, category, additionalDependencies, release) { + @Override + public String packageName() { + return packageName; + } + + @Override + public Path packageFileName() { + String packageFileNameTemlate; + switch (asStandardPackageType()) { + case LinuxDeb -> { + packageFileNameTemlate = "%s_%s-%s_%s.deb"; + } + case LinuxRpm -> { + packageFileNameTemlate = "%s-%s-%s.%s.rpm"; + } + default -> { + throw new UnsupportedOperationException(); + } + } + + return Path.of(String.format(packageFileNameTemlate, packageName(), version(), + release(), arch)); + } + }; + } + + private static String mapPackageName(String packageName, StandardPackageType pkgType) throws ConfigException { + // make sure to lower case and spaces/underscores become dashes + packageName = packageName.toLowerCase().replaceAll("[ _]", "-"); + + switch (pkgType) { + case LinuxDeb -> { + // + // Debian rules for package naming are used here + // https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Source + // + // Package names must consist only of lower case letters (a-z), + // digits (0-9), plus (+) and minus (-) signs, and periods (.). + // They must be at least two characters long and + // must start with an alphanumeric character. + // + var regexp = Pattern.compile("^[a-z][a-z\\d\\+\\-\\.]+"); + if (!regexp.matcher(packageName).matches()) { + throw new ConfigException(MessageFormat.format(I18N.getString( + "error.deb-invalid-value-for-package-name"), packageName), I18N + .getString("error.deb-invalid-value-for-package-name.advice")); + } + } + case LinuxRpm -> { + // + // Fedora rules for package naming are used here + // https://fedoraproject.org/wiki/Packaging:NamingGuidelines?rd=Packaging/NamingGuidelines + // + // all Fedora packages must be named using only the following ASCII + // characters. These characters are displayed here: + // + // abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._+ + // + var regexp = Pattern.compile("[a-z\\d\\+\\-\\.\\_]+", Pattern.CASE_INSENSITIVE); + if (!regexp.matcher(packageName).matches()) { + throw new ConfigException(MessageFormat.format(I18N.getString( + "error.rpm-invalid-value-for-package-name"), packageName), I18N + .getString("error.rpm-invalid-value-for-package-name.advice")); + } + } + default -> { + throw new IllegalArgumentException(); + } + } + + return packageName; + } + + final static class Internal { + + private static final BundlerParamInfo LINUX_CATEGORY + = new StandardBundlerParam<>( + Arguments.CLIOptions.LINUX_CATEGORY.getId(), + String.class, + params -> "misc", + (s, p) -> s); + + private static final BundlerParamInfo LINUX_PACKAGE_DEPENDENCIES + = new StandardBundlerParam<>( + Arguments.CLIOptions.LINUX_PACKAGE_DEPENDENCIES.getId(), + String.class, + params -> null, + (s, p) -> s); + + private static final BundlerParamInfo LINUX_MENU_GROUP + = new StandardBundlerParam<>( + Arguments.CLIOptions.LINUX_MENU_GROUP.getId(), + String.class, + params -> I18N.getString("param.menu-group.default"), + (s, p) -> s); + + private static final StandardBundlerParam RELEASE + = new StandardBundlerParam<>( + Arguments.CLIOptions.RELEASE.getId(), + String.class, + params -> "1", + (s, p) -> s); + } +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java new file mode 100644 index 0000000000000..411ba88506720 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.io.IOException; +import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; +import jdk.jpackage.internal.Package.StandardPackageType; + +final class LinuxPackageArch { + + static String getValue(StandardPackageType pkgType) { + switch (pkgType) { + case LinuxRpm -> { + return RpmPackageArch.VALUE; + } + case LinuxDeb -> { + return DebPackageArch.VALUE; + } + default -> { + throw new IllegalArgumentException(); + } + } + } + + private static class DebPackageArch { + + static final String VALUE = toSupplier(DebPackageArch::getValue).get(); + + private static String getValue() throws IOException { + return Executor.of("dpkg", "--print-architecture").saveOutput(true) + .executeExpectSuccess().getOutput().get(0); + } + } + + private static class RpmPackageArch { + + /* + * Various ways to get rpm arch. Needed to address JDK-8233143. rpmbuild is mandatory for + * rpm packaging, try it first. rpm is optional and may not be available, use as the last + * resort. + */ + private static enum RpmArchReader { + Rpmbuild("rpmbuild", "--eval=%{_target_cpu}"), + Rpm("rpm", "--eval=%{_target_cpu}"); + + RpmArchReader(String... cmdline) { + this.cmdline = cmdline; + } + + String getRpmArch() throws IOException { + Executor exec = Executor.of(cmdline).saveOutput(true); + switch (this) { + case Rpm -> { + exec.executeExpectSuccess(); + } + case Rpmbuild -> { + if (exec.execute() != 0) { + return null; + } + } + default -> { + throw new UnsupportedOperationException(); + } + } + return exec.getOutput().get(0); + } + + private final String[] cmdline; + } + + static final String VALUE = toSupplier(RpmPackageArch::getValue).get(); + + private static String getValue() throws IOException { + for (var rpmArchReader : RpmArchReader.values()) { + var rpmArchStr = rpmArchReader.getRpmArch(); + if (rpmArchStr != null) { + return rpmArchStr; + } + } + throw new RuntimeException("error.rpm-arch-not-detected"); + } + } +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index b510ed414118b..d2f6b9f3a3cfa 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -63,8 +63,6 @@ public final boolean validate(Map params) // we are not interested in return code, only possible exception appImageBundler.validate(params); - validateInstallDir(LINUX_INSTALL_DIR.fetchFrom(params)); - FileAssociation.verify(FileAssociation.fetchFrom(params)); // If package name has some restrictions, the string converter will @@ -115,44 +113,53 @@ public final Path execute(Map params, Path outputParentDir) throws PackagerException { IOUtils.writableOutputDir(outputParentDir); - PlatformPackage thePackage = createMetaPackage(params); + // Order is important! + LinuxPackage pkg; + if (Package.TARGET_PACKAGE.fetchFrom(params) instanceof LinuxPackage linuxPkg) { + pkg = linuxPkg; + } else { + throw new UnsupportedOperationException(); + } + var workshop = Workshop.WORKSHOP.fetchFrom(params); + + Workshop pkgWorkshop = new Workshop.Proxy(workshop) { + @Override + public Path appImageDir() { + return buildRoot().resolve("pkg-image"); + } + }; + + params.put(Workshop.WORKSHOP.getID(), pkgWorkshop); Function initAppImageLayout = imageRoot -> { - ApplicationLayout layout = appImageLayout(params); + ApplicationLayout layout = pkg.app().appLayout(); layout.pathGroup().setPath(new Object(), AppImageFile.getPathInAppImage(Path.of(""))); return layout.resolveAt(imageRoot); }; try { - Path appImage = StandardBundlerParam.getPredefinedAppImage(params); + Path appImage = pkg.predefinedAppImage(); // we either have an application image or need to build one if (appImage != null) { - initAppImageLayout.apply(appImage).copy( - thePackage.sourceApplicationLayout()); + initAppImageLayout.apply(appImage).copy(pkg.appLayout().resolveAt(pkgWorkshop + .appImageDir())); } else { - final Path srcAppImageRoot = thePackage.sourceRoot().resolve("src"); - appImage = appImageBundler.execute(params, srcAppImageRoot); - ApplicationLayout srcAppLayout = initAppImageLayout.apply( - appImage); - if (appImage.equals(PREDEFINED_RUNTIME_IMAGE.fetchFrom(params))) { - // Application image points to run-time image. - // Copy it. - srcAppLayout.copy(thePackage.sourceApplicationLayout()); - } else { - // Application image is a newly created directory tree. - // Move it. - srcAppLayout.move(thePackage.sourceApplicationLayout()); - IOUtils.deleteRecursive(srcAppImageRoot); + Files.createDirectories(workshop.appImageDir().getParent()); + appImageBundler.execute(params, workshop.appImageDir().getParent()); + Files.delete(AppImageFile.getPathInAppImage(workshop.appImageDir())); + if (pkg.isInstallDirInUsrTree()) { + initAppImageLayout.apply(workshop.appImageDir()).copy(pkg.appLayout().resolveAt( + pkgWorkshop.appImageDir())); } } for (var ca : customActions) { - ca.init(thePackage, params); + ca.init(pkgWorkshop, pkg); } - Map data = createDefaultReplacementData(params); + Map data = createDefaultReplacementData(workshop, pkg); for (var ca : customActions) { ShellCustomAction.mergeReplacementData(data, ca.instance. @@ -178,10 +185,7 @@ public final Path execute(Map params, } } - private List getListOfNeededPackages( - Map params) throws IOException { - - PlatformPackage thePackage = createMetaPackage(params); + private List getListOfNeededPackages(Workshop workshop) throws IOException { final List caPackages = customActions.stream() .map(ca -> ca.instance) @@ -189,16 +193,14 @@ private List getListOfNeededPackages( .flatMap(List::stream).toList(); final List neededLibPackages; - if (withFindNeededPackages && Files.exists(thePackage.sourceRoot())) { + if (withFindNeededPackages) { LibProvidersLookup lookup = new LibProvidersLookup(); - initLibProvidersLookup(params, lookup); + initLibProvidersLookup(lookup); - neededLibPackages = lookup.execute(thePackage.sourceRoot()); + neededLibPackages = lookup.execute(workshop.appImageDir()); } else { neededLibPackages = Collections.emptyList(); - if (!Files.exists(thePackage.sourceRoot())) { - Log.info(I18N.getString("warning.foreign-app-image")); - } + Log.info(I18N.getString("warning.foreign-app-image")); } // Merge all package lists together. @@ -211,17 +213,16 @@ private List getListOfNeededPackages( return result; } - private Map createDefaultReplacementData( - Map params) throws IOException { + private Map createDefaultReplacementData(Workshop workshop, LinuxPackage pkg) throws IOException { Map data = new HashMap<>(); - data.put("APPLICATION_PACKAGE", createMetaPackage(params).name()); - data.put("APPLICATION_VENDOR", VENDOR.fetchFrom(params)); - data.put("APPLICATION_VERSION", VERSION.fetchFrom(params)); - data.put("APPLICATION_DESCRIPTION", DESCRIPTION.fetchFrom(params)); + data.put("APPLICATION_PACKAGE", pkg.packageName()); + data.put("APPLICATION_VENDOR", pkg.app().vendor()); + data.put("APPLICATION_VERSION", pkg.version()); + data.put("APPLICATION_DESCRIPTION", pkg.description()); - String defaultDeps = String.join(", ", getListOfNeededPackages(params)); - String customDeps = LINUX_PACKAGE_DEPENDENCIES.fetchFrom(params).strip(); + String defaultDeps = String.join(", ", getListOfNeededPackages(workshop)); + String customDeps = pkg.additionalDependencies(); if (!customDeps.isEmpty() && !defaultDeps.isEmpty()) { customDeps = ", " + customDeps; } @@ -234,9 +235,7 @@ private Map createDefaultReplacementData( protected abstract List verifyOutputBundle( Map params, Path packageBundle); - protected abstract void initLibProvidersLookup( - Map params, - LibProvidersLookup libProvidersLookup); + protected abstract void initLibProvidersLookup(LibProvidersLookup libProvidersLookup); protected abstract List getToolValidators( Map params); @@ -252,95 +251,6 @@ protected abstract Path buildPackageBundle( Map params, Path outputParentDir) throws PackagerException, IOException; - protected final PlatformPackage createMetaPackage( - Map params) { - - Supplier packageLayout = () -> { - String installDir = LINUX_INSTALL_DIR.fetchFrom(params); - if (isInstallDirInUsrTree(installDir)) { - return ApplicationLayout.linuxUsrTreePackageImage( - Path.of("/").relativize(Path.of(installDir)), - packageName.fetchFrom(params)); - } - return appImageLayout(params); - }; - - return new PlatformPackage() { - @Override - public String name() { - return packageName.fetchFrom(params); - } - - @Override - public Path sourceRoot() { - return IMAGES_ROOT.fetchFrom(params).toAbsolutePath(); - } - - @Override - public ApplicationLayout sourceApplicationLayout() { - return packageLayout.get().resolveAt( - applicationInstallDir(sourceRoot())); - } - - @Override - public ApplicationLayout installedApplicationLayout() { - return packageLayout.get().resolveAt( - applicationInstallDir(Path.of("/"))); - } - - private Path applicationInstallDir(Path root) { - String installRoot = LINUX_INSTALL_DIR.fetchFrom(params); - if (isInstallDirInUsrTree(installRoot)) { - return root; - } - - Path installDir = Path.of(installRoot, name()); - if (installDir.isAbsolute()) { - installDir = Path.of("." + installDir.toString()).normalize(); - } - return root.resolve(installDir); - } - }; - } - - private ApplicationLayout appImageLayout( - Map params) { - if (StandardBundlerParam.isRuntimeInstaller(params)) { - return ApplicationLayout.javaRuntime(); - } - return ApplicationLayout.linuxAppImage(); - } - - private static void validateInstallDir(String installDir) throws - ConfigException { - - if (installDir.isEmpty()) { - throw new ConfigException(MessageFormat.format(I18N.getString( - "error.invalid-install-dir"), "/"), null); - } - - boolean valid = false; - try { - final Path installDirPath = Path.of(installDir); - valid = installDirPath.isAbsolute(); - if (valid && !installDirPath.normalize().toString().equals( - installDirPath.toString())) { - // Don't allow '/opt/foo/..' or /opt/. - valid = false; - } - } catch (InvalidPathException ex) { - } - - if (!valid) { - throw new ConfigException(MessageFormat.format(I18N.getString( - "error.invalid-install-dir"), installDir), null); - } - } - - protected static boolean isInstallDirInUsrTree(String installDir) { - return Set.of("/usr/local", "/usr").contains(installDir); - } - private final BundlerParamInfo packageName; private final Bundler appImageBundler; private boolean withFindNeededPackages; @@ -352,38 +262,12 @@ private static final class CustomActionInstance { this.factory = factory; } - void init(PlatformPackage thePackage, Map params) - throws IOException { - instance = factory.create(thePackage, params); + void init(Workshop workshop, Package pkg) throws IOException { + instance = factory.create(workshop, pkg); Objects.requireNonNull(instance); } private final ShellCustomActionFactory factory; ShellCustomAction instance; } - - private static final BundlerParamInfo LINUX_PACKAGE_DEPENDENCIES = - new StandardBundlerParam<>( - Arguments.CLIOptions.LINUX_PACKAGE_DEPENDENCIES.getId(), - String.class, - params -> "", - (s, p) -> s - ); - - static final BundlerParamInfo LINUX_INSTALL_DIR = - new StandardBundlerParam<>( - "linux-install-dir", - String.class, - params -> { - String dir = INSTALL_DIR.fetchFrom(params); - if (dir != null) { - if (dir.endsWith("/")) { - dir = dir.substring(0, dir.length()-1); - } - return dir; - } - return "/opt"; - }, - (s, p) -> s - ); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index f65210553dee3..be75545450111 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -198,9 +198,7 @@ protected Map createReplacementData( } @Override - protected void initLibProvidersLookup( - Map params, - LibProvidersLookup libProvidersLookup) { + protected void initLibProvidersLookup(LibProvidersLookup libProvidersLookup) { libProvidersLookup.setPackageLookup(file -> { return Executor.of(TOOL_RPM, "-q", "--queryformat", "%{name}\\n", @@ -242,45 +240,6 @@ protected List verifyOutputBundle( return errors; } - /** - * Various ways to get rpm arch. Needed to address JDK-8233143. rpmbuild is - * mandatory for rpm packaging, try it first. rpm is optional and may not be - * available, use as the last resort. - */ - private enum RpmArchReader { - Rpmbuild(TOOL_RPMBUILD, "--eval=%{_target_cpu}"), - Rpm(TOOL_RPM, "--eval=%{_target_cpu}"); - - RpmArchReader(String... cmdline) { - this.cmdline = cmdline; - } - - String getRpmArch() throws IOException { - Executor exec = Executor.of(cmdline).saveOutput(true); - if (this == values()[values().length - 1]) { - exec.executeExpectSuccess(); - } else if (exec.execute() != 0) { - return null; - } - - return exec.getOutput().get(0); - } - - private final String[] cmdline; - } - - private String rpmArch() throws IOException { - if (rpmArch == null) { - for (var rpmArchReader : RpmArchReader.values()) { - rpmArch = rpmArchReader.getRpmArch(); - if (rpmArch != null) { - break; - } - } - } - return rpmArch; - } - private Path specFile(Map params) { return TEMP_ROOT.fetchFrom(params).resolve(Path.of("SPECS", PACKAGE_NAME.fetchFrom(params) + ".spec")); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java new file mode 100644 index 0000000000000..c7a43da26adde --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.Map; +import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; + +interface LinuxRpmPackage extends LinuxPackage { + + String licenseType(); + + static class Impl extends LinuxPackage.Proxy implements LinuxRpmPackage { + + public Impl(LinuxPackage target, String licenseType) { + super(target); + this.licenseType = licenseType; + } + + @Override + public String licenseType() { + return licenseType; + } + + private final String licenseType; + } + + private static LinuxRpmPackage createFromParams(Map params) throws ConfigException { + var pkg = LinuxPackage.createFromParams(params, StandardPackageType.LinuxRpm); + + var licenseType = Internal.LICENSE_TYPE.fetchFrom(params); + + return new Impl(pkg, licenseType); + } + + final static class Internal { + + private static final BundlerParamInfo LICENSE_TYPE + = new StandardBundlerParam<>( + Arguments.CLIOptions.LINUX_RPM_LICENSE_TYPE.getId(), + String.class, + params -> I18N.getString("param.license-type.default"), + (s, p) -> s); + } + + static final StandardBundlerParam TARGET_PACKAGE = new StandardBundlerParam<>( + Package.PARAM_ID, LinuxRpmPackage.class, params -> { + return toFunction(LinuxRpmPackage::createFromParams).apply(params); + }, null); +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties index 3b95c8e474e79..8bc11a4f054e2 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties @@ -49,6 +49,8 @@ error.invalid-install-dir=Invalid installation directory "{0}" error.invalid-value-for-package-name=Invalid value "{0}" for the bundle name. error.invalid-value-for-package-name.advice=Set the "linux-bundle-name" option to a valid Debian package name. Note that the package names must consist only of lower case letters (a-z), digits (0-9), plus (+) and minus (-) signs, and periods (.). They must be at least two characters long and must start with an alphanumeric character. +error.rpm-arch-not-detected="Failed to detect RPM arch" + message.icon-not-png=The specified icon "{0}" is not a PNG file and will not be used. The default icon will be used in it's place. message.test-for-tool=Test for [{0}]. Result: {1} message.outputting-to-location=Generating DEB for installer to: {0}. diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java index cb65781935c8b..35460a77b2034 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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,29 +24,8 @@ */ package jdk.jpackage.internal; -import java.util.Map; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; - class LauncherAsService { - LauncherAsService(String name, Map mainParams, - OverridableResource resource) { - if (name == null || APP_NAME.fetchFrom(mainParams).equals(name)) { - // Main launcher - name = APP_NAME.fetchFrom(mainParams); - this.description = DESCRIPTION.fetchFrom(mainParams); - } else { - // Additional launcher - this.description = String.format("%s (%s)", DESCRIPTION.fetchFrom( - mainParams), name); - } - - this.name = name; - this.resource = resource; - resource.addSubstitutionDataEntry("SERVICE_DESCRIPTION", description); - } - LauncherAsService(Launcher launcher, OverridableResource resource) { this.name = launcher.name(); this.description = launcher.description(); diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java index defb76d837c9f..c80e486ab32cd 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java @@ -25,10 +25,8 @@ package jdk.jpackage.internal; import java.io.IOException; -import java.util.Map; interface ShellCustomActionFactory { - ShellCustomAction create(PlatformPackage thePackage, - Map params) throws IOException; + ShellCustomAction create(Workshop workshop, Package pkg) throws IOException; } diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java index 3d8982584e1b1..082fa36600a0b 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java @@ -55,6 +55,19 @@ class UnixLaunchersAsServices extends ShellCustomAction { factory::apply).toList(); } + UnixLaunchersAsServices(Workshop workshop, Application app, List requiredPackages, Function factory) throws IOException { + this.workshop = workshop; + this.pkg = pkg; + this.requiredPackages = requiredPackages; + + // Read launchers information + launchers = pkg. + + AppImageFile.getLaunchers(PREDEFINED_APP_IMAGE.fetchFrom( + params), params).stream().filter(LauncherInfo::isService).map( + factory::apply).toList(); + } + @Override final List requiredPackages() { if (launchers.isEmpty()) { @@ -106,15 +119,15 @@ boolean isEmpty() { abstract static class UnixLauncherAsService extends LauncherAsService { - UnixLauncherAsService(String name, Map mainParams, - OverridableResource resource) { - super(name, mainParams, resource); + UnixLauncherAsService(Launcher launcher, OverridableResource resource) { + super(launcher, resource); } abstract Path descriptorFilePath(Path root); } - private final PlatformPackage thePackage; + private final Workshop workshop; + private final Package pkg; private final List requiredPackages; private final List launchers; private final Enquoter enqouter = Enquoter.forShellLiterals(); From 0453a37c4dac1e4a9329b4bcdfdfcaff17199789 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 26 Jun 2024 16:36:00 -0400 Subject: [PATCH 0008/1101] Got rid of "params" in DesktopIntegration --- .../jpackage/internal/DesktopIntegration.java | 117 ++++++------------ .../internal/LinuxLaunchersAsServices.java | 43 +++---- .../internal/LinuxPackageBundler.java | 7 +- .../internal/MacLaunchersAsServices.java | 59 +++------ .../jdk/jpackage/internal/Application.java | 50 ++++++++ .../jpackage/internal/LauncherAsService.java | 23 +--- .../jdk/jpackage/internal/Package.java | 12 ++ .../internal/ShellCustomActionFactory.java | 6 +- .../internal/UnixLaunchersAsServices.java | 27 ++-- 9 files changed, 151 insertions(+), 193 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 6a5b200f8f304..c6abdcae31258 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -43,17 +43,9 @@ import javax.imageio.ImageIO; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import jdk.jpackage.internal.Arguments.CLIOptions; +import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; import static jdk.jpackage.internal.LinuxAppImageBuilder.DEFAULT_ICON; -import static jdk.jpackage.internal.LinuxAppImageBuilder.ICON_PNG; -import static jdk.jpackage.internal.OverridableResource.createResource; -import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; -import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; -import static jdk.jpackage.internal.StandardBundlerParam.ICON; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; /** * Helper to create files for desktop integration. @@ -68,26 +60,23 @@ final class DesktopIntegration extends ShellCustomAction { private static final List REPLACEMENT_STRING_IDS = List.of( COMMANDS_INSTALL, COMMANDS_UNINSTALL, SCRIPTS, COMMON_SCRIPTS); - private DesktopIntegration(PlatformPackage thePackage, - Map params, - Map mainParams) throws IOException { + private DesktopIntegration(Workshop workshop, Package pkg, Launcher launcher) throws IOException { - associations = FileAssociation.fetchFrom(params).stream() + associations = launcher.fileAssociations().stream() .filter(fa -> !fa.mimeTypes.isEmpty()) - .map(LinuxFileAssociation::new) - .collect(Collectors.toUnmodifiableList()); - - launchers = ADD_LAUNCHERS.fetchFrom(params); + .map(LinuxFileAssociation::new).toList(); - this.thePackage = thePackage; + this.workshop = workshop; + this.pkg = pkg; + this.launcher = launcher; // Need desktop and icon files if one of conditions is met: // - there are file associations configured // - user explicitly requested to create a shortcut boolean withDesktopFile = !associations.isEmpty() || LINUX_SHORTCUT_HINT.fetchFrom(params); - var curIconResource = LinuxAppImageBuilder.createIconResource(DEFAULT_ICON, - ICON_PNG, params, mainParams); + var curIconResource = pkg.app().createLauncherIconResource(launcher, DEFAULT_ICON, + workshop::createResource); if (curIconResource == null) { // This is additional launcher with explicit `no icon` configuration. withDesktopFile = false; @@ -100,19 +89,19 @@ private DesktopIntegration(PlatformPackage thePackage, } } - desktopFileResource = createResource("template.desktop", params) + desktopFileResource = workshop.createResource("template.desktop") .setCategory(I18N.getString("resource.menu-shortcut-descriptor")) - .setPublicName(APP_NAME.fetchFrom(params) + ".desktop"); + .setPublicName(launcher.name() + ".desktop"); - final String escapedAppFileName = APP_NAME.fetchFrom(params).replaceAll("\\s+", "_"); + final String escapedAppFileName = launcher.name().replaceAll("\\s+", "_"); // XDG recommends to use vendor prefix in desktop file names as xdg // commands copy files to system directories. // Package name should be a good prefix. final String desktopFileName = String.format("%s-%s.desktop", - thePackage.name(), escapedAppFileName); + pkg.packageName(), escapedAppFileName); final String mimeInfoFileName = String.format("%s-%s-MimeInfo.xml", - thePackage.name(), escapedAppFileName); + pkg.packageName(), escapedAppFileName); mimeInfoFile = new DesktopFile(mimeInfoFileName); @@ -123,8 +112,8 @@ private DesktopIntegration(PlatformPackage thePackage, if (curIconResource == null) { // Create default icon. - curIconResource = LinuxAppImageBuilder.createIconResource( - DEFAULT_ICON, ICON_PNG, mainParams, null); + curIconResource = pkg.app().createLauncherIconResource(pkg.app().mainLauncher(), + DEFAULT_ICON, workshop::createResource); } } else { desktopFile = null; @@ -133,51 +122,22 @@ private DesktopIntegration(PlatformPackage thePackage, iconResource = curIconResource; - desktopFileData = Collections.unmodifiableMap( - createDataForDesktopFile(params)); - - nestedIntegrations = new ArrayList<>(); - // Read launchers information from predefine app image - if (launchers.isEmpty() && - PREDEFINED_APP_IMAGE.fetchFrom(params) != null) { - List launcherInfos = - AppImageFile.getLaunchers( - PREDEFINED_APP_IMAGE.fetchFrom(params), params); - if (!launcherInfos.isEmpty()) { - launcherInfos.remove(0); // Remove main launcher - } - for (var launcherInfo : launcherInfos) { - Map launcherParams = new HashMap<>(); - Arguments.putUnlessNull(launcherParams, CLIOptions.NAME.getId(), - launcherInfo.getName()); - launcherParams = AddLauncherArguments.merge(params, - launcherParams, ICON.getID(), ICON_PNG.getID(), - ADD_LAUNCHERS.getID(), FILE_ASSOCIATIONS.getID(), - PREDEFINED_APP_IMAGE.getID()); - if (launcherInfo.isShortcut()) { - nestedIntegrations.add(new DesktopIntegration(thePackage, - launcherParams, params)); - } - } + desktopFileData = createDataForDesktopFile(); + + if (launcher != pkg.app().mainLauncher()) { + nestedIntegrations = List.of(); } else { - for (var launcherParams : launchers) { - launcherParams = AddLauncherArguments.merge(params, - launcherParams, ICON.getID(), ICON_PNG.getID(), - ADD_LAUNCHERS.getID(), FILE_ASSOCIATIONS.getID()); - if (SHORTCUT_HINT.fetchFrom(launcherParams)) { - nestedIntegrations.add(new DesktopIntegration(thePackage, - launcherParams, params)); - } - } + nestedIntegrations = pkg.app().additionalLaunchers().stream().map(toFunction(l -> { + return new DesktopIntegration(workshop, pkg, l); + })).toList(); } } - static ShellCustomAction create(PlatformPackage thePackage, - Map params) throws IOException { - if (StandardBundlerParam.isRuntimeInstaller(params)) { + static ShellCustomAction create(Workshop workshop, Package pkg) throws IOException { + if (pkg.isRuntimeInstaller()) { return ShellCustomAction.nop(REPLACEMENT_STRING_IDS); } - return new DesktopIntegration(thePackage, params, null); + return new DesktopIntegration(workshop, pkg, pkg.app().mainLauncher()); } @Override @@ -262,17 +222,16 @@ private List requiredPackagesSelf() { return Collections.emptyList(); } - private Map createDataForDesktopFile( - Map params) { + private Map createDataForDesktopFile() { Map data = new HashMap<>(); - data.put("APPLICATION_NAME", APP_NAME.fetchFrom(params)); - data.put("APPLICATION_DESCRIPTION", DESCRIPTION.fetchFrom(params)); + data.put("APPLICATION_NAME", launcher.name()); + data.put("APPLICATION_DESCRIPTION", launcher.description()); data.put("APPLICATION_ICON", Optional.ofNullable(iconFile).map( f -> f.installPath().toString()).orElse(null)); data.put("DEPLOY_BUNDLE_CATEGORY", MENU_GROUP.fetchFrom(params)); - data.put("APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo( - thePackage.installedApplicationLayout().launchersDirectory().resolve( - LinuxAppImageBuilder.getLauncherName(params)).toString())); + data.put("APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo(pkg + .installedAppLayout().launchersDirectory().resolve(launcher.executableName()) + .toString())); return data; } @@ -374,11 +333,9 @@ void applyTo(Map data) { private class DesktopFile { DesktopFile(String fileName) { - var installPath = thePackage - .installedApplicationLayout() + var installPath = pkg.installedAppLayout() .destktopIntegrationDirectory().resolve(fileName); - var srcPath = thePackage - .sourceApplicationLayout() + var srcPath = pkg.appLayout().resolveAt(workshop.appImageDir()) .destktopIntegrationDirectory().resolve(fileName); impl = new InstallableFile(srcPath, installPath); @@ -530,12 +487,12 @@ private static class LinuxFileAssociation { final int iconSize; } - private final PlatformPackage thePackage; + private final Workshop workshop; + private final Package pkg; + private final Launcher launcher; private final List associations; - private final List> launchers; - private final OverridableResource iconResource; private final OverridableResource desktopFileResource; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java index 1f86ce6fd236d..f062dd7393932 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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,17 +30,15 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import static jdk.jpackage.internal.OverridableResource.createResource; /** * Helper to install launchers as services using "systemd". */ public final class LinuxLaunchersAsServices extends UnixLaunchersAsServices { - private LinuxLaunchersAsServices(PlatformPackage thePackage, - Map params) throws IOException { - super(thePackage, REQUIRED_PACKAGES, params, li -> { - return new Launcher(thePackage, li.getName(), params); + private LinuxLaunchersAsServices(Workshop workshop, Package pkg) throws IOException { + super(workshop, pkg.app(), REQUIRED_PACKAGES, launcher -> { + return new LauncherImpl(workshop, pkg, launcher); }); } @@ -58,36 +56,31 @@ protected Map createImpl() throws IOException { return data; } - static ShellCustomAction create(PlatformPackage thePackage, - Map params) throws IOException { - if (StandardBundlerParam.isRuntimeInstaller(params)) { + static ShellCustomAction create(Workshop workshop, Package pkg) throws IOException { + if (pkg.isRuntimeInstaller()) { return ShellCustomAction.nop(LINUX_REPLACEMENT_STRING_IDS); } - return new LinuxLaunchersAsServices(thePackage, params); + return new LinuxLaunchersAsServices(workshop, pkg); } - public static Path getServiceUnitFileName(String packageName, - String launcherName) { + public static Path getServiceUnitFileName(String packageName, String launcherName) { String baseName = launcherName.replaceAll("[\\s]", "_"); return Path.of(packageName + "-" + baseName + ".service"); } - private static class Launcher extends UnixLauncherAsService { + private static class LauncherImpl extends UnixLauncherAsService { - Launcher(PlatformPackage thePackage, String name, - Map mainParams) { - super(name, mainParams, createResource("unit-template.service", - mainParams).setCategory(I18N.getString( - "resource.systemd-unit-file"))); + LauncherImpl(Workshop workshop, Package pkg, Launcher launcher) { + super(launcher, workshop.createResource("unit-template.service").setCategory(I18N + .getString("resource.systemd-unit-file"))); - unitFilename = getServiceUnitFileName(thePackage.name(), getName()); + unitFilename = getServiceUnitFileName(pkg.packageName(), launcher.executableName() + .toString()); - getResource() - .setPublicName(unitFilename) - .addSubstitutionDataEntry("APPLICATION_LAUNCHER", - Enquoter.forPropertyValues().applyTo( - thePackage.installedApplicationLayout().launchersDirectory().resolve( - getName()).toString())); + getResource().setPublicName(unitFilename).addSubstitutionDataEntry( + "APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo(pkg.appLayout() + .resolveAt(workshop.appImageDir()).launchersDirectory().resolve( + getName()).toString())); } @Override diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index b510ed414118b..bea7a69101464 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -352,9 +352,8 @@ private static final class CustomActionInstance { this.factory = factory; } - void init(PlatformPackage thePackage, Map params) - throws IOException { - instance = factory.create(thePackage, params); + void init(Workshop workshop, Package pkg) throws IOException { + instance = factory.create(workshop, pkg); Objects.requireNonNull(instance); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index b0ee96e2ee3a7..001d4b535e731 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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,51 +30,30 @@ import java.util.Map; import java.util.Optional; import java.util.function.Predicate; -import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; -import static jdk.jpackage.internal.OverridableResource.createResource; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; /** * Helper to install launchers as services using "launchd". */ public final class MacLaunchersAsServices extends UnixLaunchersAsServices { - private MacLaunchersAsServices(PlatformPackage thePackage, - Map params) throws IOException { - super(thePackage, List.of(), params, li -> { - return new Launcher(thePackage, li.getName(), params); + private MacLaunchersAsServices(Workshop workshop, Package pkg) throws IOException { + super(workshop, pkg.app(), List.of(), launcher -> { + return new MacLauncherAsService(workshop, pkg, launcher); }); } static ShellCustomAction create(Map params, Path outputDir) throws IOException { - if (StandardBundlerParam.isRuntimeInstaller(params)) { + + // Order is important! + var pkg = Package.TARGET_PACKAGE.fetchFrom(params); + var workshop = Workshop.WORKSHOP.fetchFrom(params); + + if (pkg.isRuntimeInstaller()) { return null; } - return Optional.of(new MacLaunchersAsServices(new PlatformPackage() { - @Override - public String name() { - return MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params); - } - - @Override - public Path sourceRoot() { - return outputDir; - } - - @Override - public ApplicationLayout sourceApplicationLayout() { - throw new UnsupportedOperationException(); - } - - @Override - public ApplicationLayout installedApplicationLayout() { - return ApplicationLayout.macAppImage().resolveAt(Path.of( - MacBaseInstallerBundler.getInstallDir(params, false), - APP_NAME.fetchFrom(params) + ".app")); - } - }, params)).filter(Predicate.not(MacLaunchersAsServices::isEmpty)).orElse( - null); + return Optional.of(new MacLaunchersAsServices(workshop, pkg)).filter(Predicate.not( + MacLaunchersAsServices::isEmpty)).orElse(null); } public static Path getServicePListFileName(String packageName, @@ -83,15 +62,13 @@ public static Path getServicePListFileName(String packageName, return Path.of(packageName + "-" + baseName + ".plist"); } - private static class Launcher extends UnixLauncherAsService { + private static class MacLauncherAsService extends UnixLauncherAsService { - Launcher(PlatformPackage thePackage, String name, - Map mainParams) { - super(name, mainParams, createResource("launchd.plist.template", - mainParams).setCategory(I18N.getString( - "resource.launchd-plist-file"))); + MacLauncherAsService(Workshop workshop, Package pkg, Launcher launcher) { + super(launcher, workshop.createResource("launchd.plist.template").setCategory(I18N + .getString("resource.launchd-plist-file"))); - plistFilename = getServicePListFileName(thePackage.name(), getName()); + plistFilename = getServicePListFileName(pkg.packageName(), getName()); // It is recommended to set value of "label" property in launchd // .plist file equal to the name of this .plist file without the suffix. @@ -101,7 +78,7 @@ private static class Launcher extends UnixLauncherAsService { .setPublicName(plistFilename) .addSubstitutionDataEntry("LABEL", label) .addSubstitutionDataEntry("APPLICATION_LAUNCHER", - thePackage.installedApplicationLayout().launchersDirectory().resolve( + pkg.installedAppLayout().launchersDirectory().resolve( getName()).toString()); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java index a72f64cc62e9d..3036e431dae59 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java @@ -34,6 +34,7 @@ import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import static jdk.jpackage.internal.Functional.ThrowingBiFunction.toBiFunction; +import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; @@ -99,6 +100,36 @@ default List allLaunchers() { }).orElse(List.of()); } + default OverridableResource createLauncherIconResource(Launcher launcher, String defaultIconName, + Function resourceSupplier) { + final String resourcePublicName = launcher.name() + IOUtils.getSuffix(Path.of( + defaultIconName)); + + var iconType = Internal.getLauncherIconType(launcher.icon()); + if (iconType == Internal.IconType.NoIcon) { + return null; + } + + OverridableResource resource = resourceSupplier.apply(defaultIconName) + .setCategory("icon") + .setExternal(launcher.icon()) + .setPublicName(resourcePublicName); + + if (iconType == Internal.IconType.DefaultOrResourceDirIcon && mainLauncher() != launcher) { + // No icon explicitly configured for this launcher. + // Dry-run resource creation to figure out its source. + final Path nullPath = null; + if (toSupplier(() -> resource.saveToFile(nullPath)).get() != OverridableResource.Source.ResourceDir) { + // No icon in resource dir for this launcher, inherit icon + // configured for the main launcher. + return createLauncherIconResource(mainLauncher(), defaultIconName, resourceSupplier) + .setLogPublicName(resourcePublicName); + } + } + + return resource; + } + static record Impl(String name, String description, String version, String vendor, Path predefinedRuntimeImage, RuntimeBuilder runtimeBuilder, Launcher mainLauncher, List additionalLaunchers) implements Application { @@ -224,4 +255,23 @@ static Application createFromParams(Map params, return toBiFunction(Application::createFromParams).apply(params, Launcher::createFromParams); }, null); + + static class Internal { + + private enum IconType { + DefaultOrResourceDirIcon, CustomIcon, NoIcon + }; + + private static IconType getLauncherIconType(Path iconPath) { + if (iconPath == null) { + return IconType.DefaultOrResourceDirIcon; + } + + if (iconPath.toFile().getName().isEmpty()) { + return IconType.NoIcon; + } + + return IconType.CustomIcon; + } + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java index cb65781935c8b..35460a77b2034 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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,29 +24,8 @@ */ package jdk.jpackage.internal; -import java.util.Map; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; - class LauncherAsService { - LauncherAsService(String name, Map mainParams, - OverridableResource resource) { - if (name == null || APP_NAME.fetchFrom(mainParams).equals(name)) { - // Main launcher - name = APP_NAME.fetchFrom(mainParams); - this.description = DESCRIPTION.fetchFrom(mainParams); - } else { - // Additional launcher - this.description = String.format("%s (%s)", DESCRIPTION.fetchFrom( - mainParams), name); - } - - this.name = name; - this.resource = resource; - resource.addSubstitutionDataEntry("SERVICE_DESCRIPTION", description); - } - LauncherAsService(Launcher launcher, OverridableResource resource) { this.name = launcher.name(); this.description = launcher.description(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index 8f72eefc5ae5d..0dc64e78aec46 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -99,6 +99,18 @@ default ApplicationLayout appLayout() { return app().appLayout(); } + default ApplicationLayout installedAppLayout() { + Path root = relativeInstallDir(); + if (type() instanceof StandardPackageType type) { + switch (type) { + case LinuxDeb, LinuxRpm, MacDmg, MacPkg -> { + root = Path.of("/").resolve(root); + } + } + } + return appLayout().resolveAt(root); + } + /** * Returns package file name. */ diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java index defb76d837c9f..35dfb564a4f8e 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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,10 +25,8 @@ package jdk.jpackage.internal; import java.io.IOException; -import java.util.Map; interface ShellCustomActionFactory { - ShellCustomAction create(PlatformPackage thePackage, - Map params) throws IOException; + ShellCustomAction create(Workshop workshop, Package pkg) throws IOException; } diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java index 3d8982584e1b1..e717e0b46c42c 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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 @@ -33,26 +33,21 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.AppImageFile.LauncherInfo; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; /** * Helper to install launchers as services for Unix installers. */ class UnixLaunchersAsServices extends ShellCustomAction { - UnixLaunchersAsServices(PlatformPackage thePackage, - List requiredPackages, Map params, - Function factory) throws - IOException { + UnixLaunchersAsServices(Workshop workshop, Application app, List requiredPackages, + Function factory) throws IOException { - this.thePackage = thePackage; + this.appImageDir = workshop.appImageDir(); this.requiredPackages = requiredPackages; // Read launchers information - launchers = AppImageFile.getLaunchers(PREDEFINED_APP_IMAGE.fetchFrom( - params), params).stream().filter(LauncherInfo::isService).map( - factory::apply).toList(); + launchers = app.allLaunchers().stream().filter(Launcher::isService).map(factory::apply) + .toList(); } @Override @@ -93,8 +88,7 @@ protected Map createImpl() throws IOException { data.put(COMMANDS_UNINSTALL, strigifier.apply("unregister_services")); for (var launcher : launchers) { - launcher.getResource().saveToFile(launcher.descriptorFilePath( - thePackage.sourceRoot())); + launcher.getResource().saveToFile(launcher.descriptorFilePath(appImageDir)); } return data; @@ -106,15 +100,14 @@ boolean isEmpty() { abstract static class UnixLauncherAsService extends LauncherAsService { - UnixLauncherAsService(String name, Map mainParams, - OverridableResource resource) { - super(name, mainParams, resource); + UnixLauncherAsService(Launcher launcher, OverridableResource resource) { + super(launcher, resource); } abstract Path descriptorFilePath(Path root); } - private final PlatformPackage thePackage; + private final Path appImageDir; private final List requiredPackages; private final List launchers; private final Enquoter enqouter = Enquoter.forShellLiterals(); From 29b9bc8349582b9c1244e8ae1614906ab1a23b8e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 27 Jun 2024 20:27:49 -0400 Subject: [PATCH 0009/1101] Got rid of most "params" in Linux packaging. --- .../jpackage/internal/DesktopIntegration.java | 31 +--- .../jpackage/internal/LinuxApplication.java | 41 +---- .../internal/LinuxApplicationFromParams.java | 61 +++++++ .../jpackage/internal/LinuxDebBundler.java | 152 ++++++----------- .../jpackage/internal/LinuxDebPackage.java | 43 ++--- .../internal/LinuxDebPackageFromParams.java | 50 ++++++ .../jdk/jpackage/internal/LinuxPackage.java | 71 +------- .../internal/LinuxPackageBundler.java | 55 +++--- .../internal/LinuxPackageFromParams.java | 97 +++++++++++ .../jpackage/internal/LinuxRpmBundler.java | 159 +++++------------- .../jpackage/internal/LinuxRpmPackage.java | 28 +-- .../internal/LinuxRpmPackageFromParams.java | 51 ++++++ .../internal/MacLaunchersAsServices.java | 4 +- .../jpackage/internal/AppImageBundler.java | 2 +- .../jdk/jpackage/internal/Application.java | 101 +---------- .../internal/ApplicationFromParams.java | 132 +++++++++++++++ .../jdk/jpackage/internal/Launcher.java | 21 --- .../jpackage/internal/LauncherFromParams.java | 51 ++++++ .../jdk/jpackage/internal/Package.java | 51 +----- .../jpackage/internal/PackageFromParams.java | 84 +++++++++ .../internal/StandardBundlerParam.java | 10 +- .../jdk/jpackage/internal/Workshop.java | 41 ----- .../jpackage/internal/WorkshopFromParams.java | 70 ++++++++ .../jdk/jpackage/internal/WinApplication.java | 61 +------ .../internal/WinApplicationFromParams.java | 80 +++++++++ .../jdk/jpackage/internal/WinMsiBundler.java | 8 +- .../jdk/jpackage/internal/WinMsiPackage.java | 117 ------------- .../internal/WinMsiPackageFromParams.java | 136 +++++++++++++++ 28 files changed, 977 insertions(+), 831 deletions(-) create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java create mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java create mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index c6abdcae31258..eec7aef0039cf 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -45,7 +45,6 @@ import javax.xml.stream.XMLStreamWriter; import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; import static jdk.jpackage.internal.LinuxAppImageBuilder.DEFAULT_ICON; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; /** * Helper to create files for desktop integration. @@ -60,7 +59,7 @@ final class DesktopIntegration extends ShellCustomAction { private static final List REPLACEMENT_STRING_IDS = List.of( COMMANDS_INSTALL, COMMANDS_UNINSTALL, SCRIPTS, COMMON_SCRIPTS); - private DesktopIntegration(Workshop workshop, Package pkg, Launcher launcher) throws IOException { + private DesktopIntegration(Workshop workshop, LinuxPackage pkg, LinuxLauncher launcher) throws IOException { associations = launcher.fileAssociations().stream() .filter(fa -> !fa.mimeTypes.isEmpty()) @@ -73,7 +72,7 @@ private DesktopIntegration(Workshop workshop, Package pkg, Launcher launcher) th // Need desktop and icon files if one of conditions is met: // - there are file associations configured // - user explicitly requested to create a shortcut - boolean withDesktopFile = !associations.isEmpty() || LINUX_SHORTCUT_HINT.fetchFrom(params); + boolean withDesktopFile = !associations.isEmpty() || launcher.shortcut(); var curIconResource = pkg.app().createLauncherIconResource(launcher, DEFAULT_ICON, workshop::createResource); @@ -128,7 +127,7 @@ private DesktopIntegration(Workshop workshop, Package pkg, Launcher launcher) th nestedIntegrations = List.of(); } else { nestedIntegrations = pkg.app().additionalLaunchers().stream().map(toFunction(l -> { - return new DesktopIntegration(workshop, pkg, l); + return new DesktopIntegration(workshop, pkg, (LinuxLauncher)l); })).toList(); } } @@ -137,7 +136,8 @@ static ShellCustomAction create(Workshop workshop, Package pkg) throws IOExcepti if (pkg.isRuntimeInstaller()) { return ShellCustomAction.nop(REPLACEMENT_STRING_IDS); } - return new DesktopIntegration(workshop, pkg, pkg.app().mainLauncher()); + return new DesktopIntegration(workshop, (LinuxPackage) pkg, (LinuxLauncher) pkg.app() + .mainLauncher()); } @Override @@ -228,7 +228,7 @@ private Map createDataForDesktopFile() { data.put("APPLICATION_DESCRIPTION", launcher.description()); data.put("APPLICATION_ICON", Optional.ofNullable(iconFile).map( f -> f.installPath().toString()).orElse(null)); - data.put("DEPLOY_BUNDLE_CATEGORY", MENU_GROUP.fetchFrom(params)); + data.put("DEPLOY_BUNDLE_CATEGORY", pkg.category()); data.put("APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo(pkg .installedAppLayout().launchersDirectory().resolve(launcher.executableName()) .toString())); @@ -488,7 +488,7 @@ private static class LinuxFileAssociation { } private final Workshop workshop; - private final Package pkg; + private final LinuxPackage pkg; private final Launcher launcher; private final List associations; @@ -503,21 +503,4 @@ private static class LinuxFileAssociation { private final List nestedIntegrations; private final Map desktopFileData; - - private static final BundlerParamInfo MENU_GROUP = - new StandardBundlerParam<>( - Arguments.CLIOptions.LINUX_MENU_GROUP.getId(), - String.class, - params -> I18N.getString("param.menu-group.default"), - (s, p) -> s - ); - - private static final StandardBundlerParam LINUX_SHORTCUT_HINT = - new StandardBundlerParam<>( - Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(), - Boolean.class, - params -> false, - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) - ? false : Boolean.valueOf(s) - ); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplication.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplication.java index 80e36fa42a31e..21c17c61bcf40 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplication.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplication.java @@ -25,49 +25,10 @@ package jdk.jpackage.internal; -import java.util.Map; -import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; -import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; - interface LinuxApplication extends Application { - static class Impl extends Application.Proxy implements LinuxApplication { - + static class Impl extends Application.Proxy implements LinuxApplication { Impl(Application app) { super(app); } } - - static LinuxApplication createFromParams(Map params) throws ConfigException { - var app = Application.createFromParams(params, launcherParams -> { - var launcher = Launcher.createFromParams(launcherParams); - - boolean shortcut; - if (launcherParams.containsKey(SHORTCUT_HINT.getID())) { - // This is an explicit shortcut configuration for an addition launcher - shortcut = SHORTCUT_HINT.fetchFrom(launcherParams); - } else { - shortcut = Internal.LINUX_SHORTCUT_HINT.fetchFrom(launcherParams); - } - - return new LinuxLauncher.Impl(launcher, shortcut); - }); - return new Impl(app); - } - - static final StandardBundlerParam TARGET_APPLICATION = new StandardBundlerParam<>( - Application.PARAM_ID, LinuxApplication.class, params -> { - return toFunction(LinuxApplication::createFromParams).apply(params); - }, null); - - static final class Internal { - - private static final StandardBundlerParam LINUX_SHORTCUT_HINT = - new StandardBundlerParam<>( - Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(), - Boolean.class, - params -> false, - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) - ? false : Boolean.valueOf(s) - ); - } } \ No newline at end of file diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java new file mode 100644 index 0000000000000..969ae3b43c63d --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.Map; +import static jdk.jpackage.internal.ApplicationFromParams.createBundlerParam; +import jdk.jpackage.internal.LinuxApplication.Impl; +import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; + +final class LinuxApplicationFromParams { + + private static LinuxApplication create(Map params) throws ConfigException { + var app = ApplicationFromParams.create(params, launcherParams -> { + var launcher = LauncherFromParams.create(launcherParams); + + boolean shortcut; + if (launcherParams.containsKey(SHORTCUT_HINT.getID())) { + // This is an explicit shortcut configuration for an addition launcher + shortcut = SHORTCUT_HINT.fetchFrom(launcherParams); + } else { + shortcut = LINUX_SHORTCUT_HINT.fetchFrom(launcherParams); + } + + return new LinuxLauncher.Impl(launcher, shortcut); + }); + return new Impl(app); + } + + static final StandardBundlerParam APPLICATION = createBundlerParam( + LinuxApplicationFromParams::create); + + private static final StandardBundlerParam LINUX_SHORTCUT_HINT = new StandardBundlerParam<>( + Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(), + Boolean.class, + params -> false, + (s, p) -> (s == null || "null".equalsIgnoreCase(s)) + ? false : Boolean.valueOf(s) + ); +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index 35305e372972c..e6ff1e08cd148 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -42,19 +42,14 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; -import static jdk.jpackage.internal.OverridableResource.createResource; -import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; -import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.StandardBundlerParam.RELEASE; -import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; -import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; -import static jdk.jpackage.internal.StandardBundlerParam.COPYRIGHT; +import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; +import static jdk.jpackage.internal.Package.StandardPackageType.LinuxDeb; public class LinuxDebBundler extends LinuxPackageBundler { @@ -62,60 +57,32 @@ public class LinuxDebBundler extends LinuxPackageBundler { private static final String TOOL_DPKG = "dpkg"; private static final String TOOL_FAKEROOT = "fakeroot"; - private static final BundlerParamInfo SECTION = - new StandardBundlerParam<>( - Arguments.CLIOptions.LINUX_CATEGORY.getId(), - String.class, - params -> "misc", - (s, p) -> s); - - private static final BundlerParamInfo LICENSE_TEXT = - new StandardBundlerParam<> ( - "linux.deb.licenseText", - String.class, - params -> { - try { - String licenseFile = LICENSE_FILE.fetchFrom(params); - if (licenseFile != null) { - return Files.readString(Path.of(licenseFile)); - } - } catch (IOException e) { - Log.verbose(e); - } - return "Unknown"; - }, - (s, p) -> s); - public LinuxDebBundler() { - super(PACKAGE_NAME); + super(LinuxDebPackageFromParams.PACKAGE); } @Override - public void doValidate(Map params) - throws ConfigException { + protected void doValidate(Workshop workshop, LinuxPackage pkg) throws ConfigException { // Show warning if license file is missing - if (LICENSE_FILE.fetchFrom(params) == null) { + if (pkg.licenseFile() == null) { Log.verbose(I18N.getString("message.debs-like-licenses")); } } @Override - protected List getToolValidators( - Map params) { + protected List getToolValidators() { return Stream.of(TOOL_DPKG_DEB, TOOL_DPKG, TOOL_FAKEROOT).map( ToolValidator::new).toList(); } @Override - protected Path buildPackageBundle( - Map replacementData, - Map params, Path outputParentDir) throws - PackagerException, IOException { - - prepareProjectConfig(replacementData, params); - adjustPermissionsRecursive(createMetaPackage(params).sourceRoot()); - return buildDeb(params, outputParentDir); + protected Path buildPackageBundle(Map replacementData, Workshop workshop, + LinuxPackage pkg, Path outputParentDir) throws PackagerException, IOException { + + prepareProjectConfig(replacementData, workshop, pkg); + adjustPermissionsRecursive(workshop.appImageDir()); + return buildDeb(workshop, pkg, outputParentDir); } private static final Pattern PACKAGE_NAME_REGEX = Pattern.compile("^(^\\S+):"); @@ -186,16 +153,18 @@ private static Stream findProvidingPackages(Path file) throws IOExceptio Set archPackages = new HashSet<>(); Set otherPackages = new HashSet<>(); + var debArch = LinuxPackageArch.getValue(LinuxDeb); + Executor.of(TOOL_DPKG, "-S", file.toString()) .saveOutput(true).executeExpectSuccess() .getOutput().forEach(line -> { Matcher matcher = PACKAGE_NAME_REGEX.matcher(line); if (matcher.find()) { String name = matcher.group(1); - if (name.endsWith(":" + DEB_ARCH)) { + if (name.endsWith(":" + debArch)) { // Strip arch suffix name = name.substring(0, - name.length() - (DEB_ARCH.length() + 1)); + name.length() - (debArch.length() + 1)); archPackages.add(name); } else { otherPackages.add(name); @@ -210,21 +179,20 @@ private static Stream findProvidingPackages(Path file) throws IOExceptio } @Override - protected List verifyOutputBundle( - Map params, Path packageBundle) { + protected List verifyOutputBundle(Workshop workshop, LinuxPackage pkg, + Path packageBundle) { List errors = new ArrayList<>(); String controlFileName = "control"; List properties = List.of( - new PackageProperty("Package", PACKAGE_NAME.fetchFrom(params), + new PackageProperty("Package", pkg.packageName(), "APPLICATION_PACKAGE", controlFileName), - new PackageProperty("Version", String.format("%s%s", - VERSION.fetchFrom(params), releaseSuffix(params)), + new PackageProperty("Version", ((LinuxDebPackage)pkg).versionWithRelease(), "APPLICATION_VERSION_WITH_RELEASE", controlFileName), - new PackageProperty("Architecture", DEB_ARCH, "APPLICATION_ARCH", - controlFileName)); + new PackageProperty("Architecture", LinuxPackageArch.getValue(LinuxDeb), + "APPLICATION_ARCH", controlFileName)); List cmdline = new ArrayList<>(List.of(TOOL_DPKG_DEB, "-f", packageBundle.toString())); @@ -319,10 +287,9 @@ DebianFile setExecutable() { return this; } - void create(Map data, Map params) + void create(Map data, Function resourceFactory) throws IOException { - createResource("template." + dstFilePath.getFileName().toString(), - params) + resourceFactory.apply("template." + dstFilePath.getFileName().toString()) .setCategory(I18N.getString(comment)) .setSubstitutionData(data) .saveToFile(dstFilePath); @@ -336,10 +303,9 @@ void create(Map data, Map params) private String permissions; } - private void prepareProjectConfig(Map data, - Map params) throws IOException { + private void prepareProjectConfig(Map data, Workshop workshop, LinuxPackage pkg) throws IOException { - Path configDir = createMetaPackage(params).sourceRoot().resolve("DEBIAN"); + Path configDir = workshop.appImageDir().resolve("DEBIAN"); List debianFiles = new ArrayList<>(); debianFiles.add(new DebianFile( configDir.resolve("control"), @@ -357,71 +323,47 @@ private void prepareProjectConfig(Map data, configDir.resolve("postrm"), "resource.deb-postrm-script").setExecutable()); - final String installDir = LINUX_INSTALL_DIR.fetchFrom(params); - - if (!StandardBundlerParam.isRuntimeInstaller(params) - || (isInstallDirInUsrTree(installDir) || installDir.startsWith("/usr/"))) { - debianFiles.add(new DebianFile( - getConfig_CopyrightFile(params), + Optional.ofNullable(((LinuxDebPackage)pkg).relativeCopyrightFilePath()).ifPresent(copyrightFile -> { + debianFiles.add(new DebianFile(Path.of("/").resolve(copyrightFile), "resource.copyright-file")); - } + }); for (DebianFile debianFile : debianFiles) { - debianFile.create(data, params); + debianFile.create(data, workshop::createResource); } } @Override - protected Map createReplacementData( - Map params) throws IOException { + protected Map createReplacementData(Workshop workshop, LinuxPackage pkg) throws IOException { Map data = new HashMap<>(); - data.put("APPLICATION_MAINTAINER", MAINTAINER.fetchFrom(params)); - data.put("APPLICATION_SECTION", SECTION.fetchFrom(params)); - data.put("APPLICATION_COPYRIGHT", COPYRIGHT.fetchFrom(params)); - data.put("APPLICATION_LICENSE_TEXT", LICENSE_TEXT.fetchFrom(params)); - data.put("APPLICATION_ARCH", DEB_ARCH); - data.put("APPLICATION_INSTALLED_SIZE", Long.toString( - createMetaPackage(params).sourceApplicationLayout().sizeInBytes() >> 10)); - data.put("APPLICATION_HOMEPAGE", Optional.ofNullable( - ABOUT_URL.fetchFrom(params)).map(value -> "Homepage: " + value).orElse( - "")); - data.put("APPLICATION_VERSION_WITH_RELEASE", String.format("%s%s", - VERSION.fetchFrom(params), releaseSuffix(params))); + String licenseText = Optional.ofNullable(pkg.licenseFile()).map(toFunction(Files::readString)).orElse("Unknown"); - return data; - } + data.put("APPLICATION_MAINTAINER", ((LinuxDebPackage) pkg).maintainer()); + data.put("APPLICATION_SECTION", pkg.category()); + data.put("APPLICATION_COPYRIGHT", pkg.app().copyright()); + data.put("APPLICATION_LICENSE_TEXT", licenseText); + data.put("APPLICATION_ARCH", LinuxPackageArch.getValue(LinuxDeb)); + data.put("APPLICATION_INSTALLED_SIZE", Long.toString(pkg.appLayout().resolveAt(workshop + .appImageDir()).sizeInBytes() >> 10)); + data.put("APPLICATION_HOMEPAGE", Optional.ofNullable(pkg.aboutURL()).map( + value -> "Homepage: " + value).orElse("")); + data.put("APPLICATION_VERSION_WITH_RELEASE", ((LinuxDebPackage) pkg).versionWithRelease()); - private Path getConfig_CopyrightFile(Map params) { - final String installDir = LINUX_INSTALL_DIR.fetchFrom(params); - final String packageName = PACKAGE_NAME.fetchFrom(params); - - final Path installPath; - if (isInstallDirInUsrTree(installDir) || installDir.startsWith("/usr/")) { - installPath = Path.of("/usr/share/doc/", packageName, "copyright"); - } else { - installPath = Path.of(installDir, packageName, "share/doc/copyright"); - } - - return createMetaPackage(params).sourceRoot().resolve( - Path.of("/").relativize(installPath)); + return data; } - private Path buildDeb(Map params, - Path outdir) throws IOException { - Path outFile = outdir.resolve( - FULL_PACKAGE_NAME.fetchFrom(params)+".deb"); + private Path buildDeb(Workshop workshop, LinuxPackage pkg, Path outdir) throws IOException { + Path outFile = pkg.packageFileName(); Log.verbose(MessageFormat.format(I18N.getString( "message.outputting-to-location"), outFile.toAbsolutePath().toString())); - PlatformPackage thePackage = createMetaPackage(params); - List cmdline = new ArrayList<>(); cmdline.addAll(List.of(TOOL_FAKEROOT, TOOL_DPKG_DEB)); if (Log.isVerbose()) { cmdline.add("--verbose"); } - cmdline.addAll(List.of("-b", thePackage.sourceRoot().toString(), + cmdline.addAll(List.of("-b", workshop.appImageDir().toString(), outFile.toAbsolutePath().toString())); // run dpkg diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java index b9ca6d9438c23..42cf3eab928f6 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java @@ -24,8 +24,7 @@ */ package jdk.jpackage.internal; -import java.util.Map; -import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; +import java.nio.file.Path; interface LinuxDebPackage extends LinuxPackage { @@ -35,7 +34,22 @@ default String maintainer() { return String.format("%s <%s>", app().vendor(), maintainerEmail()); } - static class Impl extends LinuxPackage.Proxy implements LinuxDebPackage { + default String versionWithRelease() { + return String.format("%s-%s", version(), release()); + } + + default Path relativeCopyrightFilePath() { + if (isRuntimeInstaller()) { + return null; + } else if (isInstallDirInUsrTree() || Path.of("/").resolve(relativeInstallDir()).startsWith( + "/usr/")) { + return Path.of("/usr/share/doc/", packageName(), "copyright"); + } else { + return relativeInstallDir().resolve("share/doc/copyright"); + } + } + + static class Impl extends LinuxPackage.Proxy implements LinuxDebPackage { public Impl(LinuxPackage target, String maintainerEmail) { super(target); @@ -49,27 +63,4 @@ public String maintainerEmail() { private final String maintainerEmail; } - - private static LinuxDebPackage createFromParams(Map params) throws ConfigException { - var pkg = LinuxPackage.createFromParams(params, StandardPackageType.LinuxDeb); - - var maintainerEmail = Internal.MAINTAINER_EMAIL.fetchFrom(params); - - return new Impl(pkg, maintainerEmail); - } - - final static class Internal { - - private static final BundlerParamInfo MAINTAINER_EMAIL - = new StandardBundlerParam<>( - Arguments.CLIOptions.LINUX_DEB_MAINTAINER.getId(), - String.class, - params -> "Unknown", - (s, p) -> s); - } - - static final StandardBundlerParam TARGET_PACKAGE = new StandardBundlerParam<>( - Package.PARAM_ID, LinuxDebPackage.class, params -> { - return toFunction(LinuxDebPackage::createFromParams).apply(params); - }, null); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java new file mode 100644 index 0000000000000..b011f400ef0ce --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.Map; +import static jdk.jpackage.internal.Package.StandardPackageType.LinuxDeb; +import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; + +final class LinuxDebPackageFromParams { + + private static LinuxDebPackage create(Map params) throws ConfigException { + var pkg = LinuxPackageFromParams.create(params, LinuxDeb); + + var maintainerEmail = MAINTAINER_EMAIL.fetchFrom(params); + + return new LinuxDebPackage.Impl(pkg, maintainerEmail); + } + + static final StandardBundlerParam PACKAGE = createBundlerParam( + LinuxDebPackageFromParams::create); + + private static final BundlerParamInfo MAINTAINER_EMAIL = new StandardBundlerParam<>( + Arguments.CLIOptions.LINUX_DEB_MAINTAINER.getId(), + String.class, + params -> "Unknown", + (s, p) -> s); + +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java index 213ddd0feae04..070b79e83542e 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java @@ -117,45 +117,7 @@ public String release() { } } - static LinuxPackage createFromParams(Map params, - StandardPackageType pkgType) throws ConfigException { - var pkg = Package.createFromParams(params, LinuxApplication.createFromParams(params), pkgType); - var menuGroupName = Internal.LINUX_MENU_GROUP.fetchFrom(params); - var category = Internal.LINUX_CATEGORY.fetchFrom(params); - var additionalDependencies = Internal.LINUX_PACKAGE_DEPENDENCIES.fetchFrom(params); - var release = Internal.RELEASE.fetchFrom(params); - - var packageName = mapPackageName(pkg.packageName(), pkgType); - var arch = LinuxPackageArch.getValue(pkgType); - - return new Impl(pkg, menuGroupName, category, additionalDependencies, release) { - @Override - public String packageName() { - return packageName; - } - - @Override - public Path packageFileName() { - String packageFileNameTemlate; - switch (asStandardPackageType()) { - case LinuxDeb -> { - packageFileNameTemlate = "%s_%s-%s_%s.deb"; - } - case LinuxRpm -> { - packageFileNameTemlate = "%s-%s-%s.%s.rpm"; - } - default -> { - throw new UnsupportedOperationException(); - } - } - - return Path.of(String.format(packageFileNameTemlate, packageName(), version(), - release(), arch)); - } - }; - } - - private static String mapPackageName(String packageName, StandardPackageType pkgType) throws ConfigException { + static String mapPackageName(String packageName, StandardPackageType pkgType) throws ConfigException { // make sure to lower case and spaces/underscores become dashes packageName = packageName.toLowerCase().replaceAll("[ _]", "-"); @@ -201,35 +163,4 @@ private static String mapPackageName(String packageName, StandardPackageType pkg return packageName; } - - final static class Internal { - - private static final BundlerParamInfo LINUX_CATEGORY - = new StandardBundlerParam<>( - Arguments.CLIOptions.LINUX_CATEGORY.getId(), - String.class, - params -> "misc", - (s, p) -> s); - - private static final BundlerParamInfo LINUX_PACKAGE_DEPENDENCIES - = new StandardBundlerParam<>( - Arguments.CLIOptions.LINUX_PACKAGE_DEPENDENCIES.getId(), - String.class, - params -> null, - (s, p) -> s); - - private static final BundlerParamInfo LINUX_MENU_GROUP - = new StandardBundlerParam<>( - Arguments.CLIOptions.LINUX_MENU_GROUP.getId(), - String.class, - params -> I18N.getString("param.menu-group.default"), - (s, p) -> s); - - private static final StandardBundlerParam RELEASE - = new StandardBundlerParam<>( - Arguments.CLIOptions.RELEASE.getId(), - String.class, - params -> "1", - (s, p) -> s); - } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 3a19d0fb2346c..46e396e96b9b1 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal; import java.io.IOException; -import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Files; import java.text.MessageFormat; @@ -34,21 +33,14 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.Supplier; import java.util.stream.Stream; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; -import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; -import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; abstract class LinuxPackageBundler extends AbstractBundler { - LinuxPackageBundler(BundlerParamInfo packageName) { - this.packageName = packageName; + LinuxPackageBundler(BundlerParamInfo pkgParam) { + this.pkgParam = pkgParam; appImageBundler = new LinuxAppBundler().setDependentTask(true); customActions = List.of(new CustomActionInstance( DesktopIntegration::create), new CustomActionInstance( @@ -58,6 +50,10 @@ abstract class LinuxPackageBundler extends AbstractBundler { @Override public final boolean validate(Map params) throws ConfigException { + + // Order is important! + LinuxPackage pkg = pkgParam.fetchFrom(params); + var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); // run basic validation to ensure requirements are met // we are not interested in return code, only possible exception @@ -65,12 +61,7 @@ public final boolean validate(Map params) FileAssociation.verify(FileAssociation.fetchFrom(params)); - // If package name has some restrictions, the string converter will - // throw an exception if invalid - packageName.getStringConverter().apply(packageName.fetchFrom(params), - params); - - for (var validator: getToolValidators(params)) { + for (var validator: getToolValidators()) { ConfigException ex = validator.validate(); if (ex != null) { throw ex; @@ -98,7 +89,7 @@ public final boolean validate(Map params) } // Packaging specific validation - doValidate(params); + doValidate(workshop, pkg); return true; } @@ -114,13 +105,8 @@ public final Path execute(Map params, IOUtils.writableOutputDir(outputParentDir); // Order is important! - LinuxPackage pkg; - if (Package.TARGET_PACKAGE.fetchFrom(params) instanceof LinuxPackage linuxPkg) { - pkg = linuxPkg; - } else { - throw new UnsupportedOperationException(); - } - var workshop = Workshop.WORKSHOP.fetchFrom(params); + LinuxPackage pkg = pkgParam.fetchFrom(params); + var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); Workshop pkgWorkshop = new Workshop.Proxy(workshop) { @Override @@ -129,7 +115,7 @@ public Path appImageDir() { } }; - params.put(Workshop.WORKSHOP.getID(), pkgWorkshop); + params.put(WorkshopFromParams.WORKSHOP.getID(), pkgWorkshop); Function initAppImageLayout = imageRoot -> { ApplicationLayout layout = pkg.app().appLayout(); @@ -166,12 +152,12 @@ public Path appImageDir() { create()); } - data.putAll(createReplacementData(params)); + data.putAll(createReplacementData(workshop, pkg)); Path packageBundle = buildPackageBundle(Collections.unmodifiableMap( - data), params, outputParentDir); + data), workshop, pkg, outputParentDir); - verifyOutputBundle(params, packageBundle).stream() + verifyOutputBundle(workshop, pkg, packageBundle).stream() .filter(Objects::nonNull) .forEachOrdered(ex -> { Log.verbose(ex.getLocalizedMessage()); @@ -233,25 +219,24 @@ private Map createDefaultReplacementData(Workshop workshop, Linu } protected abstract List verifyOutputBundle( - Map params, Path packageBundle); + Workshop workshop, LinuxPackage pkg, Path packageBundle); protected abstract void initLibProvidersLookup(LibProvidersLookup libProvidersLookup); - protected abstract List getToolValidators( - Map params); + protected abstract List getToolValidators(); - protected abstract void doValidate(Map params) + protected abstract void doValidate(Workshop workshop, LinuxPackage pkg) throws ConfigException; protected abstract Map createReplacementData( - Map params) throws IOException; + Workshop workshop, LinuxPackage pkg) throws IOException; protected abstract Path buildPackageBundle( Map replacementData, - Map params, Path outputParentDir) throws + Workshop workshop, LinuxPackage pkg, Path outputParentDir) throws PackagerException, IOException; - private final BundlerParamInfo packageName; + private final BundlerParamInfo pkgParam; private final Bundler appImageBundler; private boolean withFindNeededPackages; private final List customActions; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java new file mode 100644 index 0000000000000..d42518137932e --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.Map; +import jdk.jpackage.internal.LinuxPackage.Impl; +import static jdk.jpackage.internal.LinuxPackage.mapPackageName; +import jdk.jpackage.internal.Package.StandardPackageType; +import static jdk.jpackage.internal.Package.StandardPackageType.LinuxDeb; +import static jdk.jpackage.internal.Package.StandardPackageType.LinuxRpm; + +final class LinuxPackageFromParams { + + static LinuxPackage create(Map params, StandardPackageType pkgType) throws ConfigException { + var pkg = PackageFromParams.create(params, LinuxApplicationFromParams.APPLICATION, pkgType); + var menuGroupName = LINUX_MENU_GROUP.fetchFrom(params); + var category = LINUX_CATEGORY.fetchFrom(params); + var additionalDependencies = LINUX_PACKAGE_DEPENDENCIES.fetchFrom(params); + var release = RELEASE.fetchFrom(params); + + var packageName = mapPackageName(pkg.packageName(), pkgType); + var arch = LinuxPackageArch.getValue(pkgType); + + return new Impl(pkg, menuGroupName, category, additionalDependencies, release) { + @Override + public String packageName() { + return packageName; + } + + @Override + public Path packageFileName() { + String packageFileNameTemlate; + switch (asStandardPackageType()) { + case LinuxDeb -> { + packageFileNameTemlate = "%s_%s-%s_%s.deb"; + } + case LinuxRpm -> { + packageFileNameTemlate = "%s-%s-%s.%s.rpm"; + } + default -> { + throw new UnsupportedOperationException(); + } + } + + return Path.of(String.format(packageFileNameTemlate, packageName(), version(), + release(), arch)); + } + }; + } + + private static final BundlerParamInfo LINUX_CATEGORY = new StandardBundlerParam<>( + Arguments.CLIOptions.LINUX_CATEGORY.getId(), + String.class, + params -> "misc", + (s, p) -> s); + + private static final BundlerParamInfo LINUX_PACKAGE_DEPENDENCIES = new StandardBundlerParam<>( + Arguments.CLIOptions.LINUX_PACKAGE_DEPENDENCIES.getId(), + String.class, + params -> null, + (s, p) -> s); + + private static final BundlerParamInfo LINUX_MENU_GROUP = new StandardBundlerParam<>( + Arguments.CLIOptions.LINUX_MENU_GROUP.getId(), + String.class, + params -> I18N.getString("param.menu-group.default"), + (s, p) -> s); + + private static final StandardBundlerParam RELEASE = new StandardBundlerParam<>( + Arguments.CLIOptions.RELEASE.getId(), + String.class, + params -> "1", + (s, p) -> s); +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index be75545450111..7bbf913b83325 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 @@ -39,14 +39,6 @@ import java.util.stream.Collectors; import jdk.internal.util.OperatingSystem; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.StandardBundlerParam.RELEASE; -import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; -import static jdk.jpackage.internal.OverridableResource.createResource; -import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; /** * There are two command line options to configure license information for RPM @@ -61,58 +53,6 @@ */ public class LinuxRpmBundler extends LinuxPackageBundler { - // Fedora rules for package naming are used here - // https://fedoraproject.org/wiki/Packaging:NamingGuidelines?rd=Packaging/NamingGuidelines - // - // all Fedora packages must be named using only the following ASCII - // characters. These characters are displayed here: - // - // abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._+ - // - private static final Pattern RPM_PACKAGE_NAME_PATTERN = - Pattern.compile("[a-z\\d\\+\\-\\.\\_]+", Pattern.CASE_INSENSITIVE); - - public static final BundlerParamInfo PACKAGE_NAME = - new StandardBundlerParam<> ( - Arguments.CLIOptions.LINUX_BUNDLE_NAME.getId(), - String.class, - params -> { - String nm = INSTALLER_NAME.fetchFrom(params); - if (nm == null) return null; - - // make sure to lower case and spaces become dashes - nm = nm.toLowerCase().replaceAll("[ ]", "-"); - - return nm; - }, - (s, p) -> { - if (!RPM_PACKAGE_NAME_PATTERN.matcher(s).matches()) { - String msgKey = "error.invalid-value-for-package-name"; - throw new IllegalArgumentException( - new ConfigException(MessageFormat.format( - I18N.getString(msgKey), s), - I18N.getString(msgKey + ".advice"))); - } - - return s; - } - ); - - public static final BundlerParamInfo LICENSE_TYPE = - new StandardBundlerParam<>( - Arguments.CLIOptions.LINUX_RPM_LICENSE_TYPE.getId(), - String.class, - params -> I18N.getString("param.license-type.default"), - (s, p) -> s - ); - - public static final BundlerParamInfo GROUP = - new StandardBundlerParam<>( - Arguments.CLIOptions.LINUX_CATEGORY.getId(), - String.class, - params -> null, - (s, p) -> s); - private static final String DEFAULT_SPEC_TEMPLATE = "template.spec"; public static final String TOOL_RPM = "rpm"; @@ -121,12 +61,11 @@ public class LinuxRpmBundler extends LinuxPackageBundler { "4.10"); public LinuxRpmBundler() { - super(PACKAGE_NAME); + super(LinuxRpmPackageFromParams.PACKAGE); } @Override - public void doValidate(Map params) - throws ConfigException { + protected void doValidate(Workshop workshop, LinuxPackage pkg) throws ConfigException { } private static ToolValidator createRpmbuildToolValidator() { @@ -144,55 +83,50 @@ private static ToolValidator createRpmbuildToolValidator() { } @Override - protected List getToolValidators( - Map params) { + protected List getToolValidators() { return List.of(createRpmbuildToolValidator()); } @Override - protected Path buildPackageBundle( - Map replacementData, - Map params, Path outputParentDir) throws - PackagerException, IOException { + protected Path buildPackageBundle(Map replacementData, Workshop workshop, + LinuxPackage pkg, Path outputParentDir) throws PackagerException, IOException { - Path specFile = specFile(params); + Path specFile = specFile(workshop, pkg); // prepare spec file - createResource(DEFAULT_SPEC_TEMPLATE, params) + workshop.createResource(DEFAULT_SPEC_TEMPLATE) .setCategory(I18N.getString("resource.rpm-spec-file")) .setSubstitutionData(replacementData) .saveToFile(specFile); - return buildRPM(params, outputParentDir); + return buildRPM(workshop, pkg, outputParentDir); + } + + private static Path installPrefix(LinuxPackage pkg) { + if (pkg.isInstallDirInUsrTree()) { + return Path.of("/").resolve(pkg.relativeInstallDir()); + } else { + return pkg.relativeInstallDir().getParent(); + } } @Override - protected Map createReplacementData( - Map params) throws IOException { + protected Map createReplacementData(Workshop workshop, LinuxPackage pkg) throws IOException { Map data = new HashMap<>(); - final Path prefix = Path.of(LINUX_INSTALL_DIR.fetchFrom(params)); - - Path appDirectory = prefix; - if (!isInstallDirInUsrTree(prefix.toString())) { - appDirectory = appDirectory.resolve(PACKAGE_NAME.fetchFrom(params)); - } - - data.put("APPLICATION_RELEASE", RELEASE.fetchFrom(params)); - data.put("APPLICATION_PREFIX", prefix.toString()); - data.put("APPLICATION_DIRECTORY", appDirectory.toString()); - data.put("APPLICATION_SUMMARY", APP_NAME.fetchFrom(params)); - data.put("APPLICATION_LICENSE_TYPE", LICENSE_TYPE.fetchFrom(params)); + data.put("APPLICATION_RELEASE", pkg.release()); + data.put("APPLICATION_PREFIX", installPrefix(pkg).toString()); + data.put("APPLICATION_DIRECTORY", Path.of("/").resolve(pkg.relativeInstallDir()).toString()); + data.put("APPLICATION_SUMMARY", pkg.packageName()); + data.put("APPLICATION_LICENSE_TYPE", ((LinuxRpmPackage)pkg).licenseType()); - String licenseFile = LICENSE_FILE.fetchFrom(params); - if (licenseFile != null) { - licenseFile = Path.of(licenseFile).toAbsolutePath().normalize().toString(); - } + String licenseFile = Optional.ofNullable(pkg.licenseFile()).map(v -> { + return v.toAbsolutePath().normalize().toString(); + }).orElse(null); data.put("APPLICATION_LICENSE_FILE", licenseFile); - data.put("APPLICATION_GROUP", GROUP.fetchFrom(params)); + data.put("APPLICATION_GROUP", pkg.category()); - data.put("APPLICATION_URL", Optional.ofNullable(ABOUT_URL.fetchFrom( - params)).orElse("")); + data.put("APPLICATION_URL", Optional.ofNullable(pkg.aboutURL()).orElse("")); return data; } @@ -208,21 +142,22 @@ protected void initLibProvidersLookup(LibProvidersLookup libProvidersLookup) { } @Override - protected List verifyOutputBundle( - Map params, Path packageBundle) { + protected List verifyOutputBundle(Workshop workshop, LinuxPackage pkg, + Path packageBundle) { List errors = new ArrayList<>(); - String specFileName = specFile(params).getFileName().toString(); + String specFileName = specFile(workshop, pkg).getFileName().toString(); try { List properties = List.of( - new PackageProperty("Name", PACKAGE_NAME.fetchFrom(params), + new PackageProperty("Name", pkg.packageName(), "APPLICATION_PACKAGE", specFileName), - new PackageProperty("Version", VERSION.fetchFrom(params), + new PackageProperty("Version", pkg.version(), "APPLICATION_VERSION", specFileName), - new PackageProperty("Release", RELEASE.fetchFrom(params), + new PackageProperty("Release", pkg.release(), "APPLICATION_RELEASE", specFileName), - new PackageProperty("Arch", rpmArch(), null, specFileName)); + new PackageProperty("Arch", LinuxPackageArch.getValue( + Package.StandardPackageType.LinuxRpm), null, specFileName)); List actualValues = Executor.of(TOOL_RPM, "-qp", "--queryformat", properties.stream().map(entry -> String.format("%%{%s}", @@ -240,35 +175,29 @@ protected List verifyOutputBundle( return errors; } - private Path specFile(Map params) { - return TEMP_ROOT.fetchFrom(params).resolve(Path.of("SPECS", - PACKAGE_NAME.fetchFrom(params) + ".spec")); + private Path specFile(Workshop workshop, Package pkg) { + return workshop.buildRoot().resolve(Path.of("SPECS", pkg.packageName() + ".spec")); } - private Path buildRPM(Map params, - Path outdir) throws IOException { + private Path buildRPM(Workshop workshop, Package pkg, Path outdir) throws IOException { - Path rpmFile = outdir.toAbsolutePath().resolve(String.format( - "%s-%s-%s.%s.rpm", PACKAGE_NAME.fetchFrom(params), - VERSION.fetchFrom(params), RELEASE.fetchFrom(params), rpmArch())); + Path rpmFile = outdir.toAbsolutePath().resolve(pkg.packageFileName()); Log.verbose(MessageFormat.format(I18N.getString( "message.outputting-bundle-location"), rpmFile.getParent())); - PlatformPackage thePackage = createMetaPackage(params); - //run rpmbuild Executor.of( TOOL_RPMBUILD, - "-bb", specFile(params).toAbsolutePath().toString(), + "-bb", specFile(workshop, pkg).toAbsolutePath().toString(), "--define", String.format("%%_sourcedir %s", - thePackage.sourceRoot()), + workshop.appImageDir()), // save result to output dir "--define", String.format("%%_rpmdir %s", rpmFile.getParent()), // do not use other system directories to build as current user "--define", String.format("%%_topdir %s", - TEMP_ROOT.fetchFrom(params).toAbsolutePath()), + workshop.buildRoot().toAbsolutePath()), "--define", String.format("%%_rpmfilename %s", rpmFile.getFileName()) ).executeExpectSuccess(); @@ -298,6 +227,4 @@ public boolean supported(boolean runtimeInstaller) { public boolean isDefault() { return !LinuxDebBundler.isDebian(); } - - private String rpmArch; } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java index c7a43da26adde..40d07ad610d63 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java @@ -24,14 +24,11 @@ */ package jdk.jpackage.internal; -import java.util.Map; -import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; - interface LinuxRpmPackage extends LinuxPackage { String licenseType(); - static class Impl extends LinuxPackage.Proxy implements LinuxRpmPackage { + static class Impl extends LinuxPackage.Proxy implements LinuxRpmPackage { public Impl(LinuxPackage target, String licenseType) { super(target); @@ -45,27 +42,4 @@ public String licenseType() { private final String licenseType; } - - private static LinuxRpmPackage createFromParams(Map params) throws ConfigException { - var pkg = LinuxPackage.createFromParams(params, StandardPackageType.LinuxRpm); - - var licenseType = Internal.LICENSE_TYPE.fetchFrom(params); - - return new Impl(pkg, licenseType); - } - - final static class Internal { - - private static final BundlerParamInfo LICENSE_TYPE - = new StandardBundlerParam<>( - Arguments.CLIOptions.LINUX_RPM_LICENSE_TYPE.getId(), - String.class, - params -> I18N.getString("param.license-type.default"), - (s, p) -> s); - } - - static final StandardBundlerParam TARGET_PACKAGE = new StandardBundlerParam<>( - Package.PARAM_ID, LinuxRpmPackage.class, params -> { - return toFunction(LinuxRpmPackage::createFromParams).apply(params); - }, null); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java new file mode 100644 index 0000000000000..cdb2807877a19 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.Map; +import jdk.jpackage.internal.LinuxRpmPackage.Impl; +import static jdk.jpackage.internal.Package.StandardPackageType.LinuxRpm; +import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; + +final class LinuxRpmPackageFromParams { + + private static LinuxRpmPackage create(Map params) throws ConfigException { + var pkg = LinuxPackageFromParams.create(params, LinuxRpm); + + var licenseType = LICENSE_TYPE.fetchFrom(params); + + return new Impl(pkg, licenseType); + } + + static final StandardBundlerParam PACKAGE = createBundlerParam( + LinuxRpmPackageFromParams::create); + + private static final BundlerParamInfo LICENSE_TYPE = new StandardBundlerParam<>( + Arguments.CLIOptions.LINUX_RPM_LICENSE_TYPE.getId(), + String.class, + params -> I18N.getString("param.license-type.default"), + (s, p) -> s); + +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index 001d4b535e731..92023e159dc00 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -46,8 +46,8 @@ static ShellCustomAction create(Map params, Path outputDir) throws IOException { // Order is important! - var pkg = Package.TARGET_PACKAGE.fetchFrom(params); - var workshop = Workshop.WORKSHOP.fetchFrom(params); + var pkg = PackageFromParams.PACKAGE.fetchFrom(params); + var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); if (pkg.isRuntimeInstaller()) { return null; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java index 5b95e1674166e..06f74536cc4e2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java @@ -166,7 +166,7 @@ private Path createAppBundle(Map params, Path outputDirectory) throws PackagerException, IOException, ConfigException { - var app = Application.TARGET_APPLICATION.fetchFrom(params); + var app = ApplicationFromParams.APPLICATION.fetchFrom(params); boolean hasAppImage = PREDEFINED_APP_IMAGE.fetchFrom(params) != null; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java index 3036e431dae59..af97eccde2d21 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java @@ -25,29 +25,12 @@ package jdk.jpackage.internal; import java.nio.file.Path; -import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.function.Function; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; -import static jdk.jpackage.internal.Functional.ThrowingBiFunction.toBiFunction; import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; -import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; -import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; -import static jdk.jpackage.internal.StandardBundlerParam.ICON; -import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; -import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; -import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; -import static jdk.jpackage.internal.StandardBundlerParam.isRuntimeInstaller; interface Application { @@ -59,6 +42,8 @@ interface Application { String vendor(); + String copyright(); + Path predefinedRuntimeImage(); RuntimeBuilder runtimeBuilder(); @@ -131,8 +116,8 @@ default OverridableResource createLauncherIconResource(Launcher launcher, String } static record Impl(String name, String description, String version, String vendor, - Path predefinedRuntimeImage, RuntimeBuilder runtimeBuilder, Launcher mainLauncher, - List additionalLaunchers) implements Application { + String copyright, Path predefinedRuntimeImage, RuntimeBuilder runtimeBuilder, + Launcher mainLauncher, List additionalLaunchers) implements Application { } @@ -162,6 +147,11 @@ public String vendor() { return target.vendor(); } + @Override + public String copyright() { + return target.copyright(); + } + @Override public Path predefinedRuntimeImage() { return target.predefinedRuntimeImage(); @@ -183,79 +173,6 @@ public List additionalLaunchers() { } } - static Application createFromParams(Map params, - Function, Launcher> launcherSupplier) throws ConfigException { - var name = APP_NAME.fetchFrom(params); - var description = DESCRIPTION.fetchFrom(params); - var version = VERSION.fetchFrom(params); - var vendor = VENDOR.fetchFrom(params); - var predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); - - var predefinedAppImage = getPredefinedAppImage(params); - if (name == null && predefinedAppImage == null) { - // Can happen when no name is given, and using a foreign app-image - throw new ConfigException(I18N.getString("error.no.name"), I18N.getString( - "error.no.name.advice")); - } - - RuntimeBuilder runtimeBuilder; - - Launcher mainLauncher; - List additionalLaunchers; - if (isRuntimeInstaller(params)) { - runtimeBuilder = null; - mainLauncher = null; - additionalLaunchers = List.of(); - } else if (predefinedAppImage != null) { - runtimeBuilder = null; - - AppImageFile appImage = AppImageFile.load(predefinedAppImage); - - version = appImage.getAppVersion(); - - mainLauncher = launcherSupplier.apply(mergeParams(params, Map.of(APP_NAME.getID(), - appImage.getLauncherName(), DESCRIPTION.getID(), description))); - additionalLaunchers = appImage.getAddLaunchers().stream().map(li -> { - return launcherSupplier.apply(mergeParams(params, Map.of(APP_NAME.getID(), li - .getName(), SHORTCUT_HINT.getID(), li.isShortcut(), MENU_HINT.getID(), li - .isMenu(), LAUNCHER_AS_SERVICE.getID(), li.isService()))); - }).toList(); - } else { - var launchers = Optional.ofNullable(ADD_LAUNCHERS.fetchFrom(params)).orElseGet( - Collections::emptyList); - mainLauncher = launcherSupplier.apply(params); - additionalLaunchers = launchers.stream().map(launcherParams -> { - return launcherSupplier.apply(mergeParams(params, launcherParams)); - }).toList(); - - var startupInfos = Stream.concat(Stream.of(mainLauncher), additionalLaunchers.stream()).map( - Launcher::startupInfo).toList(); - runtimeBuilder = RuntimeBuilder.createFromParams(params, startupInfos); - } - - return new Impl(name, description, version, vendor, predefinedRuntimeImage, runtimeBuilder, - mainLauncher, additionalLaunchers); - } - - private static Map mergeParams(Map mainParams, - Map launcherParams) { - if (!launcherParams.containsKey(DESCRIPTION.getID())) { - launcherParams = new HashMap<>(launcherParams); - launcherParams.put(DESCRIPTION.getID(), String.format("%s (%s)", DESCRIPTION.fetchFrom( - mainParams), APP_NAME.fetchFrom(launcherParams))); - } - return AddLauncherArguments.merge(mainParams, launcherParams, ICON.getID(), ADD_LAUNCHERS - .getID(), FILE_ASSOCIATIONS.getID()); - } - - final static String PARAM_ID = "target.application"; - - static final StandardBundlerParam TARGET_APPLICATION = new StandardBundlerParam<>( - PARAM_ID, Application.class, params -> { - return toBiFunction(Application::createFromParams).apply(params, - Launcher::createFromParams); - }, null); - static class Internal { private enum IconType { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java new file mode 100644 index 0000000000000..de84414241c46 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Stream; +import static jdk.jpackage.internal.Functional.ThrowingBiFunction.toBiFunction; +import jdk.jpackage.internal.Functional.ThrowingFunction; +import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; +import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.COPYRIGHT; +import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; +import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; +import static jdk.jpackage.internal.StandardBundlerParam.ICON; +import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; +import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; +import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; +import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; +import static jdk.jpackage.internal.StandardBundlerParam.VERSION; +import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; +import static jdk.jpackage.internal.StandardBundlerParam.isRuntimeInstaller; + +final class ApplicationFromParams { + + static Application create(Map params, + Function, Launcher> launcherSupplier) throws ConfigException { + var name = APP_NAME.fetchFrom(params); + var description = DESCRIPTION.fetchFrom(params); + var version = VERSION.fetchFrom(params); + var vendor = VENDOR.fetchFrom(params); + var copyright = COPYRIGHT.fetchFrom(params); + var predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); + + var predefinedAppImage = getPredefinedAppImage(params); + if (name == null && predefinedAppImage == null) { + // Can happen when no name is given, and using a foreign app-image + throw new ConfigException(I18N.getString("error.no.name"), I18N.getString( + "error.no.name.advice")); + } + + RuntimeBuilder runtimeBuilder; + + Launcher mainLauncher; + List additionalLaunchers; + if (isRuntimeInstaller(params)) { + runtimeBuilder = null; + mainLauncher = null; + additionalLaunchers = List.of(); + } else if (predefinedAppImage != null) { + runtimeBuilder = null; + + AppImageFile appImage = AppImageFile.load(predefinedAppImage); + + version = appImage.getAppVersion(); + + mainLauncher = launcherSupplier.apply(mergeParams(params, Map.of(APP_NAME.getID(), + appImage.getLauncherName(), DESCRIPTION.getID(), description))); + additionalLaunchers = appImage.getAddLaunchers().stream().map(li -> { + return launcherSupplier.apply(mergeParams(params, Map.of(APP_NAME.getID(), li + .getName(), SHORTCUT_HINT.getID(), li.isShortcut(), MENU_HINT.getID(), li + .isMenu(), LAUNCHER_AS_SERVICE.getID(), li.isService()))); + }).toList(); + } else { + var launchers = Optional.ofNullable(ADD_LAUNCHERS.fetchFrom(params)).orElseGet( + Collections::emptyList); + mainLauncher = launcherSupplier.apply(params); + additionalLaunchers = launchers.stream().map(launcherParams -> { + return launcherSupplier.apply(mergeParams(params, launcherParams)); + }).toList(); + + var startupInfos = Stream.concat(Stream.of(mainLauncher), additionalLaunchers.stream()).map( + Launcher::startupInfo).toList(); + + if (predefinedRuntimeImage == null) { + runtimeBuilder = RuntimeBuilder.createFromParams(params, startupInfos); + } else { + runtimeBuilder = null; + } + } + + return new Application.Impl(name, description, version, vendor, copyright, + predefinedRuntimeImage, runtimeBuilder, mainLauncher, additionalLaunchers); + } + + private static Map mergeParams(Map mainParams, + Map launcherParams) { + if (!launcherParams.containsKey(DESCRIPTION.getID())) { + launcherParams = new HashMap<>(launcherParams); + launcherParams.put(DESCRIPTION.getID(), String.format("%s (%s)", DESCRIPTION.fetchFrom( + mainParams), APP_NAME.fetchFrom(launcherParams))); + } + return AddLauncherArguments.merge(mainParams, launcherParams, ICON.getID(), ADD_LAUNCHERS + .getID(), FILE_ASSOCIATIONS.getID()); + } + + static StandardBundlerParam createBundlerParam( + ThrowingFunction, T> valueFunc) { + return StandardBundlerParam.createBundlerParam("target.application", valueFunc); + } + + static final StandardBundlerParam APPLICATION = createBundlerParam(params -> { + return ApplicationFromParams.create(params, LauncherFromParams::create); + }); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java index cf24065aed4cc..884dcd1e623d0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java @@ -26,11 +26,6 @@ import java.nio.file.Path; import java.util.List; -import java.util.Map; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; -import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; interface Launcher { @@ -95,20 +90,4 @@ public Path icon() { return target.icon(); } } - - static Launcher createFromParams(Map params) { - var name = APP_NAME.fetchFrom(params); - - LauncherStartupInfo startupInfo = null; - if (PREDEFINED_APP_IMAGE.fetchFrom(params) == null) { - startupInfo = LauncherStartupInfo.createFromParams(params); - } - - var isService = LAUNCHER_AS_SERVICE.fetchFrom(params); - var description = DESCRIPTION.fetchFrom(params); - var icon = StandardBundlerParam.ICON.fetchFrom(params); - var fa = FileAssociation.fetchFrom(params); - - return new Impl(name, startupInfo, fa, isService, description, icon); - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java new file mode 100644 index 0000000000000..2c716dd2a555f --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.Map; +import jdk.jpackage.internal.Launcher.Impl; +import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; +import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; + +final class LauncherFromParams { + + static Launcher create(Map params) { + var name = APP_NAME.fetchFrom(params); + + LauncherStartupInfo startupInfo = null; + if (PREDEFINED_APP_IMAGE.fetchFrom(params) == null) { + startupInfo = LauncherStartupInfo.createFromParams(params); + } + + var isService = LAUNCHER_AS_SERVICE.fetchFrom(params); + var description = DESCRIPTION.fetchFrom(params); + var icon = StandardBundlerParam.ICON.fetchFrom(params); + var fa = FileAssociation.fetchFrom(params); + + return new Impl(name, startupInfo, fa, isService, description, icon); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index 0dc64e78aec46..069ca88e8b5c6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -26,17 +26,7 @@ import java.nio.file.Path; import java.text.MessageFormat; -import java.util.Map; -import java.util.Optional; import java.util.stream.Stream; -import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; -import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; -import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; -import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; interface Package { @@ -198,33 +188,7 @@ public Path relativeInstallDir() { } } - static Package createFromParams(Map params, Application app, - PackageType pkgType) throws ConfigException { - var packageName = Optional.ofNullable(INSTALLER_NAME.fetchFrom(params)).orElseGet(app::name); - var description = Optional.ofNullable(DESCRIPTION.fetchFrom(params)).orElseGet(app::name); - var version = Optional.ofNullable(VERSION.fetchFrom(params)).orElseGet(app::version); - var aboutURL = ABOUT_URL.fetchFrom(params); - var licenseFile = Optional.ofNullable(LICENSE_FILE.fetchFrom(params)).map(Path::of).orElse(null); - var predefinedAppImage = getPredefinedAppImage(params); - - var relativeInstallDir = Optional.ofNullable(INSTALL_DIR.fetchFrom(params)).map(v -> { - return toSupplier(() -> mapInstallDir(Path.of(v), pkgType)).get(); - }).orElseGet(() -> { - if (pkgType instanceof StandardPackageType stdPkgType) { - return defaultInstallDir(app, stdPkgType); - } else { - return app.appImageDirName(); - } - }); - if (relativeInstallDir.isAbsolute()) { - relativeInstallDir = relativeInstallDir.relativize(Path.of("/")); - } - - return new Impl(app, pkgType, packageName, description, version, aboutURL, licenseFile, - predefinedAppImage, relativeInstallDir); - } - - private static Path defaultInstallDir(Application app, StandardPackageType type) { + static Path defaultInstallDir(Application app, StandardPackageType type) { switch (type) { case WinExe, WinMsi -> { return app.appImageDirName(); @@ -247,7 +211,7 @@ private static Path defaultInstallDir(Application app, StandardPackageType type) } } - private static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigException { + static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigException { var ex = new ConfigException(MessageFormat.format(I18N.getString("error.invalid-install-dir"), installDir), null); @@ -279,15 +243,4 @@ private static Path mapInstallDir(Path installDir, PackageType pkgType) throws C return installDir; } - - final static String PARAM_ID = "target.package"; - - static final StandardBundlerParam TARGET_PACKAGE = new StandardBundlerParam<>( - PARAM_ID, Package.class, params -> { - return toSupplier(() -> { - return Package.createFromParams(params, Application.TARGET_APPLICATION - .fetchFrom(params), StandardPackageType.fromCmdLineType( - Workshop.PACKAGE_TYPE.fetchFrom(params))); - }).get(); - }, null); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java new file mode 100644 index 0000000000000..0df250487bd65 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.Map; +import java.util.Optional; +import jdk.jpackage.internal.Functional.ThrowingFunction; +import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; +import jdk.jpackage.internal.Package.Impl; +import jdk.jpackage.internal.Package.PackageType; +import jdk.jpackage.internal.Package.StandardPackageType; +import static jdk.jpackage.internal.Package.defaultInstallDir; +import static jdk.jpackage.internal.Package.mapInstallDir; +import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; +import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; +import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; +import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; +import static jdk.jpackage.internal.StandardBundlerParam.VERSION; +import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; + +final class PackageFromParams { + + static Package create(Map params, + StandardBundlerParam appParam, PackageType pkgType) throws ConfigException { + var app = appParam.fetchFrom(params); + var packageName = Optional.ofNullable(INSTALLER_NAME.fetchFrom(params)).orElseGet(app::name); + var description = Optional.ofNullable(DESCRIPTION.fetchFrom(params)).orElseGet(app::name); + var version = Optional.ofNullable(VERSION.fetchFrom(params)).orElseGet(app::version); + var aboutURL = ABOUT_URL.fetchFrom(params); + var licenseFile = Optional.ofNullable(LICENSE_FILE.fetchFrom(params)).map(Path::of).orElse(null); + var predefinedAppImage = getPredefinedAppImage(params); + + var relativeInstallDir = Optional.ofNullable(INSTALL_DIR.fetchFrom(params)).map(v -> { + return toSupplier(() -> mapInstallDir(Path.of(v), pkgType)).get(); + }).orElseGet(() -> { + if (pkgType instanceof StandardPackageType stdPkgType) { + return defaultInstallDir(app, stdPkgType); + } else { + return app.appImageDirName(); + } + }); + if (relativeInstallDir.isAbsolute()) { + relativeInstallDir = relativeInstallDir.relativize(Path.of("/")); + } + + return new Impl(app, pkgType, packageName, description, version, aboutURL, licenseFile, + predefinedAppImage, relativeInstallDir); + } + + static StandardBundlerParam createBundlerParam( + ThrowingFunction, T> valueFunc) { + return StandardBundlerParam.createBundlerParam("target.package", valueFunc); + } + + static final StandardBundlerParam PACKAGE = createBundlerParam(params -> { + return PackageFromParams.create(params, ApplicationFromParams.APPLICATION, + StandardPackageType.fromCmdLineType(WorkshopFromParams.PACKAGE_TYPE + .fetchFrom(params))); + }); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index a50293aedb5b8..cf36bb0d26dc8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -43,8 +43,10 @@ import java.util.Set; import java.util.function.BiFunction; import java.util.function.Function; -import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.jpackage.internal.Functional.ThrowingFunction; +import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; +import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; /** * StandardBundlerParam @@ -615,6 +617,12 @@ static void copyPredefinedRuntimeImage(Map params, } } + @SuppressWarnings({"unchecked", "rawtypes"}) + static StandardBundlerParam createBundlerParam(String id, + ThrowingFunction, T2> valueFunc) { + return new StandardBundlerParam(id, Object.class, toFunction(valueFunc), null); + } + private static List getDefaultModulePath() { return List.of( Path.of(System.getProperty("java.home"), "jmods").toAbsolutePath()); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java index ffc9a415ffe39..86932da965666 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java @@ -25,9 +25,6 @@ package jdk.jpackage.internal; import java.nio.file.Path; -import java.util.Map; -import jdk.internal.util.OperatingSystem; -import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; interface Workshop { @@ -74,42 +71,4 @@ public Path resourceDir() { private final Workshop target; } - - static Workshop createFromParams(Map params) throws ConfigException { - var root = StandardBundlerParam.TEMP_ROOT.fetchFrom(params); - var resourceDir = StandardBundlerParam.RESOURCE_DIR.fetchFrom(params); - - var defaultWorkshop = new Impl(root, resourceDir); - - Path appImageDir; - if (StandardBundlerParam.isRuntimeInstaller(params)) { - appImageDir = StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); - } else if (StandardBundlerParam.hasPredefinedAppImage(params)) { - appImageDir = StandardBundlerParam.getPredefinedAppImage(params); - } else { - Path dir; - if (PACKAGE_TYPE.fetchFrom(params).equals("app-image") || OperatingSystem.isWindows()) { - dir = Application.TARGET_APPLICATION.fetchFrom(params).appImageDirName(); - } else { - dir = Package.TARGET_PACKAGE.fetchFrom(params).relativeInstallDir(); - } - - appImageDir = defaultWorkshop.buildRoot().resolve("image").resolve(dir); - } - - return new Proxy(defaultWorkshop) { - @Override - public Path appImageDir() { - return appImageDir; - } - }; - } - - static final StandardBundlerParam WORKSHOP = new StandardBundlerParam<>( - "workshop", Workshop.class, params -> { - return toFunction(Workshop::createFromParams).apply(params); - }, null); - - static final StandardBundlerParam PACKAGE_TYPE = new StandardBundlerParam<>( - Arguments.CLIOptions.PACKAGE_TYPE.getId(), String.class, null, null); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java new file mode 100644 index 0000000000000..23a985fd3ef0a --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.Map; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.Workshop.Impl; +import jdk.jpackage.internal.Workshop.Proxy; + +final class WorkshopFromParams { + + static Workshop create(Map params) throws ConfigException { + var root = StandardBundlerParam.TEMP_ROOT.fetchFrom(params); + var resourceDir = StandardBundlerParam.RESOURCE_DIR.fetchFrom(params); + + var defaultWorkshop = new Impl(root, resourceDir); + + Path appImageDir; + if (StandardBundlerParam.isRuntimeInstaller(params)) { + appImageDir = StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); + } else if (StandardBundlerParam.hasPredefinedAppImage(params)) { + appImageDir = StandardBundlerParam.getPredefinedAppImage(params); + } else { + Path dir; + if (PACKAGE_TYPE.fetchFrom(params).equals("app-image") || OperatingSystem.isWindows()) { + dir = ApplicationFromParams.APPLICATION.fetchFrom(params).appImageDirName(); + } else { + dir = PackageFromParams.PACKAGE.fetchFrom(params).relativeInstallDir(); + } + + appImageDir = defaultWorkshop.buildRoot().resolve("image").resolve(dir); + } + + return new Proxy(defaultWorkshop) { + @Override + public Path appImageDir() { + return appImageDir; + } + }; + } + + static final StandardBundlerParam WORKSHOP = StandardBundlerParam.createBundlerParam( + "workshop", WorkshopFromParams::create); + + static final StandardBundlerParam PACKAGE_TYPE = new StandardBundlerParam<>( + Arguments.CLIOptions.PACKAGE_TYPE.getId(), String.class, null, null); +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java index 62dc71dbdf6d7..1541b5cce4986 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java @@ -24,69 +24,10 @@ */ package jdk.jpackage.internal; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; -import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; -import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; -import static jdk.jpackage.internal.WinLauncher.WinShortcut.WinShortcutDesktop; -import static jdk.jpackage.internal.WinLauncher.WinShortcut.WinShortcutStartMenu; -import static jdk.jpackage.internal.WindowsAppImageBuilder.CONSOLE_HINT; - interface WinApplication extends Application { - - static class Impl extends Application.Proxy implements WinApplication { - + static class Impl extends Application.Proxy implements WinApplication { Impl(Application app) { super(app); } } - - static WinApplication createFromParams(Map params) throws ConfigException { - var app = Application.createFromParams(params, launcherParams -> { - var launcher = Launcher.createFromParams(launcherParams); - boolean isConsole = CONSOLE_HINT.fetchFrom(launcherParams); - - var shortcuts = Map.of(WinShortcutDesktop, List.of(SHORTCUT_HINT, - Internal.WIN_SHORTCUT_HINT), WinShortcutStartMenu, - List.of(MENU_HINT, Internal.WIN_MENU_HINT)).entrySet().stream().filter( - e -> { - var shortcutParams = e.getValue(); - if (launcherParams.containsKey(shortcutParams.get(0).getID())) { - // This is an explicit shortcut configuration for an addition launcher - return shortcutParams.get(0).fetchFrom(launcherParams); - } else { - return shortcutParams.get(1).fetchFrom(launcherParams); - } - }).map(Map.Entry::getKey).collect(Collectors.toSet()); - - return new WinLauncher.Impl(launcher, isConsole, shortcuts); - }); - return new Impl(app); - } - - static final StandardBundlerParam TARGET_APPLICATION = new StandardBundlerParam<>( - Application.PARAM_ID, WinApplication.class, params -> { - return toFunction(WinApplication::createFromParams).apply(params); - }, null); - - static final class Internal { - - private static final StandardBundlerParam WIN_MENU_HINT = new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_MENU_HINT.getId(), - Boolean.class, - p -> false, - // valueOf(null) is false, - // and we actually do want null in some cases - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); - - private static final StandardBundlerParam WIN_SHORTCUT_HINT = new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_SHORTCUT_HINT.getId(), - Boolean.class, - p -> false, - // valueOf(null) is false, - // and we actually do want null in some cases - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); - } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java new file mode 100644 index 0000000000000..ca98f399d84fe --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import static jdk.jpackage.internal.ApplicationFromParams.createBundlerParam; +import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; +import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; +import static jdk.jpackage.internal.WinLauncher.WinShortcut.WinShortcutDesktop; +import static jdk.jpackage.internal.WinLauncher.WinShortcut.WinShortcutStartMenu; +import static jdk.jpackage.internal.WindowsAppImageBuilder.CONSOLE_HINT; + +final class WinApplicationFromParams { + + private static WinApplication create(Map params) throws ConfigException { + var app = ApplicationFromParams.create(params, launcherParams -> { + var launcher = LauncherFromParams.create(launcherParams); + boolean isConsole = CONSOLE_HINT.fetchFrom(launcherParams); + + var shortcuts = Map.of(WinShortcutDesktop, List.of(SHORTCUT_HINT, + WIN_SHORTCUT_HINT), WinShortcutStartMenu, + List.of(MENU_HINT, WIN_MENU_HINT)).entrySet().stream().filter( + e -> { + var shortcutParams = e.getValue(); + if (launcherParams.containsKey(shortcutParams.get(0).getID())) { + // This is an explicit shortcut configuration for an addition launcher + return shortcutParams.get(0).fetchFrom(launcherParams); + } else { + return shortcutParams.get(1).fetchFrom(launcherParams); + } + }).map(Map.Entry::getKey).collect(Collectors.toSet()); + + return new WinLauncher.Impl(launcher, isConsole, shortcuts); + }); + return new WinApplication.Impl(app); + } + + static final StandardBundlerParam APPLICATION = createBundlerParam( + WinApplicationFromParams::create); + + private static final StandardBundlerParam WIN_MENU_HINT = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_MENU_HINT.getId(), + Boolean.class, + p -> false, + // valueOf(null) is false, + // and we actually do want null in some cases + (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); + + private static final StandardBundlerParam WIN_SHORTCUT_HINT = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_SHORTCUT_HINT.getId(), + Boolean.class, + p -> false, + // valueOf(null) is false, + // and we actually do want null in some cases + (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 8e6ea3495471e..82244a37e3565 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -207,8 +207,8 @@ private void prepareProto(Map params) throws PackagerException, IOException { // Order is important! - var pkg = WinMsiPackage.TARGET_PACKAGE.fetchFrom(params); - var workshop = Workshop.WORKSHOP.fetchFrom(params); + var pkg = WinMsiPackageFromParams.PACKAGE.fetchFrom(params); + var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); Path appImage = pkg.predefinedAppImage(); @@ -254,8 +254,8 @@ public Path execute(Map params, Path outputParentDir) throws PackagerException { // Order is important! - var pkg = WinMsiPackage.TARGET_PACKAGE.fetchFrom(params); - var workshop = Workshop.WORKSHOP.fetchFrom(params); + var pkg = WinMsiPackageFromParams.PACKAGE.fetchFrom(params); + var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); IOUtils.writableOutputDir(outputParentDir); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java index 5a5e931b4ed27..502dad9514e13 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -26,13 +25,8 @@ package jdk.jpackage.internal; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; import java.nio.file.Path; -import java.util.Map; -import java.util.Optional; import java.util.UUID; -import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; -import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; interface WinMsiPackage extends Package { @@ -128,119 +122,8 @@ public Path serviceInstaller() { private final Path serviceInstaller; } - private static WinMsiPackage createFromParams(Map params) throws ConfigException { - var pkg = Package.createFromParams(params, WinApplication.createFromParams(params), - StandardPackageType.WinMsi); - var withInstallDirChooser = Internal.INSTALLDIR_CHOOSER.fetchFrom(params); - var withShortcutPrompt = Internal.SHORTCUT_PROMPT.fetchFrom(params); - var helpURL = Internal.HELP_URL.fetchFrom(params); - var updateURL = Internal.UPDATE_URL.fetchFrom(params); - var startMenuGroupName = Internal.MENU_GROUP.fetchFrom(params); - var isSystemWideInstall = Internal.MSI_SYSTEM_WIDE.fetchFrom(params); - var upgradeCode = getUpgradeCode(params); - - try { - MsiVersion.of(pkg.version()); - } catch (IllegalArgumentException ex) { - throw new ConfigException(ex.getMessage(), I18N.getString( - "error.version-string-wrong-format.advice"), ex); - } - - Path serviceInstaller = null; - if (!pkg.app().isService()) { - serviceInstaller = null; - } else { - Path resourceDir = RESOURCE_DIR.fetchFrom(params); - if (resourceDir != null) { - serviceInstaller = resourceDir.resolve("service-installer.exe"); - if (!Files.exists(serviceInstaller)) { - throw new ConfigException(I18N.getString( - "error.missing-service-installer"), I18N.getString( - "error.missing-service-installer.advice")); - } - } - } - - return new Impl(pkg, withInstallDirChooser, withShortcutPrompt, helpURL, updateURL, - startMenuGroupName, isSystemWideInstall, upgradeCode, serviceInstaller); - } - - private static UUID getUpgradeCode(Map params) throws ConfigException { - try { - return Optional.ofNullable(Internal.UPGRADE_UUID.fetchFrom(params)) - .map(UUID::fromString).orElse( - null); - } catch (IllegalArgumentException ex) { - throw new ConfigException(ex); - } - } - private static UUID createNameUUID(String... components) { String key = String.join("/", components); return UUID.nameUUIDFromBytes(key.getBytes(StandardCharsets.UTF_8)); } - - final static class Internal { - - private static final BundlerParamInfo INSTALLDIR_CHOOSER - = new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_DIR_CHOOSER.getId(), - Boolean.class, - params -> false, - (s, p) -> Boolean.valueOf(s) - ); - - private static final StandardBundlerParam SHORTCUT_PROMPT - = new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_SHORTCUT_PROMPT.getId(), - Boolean.class, - params -> false, - (s, p) -> Boolean.valueOf(s) - ); - - private static final StandardBundlerParam MENU_GROUP - = new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_MENU_GROUP.getId(), - String.class, - params -> I18N.getString("param.menu-group.default"), - (s, p) -> s - ); - - private static final StandardBundlerParam MSI_SYSTEM_WIDE - = new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_PER_USER_INSTALLATION.getId(), - Boolean.class, - params -> true, // MSIs default to system wide - // valueOf(null) is false, - // and we actually do want null - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? null - : Boolean.valueOf(s) - ); - - private static final BundlerParamInfo HELP_URL - = new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_HELP_URL.getId(), - String.class, - null, - (s, p) -> s); - - private static final BundlerParamInfo UPDATE_URL - = new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_UPDATE_URL.getId(), - String.class, - null, - (s, p) -> s); - - private static final BundlerParamInfo UPGRADE_UUID - = new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_UPGRADE_UUID.getId(), - String.class, - null, - (s, p) -> s); - } - - static final StandardBundlerParam TARGET_PACKAGE = new StandardBundlerParam<>( - Package.PARAM_ID, WinMsiPackage.class, params -> { - return toFunction(WinMsiPackage::createFromParams).apply(params); - }, null); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java new file mode 100644 index 0000000000000..b46b71f8d8baa --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import static jdk.jpackage.internal.Package.StandardPackageType.WinMsi; +import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; +import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; +import jdk.jpackage.internal.WinMsiPackage.Impl; + +final class WinMsiPackageFromParams { + + private static WinMsiPackage create(Map params) throws ConfigException { + var pkg = PackageFromParams.create(params, WinApplicationFromParams.APPLICATION, WinMsi); + var withInstallDirChooser = INSTALLDIR_CHOOSER.fetchFrom(params); + var withShortcutPrompt = SHORTCUT_PROMPT.fetchFrom(params); + var helpURL = HELP_URL.fetchFrom(params); + var updateURL = UPDATE_URL.fetchFrom(params); + var startMenuGroupName = MENU_GROUP.fetchFrom(params); + var isSystemWideInstall = MSI_SYSTEM_WIDE.fetchFrom(params); + var upgradeCode = getUpgradeCode(params); + + try { + MsiVersion.of(pkg.version()); + } catch (IllegalArgumentException ex) { + throw new ConfigException(ex.getMessage(), I18N.getString( + "error.version-string-wrong-format.advice"), ex); + } + + Path serviceInstaller = null; + if (!pkg.app().isService()) { + serviceInstaller = null; + } else { + Path resourceDir = RESOURCE_DIR.fetchFrom(params); + if (resourceDir != null) { + serviceInstaller = resourceDir.resolve("service-installer.exe"); + if (!Files.exists(serviceInstaller)) { + throw new ConfigException(I18N.getString( + "error.missing-service-installer"), I18N.getString( + "error.missing-service-installer.advice")); + } + } + } + + return new Impl(pkg, withInstallDirChooser, withShortcutPrompt, helpURL, updateURL, + startMenuGroupName, isSystemWideInstall, upgradeCode, serviceInstaller); + } + + private static UUID getUpgradeCode(Map params) throws ConfigException { + try { + return Optional.ofNullable(UPGRADE_UUID.fetchFrom(params)) + .map(UUID::fromString).orElse( + null); + } catch (IllegalArgumentException ex) { + throw new ConfigException(ex); + } + } + + static final StandardBundlerParam PACKAGE = createBundlerParam( + WinMsiPackageFromParams::create); + + private static final BundlerParamInfo INSTALLDIR_CHOOSER = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_DIR_CHOOSER.getId(), + Boolean.class, + params -> false, + (s, p) -> Boolean.valueOf(s) + ); + + private static final StandardBundlerParam SHORTCUT_PROMPT = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_SHORTCUT_PROMPT.getId(), + Boolean.class, + params -> false, + (s, p) -> Boolean.valueOf(s) + ); + + private static final StandardBundlerParam MENU_GROUP = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_MENU_GROUP.getId(), + String.class, + params -> I18N.getString("param.menu-group.default"), + (s, p) -> s + ); + + private static final StandardBundlerParam MSI_SYSTEM_WIDE = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_PER_USER_INSTALLATION.getId(), + Boolean.class, + params -> true, // MSIs default to system wide + // valueOf(null) is false, + // and we actually do want null + (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? null + : Boolean.valueOf(s) + ); + + private static final BundlerParamInfo HELP_URL = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_HELP_URL.getId(), + String.class, + null, + (s, p) -> s); + + private static final BundlerParamInfo UPDATE_URL = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_UPDATE_URL.getId(), + String.class, + null, + (s, p) -> s); + + private static final BundlerParamInfo UPGRADE_UUID = new StandardBundlerParam<>( + Arguments.CLIOptions.WIN_UPGRADE_UUID.getId(), + String.class, + null, + (s, p) -> s); +} From 684adb01caa9046361b4f46a42074c4c0a18adeb Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 27 Jun 2024 21:38:09 -0400 Subject: [PATCH 0010/1101] Move validation away from "FromParams" classes --- .../jpackage/internal/LinuxDebBundler.java | 5 +- .../jdk/jpackage/internal/LinuxPackage.java | 58 +++++++++++++++++-- .../internal/LinuxPackageBundler.java | 4 +- .../internal/LinuxPackageFromParams.java | 33 +---------- .../jpackage/internal/LinuxRpmBundler.java | 3 +- .../internal/MacLaunchersAsServices.java | 4 +- .../jdk/jpackage/internal/ProxyBase.java | 2 +- .../jdk/jpackage/internal/WinMsiPackage.java | 23 ++++++-- .../internal/WinMsiPackageFromParams.java | 26 ++------- 9 files changed, 86 insertions(+), 72 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index e6ff1e08cd148..9ab75ab95b5ca 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -191,8 +191,7 @@ protected List verifyOutputBundle(Workshop workshop, LinuxPacka new PackageProperty("Version", ((LinuxDebPackage)pkg).versionWithRelease(), "APPLICATION_VERSION_WITH_RELEASE", controlFileName), - new PackageProperty("Architecture", LinuxPackageArch.getValue(LinuxDeb), - "APPLICATION_ARCH", controlFileName)); + new PackageProperty("Architecture", pkg.arch(), "APPLICATION_ARCH", controlFileName)); List cmdline = new ArrayList<>(List.of(TOOL_DPKG_DEB, "-f", packageBundle.toString())); @@ -343,7 +342,7 @@ protected Map createReplacementData(Workshop workshop, LinuxPack data.put("APPLICATION_SECTION", pkg.category()); data.put("APPLICATION_COPYRIGHT", pkg.app().copyright()); data.put("APPLICATION_LICENSE_TEXT", licenseText); - data.put("APPLICATION_ARCH", LinuxPackageArch.getValue(LinuxDeb)); + data.put("APPLICATION_ARCH", pkg.arch()); data.put("APPLICATION_INSTALLED_SIZE", Long.toString(pkg.appLayout().resolveAt(workshop .appImageDir()).sizeInBytes() >> 10)); data.put("APPLICATION_HOMEPAGE", Optional.ofNullable(pkg.aboutURL()).map( diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java index 070b79e83542e..99b4bd51b3a4c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java @@ -26,7 +26,6 @@ import java.nio.file.Path; import java.text.MessageFormat; -import java.util.Map; import java.util.Set; import java.util.regex.Pattern; @@ -40,6 +39,8 @@ interface LinuxPackage extends Package { String release(); + String arch(); + @Override default ApplicationLayout appLayout() { if (isInstallDirInUsrTree()) { @@ -55,13 +56,49 @@ default boolean isInstallDirInUsrTree() { static class Impl extends Package.Proxy implements LinuxPackage { - public Impl(Package target, String menuGroupName, String category, - String additionalDependencies, String release) { + Impl(Package target, String menuGroupName, String category, String additionalDependencies, + String release) throws ConfigException { + this(target, menuGroupName, category, additionalDependencies, release, LinuxPackageArch + .getValue(target.asStandardPackageType())); + } + + Impl(Package target, String menuGroupName, String category, + String additionalDependencies, String release, String arch) throws ConfigException { super(target); + if (target.type() instanceof StandardPackageType type) { + packageName = mapPackageName(target.packageName(), type); + } else { + packageName = target.packageName(); + } this.menuGroupName = menuGroupName; this.category = category; this.additionalDependencies = additionalDependencies; this.release = release; + this.arch = arch; + } + + @Override + public String packageName() { + return packageName; + } + + @Override + public Path packageFileName() { + String packageFileNameTemlate; + switch (asStandardPackageType()) { + case LinuxDeb -> { + packageFileNameTemlate = "%s_%s-%s_%s.deb"; + } + case LinuxRpm -> { + packageFileNameTemlate = "%s-%s-%s.%s.rpm"; + } + default -> { + throw new UnsupportedOperationException(); + } + } + + return Path.of(String.format(packageFileNameTemlate, packageName(), version(), + release(), arch())); } @Override @@ -84,10 +121,18 @@ public String release() { return release; } + @Override + public String arch() { + return arch; + } + + private final String packageName; + private final String menuGroupName; private final String category; private final String additionalDependencies; private final String release; + private final String arch; } static class Proxy extends Package.Proxy implements LinuxPackage { @@ -115,9 +160,14 @@ public String additionalDependencies() { public String release() { return target.release(); } + + @Override + public String arch() { + return target.arch(); + } } - static String mapPackageName(String packageName, StandardPackageType pkgType) throws ConfigException { + private static String mapPackageName(String packageName, StandardPackageType pkgType) throws ConfigException { // make sure to lower case and spaces/underscores become dashes packageName = packageName.toLowerCase().replaceAll("[ _]", "-"); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 46e396e96b9b1..cdfaf1da752e5 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -50,7 +50,7 @@ abstract class LinuxPackageBundler extends AbstractBundler { @Override public final boolean validate(Map params) throws ConfigException { - + // Order is important! LinuxPackage pkg = pkgParam.fetchFrom(params); var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); @@ -114,7 +114,7 @@ public Path appImageDir() { return buildRoot().resolve("pkg-image"); } }; - + params.put(WorkshopFromParams.WORKSHOP.getID(), pkgWorkshop); Function initAppImageLayout = imageRoot -> { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java index d42518137932e..b581ac8fba519 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java @@ -24,13 +24,9 @@ */ package jdk.jpackage.internal; -import java.nio.file.Path; import java.util.Map; import jdk.jpackage.internal.LinuxPackage.Impl; -import static jdk.jpackage.internal.LinuxPackage.mapPackageName; import jdk.jpackage.internal.Package.StandardPackageType; -import static jdk.jpackage.internal.Package.StandardPackageType.LinuxDeb; -import static jdk.jpackage.internal.Package.StandardPackageType.LinuxRpm; final class LinuxPackageFromParams { @@ -41,34 +37,7 @@ static LinuxPackage create(Map params, StandardPackageTy var additionalDependencies = LINUX_PACKAGE_DEPENDENCIES.fetchFrom(params); var release = RELEASE.fetchFrom(params); - var packageName = mapPackageName(pkg.packageName(), pkgType); - var arch = LinuxPackageArch.getValue(pkgType); - - return new Impl(pkg, menuGroupName, category, additionalDependencies, release) { - @Override - public String packageName() { - return packageName; - } - - @Override - public Path packageFileName() { - String packageFileNameTemlate; - switch (asStandardPackageType()) { - case LinuxDeb -> { - packageFileNameTemlate = "%s_%s-%s_%s.deb"; - } - case LinuxRpm -> { - packageFileNameTemlate = "%s-%s-%s.%s.rpm"; - } - default -> { - throw new UnsupportedOperationException(); - } - } - - return Path.of(String.format(packageFileNameTemlate, packageName(), version(), - release(), arch)); - } - }; + return new Impl(pkg, menuGroupName, category, additionalDependencies, release); } private static final BundlerParamInfo LINUX_CATEGORY = new StandardBundlerParam<>( diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index 7bbf913b83325..6f92171a609d8 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -156,8 +156,7 @@ protected List verifyOutputBundle(Workshop workshop, LinuxPacka "APPLICATION_VERSION", specFileName), new PackageProperty("Release", pkg.release(), "APPLICATION_RELEASE", specFileName), - new PackageProperty("Arch", LinuxPackageArch.getValue( - Package.StandardPackageType.LinuxRpm), null, specFileName)); + new PackageProperty("Arch", pkg.arch(), null, specFileName)); List actualValues = Executor.of(TOOL_RPM, "-qp", "--queryformat", properties.stream().map(entry -> String.format("%%{%s}", diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index 92023e159dc00..1349ff3e65b95 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -44,11 +44,11 @@ private MacLaunchersAsServices(Workshop workshop, Package pkg) throws IOExceptio static ShellCustomAction create(Map params, Path outputDir) throws IOException { - + // Order is important! var pkg = PackageFromParams.PACKAGE.fetchFrom(params); var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); - + if (pkg.isRuntimeInstaller()) { return null; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ProxyBase.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ProxyBase.java index 4f11954377048..91b0974aefafb 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ProxyBase.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ProxyBase.java @@ -28,6 +28,6 @@ abstract class ProxyBase { ProxyBase(T target) { this.target = target; } - + protected final T target; } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java index 502dad9514e13..b2ac220c7ee58 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java @@ -25,7 +25,9 @@ package jdk.jpackage.internal; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.Optional; import java.util.UUID; interface WinMsiPackage extends Package { @@ -56,8 +58,21 @@ static class Impl extends Package.Proxy implements WinMsiPackage { Impl(Package pkg, boolean withInstallDirChooser, boolean withShortcutPrompt, String helpURL, String updateURL, String startMenuGroupName, boolean isSystemWideInstall, - UUID upgradeCode, Path serviceInstaller) { + UUID upgradeCode, Path serviceInstaller) throws ConfigException { super(pkg); + + try { + MsiVersion.of(pkg.version()); + } catch (IllegalArgumentException ex) { + throw new ConfigException(ex.getMessage(), I18N.getString( + "error.version-string-wrong-format.advice"), ex); + } + + if (pkg.app().isService() && serviceInstaller == null || !Files.exists(serviceInstaller)) { + throw new ConfigException(I18N.getString("error.missing-service-installer"), I18N + .getString("error.missing-service-installer.advice")); + } + this.withInstallDirChooser = withInstallDirChooser; this.withShortcutPrompt = withShortcutPrompt; this.helpURL = helpURL; @@ -100,11 +115,7 @@ public boolean isSystemWideInstall() { @Override public UUID upgradeCode() { - if (upgradeCode == null) { - return WinMsiPackage.super.upgradeCode(); - } else { - return upgradeCode; - } + return Optional.ofNullable(upgradeCode).orElseGet(WinMsiPackage.super::upgradeCode); } @Override diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java index b46b71f8d8baa..529f3a4ead25f 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java @@ -24,7 +24,6 @@ */ package jdk.jpackage.internal; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; import java.util.Optional; @@ -46,26 +45,14 @@ private static WinMsiPackage create(Map params) throws C var isSystemWideInstall = MSI_SYSTEM_WIDE.fetchFrom(params); var upgradeCode = getUpgradeCode(params); - try { - MsiVersion.of(pkg.version()); - } catch (IllegalArgumentException ex) { - throw new ConfigException(ex.getMessage(), I18N.getString( - "error.version-string-wrong-format.advice"), ex); - } - - Path serviceInstaller = null; + final Path serviceInstaller; if (!pkg.app().isService()) { serviceInstaller = null; } else { - Path resourceDir = RESOURCE_DIR.fetchFrom(params); - if (resourceDir != null) { - serviceInstaller = resourceDir.resolve("service-installer.exe"); - if (!Files.exists(serviceInstaller)) { - throw new ConfigException(I18N.getString( - "error.missing-service-installer"), I18N.getString( - "error.missing-service-installer.advice")); - } - } + serviceInstaller = Optional.ofNullable(RESOURCE_DIR.fetchFrom(params)).map( + resourceDir -> { + return resourceDir.resolve("service-installer.exe"); + }).orElse(null); } return new Impl(pkg, withInstallDirChooser, withShortcutPrompt, helpURL, updateURL, @@ -74,8 +61,7 @@ private static WinMsiPackage create(Map params) throws C private static UUID getUpgradeCode(Map params) throws ConfigException { try { - return Optional.ofNullable(UPGRADE_UUID.fetchFrom(params)) - .map(UUID::fromString).orElse( + return Optional.ofNullable(UPGRADE_UUID.fetchFrom(params)).map(UUID::fromString).orElse( null); } catch (IllegalArgumentException ex) { throw new ConfigException(ex); From d552f6d55d49899e5074ee628b28b61cb0d1dc76 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 1 Jul 2024 13:39:59 -0400 Subject: [PATCH 0011/1101] - Encapsulate building of a runtime by jlink or copying from the external directory in RuntimeBuilder interface - Add ctor to BundlerParamInfo class and make StandardBundlerParam class a storage for standard parameters - Add defaults to Application/Package and derived interfaces --- .../internal/LinuxAppImageBuilder.java | 4 +- .../internal/LinuxApplicationFromParams.java | 4 +- .../internal/LinuxDebPackageFromParams.java | 4 +- .../jdk/jpackage/internal/LinuxPackage.java | 12 + .../internal/LinuxPackageFromParams.java | 29 +-- .../internal/LinuxRpmPackageFromParams.java | 4 +- .../jdk/jpackage/internal/MacAppBundler.java | 10 +- .../jpackage/internal/MacAppImageBuilder.java | 51 ++-- .../internal/MacBaseInstallerBundler.java | 18 +- .../jdk/jpackage/internal/MacDmgBundler.java | 4 +- .../jdk/jpackage/internal/MacPkgBundler.java | 10 +- .../jpackage/internal/AbstractBundler.java | 2 +- .../jpackage/internal/AppImageBundler.java | 8 +- .../jdk/jpackage/internal/Application.java | 27 +- .../internal/ApplicationFromParams.java | 19 +- .../jpackage/internal/BundlerParamInfo.java | 58 +++-- .../internal/JLinkRuntimeBuilder.java | 227 +++++++++++++++++ .../jdk/jpackage/internal/LauncherData.java | 2 +- .../jdk/jpackage/internal/Package.java | 13 +- .../jpackage/internal/PackageFromParams.java | 8 +- .../jdk/jpackage/internal/RuntimeBuilder.java | 232 +++-------------- .../internal/RuntimeBuilderFromParams.java | 61 +++++ .../internal/StandardBundlerParam.java | 237 ++++++------------ .../jpackage/internal/WorkshopFromParams.java | 7 +- .../internal/WinApplicationFromParams.java | 6 +- .../jdk/jpackage/internal/WinExeBundler.java | 4 +- .../jdk/jpackage/internal/WinMsiBundler.java | 2 - .../internal/WinMsiPackageFromParams.java | 32 +-- .../internal/WindowsAppImageBuilder.java | 8 +- 29 files changed, 570 insertions(+), 533 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderFromParams.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index 7291d56218a21..f4754dc236724 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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 @@ -39,7 +39,7 @@ public class LinuxAppImageBuilder extends AbstractAppImageBuilder { static final BundlerParamInfo ICON_PNG = - new StandardBundlerParam<>( + new BundlerParamInfo<>( "icon.png", Path.class, params -> { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java index 969ae3b43c63d..67278db23ae67 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java @@ -48,10 +48,10 @@ private static LinuxApplication create(Map params) throw return new Impl(app); } - static final StandardBundlerParam APPLICATION = createBundlerParam( + static final BundlerParamInfo APPLICATION = createBundlerParam( LinuxApplicationFromParams::create); - private static final StandardBundlerParam LINUX_SHORTCUT_HINT = new StandardBundlerParam<>( + private static final BundlerParamInfo LINUX_SHORTCUT_HINT = new BundlerParamInfo<>( Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(), Boolean.class, params -> false, diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java index b011f400ef0ce..76b9a05898c1a 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java @@ -38,10 +38,10 @@ private static LinuxDebPackage create(Map params) throws return new LinuxDebPackage.Impl(pkg, maintainerEmail); } - static final StandardBundlerParam PACKAGE = createBundlerParam( + static final BundlerParamInfo PACKAGE = createBundlerParam( LinuxDebPackageFromParams::create); - private static final BundlerParamInfo MAINTAINER_EMAIL = new StandardBundlerParam<>( + private static final BundlerParamInfo MAINTAINER_EMAIL = new BundlerParamInfo<>( Arguments.CLIOptions.LINUX_DEB_MAINTAINER.getId(), String.class, params -> "Unknown", diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java index 99b4bd51b3a4c..7a7c1c0ad1bf1 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java @@ -26,6 +26,7 @@ import java.nio.file.Path; import java.text.MessageFormat; +import java.util.Optional; import java.util.Set; import java.util.regex.Pattern; @@ -70,6 +71,11 @@ static class Impl extends Package.Proxy implements LinuxPackage { } else { packageName = target.packageName(); } + + menuGroupName = Optional.ofNullable(menuGroupName).orElseGet(DEFAULTS::menuGroupName); + category = Optional.ofNullable(category).orElseGet(DEFAULTS::category); + release = Optional.ofNullable(release).orElseGet(DEFAULTS::release); + this.menuGroupName = menuGroupName; this.category = category; this.additionalDependencies = additionalDependencies; @@ -167,6 +173,12 @@ public String arch() { } } + static record Defaults(String release, String menuGroupName, String category) { + } + + static final Defaults DEFAULTS = new Defaults("1", I18N.getString("param.menu-group.default"), + "misc"); + private static String mapPackageName(String packageName, StandardPackageType pkgType) throws ConfigException { // make sure to lower case and spaces/underscores become dashes packageName = packageName.toLowerCase().replaceAll("[ _]", "-"); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java index b581ac8fba519..64a8daddb0709 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal; import java.util.Map; +import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import jdk.jpackage.internal.LinuxPackage.Impl; import jdk.jpackage.internal.Package.StandardPackageType; @@ -40,27 +41,15 @@ static LinuxPackage create(Map params, StandardPackageTy return new Impl(pkg, menuGroupName, category, additionalDependencies, release); } - private static final BundlerParamInfo LINUX_CATEGORY = new StandardBundlerParam<>( - Arguments.CLIOptions.LINUX_CATEGORY.getId(), - String.class, - params -> "misc", - (s, p) -> s); + private static final BundlerParamInfo LINUX_CATEGORY = createStringBundlerParam( + Arguments.CLIOptions.LINUX_CATEGORY.getId()); - private static final BundlerParamInfo LINUX_PACKAGE_DEPENDENCIES = new StandardBundlerParam<>( - Arguments.CLIOptions.LINUX_PACKAGE_DEPENDENCIES.getId(), - String.class, - params -> null, - (s, p) -> s); + private static final BundlerParamInfo LINUX_PACKAGE_DEPENDENCIES = createStringBundlerParam( + Arguments.CLIOptions.LINUX_PACKAGE_DEPENDENCIES.getId()); - private static final BundlerParamInfo LINUX_MENU_GROUP = new StandardBundlerParam<>( - Arguments.CLIOptions.LINUX_MENU_GROUP.getId(), - String.class, - params -> I18N.getString("param.menu-group.default"), - (s, p) -> s); + private static final BundlerParamInfo LINUX_MENU_GROUP = createStringBundlerParam( + Arguments.CLIOptions.LINUX_MENU_GROUP.getId()); - private static final StandardBundlerParam RELEASE = new StandardBundlerParam<>( - Arguments.CLIOptions.RELEASE.getId(), - String.class, - params -> "1", - (s, p) -> s); + private static final BundlerParamInfo RELEASE = createStringBundlerParam( + Arguments.CLIOptions.RELEASE.getId()); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java index cdb2807877a19..bcdc7fad41643 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java @@ -39,10 +39,10 @@ private static LinuxRpmPackage create(Map params) throws return new Impl(pkg, licenseType); } - static final StandardBundlerParam PACKAGE = createBundlerParam( + static final BundlerParamInfo PACKAGE = createBundlerParam( LinuxRpmPackageFromParams::create); - private static final BundlerParamInfo LICENSE_TYPE = new StandardBundlerParam<>( + private static final BundlerParamInfo LICENSE_TYPE = new BundlerParamInfo<>( Arguments.CLIOptions.LINUX_RPM_LICENSE_TYPE.getId(), String.class, params -> I18N.getString("param.license-type.default"), diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index 06796db98847a..06814bd5fe914 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 @@ -47,14 +47,14 @@ public MacAppBundler() { private static final String TEMPLATE_BUNDLE_ICON = "JavaApp.icns"; public static final BundlerParamInfo DEFAULT_ICNS_ICON = - new StandardBundlerParam<>( + new BundlerParamInfo<>( ".mac.default.icns", String.class, params -> TEMPLATE_BUNDLE_ICON, (s, p) -> s); public static final BundlerParamInfo DEVELOPER_ID_APP_SIGNING_KEY = - new StandardBundlerParam<>( + new BundlerParamInfo<>( "mac.signing-key-developer-id-app", String.class, params -> { @@ -86,14 +86,14 @@ public MacAppBundler() { (s, p) -> s); public static final BundlerParamInfo APP_IMAGE_SIGN_IDENTITY = - new StandardBundlerParam<>( + new BundlerParamInfo<>( Arguments.CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getId(), String.class, params -> "", null); public static final BundlerParamInfo BUNDLE_ID_SIGNING_PREFIX = - new StandardBundlerParam<>( + new BundlerParamInfo<>( Arguments.CLIOptions.MAC_BUNDLE_SIGNING_PREFIX.getId(), String.class, params -> getIdentifier(params) + ".", diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java index 472e58cd1a2e3..bb698cfb7b7c8 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -57,7 +57,6 @@ import static jdk.jpackage.internal.MacAppBundler.DEVELOPER_ID_APP_SIGNING_KEY; import static jdk.jpackage.internal.MacAppBundler.APP_IMAGE_SIGN_IDENTITY; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; -import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; import static jdk.jpackage.internal.MacBaseInstallerBundler.INSTALLER_SIGN_IDENTITY; import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; @@ -76,8 +75,6 @@ import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; -import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; -import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage; public class MacAppImageBuilder extends AbstractAppImageBuilder { @@ -103,28 +100,28 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { private static List keyChains; public static final BundlerParamInfo - MAC_CONFIGURE_LAUNCHER_IN_PLIST = new StandardBundlerParam<>( + MAC_CONFIGURE_LAUNCHER_IN_PLIST = new BundlerParamInfo<>( "mac.configure-launcher-in-plist", Boolean.class, params -> Boolean.FALSE, (s, p) -> Boolean.valueOf(s)); public static final BundlerParamInfo MAC_CF_BUNDLE_NAME = - new StandardBundlerParam<>( + new BundlerParamInfo<>( Arguments.CLIOptions.MAC_BUNDLE_NAME.getId(), String.class, params -> null, (s, p) -> s); public static final BundlerParamInfo APP_CATEGORY = - new StandardBundlerParam<>( + new BundlerParamInfo<>( Arguments.CLIOptions.MAC_CATEGORY.getId(), String.class, params -> "utilities", (s, p) -> s); public static final BundlerParamInfo MAC_CF_BUNDLE_IDENTIFIER = - new StandardBundlerParam<>( + new BundlerParamInfo<>( Arguments.CLIOptions.MAC_BUNDLE_IDENTIFIER.getId(), String.class, params -> { @@ -142,7 +139,7 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { (s, p) -> s); public static final BundlerParamInfo ICON_ICNS = - new StandardBundlerParam<>( + new BundlerParamInfo<>( "icon.icns", Path.class, params -> { @@ -158,7 +155,7 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { (s, p) -> Path.of(s)); public static final BundlerParamInfo ENTITLEMENTS = - new StandardBundlerParam<>( + new BundlerParamInfo<>( Arguments.CLIOptions.MAC_ENTITLEMENTS.getId(), Path.class, params -> { @@ -179,56 +176,56 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { (s, p) -> Path.of(s) ); - private static final StandardBundlerParam FA_MAC_CFBUNDLETYPEROLE = - new StandardBundlerParam<>( + private static final BundlerParamInfo FA_MAC_CFBUNDLETYPEROLE = + new BundlerParamInfo<>( Arguments.MAC_CFBUNDLETYPEROLE, String.class, params -> "Editor", (s, p) -> s ); - private static final StandardBundlerParam FA_MAC_LSHANDLERRANK = - new StandardBundlerParam<>( + private static final BundlerParamInfo FA_MAC_LSHANDLERRANK = + new BundlerParamInfo<>( Arguments.MAC_LSHANDLERRANK, String.class, params -> "Owner", (s, p) -> s ); - private static final StandardBundlerParam FA_MAC_NSSTORETYPEKEY = - new StandardBundlerParam<>( + private static final BundlerParamInfo FA_MAC_NSSTORETYPEKEY = + new BundlerParamInfo<>( Arguments.MAC_NSSTORETYPEKEY, String.class, params -> null, (s, p) -> s ); - private static final StandardBundlerParam FA_MAC_NSDOCUMENTCLASS = - new StandardBundlerParam<>( + private static final BundlerParamInfo FA_MAC_NSDOCUMENTCLASS = + new BundlerParamInfo<>( Arguments.MAC_NSDOCUMENTCLASS, String.class, params -> null, (s, p) -> s ); - private static final StandardBundlerParam FA_MAC_LSTYPEISPACKAGE = - new StandardBundlerParam<>( + private static final BundlerParamInfo FA_MAC_LSTYPEISPACKAGE = + new BundlerParamInfo<>( Arguments.MAC_LSTYPEISPACKAGE, String.class, params -> null, (s, p) -> s ); - private static final StandardBundlerParam FA_MAC_LSDOCINPLACE = - new StandardBundlerParam<>( + private static final BundlerParamInfo FA_MAC_LSDOCINPLACE = + new BundlerParamInfo<>( Arguments.MAC_LSDOCINPLACE, String.class, params -> null, (s, p) -> s ); - private static final StandardBundlerParam FA_MAC_UIDOCBROWSER = - new StandardBundlerParam<>( + private static final BundlerParamInfo FA_MAC_UIDOCBROWSER = + new BundlerParamInfo<>( Arguments.MAC_UIDOCBROWSER, String.class, params -> null, @@ -236,8 +233,8 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { ); @SuppressWarnings("unchecked") - private static final StandardBundlerParam> FA_MAC_NSEXPORTABLETYPES = - new StandardBundlerParam<>( + private static final BundlerParamInfo> FA_MAC_NSEXPORTABLETYPES = + new BundlerParamInfo<>( Arguments.MAC_NSEXPORTABLETYPES, (Class>) (Object) List.class, params -> null, @@ -245,8 +242,8 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { ); @SuppressWarnings("unchecked") - private static final StandardBundlerParam> FA_MAC_UTTYPECONFORMSTO = - new StandardBundlerParam<>( + private static final BundlerParamInfo> FA_MAC_UTTYPECONFORMSTO = + new BundlerParamInfo<>( Arguments.MAC_UTTYPECONFORMSTO, (Class>) (Object) List.class, params -> Arrays.asList("public.data"), diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index 8d9db0a007783..a4a73515d5555 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, 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,19 +25,13 @@ package jdk.jpackage.internal; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.PrintStream; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; @@ -48,7 +42,7 @@ public abstract class MacBaseInstallerBundler extends AbstractBundler { private final BundlerParamInfo APP_IMAGE_TEMP_ROOT = - new StandardBundlerParam<>( + new BundlerParamInfo<>( "mac.app.imageRoot", Path.class, params -> { @@ -66,28 +60,28 @@ public abstract class MacBaseInstallerBundler extends AbstractBundler { (s, p) -> Path.of(s)); public static final BundlerParamInfo SIGNING_KEY_USER = - new StandardBundlerParam<>( + new BundlerParamInfo<>( Arguments.CLIOptions.MAC_SIGNING_KEY_NAME.getId(), String.class, params -> "", null); public static final BundlerParamInfo SIGNING_KEYCHAIN = - new StandardBundlerParam<>( + new BundlerParamInfo<>( Arguments.CLIOptions.MAC_SIGNING_KEYCHAIN.getId(), String.class, params -> "", null); public static final BundlerParamInfo INSTALLER_SIGN_IDENTITY = - new StandardBundlerParam<>( + new BundlerParamInfo<>( Arguments.CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getId(), String.class, params -> "", null); public static final BundlerParamInfo MAC_INSTALLER_NAME = - new StandardBundlerParam<> ( + new BundlerParamInfo<> ( "mac.installerName", String.class, params -> { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java index 7d100832dbaf4..04a3dffa95ff4 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 @@ -65,7 +65,7 @@ public class MacDmgBundler extends MacBaseInstallerBundler { static final String DEFAULT_LICENSE_PLIST="lic_template.plist"; public static final BundlerParamInfo INSTALLER_SUFFIX = - new StandardBundlerParam<> ( + new BundlerParamInfo<> ( "mac.dmg.installerName.suffix", String.class, params -> "", diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 6ac84975451b4..1dc21c1065d2e 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, 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 @@ -72,7 +72,7 @@ public class MacPkgBundler extends MacBaseInstallerBundler { private static final String DEFAULT_PDF = "product-def.plist"; private static final BundlerParamInfo PACKAGES_ROOT = - new StandardBundlerParam<>( + new BundlerParamInfo<>( "mac.pkg.packagesRoot", Path.class, params -> { @@ -89,7 +89,7 @@ public class MacPkgBundler extends MacBaseInstallerBundler { protected final BundlerParamInfo SCRIPTS_DIR = - new StandardBundlerParam<>( + new BundlerParamInfo<>( "mac.pkg.scriptsDir", Path.class, params -> { @@ -106,7 +106,7 @@ public class MacPkgBundler extends MacBaseInstallerBundler { public static final BundlerParamInfo DEVELOPER_ID_INSTALLER_SIGNING_KEY = - new StandardBundlerParam<>( + new BundlerParamInfo<>( "mac.signing-key-developer-id-installer", String.class, params -> { @@ -139,7 +139,7 @@ public class MacPkgBundler extends MacBaseInstallerBundler { (s, p) -> s); public static final BundlerParamInfo INSTALLER_SUFFIX = - new StandardBundlerParam<> ( + new BundlerParamInfo<> ( "mac.pkg.installerName.suffix", String.class, params -> "", diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java index b615176fd15cf..17d43b90213e1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java @@ -40,7 +40,7 @@ abstract class AbstractBundler implements Bundler { static final BundlerParamInfo IMAGES_ROOT = - new StandardBundlerParam<>( + new BundlerParamInfo<>( "imagesRoot", Path.class, params -> diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java index 06f74536cc4e2..3a07d995a3cda 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java @@ -170,7 +170,6 @@ private Path createAppBundle(Map params, boolean hasAppImage = PREDEFINED_APP_IMAGE.fetchFrom(params) != null; - boolean hasRuntimeImage = app.predefinedRuntimeImage() != null; Path rootDirectory = hasAppImage ? PREDEFINED_APP_IMAGE.fetchFrom(params) : @@ -178,12 +177,7 @@ private Path createAppBundle(Map params, AbstractAppImageBuilder appBuilder = appImageSupplier.apply(rootDirectory); if (!hasAppImage) { - if (!hasRuntimeImage) { - app.runtimeBuilder().execute(appBuilder.getAppLayout().runtimeHomeDirectory()); - } else { - StandardBundlerParam.copyPredefinedRuntimeImage( - params, appBuilder.getAppLayout()); - } + app.runtimeBuilder().createRuntime(appBuilder.getAppLayout()); } appBuilder.prepareApplicationFiles(params); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java index af97eccde2d21..9948f61c9c044 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java @@ -25,6 +25,8 @@ package jdk.jpackage.internal; import java.nio.file.Path; +import java.text.MessageFormat; +import java.util.Date; import java.util.List; import java.util.Optional; import java.util.function.Function; @@ -44,8 +46,6 @@ interface Application { String copyright(); - Path predefinedRuntimeImage(); - RuntimeBuilder runtimeBuilder(); default Path appImageDirName() { @@ -116,11 +116,25 @@ default OverridableResource createLauncherIconResource(Launcher launcher, String } static record Impl(String name, String description, String version, String vendor, - String copyright, Path predefinedRuntimeImage, RuntimeBuilder runtimeBuilder, - Launcher mainLauncher, List additionalLaunchers) implements Application { + String copyright, RuntimeBuilder runtimeBuilder, Launcher mainLauncher, + List additionalLaunchers) implements Application { + public Impl { + name = Optional.ofNullable(name).orElseGet(mainLauncher::name); + description = Optional.ofNullable(description).orElseGet(DEFAULTS::description); + version = Optional.ofNullable(version).orElseGet(DEFAULTS::version); + vendor = Optional.ofNullable(vendor).orElseGet(DEFAULTS::vendor); + copyright = Optional.ofNullable(copyright).orElseGet(DEFAULTS::copyright); + } + } + + static record Defaults(String description, String version, String vendor, String copyright) { } + static final Defaults DEFAULTS = new Defaults(I18N.getString("param.description.default"), "1.0", + I18N.getString("param.vendor.default"), MessageFormat.format(I18N.getString( + "param.copyright.default"), new Date())); + static class Proxy extends ProxyBase implements Application { Proxy(T target) { @@ -152,11 +166,6 @@ public String copyright() { return target.copyright(); } - @Override - public Path predefinedRuntimeImage() { - return target.predefinedRuntimeImage(); - } - @Override public RuntimeBuilder runtimeBuilder() { return target.runtimeBuilder(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java index de84414241c46..c576b1bc236a9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java @@ -31,7 +31,6 @@ import java.util.Optional; import java.util.function.Function; import java.util.stream.Stream; -import static jdk.jpackage.internal.Functional.ThrowingBiFunction.toBiFunction; import jdk.jpackage.internal.Functional.ThrowingFunction; import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; @@ -41,7 +40,6 @@ import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; @@ -57,7 +55,6 @@ static Application create(Map params, var version = VERSION.fetchFrom(params); var vendor = VENDOR.fetchFrom(params); var copyright = COPYRIGHT.fetchFrom(params); - var predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); var predefinedAppImage = getPredefinedAppImage(params); if (name == null && predefinedAppImage == null) { @@ -99,15 +96,11 @@ static Application create(Map params, var startupInfos = Stream.concat(Stream.of(mainLauncher), additionalLaunchers.stream()).map( Launcher::startupInfo).toList(); - if (predefinedRuntimeImage == null) { - runtimeBuilder = RuntimeBuilder.createFromParams(params, startupInfos); - } else { - runtimeBuilder = null; - } + runtimeBuilder = RuntimeBuilderFromParams.create(params, startupInfos); } - return new Application.Impl(name, description, version, vendor, copyright, - predefinedRuntimeImage, runtimeBuilder, mainLauncher, additionalLaunchers); + return new Application.Impl(name, description, version, vendor, copyright, runtimeBuilder, + mainLauncher, additionalLaunchers); } private static Map mergeParams(Map mainParams, @@ -121,12 +114,12 @@ static Application create(Map params, .getID(), FILE_ASSOCIATIONS.getID()); } - static StandardBundlerParam createBundlerParam( + static BundlerParamInfo createBundlerParam( ThrowingFunction, T> valueFunc) { - return StandardBundlerParam.createBundlerParam("target.application", valueFunc); + return BundlerParamInfo.createBundlerParam("target.application", valueFunc); } - static final StandardBundlerParam APPLICATION = createBundlerParam(params -> { + static final BundlerParamInfo APPLICATION = createBundlerParam(params -> { return ApplicationFromParams.create(params, LauncherFromParams::create); }); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java index fa99073ff7f79..26316a20d3dc6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, 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,40 +22,40 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.jpackage.internal; import java.util.Map; import java.util.function.BiFunction; import java.util.function.Function; +import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; /** * BundlerParamInfo * * A BundlerParamInfo encapsulates an individual bundler parameter of type . + * + * @param id The command line and hashmap name of the parameter + * + * @param valueType Type of the parameter + * + * @param defaultValueFunction If the value is not set, and no fallback value is found, the + * parameter uses the value returned by the producer. + * + * @param stringConverter An optional string converter for command line arguments. */ -class BundlerParamInfo { - - /** - * The command line and hashmap name of the parameter - */ - String id; - - /** - * Type of the parameter - */ - Class valueType; - - /** - * If the value is not set, and no fallback value is found, - * the parameter uses the value returned by the producer. - */ - Function, T> defaultValueFunction; - - /** - * An optional string converter for command line arguments. - */ - BiFunction, T> stringConverter; +record BundlerParamInfo(String id, Class valueType, + Function, T> defaultValueFunction, + BiFunction, T> stringConverter) { + + static BundlerParamInfo createStringBundlerParam(String id) { + return new BundlerParamInfo<>(id, String.class, null, null); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + static BundlerParamInfo createBundlerParam(String id, + Functional.ThrowingFunction, T2> valueFunc) { + return new BundlerParamInfo(id, Object.class, toFunction(valueFunc), null); + } String getID() { return id; @@ -66,8 +66,7 @@ Class getValueType() { } /** - * Returns true if value was not provided on command line for this - * parameter. + * Returns true if value was not provided on command line for this parameter. * * @param params - params from which value will be fetch * @return true if value was not provided on command line, false otherwise @@ -89,8 +88,7 @@ boolean getIsDefaultValue(Map params) { return defaultValueFunction; } - BiFunction,T> - getStringConverter() { + BiFunction, T> getStringConverter() { return stringConverter; } @@ -104,7 +102,7 @@ final T fetchFrom(Map params, boolean invokeDefault) { Object o = params.get(getID()); if (o instanceof String && getStringConverter() != null) { - return getStringConverter().apply((String)o, params); + return getStringConverter().apply((String) o, params); } Class klass = getValueType(); @@ -122,7 +120,7 @@ final T fetchFrom(Map params, } if (invokeDefault && (getDefaultValueFunction() != null)) { - T result = getDefaultValueFunction().apply(params); + T result = getDefaultValueFunction().apply(params); if (result != null) { params.put(getID(), result); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java new file mode 100644 index 0000000000000..5c07fee9e2773 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.lang.module.ResolvedModule; +import java.nio.file.Path; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Supplier; +import java.util.jar.JarFile; +import java.util.spi.ToolProvider; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import jdk.internal.module.ModulePath; + +final class JLinkRuntimeBuilder implements RuntimeBuilder { + + private JLinkRuntimeBuilder(List jlinkCmdLine) { + this.jlinkCmdLine = jlinkCmdLine; + } + + @Override + public void createRuntime(ApplicationLayout appLayout) throws PackagerException, IOException { + var args = new ArrayList(); + args.add("--output"); + args.add(appLayout.runtimeHomeDirectory().toString()); + args.addAll(jlinkCmdLine); + + StringWriter writer = new StringWriter(); + PrintWriter pw = new PrintWriter(writer); + + int retVal = LazyLoad.JLINK_TOOL.run(pw, pw, args.toArray(String[]::new)); + String jlinkOut = writer.toString(); + + args.add(0, "jlink"); + Log.verbose(args, List.of(jlinkOut), retVal, -1); + if (retVal != 0) { + throw new PackagerException("error.jlink.failed", jlinkOut); + } + } + + static ModuleFinder createModuleFinder(Collection modulePath) { + return ModuleFinder.compose( + ModulePath.of(JarFile.runtimeVersion(), true, + modulePath.toArray(Path[]::new)), + ModuleFinder.ofSystem()); + } + + static RuntimeBuilder createJLinkRuntimeBuilder(List modulePath, Set addModules, + Set limitModules, List options, List startupInfos) throws ConfigException { + return new JLinkRuntimeBuilder(createJLinkCmdline(modulePath, addModules, limitModules, + options, startupInfos)); + } + + private static List createJLinkCmdline(List modulePath, Set addModules, + Set limitModules, List options, List startupInfos) throws ConfigException { + List launcherModules = startupInfos.stream().map(si -> { + if (si instanceof LauncherModularStartupInfo siModular) { + return siModular.moduleName(); + } else { + return (String) null; + } + }).filter(Objects::nonNull).toList(); + + if (launcherModules.isEmpty() && addModules.isEmpty()) { + addModules = Set.of(ALL_DEFAULT); + } + + var modules = createModuleList(modulePath, addModules, limitModules); + + modules.addAll(launcherModules); + + var args = new ArrayList(); + if (!modulePath.isEmpty()) { + args.add("--module-path"); + args.add(getPathList(modulePath)); + } + if (!modules.isEmpty()) { + args.add("--add-modules"); + args.add(getStringList(modules)); + } + if (!limitModules.isEmpty()) { + args.add("--limit-modules"); + args.add(getStringList(limitModules)); + } + + for (String option : options) { + switch (option) { + case "--output", "--add-modules", "--module-path" -> { + throw new ConfigException(MessageFormat.format(I18N.getString( + "error.blocked.option"), option), null); + } + default -> { + args.add(option); + } + } + } + + return args; + } + + /* + * Returns the set of modules that would be visible by default for + * a non-modular-aware application consisting of the given elements. + */ + private static Set getDefaultModules( + Collection paths, Collection addModules) { + + // the modules in the run-time image that export an API + Stream systemRoots = ModuleFinder.ofSystem().findAll().stream() + .map(ModuleReference::descriptor) + .filter(JLinkRuntimeBuilder::exportsAPI) + .map(ModuleDescriptor::name); + + Set roots = Stream.concat(systemRoots, + addModules.stream()).collect(Collectors.toSet()); + + ModuleFinder finder = createModuleFinder(paths); + + return Configuration.empty() + .resolveAndBind(finder, ModuleFinder.of(), roots) + .modules() + .stream() + .map(ResolvedModule::name) + .collect(Collectors.toSet()); + } + + /* + * Returns true if the given module exports an API to all module. + */ + private static boolean exportsAPI(ModuleDescriptor descriptor) { + return descriptor.exports() + .stream() + .anyMatch(e -> !e.isQualified()); + } + + private static Set createModuleList(List paths, + Set addModules, Set limitModules) { + + final Set modules = new HashSet<>(); + + final Map>> phonyModules = Map.of( + ALL_MODULE_PATH, + () -> createModuleFinder(paths) + .findAll() + .stream() + .map(ModuleReference::descriptor) + .map(ModuleDescriptor::name) + .collect(Collectors.toSet()), + ALL_DEFAULT, + () -> getDefaultModules(paths, modules)); + + Supplier> phonyModule = null; + for (var module : addModules) { + phonyModule = phonyModules.get(module); + if (phonyModule == null) { + modules.add(module); + } + } + + if (phonyModule != null) { + modules.addAll(phonyModule.get()); + } + + return modules; + } + + private static String getPathList(List pathList) { + return pathList.stream() + .map(Path::toString) + .collect(Collectors.joining(File.pathSeparator)); + } + + private static String getStringList(Set strings) { + return strings.stream().collect(Collectors.joining(",")); + } + + private final List jlinkCmdLine; + + // The token for "all modules on the module path". + private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; + + // The token for "all valid runtime modules". + private static final String ALL_DEFAULT = "ALL-DEFAULT"; + + private static class LazyLoad { + + static final ToolProvider JLINK_TOOL = ToolProvider.findFirst( + "jlink").orElseThrow(); + }; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java index 7044f0e4350f9..01b3a9a9b6690 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java @@ -141,7 +141,7 @@ private static LauncherData createModular(String mainModule, launcherData.modulePath = getModulePath(params); // Try to find module in the specified module path list. - ModuleReference moduleRef = RuntimeBuilder.createModuleFinder( + ModuleReference moduleRef = JLinkRuntimeBuilder.createModuleFinder( launcherData.modulePath).find(moduleName).orElse(null); if (moduleRef != null) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index 069ca88e8b5c6..25836beaab08e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -26,6 +26,7 @@ import java.nio.file.Path; import java.text.MessageFormat; +import java.util.Optional; import java.util.stream.Stream; interface Package { @@ -111,13 +112,9 @@ default Path packageFileName() { return Path .of(String.format("%s-%s%s", packageName(), version(), type.suffix())); } - default -> { - throw new UnsupportedOperationException(); - } } - } else { - throw new UnsupportedOperationException(); } + throw new UnsupportedOperationException(); } default boolean isRuntimeInstaller() { @@ -133,7 +130,11 @@ default boolean isRuntimeInstaller() { static record Impl(Application app, PackageType type, String packageName, String description, String version, String aboutURL, Path licenseFile, Path predefinedAppImage, Path relativeInstallDir) implements Package { - + public Impl { + packageName = Optional.ofNullable(packageName).orElseGet(app::name); + description = Optional.ofNullable(description).orElseGet(app::description); + version = Optional.ofNullable(version).orElseGet(app::version); + } } static class Proxy extends ProxyBase implements Package { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java index 0df250487bd65..f1b2899b322e0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java @@ -45,7 +45,7 @@ final class PackageFromParams { static Package create(Map params, - StandardBundlerParam appParam, PackageType pkgType) throws ConfigException { + BundlerParamInfo appParam, PackageType pkgType) throws ConfigException { var app = appParam.fetchFrom(params); var packageName = Optional.ofNullable(INSTALLER_NAME.fetchFrom(params)).orElseGet(app::name); var description = Optional.ofNullable(DESCRIPTION.fetchFrom(params)).orElseGet(app::name); @@ -71,12 +71,12 @@ static Package create(Map params, predefinedAppImage, relativeInstallDir); } - static StandardBundlerParam createBundlerParam( + static BundlerParamInfo createBundlerParam( ThrowingFunction, T> valueFunc) { - return StandardBundlerParam.createBundlerParam("target.package", valueFunc); + return BundlerParamInfo.createBundlerParam("target.package", valueFunc); } - static final StandardBundlerParam PACKAGE = createBundlerParam(params -> { + static final BundlerParamInfo PACKAGE = createBundlerParam(params -> { return PackageFromParams.create(params, ApplicationFromParams.APPLICATION, StandardPackageType.fromCmdLineType(WorkshopFromParams.PACKAGE_TYPE .fetchFrom(params))); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilder.java index cdadccdb9d64b..01138b679614c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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,217 +24,61 @@ */ package jdk.jpackage.internal; -import java.io.File; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.module.Configuration; -import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleFinder; -import java.lang.module.ModuleReference; -import java.lang.module.ResolvedModule; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.LinkOption; import java.nio.file.Path; import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; +import java.util.Arrays; import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.function.Supplier; -import java.util.jar.JarFile; -import java.util.spi.ToolProvider; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import jdk.internal.module.ModulePath; -import static jdk.jpackage.internal.StandardBundlerParam.ADD_MODULES; -import static jdk.jpackage.internal.StandardBundlerParam.JLINK_OPTIONS; -import static jdk.jpackage.internal.StandardBundlerParam.LIMIT_MODULES; -import static jdk.jpackage.internal.StandardBundlerParam.MODULE_PATH; +import jdk.internal.util.OperatingSystem; -final class RuntimeBuilder { +interface RuntimeBuilder { - private RuntimeBuilder(List jlinkCmdLine) { - this.jlinkCmdLine = jlinkCmdLine; - } - - void execute(Path outputDir) throws PackagerException { - var args = new ArrayList(); - args.add("--output"); - args.add(outputDir.toString()); - args.addAll(jlinkCmdLine); - - StringWriter writer = new StringWriter(); - PrintWriter pw = new PrintWriter(writer); + void createRuntime(ApplicationLayout appLayout) throws PackagerException, IOException; - int retVal = LazyLoad.JLINK_TOOL.run(pw, pw, args.toArray(String[]::new)); - String jlinkOut = writer.toString(); - - args.add(0, "jlink"); - Log.verbose(args, List.of(jlinkOut), retVal, -1); - if (retVal != 0) { - throw new PackagerException("error.jlink.failed", jlinkOut); + static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, Path... modulePath) throws ConfigException { + if (!Files.exists(runtimeDir)) { + throw new ConfigException(MessageFormat.format(I18N.getString( + "message.runtime-image-dir-does-not-exist"), "--runtime-image", runtimeDir + .toString()), MessageFormat.format(I18N.getString( + "message.runtime-image-dir-does-not-exist.advice"), "--runtime-image")); } - } - static ModuleFinder createModuleFinder(Collection modulePath) { - return ModuleFinder.compose( - ModulePath.of(JarFile.runtimeVersion(), true, - modulePath.toArray(Path[]::new)), - ModuleFinder.ofSystem()); - } + return appLayout -> { + final Path runtimeHome = getRuntimeHome(runtimeDir); - static RuntimeBuilder createFromParams(Map params, - List startupInfos) throws ConfigException { - List modulePath = Optional.ofNullable(MODULE_PATH.fetchFrom(params)).orElseGet( - Collections::emptyList); - Set addModules = Optional.ofNullable(ADD_MODULES.fetchFrom(params)).orElseGet( - Collections::emptySet); - Set limitModules = Optional.ofNullable(LIMIT_MODULES.fetchFrom(params)).orElseGet( - Collections::emptySet); - List options = Optional.ofNullable(JLINK_OPTIONS.fetchFrom(params)).orElseGet( - Collections::emptyList); + // copy whole runtime, need to skip jmods and src.zip + final List excludes = Arrays.asList("jmods", "src.zip"); + IOUtils.copyRecursive(runtimeHome, appLayout.runtimeHomeDirectory(), excludes, + LinkOption.NOFOLLOW_LINKS); - return new RuntimeBuilder(createJLinkCmdline(modulePath, addModules, limitModules, options, - startupInfos)); - } - - private static List createJLinkCmdline(List modulePath, Set addModules, - Set limitModules, List options, List startupInfos) throws ConfigException { - List launcherModules = startupInfos.stream().map(si -> { - if (si instanceof LauncherModularStartupInfo siModular) { - return siModular.moduleName(); - } else { - return (String) null; - } - }).filter(Objects::nonNull).toList(); - - if (launcherModules.isEmpty() && addModules.isEmpty()) { - addModules = Set.of(ALL_DEFAULT); - } + // if module-path given - copy modules to appDir/mods + List defaultModulePath = getDefaultModulePath(); + Path dest = appLayout.appModsDirectory(); - var modules = createModuleList(modulePath, addModules, limitModules); - - modules.addAll(launcherModules); - - var args = new ArrayList(); - if (!modulePath.isEmpty()) { - args.add("--module-path"); - args.add(getPathList(modulePath)); - } - if (!modules.isEmpty()) { - args.add("--add-modules"); - args.add(getStringList(modules)); - } - if (!limitModules.isEmpty()) { - args.add("--limit-modules"); - args.add(getStringList(limitModules)); - } - - for (String option : options) { - switch (option) { - case "--output", "--add-modules", "--module-path" -> { - throw new ConfigException(MessageFormat.format(I18N.getString( - "error.blocked.option"), option), null); - } - default -> { - args.add(option); + for (Path mp : modulePath) { + if (!defaultModulePath.contains(mp)) { + IOUtils.copyRecursive(mp, dest); } } - } - - return args; + }; } - /* - * Returns the set of modules that would be visible by default for - * a non-modular-aware application consisting of the given elements. - */ - private static Set getDefaultModules( - Collection paths, Collection addModules) { - - // the modules in the run-time image that export an API - Stream systemRoots = ModuleFinder.ofSystem().findAll().stream() - .map(ModuleReference::descriptor) - .filter(RuntimeBuilder::exportsAPI) - .map(ModuleDescriptor::name); - - Set roots = Stream.concat(systemRoots, - addModules.stream()).collect(Collectors.toSet()); - - ModuleFinder finder = createModuleFinder(paths); - - return Configuration.empty() - .resolveAndBind(finder, ModuleFinder.of(), roots) - .modules() - .stream() - .map(ResolvedModule::name) - .collect(Collectors.toSet()); - } - - /* - * Returns true if the given module exports an API to all module. - */ - private static boolean exportsAPI(ModuleDescriptor descriptor) { - return descriptor.exports() - .stream() - .anyMatch(e -> !e.isQualified()); - } - - private static Set createModuleList(List paths, - Set addModules, Set limitModules) { - - final Set modules = new HashSet<>(); - - final Map>> phonyModules = Map.of( - ALL_MODULE_PATH, - () -> createModuleFinder(paths) - .findAll() - .stream() - .map(ModuleReference::descriptor) - .map(ModuleDescriptor::name) - .collect(Collectors.toSet()), - ALL_DEFAULT, - () -> getDefaultModules(paths, modules)); - - Supplier> phonyModule = null; - for (var module : addModules) { - phonyModule = phonyModules.get(module); - if (phonyModule == null) { - modules.add(module); + private static Path getRuntimeHome(Path runtimeDir) { + if (OperatingSystem.isMacOS()) { + // On Mac topImage can be runtime root or runtime home. + Path runtimeHome = runtimeDir.resolve("Contents/Home"); + if (Files.isDirectory(runtimeHome)) { + // topImage references runtime root, adjust it to pick data from + // runtime home + return runtimeHome; } } - - if (phonyModule != null) { - modules.addAll(phonyModule.get()); - } - - return modules; - } - - private static String getPathList(List pathList) { - return pathList.stream() - .map(Path::toString) - .collect(Collectors.joining(File.pathSeparator)); + return runtimeDir; } - private static String getStringList(Set strings) { - return strings.stream().collect(Collectors.joining(",")); + static List getDefaultModulePath() { + return List.of(Path.of(System.getProperty("java.home"), "jmods").toAbsolutePath()); } - - private final List jlinkCmdLine; - - // The token for "all modules on the module path". - private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; - - // The token for "all valid runtime modules". - private static final String ALL_DEFAULT = "ALL-DEFAULT"; - - private static class LazyLoad { - - static final ToolProvider JLINK_TOOL = ToolProvider.findFirst( - "jlink").orElseThrow(); - }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderFromParams.java new file mode 100644 index 0000000000000..ac364d069fb29 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderFromParams.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import static jdk.jpackage.internal.StandardBundlerParam.ADD_MODULES; +import static jdk.jpackage.internal.StandardBundlerParam.JLINK_OPTIONS; +import static jdk.jpackage.internal.StandardBundlerParam.LIMIT_MODULES; +import static jdk.jpackage.internal.StandardBundlerParam.MODULE_PATH; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; + +final class RuntimeBuilderFromParams { + + static RuntimeBuilder create(Map params, + List startupInfos) throws ConfigException { + List modulePath = Optional.ofNullable(MODULE_PATH.fetchFrom(params)).orElseGet( + List::of); + + Path predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); + if (predefinedRuntimeImage != null) { + return RuntimeBuilder.createCopyingRuntimeBuilder(predefinedRuntimeImage, modulePath + .toArray(Path[]::new)); + } else { + Set addModules = Optional.ofNullable(ADD_MODULES.fetchFrom(params)).orElseGet( + Set::of); + Set limitModules = Optional.ofNullable(LIMIT_MODULES.fetchFrom(params)) + .orElseGet(Set::of); + List options = Optional.ofNullable(JLINK_OPTIONS.fetchFrom(params)).orElseGet( + List::of); + return JLinkRuntimeBuilder.createJLinkRuntimeBuilder(modulePath, addModules, + limitModules, options, startupInfos); + + } + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index cf36bb0d26dc8..d82c4dcdfdc09 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -25,12 +25,10 @@ package jdk.jpackage.internal; -import jdk.internal.util.OperatingSystem; import java.io.File; import java.io.IOException; import java.nio.file.Files; -import java.nio.file.LinkOption; import java.nio.file.Path; import java.text.MessageFormat; import java.util.ArrayList; @@ -41,25 +39,19 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.BiFunction; -import java.util.function.Function; import java.util.stream.Stream; -import jdk.jpackage.internal.Functional.ThrowingFunction; -import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; -import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; +import static jdk.jpackage.internal.RuntimeBuilder.getDefaultModulePath; /** - * StandardBundlerParam + * Standard bundler parameters. * - * A parameter to a bundler. - * - * Also contains static definitions of all of the common bundler parameters. + * Contains static definitions of all of the common bundler parameters. * (additional platform specific and mode specific bundler parameters * are defined in each of the specific bundlers) * * Also contains static methods that operate on maps of parameters. */ -class StandardBundlerParam extends BundlerParamInfo { +final class StandardBundlerParam { private static final String JAVABASEJMOD = "java.base.jmod"; private static final String DEFAULT_VERSION = "1.0"; @@ -70,18 +62,8 @@ class StandardBundlerParam extends BundlerParamInfo { "--no-man-pages", "--no-header-files"}; - StandardBundlerParam(String id, Class valueType, - Function, T> defaultValueFunction, - BiFunction, T> stringConverter) - { - this.id = id; - this.valueType = valueType; - this.defaultValueFunction = defaultValueFunction; - this.stringConverter = stringConverter; - } - - static final StandardBundlerParam LAUNCHER_DATA = - new StandardBundlerParam<>( + static final BundlerParamInfo LAUNCHER_DATA = + new BundlerParamInfo<>( "launcherData", LauncherData.class, params -> { @@ -94,8 +76,8 @@ class StandardBundlerParam extends BundlerParamInfo { null ); - static final StandardBundlerParam SOURCE_DIR = - new StandardBundlerParam<>( + static final BundlerParamInfo SOURCE_DIR = + new BundlerParamInfo<>( Arguments.CLIOptions.INPUT.getId(), Path.class, p -> null, @@ -104,16 +86,16 @@ class StandardBundlerParam extends BundlerParamInfo { // note that each bundler is likely to replace this one with // their own converter - static final StandardBundlerParam MAIN_JAR = - new StandardBundlerParam<>( + static final BundlerParamInfo MAIN_JAR = + new BundlerParamInfo<>( Arguments.CLIOptions.MAIN_JAR.getId(), Path.class, params -> LAUNCHER_DATA.fetchFrom(params).mainJarName(), null ); - static final StandardBundlerParam MAIN_CLASS = - new StandardBundlerParam<>( + static final BundlerParamInfo MAIN_CLASS = + new BundlerParamInfo<>( Arguments.CLIOptions.APPCLASS.getId(), String.class, params -> { @@ -128,24 +110,24 @@ class StandardBundlerParam extends BundlerParamInfo { (s, p) -> s ); - static final StandardBundlerParam PREDEFINED_RUNTIME_IMAGE = - new StandardBundlerParam<>( + static final BundlerParamInfo PREDEFINED_RUNTIME_IMAGE = + new BundlerParamInfo<>( Arguments.CLIOptions.PREDEFINED_RUNTIME_IMAGE.getId(), Path.class, params -> null, (s, p) -> Path.of(s) ); - static final StandardBundlerParam PREDEFINED_APP_IMAGE = - new StandardBundlerParam<>( + static final BundlerParamInfo PREDEFINED_APP_IMAGE = + new BundlerParamInfo<>( Arguments.CLIOptions.PREDEFINED_APP_IMAGE.getId(), Path.class, params -> null, (s, p) -> Path.of(s)); // this is the raw --app-name arg - used in APP_NAME and INSTALLER_NAME - static final StandardBundlerParam NAME = - new StandardBundlerParam<>( + static final BundlerParamInfo NAME = + new BundlerParamInfo<>( Arguments.CLIOptions.NAME.getId(), String.class, params -> null, @@ -154,8 +136,8 @@ class StandardBundlerParam extends BundlerParamInfo { // this is the application name, either from the app-image (if given), // the name (if given) derived from the main-class, or the runtime image - static final StandardBundlerParam APP_NAME = - new StandardBundlerParam<>( + static final BundlerParamInfo APP_NAME = + new BundlerParamInfo<>( "application-name", String.class, params -> { @@ -181,8 +163,8 @@ class StandardBundlerParam extends BundlerParamInfo { (s, p) -> s ); - static final StandardBundlerParam INSTALLER_NAME = - new StandardBundlerParam<>( + static final BundlerParamInfo INSTALLER_NAME = + new BundlerParamInfo<>( "installer-name", String.class, params -> { @@ -193,32 +175,32 @@ class StandardBundlerParam extends BundlerParamInfo { (s, p) -> s ); - static final StandardBundlerParam ICON = - new StandardBundlerParam<>( + static final BundlerParamInfo ICON = + new BundlerParamInfo<>( Arguments.CLIOptions.ICON.getId(), Path.class, params -> null, (s, p) -> Path.of(s) ); - static final StandardBundlerParam ABOUT_URL = - new StandardBundlerParam<>( + static final BundlerParamInfo ABOUT_URL = + new BundlerParamInfo<>( Arguments.CLIOptions.ABOUT_URL.getId(), String.class, params -> null, (s, p) -> s ); - static final StandardBundlerParam VENDOR = - new StandardBundlerParam<>( + static final BundlerParamInfo VENDOR = + new BundlerParamInfo<>( Arguments.CLIOptions.VENDOR.getId(), String.class, params -> I18N.getString("param.vendor.default"), (s, p) -> s ); - static final StandardBundlerParam DESCRIPTION = - new StandardBundlerParam<>( + static final BundlerParamInfo DESCRIPTION = + new BundlerParamInfo<>( Arguments.CLIOptions.DESCRIPTION.getId(), String.class, params -> params.containsKey(APP_NAME.getID()) @@ -227,8 +209,8 @@ class StandardBundlerParam extends BundlerParamInfo { (s, p) -> s ); - static final StandardBundlerParam COPYRIGHT = - new StandardBundlerParam<>( + static final BundlerParamInfo COPYRIGHT = + new BundlerParamInfo<>( Arguments.CLIOptions.COPYRIGHT.getId(), String.class, params -> MessageFormat.format(I18N.getString( @@ -237,8 +219,8 @@ class StandardBundlerParam extends BundlerParamInfo { ); @SuppressWarnings("unchecked") - static final StandardBundlerParam> ARGUMENTS = - new StandardBundlerParam<>( + static final BundlerParamInfo> ARGUMENTS = + new BundlerParamInfo<>( Arguments.CLIOptions.ARGUMENTS.getId(), (Class>) (Object) List.class, params -> Collections.emptyList(), @@ -246,24 +228,24 @@ class StandardBundlerParam extends BundlerParamInfo { ); @SuppressWarnings("unchecked") - static final StandardBundlerParam> JAVA_OPTIONS = - new StandardBundlerParam<>( + static final BundlerParamInfo> JAVA_OPTIONS = + new BundlerParamInfo<>( Arguments.CLIOptions.JAVA_OPTIONS.getId(), (Class>) (Object) List.class, params -> Collections.emptyList(), (s, p) -> Arrays.asList(s.split("\n\n")) ); - static final StandardBundlerParam VERSION = - new StandardBundlerParam<>( + static final BundlerParamInfo VERSION = + new BundlerParamInfo<>( Arguments.CLIOptions.VERSION.getId(), String.class, StandardBundlerParam::getDefaultAppVersion, (s, p) -> s ); - static final StandardBundlerParam RELEASE = - new StandardBundlerParam<>( + static final BundlerParamInfo RELEASE = + new BundlerParamInfo<>( Arguments.CLIOptions.RELEASE.getId(), String.class, params -> DEFAULT_RELEASE, @@ -271,16 +253,16 @@ class StandardBundlerParam extends BundlerParamInfo { ); @SuppressWarnings("unchecked") - public static final StandardBundlerParam LICENSE_FILE = - new StandardBundlerParam<>( + public static final BundlerParamInfo LICENSE_FILE = + new BundlerParamInfo<>( Arguments.CLIOptions.LICENSE_FILE.getId(), String.class, params -> null, (s, p) -> s ); - static final StandardBundlerParam TEMP_ROOT = - new StandardBundlerParam<>( + static final BundlerParamInfo TEMP_ROOT = + new BundlerParamInfo<>( Arguments.CLIOptions.TEMP_ROOT.getId(), Path.class, params -> { @@ -293,8 +275,8 @@ class StandardBundlerParam extends BundlerParamInfo { (s, p) -> Path.of(s) ); - public static final StandardBundlerParam CONFIG_ROOT = - new StandardBundlerParam<>( + public static final BundlerParamInfo CONFIG_ROOT = + new BundlerParamInfo<>( "configRoot", Path.class, params -> { @@ -309,8 +291,8 @@ class StandardBundlerParam extends BundlerParamInfo { (s, p) -> null ); - static final StandardBundlerParam VERBOSE = - new StandardBundlerParam<>( + static final BundlerParamInfo VERBOSE = + new BundlerParamInfo<>( Arguments.CLIOptions.VERBOSE.getId(), Boolean.class, params -> false, @@ -319,8 +301,8 @@ class StandardBundlerParam extends BundlerParamInfo { true : Boolean.valueOf(s) ); - static final StandardBundlerParam SHORTCUT_HINT = - new StandardBundlerParam<>( + static final BundlerParamInfo SHORTCUT_HINT = + new BundlerParamInfo<>( "shortcut-hint", // not directly related to a CLI option Boolean.class, params -> true, // defaults to true @@ -328,8 +310,8 @@ class StandardBundlerParam extends BundlerParamInfo { true : Boolean.valueOf(s) ); - static final StandardBundlerParam MENU_HINT = - new StandardBundlerParam<>( + static final BundlerParamInfo MENU_HINT = + new BundlerParamInfo<>( "menu-hint", // not directly related to a CLI option Boolean.class, params -> true, // defaults to true @@ -337,8 +319,8 @@ class StandardBundlerParam extends BundlerParamInfo { true : Boolean.valueOf(s) ); - static final StandardBundlerParam RESOURCE_DIR = - new StandardBundlerParam<>( + static final BundlerParamInfo RESOURCE_DIR = + new BundlerParamInfo<>( Arguments.CLIOptions.RESOURCE_DIR.getId(), Path.class, params -> null, @@ -346,15 +328,15 @@ class StandardBundlerParam extends BundlerParamInfo { ); static final BundlerParamInfo INSTALL_DIR = - new StandardBundlerParam<>( + new BundlerParamInfo<>( Arguments.CLIOptions.INSTALL_DIR.getId(), String.class, params -> null, (s, p) -> s ); - static final StandardBundlerParam LAUNCHER_AS_SERVICE = - new StandardBundlerParam<>( + static final BundlerParamInfo LAUNCHER_AS_SERVICE = + new BundlerParamInfo<>( Arguments.CLIOptions.LAUNCHER_AS_SERVICE.getId(), Boolean.class, params -> false, @@ -365,8 +347,8 @@ class StandardBundlerParam extends BundlerParamInfo { @SuppressWarnings("unchecked") - static final StandardBundlerParam>> ADD_LAUNCHERS = - new StandardBundlerParam<>( + static final BundlerParamInfo>> ADD_LAUNCHERS = + new BundlerParamInfo<>( Arguments.CLIOptions.ADD_LAUNCHER.getId(), (Class>>) (Object) List.class, @@ -376,9 +358,9 @@ class StandardBundlerParam extends BundlerParamInfo { ); @SuppressWarnings("unchecked") - static final StandardBundlerParam + static final BundlerParamInfo >> FILE_ASSOCIATIONS = - new StandardBundlerParam<>( + new BundlerParamInfo<>( Arguments.CLIOptions.FILE_ASSOCIATIONS.getId(), (Class>>) (Object) List.class, @@ -388,8 +370,8 @@ class StandardBundlerParam extends BundlerParamInfo { ); @SuppressWarnings("unchecked") - static final StandardBundlerParam> FA_EXTENSIONS = - new StandardBundlerParam<>( + static final BundlerParamInfo> FA_EXTENSIONS = + new BundlerParamInfo<>( "fileAssociation.extension", (Class>) (Object) List.class, params -> null, // null means not matched to an extension @@ -397,8 +379,8 @@ class StandardBundlerParam extends BundlerParamInfo { ); @SuppressWarnings("unchecked") - static final StandardBundlerParam> FA_CONTENT_TYPE = - new StandardBundlerParam<>( + static final BundlerParamInfo> FA_CONTENT_TYPE = + new BundlerParamInfo<>( "fileAssociation.contentType", (Class>) (Object) List.class, params -> null, @@ -406,16 +388,16 @@ class StandardBundlerParam extends BundlerParamInfo { (s, p) -> Arrays.asList(s.split("(,|\\s)+")) ); - static final StandardBundlerParam FA_DESCRIPTION = - new StandardBundlerParam<>( + static final BundlerParamInfo FA_DESCRIPTION = + new BundlerParamInfo<>( "fileAssociation.description", String.class, p -> null, (s, p) -> s ); - static final StandardBundlerParam FA_ICON = - new StandardBundlerParam<>( + static final BundlerParamInfo FA_ICON = + new BundlerParamInfo<>( "fileAssociation.icon", Path.class, ICON::fetchFrom, @@ -424,7 +406,7 @@ class StandardBundlerParam extends BundlerParamInfo { @SuppressWarnings("unchecked") static final BundlerParamInfo> DMG_CONTENT = - new StandardBundlerParam<>( + new BundlerParamInfo<>( Arguments.CLIOptions.DMG_CONTENT.getId(), (Class>) (Object)List.class, p -> Collections.emptyList(), @@ -432,8 +414,8 @@ class StandardBundlerParam extends BundlerParamInfo { ); @SuppressWarnings("unchecked") - static final StandardBundlerParam> APP_CONTENT = - new StandardBundlerParam<>( + static final BundlerParamInfo> APP_CONTENT = + new BundlerParamInfo<>( Arguments.CLIOptions.APP_CONTENT.getId(), (Class>) (Object)List.class, p->Collections.emptyList(), @@ -442,7 +424,7 @@ class StandardBundlerParam extends BundlerParamInfo { @SuppressWarnings("unchecked") static final BundlerParamInfo> MODULE_PATH = - new StandardBundlerParam<>( + new BundlerParamInfo<>( Arguments.CLIOptions.MODULE_PATH.getId(), (Class>) (Object)List.class, p -> getDefaultModulePath(), @@ -487,7 +469,7 @@ private static Path findPathOfModule( List modulePath, String moduleName) } static final BundlerParamInfo MODULE = - new StandardBundlerParam<>( + new BundlerParamInfo<>( Arguments.CLIOptions.MODULE.getId(), String.class, p -> null, @@ -497,7 +479,7 @@ private static Path findPathOfModule( List modulePath, String moduleName) @SuppressWarnings("unchecked") static final BundlerParamInfo> ADD_MODULES = - new StandardBundlerParam<>( + new BundlerParamInfo<>( Arguments.CLIOptions.ADD_MODULES.getId(), (Class>) (Object) Set.class, p -> new LinkedHashSet(), @@ -505,8 +487,8 @@ private static Path findPathOfModule( List modulePath, String moduleName) ); @SuppressWarnings("unchecked") - static final StandardBundlerParam> JLINK_OPTIONS = - new StandardBundlerParam<>( + static final BundlerParamInfo> JLINK_OPTIONS = + new BundlerParamInfo<>( Arguments.CLIOptions.JLINK_OPTIONS.getId(), (Class>) (Object) List.class, p -> Arrays.asList(DEFAULT_JLINK_OPTIONS), @@ -514,15 +496,15 @@ private static Path findPathOfModule( List modulePath, String moduleName) @SuppressWarnings("unchecked") static final BundlerParamInfo> LIMIT_MODULES = - new StandardBundlerParam<>( + new BundlerParamInfo<>( "limit-modules", (Class>) (Object) Set.class, p -> new LinkedHashSet(), (s, p) -> new LinkedHashSet<>(Arrays.asList(s.split(","))) ); - static final StandardBundlerParam SIGN_BUNDLE = - new StandardBundlerParam<>( + static final BundlerParamInfo SIGN_BUNDLE = + new BundlerParamInfo<>( Arguments.CLIOptions.MAC_SIGN.getId(), Boolean.class, params -> false, @@ -530,8 +512,8 @@ private static Path findPathOfModule( List modulePath, String moduleName) null : Boolean.valueOf(s) ); - static final StandardBundlerParam APP_STORE = - new StandardBundlerParam<>( + static final BundlerParamInfo APP_STORE = + new BundlerParamInfo<>( Arguments.CLIOptions.MAC_APP_STORE.getId(), Boolean.class, params -> { @@ -573,61 +555,6 @@ static Path getPredefinedAppImage(Map params) { return applicationImage; } - static void copyPredefinedRuntimeImage(Map params, - ApplicationLayout appLayout) throws IOException, ConfigException { - Path topImage = PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); - if (!IOUtils.exists(topImage)) { - throw new ConfigException( - MessageFormat.format(I18N.getString( - "message.runtime-image-dir-does-not-exist"), - PREDEFINED_RUNTIME_IMAGE.getID(), - topImage.toString()), - MessageFormat.format(I18N.getString( - "message.runtime-image-dir-does-not-exist.advice"), - PREDEFINED_RUNTIME_IMAGE.getID())); - } - - if (OperatingSystem.isMacOS()) { - // On Mac topImage can be runtime root or runtime home. - Path runtimeHome = topImage.resolve("Contents/Home"); - if (Files.isDirectory(runtimeHome)) { - // topImage references runtime root, adjust it to pick data from - // runtime home - topImage = runtimeHome; - } - } - - // copy whole runtime, need to skip jmods and src.zip - final List excludes = Arrays.asList("jmods", "src.zip"); - IOUtils.copyRecursive(topImage, appLayout.runtimeHomeDirectory(), - excludes, LinkOption.NOFOLLOW_LINKS); - - // if module-path given - copy modules to appDir/mods - List modulePath = MODULE_PATH.fetchFrom(params); - List defaultModulePath = getDefaultModulePath(); - Path dest = appLayout.appModsDirectory(); - - if (dest != null) { - for (Path mp : modulePath) { - if (!defaultModulePath.contains(mp)) { - Files.createDirectories(dest); - IOUtils.copyRecursive(mp, dest); - } - } - } - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - static StandardBundlerParam createBundlerParam(String id, - ThrowingFunction, T2> valueFunc) { - return new StandardBundlerParam(id, Object.class, toFunction(valueFunc), null); - } - - private static List getDefaultModulePath() { - return List.of( - Path.of(System.getProperty("java.home"), "jmods").toAbsolutePath()); - } - private static String getDefaultAppVersion(Map params) { String appVersion = DEFAULT_VERSION; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java index 23a985fd3ef0a..5255dec98c78b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java @@ -27,6 +27,7 @@ import java.nio.file.Path; import java.util.Map; import jdk.internal.util.OperatingSystem; +import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import jdk.jpackage.internal.Workshop.Impl; import jdk.jpackage.internal.Workshop.Proxy; @@ -62,9 +63,9 @@ public Path appImageDir() { }; } - static final StandardBundlerParam WORKSHOP = StandardBundlerParam.createBundlerParam( + static final BundlerParamInfo WORKSHOP = BundlerParamInfo.createBundlerParam( "workshop", WorkshopFromParams::create); - static final StandardBundlerParam PACKAGE_TYPE = new StandardBundlerParam<>( - Arguments.CLIOptions.PACKAGE_TYPE.getId(), String.class, null, null); + static final BundlerParamInfo PACKAGE_TYPE = createStringBundlerParam( + Arguments.CLIOptions.PACKAGE_TYPE.getId()); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java index ca98f399d84fe..0ed602a7f3f49 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java @@ -59,10 +59,10 @@ private static WinApplication create(Map params) throws return new WinApplication.Impl(app); } - static final StandardBundlerParam APPLICATION = createBundlerParam( + static final BundlerParamInfo APPLICATION = createBundlerParam( WinApplicationFromParams::create); - private static final StandardBundlerParam WIN_MENU_HINT = new StandardBundlerParam<>( + private static final BundlerParamInfo WIN_MENU_HINT = new BundlerParamInfo<>( Arguments.CLIOptions.WIN_MENU_HINT.getId(), Boolean.class, p -> false, @@ -70,7 +70,7 @@ private static WinApplication create(Map params) throws // and we actually do want null in some cases (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); - private static final StandardBundlerParam WIN_SHORTCUT_HINT = new StandardBundlerParam<>( + private static final BundlerParamInfo WIN_SHORTCUT_HINT = new BundlerParamInfo<>( Arguments.CLIOptions.WIN_SHORTCUT_HINT.getId(), Boolean.class, p -> false, diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java index c8aae5922873a..69d15bd8d7047 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ public class WinExeBundler extends AbstractBundler { } public static final BundlerParamInfo EXE_IMAGE_DIR - = new StandardBundlerParam<>( + = new BundlerParamInfo<>( "win.exe.imageDir", Path.class, params -> { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 82244a37e3565..6adf6c6e0727e 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -35,7 +35,6 @@ import java.nio.file.PathMatcher; import java.text.MessageFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; @@ -52,7 +51,6 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.WixToolset.WixToolsetType; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java index 529f3a4ead25f..b773918dec827 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.Optional; import java.util.UUID; +import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import static jdk.jpackage.internal.Package.StandardPackageType.WinMsi; import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; @@ -68,31 +69,31 @@ private static UUID getUpgradeCode(Map params) throws Co } } - static final StandardBundlerParam PACKAGE = createBundlerParam( + static final BundlerParamInfo PACKAGE = createBundlerParam( WinMsiPackageFromParams::create); - private static final BundlerParamInfo INSTALLDIR_CHOOSER = new StandardBundlerParam<>( + private static final BundlerParamInfo INSTALLDIR_CHOOSER = new BundlerParamInfo<>( Arguments.CLIOptions.WIN_DIR_CHOOSER.getId(), Boolean.class, params -> false, (s, p) -> Boolean.valueOf(s) ); - private static final StandardBundlerParam SHORTCUT_PROMPT = new StandardBundlerParam<>( + private static final BundlerParamInfo SHORTCUT_PROMPT = new BundlerParamInfo<>( Arguments.CLIOptions.WIN_SHORTCUT_PROMPT.getId(), Boolean.class, params -> false, (s, p) -> Boolean.valueOf(s) ); - private static final StandardBundlerParam MENU_GROUP = new StandardBundlerParam<>( + private static final BundlerParamInfo MENU_GROUP = new BundlerParamInfo<>( Arguments.CLIOptions.WIN_MENU_GROUP.getId(), String.class, params -> I18N.getString("param.menu-group.default"), (s, p) -> s ); - private static final StandardBundlerParam MSI_SYSTEM_WIDE = new StandardBundlerParam<>( + private static final BundlerParamInfo MSI_SYSTEM_WIDE = new BundlerParamInfo<>( Arguments.CLIOptions.WIN_PER_USER_INSTALLATION.getId(), Boolean.class, params -> true, // MSIs default to system wide @@ -102,21 +103,12 @@ private static UUID getUpgradeCode(Map params) throws Co : Boolean.valueOf(s) ); - private static final BundlerParamInfo HELP_URL = new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_HELP_URL.getId(), - String.class, - null, - (s, p) -> s); + private static final BundlerParamInfo HELP_URL = createStringBundlerParam( + Arguments.CLIOptions.WIN_HELP_URL.getId()); - private static final BundlerParamInfo UPDATE_URL = new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_UPDATE_URL.getId(), - String.class, - null, - (s, p) -> s); + private static final BundlerParamInfo UPDATE_URL = createStringBundlerParam( + Arguments.CLIOptions.WIN_UPDATE_URL.getId()); - private static final BundlerParamInfo UPGRADE_UUID = new StandardBundlerParam<>( - Arguments.CLIOptions.WIN_UPGRADE_UUID.getId(), - String.class, - null, - (s, p) -> s); + private static final BundlerParamInfo UPGRADE_UUID = createStringBundlerParam( + Arguments.CLIOptions.WIN_UPGRADE_UUID.getId()); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsAppImageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsAppImageBuilder.java index 9a9a70065502a..0ed3650fbc299 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsAppImageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsAppImageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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 @@ -45,7 +45,7 @@ public class WindowsAppImageBuilder extends AbstractAppImageBuilder { private static final String TEMPLATE_APP_ICON ="JavaApp.ico"; public static final BundlerParamInfo ICON_ICO = - new StandardBundlerParam<>( + new BundlerParamInfo<>( "icon.ico", Path.class, params -> { @@ -60,8 +60,8 @@ public class WindowsAppImageBuilder extends AbstractAppImageBuilder { }, (s, p) -> Path.of(s)); - public static final StandardBundlerParam CONSOLE_HINT = - new StandardBundlerParam<>( + public static final BundlerParamInfo CONSOLE_HINT = + new BundlerParamInfo<>( Arguments.CLIOptions.WIN_CONSOLE_HINT.getId(), Boolean.class, params -> false, From 7249398f2697a30a4d70d31f02f3882fd0fe7728 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 22 Jul 2024 13:46:00 -0400 Subject: [PATCH 0012/1101] Add defaults to DEB packager --- .../jdk/jpackage/internal/LinuxDebPackage.java | 5 +++++ .../internal/LinuxDebPackageFromParams.java | 13 ++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java index 42cf3eab928f6..b07ce40286786 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java @@ -63,4 +63,9 @@ public String maintainerEmail() { private final String maintainerEmail; } + + static record Defaults(String maintainerEmail) { + } + + static final Defaults DEFAULTS = new Defaults("Unknown"); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java index 76b9a05898c1a..706b329176840 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java @@ -25,6 +25,8 @@ package jdk.jpackage.internal; import java.util.Map; +import java.util.Optional; +import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import static jdk.jpackage.internal.Package.StandardPackageType.LinuxDeb; import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; @@ -33,7 +35,8 @@ final class LinuxDebPackageFromParams { private static LinuxDebPackage create(Map params) throws ConfigException { var pkg = LinuxPackageFromParams.create(params, LinuxDeb); - var maintainerEmail = MAINTAINER_EMAIL.fetchFrom(params); + var maintainerEmail = Optional.ofNullable(MAINTAINER_EMAIL.fetchFrom(params)).orElseGet( + LinuxDebPackage.DEFAULTS::maintainerEmail); return new LinuxDebPackage.Impl(pkg, maintainerEmail); } @@ -41,10 +44,6 @@ private static LinuxDebPackage create(Map params) throws static final BundlerParamInfo PACKAGE = createBundlerParam( LinuxDebPackageFromParams::create); - private static final BundlerParamInfo MAINTAINER_EMAIL = new BundlerParamInfo<>( - Arguments.CLIOptions.LINUX_DEB_MAINTAINER.getId(), - String.class, - params -> "Unknown", - (s, p) -> s); - + private static final BundlerParamInfo MAINTAINER_EMAIL = createStringBundlerParam( + Arguments.CLIOptions.LINUX_DEB_MAINTAINER.getId()); } From 532f4ef532edc46933e82f38ac1395e51c99c207 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 18 Oct 2024 16:27:13 -0400 Subject: [PATCH 0013/1101] Bugfix --- .../jdk/jpackage/internal/LinuxPackage.java | 46 +++++++++---------- .../internal/LinuxPackageBundler.java | 3 +- .../jpackage/internal/PackageFromParams.java | 2 +- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java index 7a7c1c0ad1bf1..cacf33e910d17 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java @@ -51,6 +51,24 @@ default ApplicationLayout appLayout() { } } + @Override + default Path packageFileName() { + String packageFileNameTemlate; + switch (asStandardPackageType()) { + case LinuxDeb -> { + packageFileNameTemlate = "%s_%s-%s_%s.deb"; + } + case LinuxRpm -> { + packageFileNameTemlate = "%s-%s-%s.%s.rpm"; + } + default -> { + throw new UnsupportedOperationException(); + } + } + + return Path.of(String.format(packageFileNameTemlate, packageName(), version(), release(), arch())); + } + default boolean isInstallDirInUsrTree() { return Set.of(Path.of("usr/local"), Path.of("usr")).contains(relativeInstallDir()); } @@ -72,14 +90,11 @@ static class Impl extends Package.Proxy implements LinuxPackage { packageName = target.packageName(); } - menuGroupName = Optional.ofNullable(menuGroupName).orElseGet(DEFAULTS::menuGroupName); - category = Optional.ofNullable(category).orElseGet(DEFAULTS::category); - release = Optional.ofNullable(release).orElseGet(DEFAULTS::release); + this.menuGroupName = Optional.ofNullable(menuGroupName).orElseGet(DEFAULTS::menuGroupName); + this.category = Optional.ofNullable(category).orElseGet(DEFAULTS::category); + this.release = Optional.ofNullable(release).orElseGet(DEFAULTS::release); - this.menuGroupName = menuGroupName; - this.category = category; this.additionalDependencies = additionalDependencies; - this.release = release; this.arch = arch; } @@ -88,25 +103,6 @@ public String packageName() { return packageName; } - @Override - public Path packageFileName() { - String packageFileNameTemlate; - switch (asStandardPackageType()) { - case LinuxDeb -> { - packageFileNameTemlate = "%s_%s-%s_%s.deb"; - } - case LinuxRpm -> { - packageFileNameTemlate = "%s-%s-%s.%s.rpm"; - } - default -> { - throw new UnsupportedOperationException(); - } - } - - return Path.of(String.format(packageFileNameTemlate, packageName(), version(), - release(), arch())); - } - @Override public String menuGroupName() { return menuGroupName; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index cdfaf1da752e5..669218d8aee81 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -33,6 +33,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; @@ -208,7 +209,7 @@ private Map createDefaultReplacementData(Workshop workshop, Linu data.put("APPLICATION_DESCRIPTION", pkg.description()); String defaultDeps = String.join(", ", getListOfNeededPackages(workshop)); - String customDeps = pkg.additionalDependencies(); + String customDeps = Optional.ofNullable(pkg.additionalDependencies()).orElse(""); if (!customDeps.isEmpty() && !defaultDeps.isEmpty()) { customDeps = ", " + customDeps; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java index f1b2899b322e0..9a83b0cc642d8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java @@ -64,7 +64,7 @@ static Package create(Map params, } }); if (relativeInstallDir.isAbsolute()) { - relativeInstallDir = relativeInstallDir.relativize(Path.of("/")); + relativeInstallDir = Path.of("/").relativize(relativeInstallDir); } return new Impl(app, pkgType, packageName, description, version, aboutURL, licenseFile, From 1a7c9b93aeb2c4ff29eb016f359dbcd13bd93ba9 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 18 Oct 2024 20:54:00 -0400 Subject: [PATCH 0014/1101] Make AppAboutUrlTest test pass for rpm packaging --- .../jdk/jpackage/internal/LinuxPackage.java | 43 ++++++------- .../internal/LinuxPackageBundler.java | 32 +++++----- .../jpackage/internal/LinuxRpmBundler.java | 8 +-- .../jdk/jpackage/internal/Package.java | 61 ++++++++++--------- .../jpackage/internal/PackageFromParams.java | 22 +++---- .../jpackage/internal/WorkshopFromParams.java | 9 +-- 6 files changed, 86 insertions(+), 89 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java index cacf33e910d17..3ca6215d7c02c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java @@ -83,11 +83,10 @@ static class Impl extends Package.Proxy implements LinuxPackage { Impl(Package target, String menuGroupName, String category, String additionalDependencies, String release, String arch) throws ConfigException { - super(target); - if (target.type() instanceof StandardPackageType type) { - packageName = mapPackageName(target.packageName(), type); - } else { - packageName = target.packageName(); + super(fixPackageName(target)); + + if (type() instanceof StandardPackageType type) { + validatePackageName(packageName(), type); } this.menuGroupName = Optional.ofNullable(menuGroupName).orElseGet(DEFAULTS::menuGroupName); @@ -98,11 +97,6 @@ static class Impl extends Package.Proxy implements LinuxPackage { this.arch = arch; } - @Override - public String packageName() { - return packageName; - } - @Override public String menuGroupName() { return menuGroupName; @@ -127,8 +121,22 @@ public String release() { public String arch() { return arch; } - - private final String packageName; + + private static Package fixPackageName(Package pkg) { + var packageName = pkg.packageName(); + if (pkg.type() instanceof StandardPackageType type) { + switch (type) { + case LinuxDeb, LinuxRpm -> { + // make sure to lower case and spaces/underscores become dashes + packageName = packageName.toLowerCase().replaceAll("[ _]", "-"); + } + } + } + return new Package.Impl(pkg.app(), pkg.type(), packageName, + pkg.description(), pkg.version(), pkg.aboutURL(), + pkg.licenseFile(), pkg.predefinedAppImage(), + pkg.configuredRelativeInstallDir()); + } private final String menuGroupName; private final String category; @@ -175,10 +183,8 @@ static record Defaults(String release, String menuGroupName, String category) { static final Defaults DEFAULTS = new Defaults("1", I18N.getString("param.menu-group.default"), "misc"); - private static String mapPackageName(String packageName, StandardPackageType pkgType) throws ConfigException { - // make sure to lower case and spaces/underscores become dashes - packageName = packageName.toLowerCase().replaceAll("[ _]", "-"); - + static void validatePackageName(String packageName, + StandardPackageType pkgType) throws ConfigException { switch (pkgType) { case LinuxDeb -> { // @@ -214,11 +220,6 @@ private static String mapPackageName(String packageName, StandardPackageType pkg .getString("error.rpm-invalid-value-for-package-name.advice")); } } - default -> { - throw new IllegalArgumentException(); - } } - - return packageName; } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 669218d8aee81..763e934ac738b 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -126,39 +126,41 @@ public Path appImageDir() { }; try { - Path appImage = pkg.predefinedAppImage(); + Path srcAppImageDir = pkg.predefinedAppImage(); // we either have an application image or need to build one - if (appImage != null) { - initAppImageLayout.apply(appImage).copy(pkg.appLayout().resolveAt(pkgWorkshop - .appImageDir())); + if (srcAppImageDir == null) { + srcAppImageDir = workshop.appImageDir(); + Files.createDirectories(srcAppImageDir.getParent()); + appImageBundler.execute(params, srcAppImageDir.getParent()); + } + + Path dstAppImageDir; + if (pkg.isInstallDirInUsrTree()) { + dstAppImageDir = pkgWorkshop.appImageDir(); } else { - Files.createDirectories(workshop.appImageDir().getParent()); - appImageBundler.execute(params, workshop.appImageDir().getParent()); - Files.delete(AppImageFile.getPathInAppImage(workshop.appImageDir())); - if (pkg.isInstallDirInUsrTree()) { - initAppImageLayout.apply(workshop.appImageDir()).copy(pkg.appLayout().resolveAt( - pkgWorkshop.appImageDir())); - } + dstAppImageDir = pkgWorkshop.appImageDir().resolve(pkg.relativeInstallDir()); } + initAppImageLayout.apply(srcAppImageDir).copy(pkg.appLayout().resolveAt(dstAppImageDir)); + for (var ca : customActions) { ca.init(pkgWorkshop, pkg); } - Map data = createDefaultReplacementData(workshop, pkg); + Map data = createDefaultReplacementData(pkgWorkshop, pkg); for (var ca : customActions) { ShellCustomAction.mergeReplacementData(data, ca.instance. create()); } - data.putAll(createReplacementData(workshop, pkg)); + data.putAll(createReplacementData(pkgWorkshop, pkg)); Path packageBundle = buildPackageBundle(Collections.unmodifiableMap( - data), workshop, pkg, outputParentDir); + data), pkgWorkshop, pkg, outputParentDir); - verifyOutputBundle(workshop, pkg, packageBundle).stream() + verifyOutputBundle(pkgWorkshop, pkg, packageBundle).stream() .filter(Objects::nonNull) .forEachOrdered(ex -> { Log.verbose(ex.getLocalizedMessage()); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index 6f92171a609d8..778110066670e 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -103,11 +103,11 @@ protected Path buildPackageBundle(Map replacementData, Workshop } private static Path installPrefix(LinuxPackage pkg) { - if (pkg.isInstallDirInUsrTree()) { - return Path.of("/").resolve(pkg.relativeInstallDir()); - } else { - return pkg.relativeInstallDir().getParent(); + Path path = pkg.relativeInstallDir(); + if (!pkg.isInstallDirInUsrTree()) { + path = path.getParent(); } + return Path.of("/").resolve(path); } @Override diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index 25836beaab08e..9783a5ced8ccc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -125,15 +125,43 @@ default boolean isRuntimeInstaller() { * Returns relative path to the package installation directory. On Windows it should be relative * to %ProgramFiles% and relative to the system root ('/') on other platforms. */ - Path relativeInstallDir(); + default Path relativeInstallDir() { + return Optional.ofNullable(configuredRelativeInstallDir()).orElseGet( + this::defaultRelativeInstallDir); + } + + Path configuredRelativeInstallDir(); + + default Path defaultRelativeInstallDir() { + switch (type()) { + case StandardPackageType.WinExe, StandardPackageType.WinMsi -> { + return app().appImageDirName(); + } + case StandardPackageType.LinuxDeb, StandardPackageType.LinuxRpm -> { + return Path.of("opt").resolve(packageName()); + } + case StandardPackageType.MacDmg, StandardPackageType.MacPkg -> { + String root; + if (isRuntimeInstaller()) { + root = "Library/Java/JavaVirtualMachines"; + } else { + root = "Applications"; + } + return Path.of(root).resolve(packageName()); + } + default -> { + return null; + } + } + } static record Impl(Application app, PackageType type, String packageName, String description, String version, String aboutURL, Path licenseFile, Path predefinedAppImage, - Path relativeInstallDir) implements Package { + Path configuredRelativeInstallDir) implements Package { public Impl { - packageName = Optional.ofNullable(packageName).orElseGet(app::name); description = Optional.ofNullable(description).orElseGet(app::description); version = Optional.ofNullable(version).orElseGet(app::version); + packageName = Optional.ofNullable(packageName).orElseGet(app::name); } } @@ -184,31 +212,8 @@ public Path predefinedAppImage() { } @Override - public Path relativeInstallDir() { - return target.relativeInstallDir(); - } - } - - static Path defaultInstallDir(Application app, StandardPackageType type) { - switch (type) { - case WinExe, WinMsi -> { - return app.appImageDirName(); - } - case LinuxDeb, LinuxRpm -> { - return Path.of("/opt").resolve(app.appImageDirName()); - } - case MacDmg, MacPkg -> { - String root; - if (app.isRuntime()) { - root = "/Library/Java/JavaVirtualMachines"; - } else { - root = "/Applications"; - } - return Path.of(root).resolve(app.appImageDirName()); - } - default -> { - throw new IllegalArgumentException(); - } + public Path configuredRelativeInstallDir() { + return target.configuredRelativeInstallDir(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java index 9a83b0cc642d8..3f12392ba0dbf 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java @@ -32,7 +32,6 @@ import jdk.jpackage.internal.Package.Impl; import jdk.jpackage.internal.Package.PackageType; import jdk.jpackage.internal.Package.StandardPackageType; -import static jdk.jpackage.internal.Package.defaultInstallDir; import static jdk.jpackage.internal.Package.mapInstallDir; import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; @@ -54,18 +53,15 @@ static Package create(Map params, var licenseFile = Optional.ofNullable(LICENSE_FILE.fetchFrom(params)).map(Path::of).orElse(null); var predefinedAppImage = getPredefinedAppImage(params); - var relativeInstallDir = Optional.ofNullable(INSTALL_DIR.fetchFrom(params)).map(v -> { - return toSupplier(() -> mapInstallDir(Path.of(v), pkgType)).get(); - }).orElseGet(() -> { - if (pkgType instanceof StandardPackageType stdPkgType) { - return defaultInstallDir(app, stdPkgType); - } else { - return app.appImageDirName(); - } - }); - if (relativeInstallDir.isAbsolute()) { - relativeInstallDir = Path.of("/").relativize(relativeInstallDir); - } + Path relativeInstallDir = Optional.ofNullable(INSTALL_DIR.fetchFrom(params)).map(v -> { + return toSupplier(() -> { + var path = mapInstallDir(Path.of(v), pkgType); + if (path.isAbsolute()) { + path = Path.of("/").relativize(path); + } + return path; + }).get(); + }).orElse(null); return new Impl(app, pkgType, packageName, description, version, aboutURL, licenseFile, predefinedAppImage, relativeInstallDir); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java index 5255dec98c78b..9686797e12ad4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java @@ -26,7 +26,6 @@ import java.nio.file.Path; import java.util.Map; -import jdk.internal.util.OperatingSystem; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import jdk.jpackage.internal.Workshop.Impl; import jdk.jpackage.internal.Workshop.Proxy; @@ -45,13 +44,7 @@ static Workshop create(Map params) throws ConfigExceptio } else if (StandardBundlerParam.hasPredefinedAppImage(params)) { appImageDir = StandardBundlerParam.getPredefinedAppImage(params); } else { - Path dir; - if (PACKAGE_TYPE.fetchFrom(params).equals("app-image") || OperatingSystem.isWindows()) { - dir = ApplicationFromParams.APPLICATION.fetchFrom(params).appImageDirName(); - } else { - dir = PackageFromParams.PACKAGE.fetchFrom(params).relativeInstallDir(); - } - + Path dir = ApplicationFromParams.APPLICATION.fetchFrom(params).appImageDirName(); appImageDir = defaultWorkshop.buildRoot().resolve("image").resolve(dir); } From c03719e2277bff1a1a6a2a234dfa81774144ea9c Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 19 Oct 2024 09:08:55 -0400 Subject: [PATCH 0015/1101] Fix LinuxBundleNameTest test --- .../jdk/jpackage/internal/LinuxPackage.java | 34 +++++---- .../internal/LinuxPackageFromParams.java | 13 ++++ .../classes/jdk/jpackage/internal/Getter.java | 37 ++++++++++ .../jdk/jpackage/internal/Package.java | 72 +++++++++++++++++-- 4 files changed, 134 insertions(+), 22 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/Getter.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java index 3ca6215d7c02c..8d0b0cf6cf65c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java @@ -83,7 +83,21 @@ static class Impl extends Package.Proxy implements LinuxPackage { Impl(Package target, String menuGroupName, String category, String additionalDependencies, String release, String arch) throws ConfigException { - super(fixPackageName(target)); + super(Package.override(target, new Package.Unsupported() { + @Override + public String packageName() { + var packageName = super.packageName(); + if (type() instanceof StandardPackageType type) { + switch (type) { + case LinuxDeb, LinuxRpm -> { + // make sure to lower case and spaces/underscores become dashes + packageName = packageName.toLowerCase().replaceAll("[ _]", "-"); + } + } + } + return packageName; + } + })); if (type() instanceof StandardPackageType type) { validatePackageName(packageName(), type); @@ -121,22 +135,6 @@ public String release() { public String arch() { return arch; } - - private static Package fixPackageName(Package pkg) { - var packageName = pkg.packageName(); - if (pkg.type() instanceof StandardPackageType type) { - switch (type) { - case LinuxDeb, LinuxRpm -> { - // make sure to lower case and spaces/underscores become dashes - packageName = packageName.toLowerCase().replaceAll("[ _]", "-"); - } - } - } - return new Package.Impl(pkg.app(), pkg.type(), packageName, - pkg.description(), pkg.version(), pkg.aboutURL(), - pkg.licenseFile(), pkg.predefinedAppImage(), - pkg.configuredRelativeInstallDir()); - } private final String menuGroupName; private final String category; @@ -183,7 +181,7 @@ static record Defaults(String release, String menuGroupName, String category) { static final Defaults DEFAULTS = new Defaults("1", I18N.getString("param.menu-group.default"), "misc"); - static void validatePackageName(String packageName, + private static void validatePackageName(String packageName, StandardPackageType pkgType) throws ConfigException { switch (pkgType) { case LinuxDeb -> { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java index 64a8daddb0709..a7836d649a7b7 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java @@ -38,6 +38,16 @@ static LinuxPackage create(Map params, StandardPackageTy var additionalDependencies = LINUX_PACKAGE_DEPENDENCIES.fetchFrom(params); var release = RELEASE.fetchFrom(params); + var packageName = LINUX_PACKAGE_NAME.fetchFrom(params); + if (packageName != null) { + pkg = Package.override(pkg, new Package.Unsupported() { + @Override + public String packageName() { + return packageName; + } + }); + } + return new Impl(pkg, menuGroupName, category, additionalDependencies, release); } @@ -52,4 +62,7 @@ static LinuxPackage create(Map params, StandardPackageTy private static final BundlerParamInfo RELEASE = createStringBundlerParam( Arguments.CLIOptions.RELEASE.getId()); + + private static final BundlerParamInfo LINUX_PACKAGE_NAME = createStringBundlerParam( + Arguments.CLIOptions.LINUX_BUNDLE_NAME.getId()); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Getter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Getter.java new file mode 100644 index 0000000000000..7d98721af0612 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Getter.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.function.Function; + +final class Getter { + static T getValueOrDefault(C mainSrc, C defaultSrc, Function getter) { + try { + return getter.apply(mainSrc); + } catch (UnsupportedOperationException ex) { + return getter.apply(defaultSrc); + } + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index 9783a5ced8ccc..49c4205bf057c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -28,6 +28,7 @@ import java.text.MessageFormat; import java.util.Optional; import java.util.stream.Stream; +import static jdk.jpackage.internal.Getter.getValueOrDefault; interface Package { @@ -155,16 +156,66 @@ default Path defaultRelativeInstallDir() { } } - static record Impl(Application app, PackageType type, String packageName, String description, - String version, String aboutURL, Path licenseFile, Path predefinedAppImage, - Path configuredRelativeInstallDir) implements Package { - public Impl { + static record Impl(Application app, PackageType type, String packageName, + String description, String version, String aboutURL, Path licenseFile, + Path predefinedAppImage, Path configuredRelativeInstallDir) implements Package { + + public Impl { description = Optional.ofNullable(description).orElseGet(app::description); version = Optional.ofNullable(version).orElseGet(app::version); packageName = Optional.ofNullable(packageName).orElseGet(app::name); } } + static class Unsupported implements Package { + + @Override + public Application app() { + throw new UnsupportedOperationException(); + } + + @Override + public PackageType type() { + throw new UnsupportedOperationException(); + } + + @Override + public String packageName() { + throw new UnsupportedOperationException(); + } + + @Override + public String description() { + throw new UnsupportedOperationException(); + } + + @Override + public String version() { + throw new UnsupportedOperationException(); + } + + @Override + public String aboutURL() { + throw new UnsupportedOperationException(); + } + + @Override + public Path licenseFile() { + throw new UnsupportedOperationException(); + } + + @Override + public Path predefinedAppImage() { + throw new UnsupportedOperationException(); + } + + @Override + public Path configuredRelativeInstallDir() { + throw new UnsupportedOperationException(); + } + + } + static class Proxy extends ProxyBase implements Package { Proxy(T target) { @@ -217,6 +268,19 @@ public Path configuredRelativeInstallDir() { } } + static Package override(Package base, Package overrides) { + return new Impl( + getValueOrDefault(overrides, base, Package::app), + getValueOrDefault(overrides, base, Package::type), + getValueOrDefault(overrides, base, Package::packageName), + getValueOrDefault(overrides, base, Package::description), + getValueOrDefault(overrides, base, Package::version), + getValueOrDefault(overrides, base, Package::aboutURL), + getValueOrDefault(overrides, base, Package::licenseFile), + getValueOrDefault(overrides, base, Package::predefinedAppImage), + getValueOrDefault(overrides, base, Package::configuredRelativeInstallDir)); + } + static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigException { var ex = new ConfigException(MessageFormat.format(I18N.getString("error.invalid-install-dir"), installDir), null); From 850dc2213720ad6f4d3e8db8e945179fa7d9c489 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 19 Oct 2024 17:04:55 -0400 Subject: [PATCH 0016/1101] Bugfix --- .../linux/classes/jdk/jpackage/internal/LinuxPackage.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java index 8d0b0cf6cf65c..202da716cdb01 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java @@ -86,8 +86,8 @@ static class Impl extends Package.Proxy implements LinuxPackage { super(Package.override(target, new Package.Unsupported() { @Override public String packageName() { - var packageName = super.packageName(); - if (type() instanceof StandardPackageType type) { + var packageName = target.packageName(); + if (target.type() instanceof StandardPackageType type) { switch (type) { case LinuxDeb, LinuxRpm -> { // make sure to lower case and spaces/underscores become dashes From 28447b011ed388afa29ed7760b064b112966e660 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 21 Oct 2024 11:28:27 -0400 Subject: [PATCH 0017/1101] Check the value of `Exec` key in .desktop file references one of app launchers --- .../helpers/jdk/jpackage/test/LinuxHelper.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index bf5ced09bc771..6e3354a040cce 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -399,6 +399,13 @@ static void addBundleDesktopIntegrationVerifier(PackageTest test, private static void verifyDesktopFile(JPackageCommand cmd, Path desktopFile) throws IOException { TKit.trace(String.format("Check [%s] file BEGIN", desktopFile)); + + var launcherName = Stream.of(List.of(cmd.name()), cmd.addLauncherNames()).flatMap(List::stream).filter(name -> { + return getDesktopFile(cmd, name).equals(desktopFile); + }).findAny(); + TKit.assertTrue(launcherName.isPresent(), + "Check the desktop file corresponds to one of app launchers"); + List lines = Files.readAllLines(desktopFile); TKit.assertEquals("[Desktop Entry]", lines.get(0), "Check file header"); @@ -428,7 +435,7 @@ private static void verifyDesktopFile(JPackageCommand cmd, Path desktopFile) "Check value of [%s] key", key)); } - // Verify value of `Exec` property in .desktop files are escaped if required + // Verify the value of `Exec` key in is escaped if required String launcherPath = data.get("Exec"); if (Pattern.compile("\\s").matcher(launcherPath).find()) { TKit.assertTrue(launcherPath.startsWith("\"") @@ -437,6 +444,12 @@ private static void verifyDesktopFile(JPackageCommand cmd, Path desktopFile) launcherPath = launcherPath.substring(1, launcherPath.length() - 1); } + TKit.assertEquals(launcherPath.toString(), cmd.pathToPackageFile( + cmd.appLauncherPath(launcherName.get())).toString(), + String.format( + "Check the value of [Exec] key references [%s] app launcher", + launcherName.get())); + Stream.of(launcherPath, data.get("Icon")) .map(Path::of) .map(cmd::pathToUnpackedPackageFile) From d98129a0bf0cab2c4a90941f3852a0235601e172 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 21 Oct 2024 11:32:35 -0400 Subject: [PATCH 0018/1101] Add getter for PathGroup's keys --- .../share/classes/jdk/jpackage/internal/PathGroup.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java index 24fb394e100d0..c32e0b5248075 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.BiFunction; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -61,6 +62,13 @@ void setPath(Object id, Path path) { } } + /** + * All configured IDs. + */ + Set keys() { + return entries.keySet(); + } + /** * All configured entries. */ From 580371e94bbc3f8c616ec9ec02290eff2acccd0d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 21 Oct 2024 11:33:56 -0400 Subject: [PATCH 0019/1101] Disable access to DEFAULTS field. --- .../jdk/jpackage/internal/Application.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java index 9948f61c9c044..3edb7de4540a1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java @@ -120,21 +120,21 @@ static record Impl(String name, String description, String version, String vendo List additionalLaunchers) implements Application { public Impl { name = Optional.ofNullable(name).orElseGet(mainLauncher::name); - description = Optional.ofNullable(description).orElseGet(DEFAULTS::description); - version = Optional.ofNullable(version).orElseGet(DEFAULTS::version); - vendor = Optional.ofNullable(vendor).orElseGet(DEFAULTS::vendor); - copyright = Optional.ofNullable(copyright).orElseGet(DEFAULTS::copyright); + description = Optional.ofNullable(description).orElseGet(Defaults.INSTANCE::description); + version = Optional.ofNullable(version).orElseGet(Defaults.INSTANCE::version); + vendor = Optional.ofNullable(vendor).orElseGet(Defaults.INSTANCE::vendor); + copyright = Optional.ofNullable(copyright).orElseGet(Defaults.INSTANCE::copyright); } } static record Defaults(String description, String version, String vendor, String copyright) { - + private static final Defaults INSTANCE = new Defaults( + I18N.getString("param.description.default"), + "1.0", + I18N.getString("param.vendor.default"), + MessageFormat.format(I18N.getString("param.copyright.default"), new Date())); } - static final Defaults DEFAULTS = new Defaults(I18N.getString("param.description.default"), "1.0", - I18N.getString("param.vendor.default"), MessageFormat.format(I18N.getString( - "param.copyright.default"), new Date())); - static class Proxy extends ProxyBase implements Application { Proxy(T target) { From af28a7c674be73d9444c8aa69f0b50a317398f45 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 21 Oct 2024 11:36:30 -0400 Subject: [PATCH 0020/1101] - Disable access to DEFAULTS field --- .../jdk/jpackage/internal/LinuxDebPackage.java | 7 ++++--- .../jpackage/internal/LinuxDebPackageFromParams.java | 4 +--- .../jdk/jpackage/internal/LinuxRpmPackage.java | 11 ++++++++++- .../jpackage/internal/LinuxRpmPackageFromParams.java | 9 +++------ 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java index b07ce40286786..3057df281f97a 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal; import java.nio.file.Path; +import java.util.Optional; interface LinuxDebPackage extends LinuxPackage { @@ -53,7 +54,8 @@ static class Impl extends LinuxPackage.Proxy implements LinuxDebPa public Impl(LinuxPackage target, String maintainerEmail) { super(target); - this.maintainerEmail = maintainerEmail; + this.maintainerEmail = Optional.ofNullable(maintainerEmail).orElseGet( + LinuxDebPackage.Defaults.INSTANCE::maintainerEmail); } @Override @@ -65,7 +67,6 @@ public String maintainerEmail() { } static record Defaults(String maintainerEmail) { + static final Defaults INSTANCE = new Defaults("Unknown"); } - - static final Defaults DEFAULTS = new Defaults("Unknown"); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java index 706b329176840..00e6b3f14a136 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal; import java.util.Map; -import java.util.Optional; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import static jdk.jpackage.internal.Package.StandardPackageType.LinuxDeb; import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; @@ -35,8 +34,7 @@ final class LinuxDebPackageFromParams { private static LinuxDebPackage create(Map params) throws ConfigException { var pkg = LinuxPackageFromParams.create(params, LinuxDeb); - var maintainerEmail = Optional.ofNullable(MAINTAINER_EMAIL.fetchFrom(params)).orElseGet( - LinuxDebPackage.DEFAULTS::maintainerEmail); + var maintainerEmail = MAINTAINER_EMAIL.fetchFrom(params); return new LinuxDebPackage.Impl(pkg, maintainerEmail); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java index 40d07ad610d63..737fa71b0bf61 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal; +import java.util.Optional; + interface LinuxRpmPackage extends LinuxPackage { String licenseType(); @@ -32,7 +34,8 @@ static class Impl extends LinuxPackage.Proxy implements LinuxRpmPa public Impl(LinuxPackage target, String licenseType) { super(target); - this.licenseType = licenseType; + this.licenseType = Optional.ofNullable(licenseType).orElseGet( + LinuxRpmPackage.Defaults.INSTANCE::licenseType); } @Override @@ -42,4 +45,10 @@ public String licenseType() { private final String licenseType; } + + static record Defaults(String licenseType) { + + private final static Defaults INSTANCE = new Defaults(I18N.getString( + "param.license-type.default")); + } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java index bcdc7fad41643..388d16c165af8 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal; import java.util.Map; +import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import jdk.jpackage.internal.LinuxRpmPackage.Impl; import static jdk.jpackage.internal.Package.StandardPackageType.LinuxRpm; import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; @@ -42,10 +43,6 @@ private static LinuxRpmPackage create(Map params) throws static final BundlerParamInfo PACKAGE = createBundlerParam( LinuxRpmPackageFromParams::create); - private static final BundlerParamInfo LICENSE_TYPE = new BundlerParamInfo<>( - Arguments.CLIOptions.LINUX_RPM_LICENSE_TYPE.getId(), - String.class, - params -> I18N.getString("param.license-type.default"), - (s, p) -> s); - + private static final BundlerParamInfo LICENSE_TYPE = createStringBundlerParam( + Arguments.CLIOptions.LINUX_RPM_LICENSE_TYPE.getId()); } From 1914cc6d8ce2793040291d1996015909da053d2b Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 21 Oct 2024 11:37:21 -0400 Subject: [PATCH 0021/1101] Disable better default launcher description to pass existing tests --- .../jdk/jpackage/internal/ApplicationFromParams.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java index c576b1bc236a9..9c5f79dc4de44 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java @@ -107,8 +107,10 @@ static Application create(Map params, Map launcherParams) { if (!launcherParams.containsKey(DESCRIPTION.getID())) { launcherParams = new HashMap<>(launcherParams); - launcherParams.put(DESCRIPTION.getID(), String.format("%s (%s)", DESCRIPTION.fetchFrom( - mainParams), APP_NAME.fetchFrom(launcherParams))); +// FIXME: this is a good improvement but it fails existing tests +// launcherParams.put(DESCRIPTION.getID(), String.format("%s (%s)", DESCRIPTION.fetchFrom( +// mainParams), APP_NAME.fetchFrom(launcherParams))); + launcherParams.put(DESCRIPTION.getID(), DESCRIPTION.fetchFrom(mainParams)); } return AddLauncherArguments.merge(mainParams, launcherParams, ICON.getID(), ADD_LAUNCHERS .getID(), FILE_ASSOCIATIONS.getID()); From f7aaaca6b2b956711d3da56f21d5d5eb87b0ae88 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 21 Oct 2024 11:41:18 -0400 Subject: [PATCH 0022/1101] Reformatted --- .../internal/WixAppImageFragmentBuilder.java | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index 65dcb381a6214..227f6b6e7ca63 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -78,8 +78,8 @@ void initFromParams(Workshop workshop, WinMsiPackage pkg) { pkg.app().name(), pkg.version()).toString(); - installDir = (systemWide ? PROGRAM_FILES : LOCAL_PROGRAM_FILES).resolve(pkg. - relativeInstallDir()); + installDir = (systemWide ? PROGRAM_FILES : LOCAL_PROGRAM_FILES).resolve( + pkg.relativeInstallDir()); do { ApplicationLayout layout = pkg.appLayout(); @@ -111,9 +111,10 @@ void initFromParams(Workshop workshop, WinMsiPackage pkg) { if (!launchersAsServices.isEmpty()) { // Service installer tool will be installed in launchers directory - serviceInstaller = new InstallableFile(pkg.serviceInstaller().toAbsolutePath() - .normalize(), installedAppImage.launchersDirectory().resolve(pkg - .serviceInstaller().getFileName())); + serviceInstaller = new InstallableFile( + pkg.serviceInstaller().toAbsolutePath().normalize(), + installedAppImage.launchersDirectory().resolve( + pkg.serviceInstaller().getFileName())); } programMenuFolderName = pkg.startMenuGroupName(); @@ -350,8 +351,7 @@ private static void addComponentGroup(XMLStreamWriter xml, String id, List componentIds) throws XMLStreamException, IOException { xml.writeStartElement("ComponentGroup"); xml.writeAttribute("Id", id); - componentIds = componentIds.stream().filter(Objects::nonNull).collect( - Collectors.toList()); + componentIds = componentIds.stream().filter(Objects::nonNull).toList(); for (var componentId : componentIds) { xml.writeStartElement("ComponentRef"); xml.writeAttribute("Id", componentId); @@ -455,12 +455,11 @@ private void addShortcutComponentGroup(XMLStreamWriter xml) throws Set defineShortcutFolders = new HashSet<>(); for (var launcher : launchers) { for (var folder : shortcutFolders) { - Path launcherPath = installedAppImage.launchersDirectory().resolve(launcher - .executableName()); + Path launcherPath = installedAppImage.launchersDirectory().resolve( + launcher.executableName()); if (folder.isRequestedFor(launcher)) { - String componentId = addShortcutComponent(xml, launcherPath, - folder); + String componentId = addShortcutComponent(xml, launcherPath, folder); if (componentId != null) { Path folderPath = folder.getPath(this); @@ -520,8 +519,7 @@ private List addFaComponents(XMLStreamWriter xml, xml.writeAttribute("Description", fa.description); if (fa.iconPath != null) { - xml.writeAttribute("Icon", Id.File.of(getInstalledFaIcoPath( - fa))); + xml.writeAttribute("Icon", Id.File.of(getInstalledFaIcoPath(fa))); xml.writeAttribute("IconIndex", "0"); } @@ -599,7 +597,8 @@ private List addRootBranch(XMLStreamWriter xml, Path path) return List.of(); } - private void startDirectoryElement(XMLStreamWriter xml, String wix3ElementName, Path path) throws XMLStreamException { + private void startDirectoryElement(XMLStreamWriter xml, + String wix3ElementName, Path path) throws XMLStreamException { final String elementName; switch (getWixType()) { case Wix3 -> { From 0be1d72e8415d5d2ac7244a1901305896e12b988 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 21 Oct 2024 11:44:16 -0400 Subject: [PATCH 0023/1101] Added Package.packageLayout(). Now there are three app layouts for the package: source app image layout, layout of app image for packaging, and layout of installed app image --- .../jpackage/internal/DesktopIntegration.java | 8 +- .../internal/LinuxLaunchersAsServices.java | 17 ++-- .../jdk/jpackage/internal/LinuxPackage.java | 17 ++-- .../internal/LinuxPackageBundler.java | 19 ++-- .../internal/MacLaunchersAsServices.java | 2 +- .../jdk/jpackage/internal/Package.java | 97 +++++++++++++------ .../jpackage/internal/PackageFromParams.java | 12 +-- .../jdk/jpackage/internal/WinMsiBundler.java | 12 +-- 8 files changed, 108 insertions(+), 76 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index eec7aef0039cf..1b80c41fe037c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -230,7 +230,7 @@ private Map createDataForDesktopFile() { f -> f.installPath().toString()).orElse(null)); data.put("DEPLOY_BUNDLE_CATEGORY", pkg.category()); data.put("APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo(pkg - .installedAppLayout().launchersDirectory().resolve(launcher.executableName()) + .installedPackageLayout().launchersDirectory().resolve(launcher.executableName()) .toString())); return data; @@ -333,9 +333,9 @@ void applyTo(Map data) { private class DesktopFile { DesktopFile(String fileName) { - var installPath = pkg.installedAppLayout() + var installPath = pkg.installedPackageLayout() .destktopIntegrationDirectory().resolve(fileName); - var srcPath = pkg.appLayout().resolveAt(workshop.appImageDir()) + var srcPath = pkg.packageLayout().resolveAt(workshop.appImageDir()) .destktopIntegrationDirectory().resolve(fileName); impl = new InstallableFile(srcPath, installPath); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java index f062dd7393932..8720c594d6944 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java @@ -71,16 +71,19 @@ public static Path getServiceUnitFileName(String packageName, String launcherNam private static class LauncherImpl extends UnixLauncherAsService { LauncherImpl(Workshop workshop, Package pkg, Launcher launcher) { - super(launcher, workshop.createResource("unit-template.service").setCategory(I18N - .getString("resource.systemd-unit-file"))); + super(launcher, + workshop.createResource("unit-template.service").setCategory( + I18N.getString("resource.systemd-unit-file"))); - unitFilename = getServiceUnitFileName(pkg.packageName(), launcher.executableName() - .toString()); + unitFilename = getServiceUnitFileName(pkg.packageName(), + launcher.executableName().toString()); getResource().setPublicName(unitFilename).addSubstitutionDataEntry( - "APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo(pkg.appLayout() - .resolveAt(workshop.appImageDir()).launchersDirectory().resolve( - getName()).toString())); + "APPLICATION_LAUNCHER", + Enquoter.forPropertyValues().applyTo( + pkg.installedPackageLayout().resolveAt( + workshop.appImageDir()).launchersDirectory().resolve( + getName()).toString())); } @Override diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java index 202da716cdb01..c0336275d13d7 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java @@ -43,11 +43,11 @@ interface LinuxPackage extends Package { String arch(); @Override - default ApplicationLayout appLayout() { + default ApplicationLayout packageLayout() { if (isInstallDirInUsrTree()) { return ApplicationLayout.linuxUsrTreePackageImage(relativeInstallDir(), packageName()); } else { - return Package.super.appLayout(); + return Package.super.packageLayout(); } } @@ -70,7 +70,7 @@ default Path packageFileName() { } default boolean isInstallDirInUsrTree() { - return Set.of(Path.of("usr/local"), Path.of("usr")).contains(relativeInstallDir()); + return !relativeInstallDir().getFileName().equals(Path.of(packageName())); } static class Impl extends Package.Proxy implements LinuxPackage { @@ -103,9 +103,9 @@ public String packageName() { validatePackageName(packageName(), type); } - this.menuGroupName = Optional.ofNullable(menuGroupName).orElseGet(DEFAULTS::menuGroupName); - this.category = Optional.ofNullable(category).orElseGet(DEFAULTS::category); - this.release = Optional.ofNullable(release).orElseGet(DEFAULTS::release); + this.menuGroupName = Optional.ofNullable(menuGroupName).orElseGet(Defaults.INSTANCE::menuGroupName); + this.category = Optional.ofNullable(category).orElseGet(Defaults.INSTANCE::category); + this.release = Optional.ofNullable(release).orElseGet(Defaults.INSTANCE::release); this.additionalDependencies = additionalDependencies; this.arch = arch; @@ -176,11 +176,10 @@ public String arch() { } static record Defaults(String release, String menuGroupName, String category) { + private static final Defaults INSTANCE = new Defaults("1", + I18N.getString("param.menu-group.default"), "misc"); } - static final Defaults DEFAULTS = new Defaults("1", I18N.getString("param.menu-group.default"), - "misc"); - private static void validatePackageName(String packageName, StandardPackageType pkgType) throws ConfigException { switch (pkgType) { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 763e934ac738b..59718af7a90c2 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -119,7 +119,7 @@ public Path appImageDir() { params.put(WorkshopFromParams.WORKSHOP.getID(), pkgWorkshop); Function initAppImageLayout = imageRoot -> { - ApplicationLayout layout = pkg.app().appLayout(); + ApplicationLayout layout = pkg.appLayout(); layout.pathGroup().setPath(new Object(), AppImageFile.getPathInAppImage(Path.of(""))); return layout.resolveAt(imageRoot); @@ -129,21 +129,21 @@ public Path appImageDir() { Path srcAppImageDir = pkg.predefinedAppImage(); // we either have an application image or need to build one - if (srcAppImageDir == null) { + boolean moveLayout = (srcAppImageDir == null); + if (moveLayout) { srcAppImageDir = workshop.appImageDir(); Files.createDirectories(srcAppImageDir.getParent()); appImageBundler.execute(params, srcAppImageDir.getParent()); } - Path dstAppImageDir; - if (pkg.isInstallDirInUsrTree()) { - dstAppImageDir = pkgWorkshop.appImageDir(); + var srcLayout = initAppImageLayout.apply(srcAppImageDir); + var dstLayout = pkg.packageLayout().resolveAt(pkgWorkshop.appImageDir()); + if (moveLayout) { + srcLayout.move(dstLayout); } else { - dstAppImageDir = pkgWorkshop.appImageDir().resolve(pkg.relativeInstallDir()); + srcLayout.copy(dstLayout); } - initAppImageLayout.apply(srcAppImageDir).copy(pkg.appLayout().resolveAt(dstAppImageDir)); - for (var ca : customActions) { ca.init(pkgWorkshop, pkg); } @@ -151,8 +151,7 @@ public Path appImageDir() { Map data = createDefaultReplacementData(pkgWorkshop, pkg); for (var ca : customActions) { - ShellCustomAction.mergeReplacementData(data, ca.instance. - create()); + ShellCustomAction.mergeReplacementData(data, ca.instance.create()); } data.putAll(createReplacementData(pkgWorkshop, pkg)); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index 1349ff3e65b95..db0a866a4dd41 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -78,7 +78,7 @@ private static class MacLauncherAsService extends UnixLauncherAsService { .setPublicName(plistFilename) .addSubstitutionDataEntry("LABEL", label) .addSubstitutionDataEntry("APPLICATION_LAUNCHER", - pkg.installedAppLayout().launchersDirectory().resolve( + pkg.installedPackageLayout().launchersDirectory().resolve( getName()).toString()); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index 49c4205bf057c..f187680a8447a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -91,7 +91,19 @@ default ApplicationLayout appLayout() { return app().appLayout(); } - default ApplicationLayout installedAppLayout() { + default ApplicationLayout packageLayout() { + var layout = appLayout(); + var pathGroup = layout.pathGroup(); + var baseDir = relativeInstallDir(); + + for (var key : pathGroup.keys()) { + pathGroup.setPath(key, baseDir.resolve(pathGroup.getPath(key))); + } + + return layout; + } + + default ApplicationLayout installedPackageLayout() { Path root = relativeInstallDir(); if (type() instanceof StandardPackageType type) { switch (type) { @@ -123,42 +135,64 @@ default boolean isRuntimeInstaller() { } /** - * Returns relative path to the package installation directory. On Windows it should be relative - * to %ProgramFiles% and relative to the system root ('/') on other platforms. + * Returns relative path to the package installation directory. + * + * On Windows it should be relative to %ProgramFiles% and relative + * to the system root ('/') on other platforms. */ default Path relativeInstallDir() { - return Optional.ofNullable(configuredRelativeInstallDir()).orElseGet( - this::defaultRelativeInstallDir); + var path = Optional.ofNullable(configuredInstallBaseDir()).map(v -> { + switch (asStandardPackageType()) { + case LinuxDeb, LinuxRpm -> { + switch (v.toString()) { + case "/usr", "/usr/local" -> { + return v; + } + } + } + } + return v.resolve(packageName()); + }).orElseGet(this::defaultInstallDir); + + switch (asStandardPackageType()) { + case WinExe, WinMsi -> { + return path; + } + default -> { + return Path.of("/").relativize(path); + } + } } - Path configuredRelativeInstallDir(); + Path configuredInstallBaseDir(); - default Path defaultRelativeInstallDir() { - switch (type()) { - case StandardPackageType.WinExe, StandardPackageType.WinMsi -> { - return app().appImageDirName(); + default Path defaultInstallDir() { + Path base; + switch (asStandardPackageType()) { + case WinExe, WinMsi -> { + base = Path.of(""); } - case StandardPackageType.LinuxDeb, StandardPackageType.LinuxRpm -> { - return Path.of("opt").resolve(packageName()); + case LinuxDeb, LinuxRpm -> { + base = Path.of("/opt"); } - case StandardPackageType.MacDmg, StandardPackageType.MacPkg -> { - String root; + case MacDmg, MacPkg -> { if (isRuntimeInstaller()) { - root = "Library/Java/JavaVirtualMachines"; + base = Path.of("/Library/Java/JavaVirtualMachines"); } else { - root = "Applications"; + base = Path.of("/Applications"); } - return Path.of(root).resolve(packageName()); } default -> { - return null; + throw new UnsupportedOperationException(); } } + + return base.resolve(packageName()); } static record Impl(Application app, PackageType type, String packageName, String description, String version, String aboutURL, Path licenseFile, - Path predefinedAppImage, Path configuredRelativeInstallDir) implements Package { + Path predefinedAppImage, Path configuredInstallBaseDir) implements Package { public Impl { description = Optional.ofNullable(description).orElseGet(app::description); @@ -210,7 +244,7 @@ public Path predefinedAppImage() { } @Override - public Path configuredRelativeInstallDir() { + public Path configuredInstallBaseDir() { throw new UnsupportedOperationException(); } @@ -263,8 +297,8 @@ public Path predefinedAppImage() { } @Override - public Path configuredRelativeInstallDir() { - return target.configuredRelativeInstallDir(); + public Path configuredInstallBaseDir() { + return target.configuredInstallBaseDir(); } } @@ -278,7 +312,7 @@ static Package override(Package base, Package overrides) { getValueOrDefault(overrides, base, Package::aboutURL), getValueOrDefault(overrides, base, Package::licenseFile), getValueOrDefault(overrides, base, Package::predefinedAppImage), - getValueOrDefault(overrides, base, Package::configuredRelativeInstallDir)); + getValueOrDefault(overrides, base, Package::configuredInstallBaseDir)); } static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigException { @@ -294,16 +328,17 @@ static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigExc throw ex; } - if (pkgType instanceof StandardPackageType stdPkgType) { - switch (stdPkgType) { - case WinExe, WinMsi -> { - if (installDir.isAbsolute()) { - throw ex; - } + switch (pkgType) { + case StandardPackageType.WinExe, StandardPackageType.WinMsi -> { + if (installDir.isAbsolute()) { + throw ex; + } + } + default -> { + if (!installDir.isAbsolute()) { + throw ex; } } - } else if (!installDir.isAbsolute()) { - throw ex; } if (!installDir.normalize().toString().equals(installDir.toString())) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java index 3f12392ba0dbf..948171c835939 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java @@ -53,18 +53,14 @@ static Package create(Map params, var licenseFile = Optional.ofNullable(LICENSE_FILE.fetchFrom(params)).map(Path::of).orElse(null); var predefinedAppImage = getPredefinedAppImage(params); - Path relativeInstallDir = Optional.ofNullable(INSTALL_DIR.fetchFrom(params)).map(v -> { + Path installBaseDir = Optional.ofNullable(INSTALL_DIR.fetchFrom(params)).map(v -> { return toSupplier(() -> { - var path = mapInstallDir(Path.of(v), pkgType); - if (path.isAbsolute()) { - path = Path.of("/").relativize(path); - } - return path; + return mapInstallDir(Path.of(v), pkgType); }).get(); }).orElse(null); - return new Impl(app, pkgType, packageName, description, version, aboutURL, licenseFile, - predefinedAppImage, relativeInstallDir); + return new Impl(app, pkgType, packageName, description, version, + aboutURL, licenseFile, predefinedAppImage, installBaseDir); } static BundlerParamInfo createBundlerParam( diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 6adf6c6e0727e..2827dca550c8f 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -218,7 +218,7 @@ private void prepareProto(Map params) appImageBundler.execute(params, workshop.appImageDir().getParent()); } - var appImageLayout = pkg.appLayout().resolveAt(workshop.appImageDir()); + var pkgLayout = pkg.packageLayout().resolveAt(workshop.appImageDir()); // Configure installer icon if (pkg.isRuntimeInstaller()) { @@ -226,12 +226,12 @@ private void prepareProto(Map params) // Assume java.exe exists in Java Runtime being packed. // Ignore custom icon if any as we don't want to copy anything in // Java Runtime image. - installerIcon = appImageLayout.runtimeDirectory().resolve(Path.of("bin", "java.exe")); + installerIcon = pkgLayout.runtimeDirectory().resolve(Path.of("bin", "java.exe")); } else { - installerIcon = appImageLayout.launchersDirectory().resolve(pkg.app().mainLauncher() + installerIcon = pkgLayout.launchersDirectory().resolve(pkg.app().mainLauncher() .executableName()); - new PackageFile(pkg.packageName()).save(appImageLayout); + new PackageFile(pkg.packageName()).save(pkgLayout); } installerIcon = installerIcon.toAbsolutePath(); @@ -317,8 +317,8 @@ private Map prepareMainProjectFile(Workshop workshop, WinMsiPack data.put("JpAboutURL", value); }); - data.put("JpAppSizeKb", Long.toString(pkg.appLayout().resolveAt(workshop.appImageDir()) - .sizeInBytes() >> 10)); + data.put("JpAppSizeKb", Long.toString(pkg.packageLayout().resolveAt( + workshop.appImageDir()).sizeInBytes() >> 10)); data.put("JpConfigDir", workshop.configDir().toAbsolutePath().toString()); From f94eee3fc37ea9800543b9ea7f04cd355efccf11 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 21 Oct 2024 11:50:52 -0400 Subject: [PATCH 0024/1101] Update javadoc --- .../share/classes/jdk/jpackage/internal/Package.java | 11 ++++++++++- .../share/classes/jdk/jpackage/internal/Workshop.java | 7 ++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index f187680a8447a..f22def824f30b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -87,10 +87,16 @@ default StandardPackageType asStandardPackageType() { Path predefinedAppImage(); + /** + * Returns source app image layout. + */ default ApplicationLayout appLayout() { return app().appLayout(); } + /** + * Returns app image layout inside of the package. + */ default ApplicationLayout packageLayout() { var layout = appLayout(); var pathGroup = layout.pathGroup(); @@ -103,6 +109,9 @@ default ApplicationLayout packageLayout() { return layout; } + /** + * Returns app image layout of the installed package. + */ default ApplicationLayout installedPackageLayout() { Path root = relativeInstallDir(); if (type() instanceof StandardPackageType type) { @@ -247,7 +256,7 @@ public Path predefinedAppImage() { public Path configuredInstallBaseDir() { throw new UnsupportedOperationException(); } - + } static class Proxy extends ProxyBase implements Package { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java index 86932da965666..983e52db01788 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java @@ -33,9 +33,10 @@ interface Workshop { Path resourceDir(); /** - * Returns path to application image directory. When building app image this is the path to a - * directory where it is assembled. When building a package this is the path to the source app - * image. + * Returns path to application image directory. + * + * The return value is supposed to be used as a parameter for + * ApplicationLayout#resolveAt function. */ default Path appImageDir() { return buildRoot().resolve("image"); From 538b1c53f31b38471d18671f6c5ee695cb5d4962 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 21 Oct 2024 13:53:46 -0400 Subject: [PATCH 0025/1101] Fix to make AddLShortcutTest rpm test pass --- .../jdk/jpackage/internal/DesktopIntegration.java | 10 +++++++--- .../internal/LinuxApplicationFromParams.java | 14 ++++++-------- .../jdk/jpackage/internal/LinuxLauncher.java | 10 ++++++---- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 1b80c41fe037c..0811fa935294f 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -72,7 +72,7 @@ private DesktopIntegration(Workshop workshop, LinuxPackage pkg, LinuxLauncher la // Need desktop and icon files if one of conditions is met: // - there are file associations configured // - user explicitly requested to create a shortcut - boolean withDesktopFile = !associations.isEmpty() || launcher.shortcut(); + boolean withDesktopFile = !associations.isEmpty() || launcher.shortcut().orElse(false); var curIconResource = pkg.app().createLauncherIconResource(launcher, DEFAULT_ICON, workshop::createResource); @@ -126,8 +126,12 @@ private DesktopIntegration(Workshop workshop, LinuxPackage pkg, LinuxLauncher la if (launcher != pkg.app().mainLauncher()) { nestedIntegrations = List.of(); } else { - nestedIntegrations = pkg.app().additionalLaunchers().stream().map(toFunction(l -> { - return new DesktopIntegration(workshop, pkg, (LinuxLauncher)l); + nestedIntegrations = pkg.app().additionalLaunchers().stream().map(v -> { + return (LinuxLauncher)v; + }).filter(l -> { + return l.shortcut().orElse(true); + }).map(toFunction(l -> { + return new DesktopIntegration(workshop, pkg, l); })).toList(); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java index 67278db23ae67..26c661e9f2674 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal; import java.util.Map; +import java.util.stream.Stream; import static jdk.jpackage.internal.ApplicationFromParams.createBundlerParam; import jdk.jpackage.internal.LinuxApplication.Impl; import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; @@ -35,14 +36,11 @@ private static LinuxApplication create(Map params) throw var app = ApplicationFromParams.create(params, launcherParams -> { var launcher = LauncherFromParams.create(launcherParams); - boolean shortcut; - if (launcherParams.containsKey(SHORTCUT_HINT.getID())) { - // This is an explicit shortcut configuration for an addition launcher - shortcut = SHORTCUT_HINT.fetchFrom(launcherParams); - } else { - shortcut = LINUX_SHORTCUT_HINT.fetchFrom(launcherParams); - } - + var shortcut = Stream.of(SHORTCUT_HINT, LINUX_SHORTCUT_HINT).filter(param -> { + return launcherParams.containsKey(param.getID()); + }).map(param -> { + return param.fetchFrom(launcherParams); + }).findFirst(); return new LinuxLauncher.Impl(launcher, shortcut); }); return new Impl(app); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java index 38dd21133c5d8..301e99bae8490 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java @@ -24,22 +24,24 @@ */ package jdk.jpackage.internal; +import java.util.Optional; + interface LinuxLauncher extends Launcher { - boolean shortcut(); + Optional shortcut(); static class Impl extends Launcher.Proxy implements LinuxLauncher { - Impl(Launcher launcher, boolean shortcut) { + Impl(Launcher launcher, Optional shortcut) { super(launcher); this.shortcut = shortcut; } @Override - public boolean shortcut() { + public Optional shortcut() { return shortcut; } - private final boolean shortcut; + private final Optional shortcut; } } From 184165c2e0751ebf376735f2927d84e08ef9e23a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 04:07:33 -0400 Subject: [PATCH 0026/1101] Fix imports --- .../linux/classes/jdk/jpackage/internal/LinuxPackage.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java index c0336275d13d7..597323d1fd6f6 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java @@ -27,7 +27,6 @@ import java.nio.file.Path; import java.text.MessageFormat; import java.util.Optional; -import java.util.Set; import java.util.regex.Pattern; interface LinuxPackage extends Package { From 10287400018212e2635d8ac6990e45ff83622719 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 04:11:52 -0400 Subject: [PATCH 0027/1101] Streamlined LauncherStartupInfo and derived class. --- .../jpackage/internal/LauncherFromParams.java | 2 +- .../internal/LauncherJarStartupInfo.java | 25 ++++ .../internal/LauncherModularStartupInfo.java | 25 ++++ .../internal/LauncherStartupInfo.java | 125 ++++++++---------- .../LauncherStartupInfoFromParams.java | 55 ++++++++ 5 files changed, 160 insertions(+), 72 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java index 2c716dd2a555f..06d8abc2379a4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java @@ -38,7 +38,7 @@ static Launcher create(Map params) { LauncherStartupInfo startupInfo = null; if (PREDEFINED_APP_IMAGE.fetchFrom(params) == null) { - startupInfo = LauncherStartupInfo.createFromParams(params); + startupInfo = LauncherStartupInfoFromParams.create(params); } var isService = LAUNCHER_AS_SERVICE.fetchFrom(params); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java index eb9ed36e2e49c..464ba7f9f8785 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java @@ -28,4 +28,29 @@ interface LauncherJarStartupInfo extends LauncherStartupInfo { Path jarPath(); + + boolean isClassNameFromMainJar(); + + final static class Impl extends LauncherStartupInfo.Proxy + implements LauncherJarStartupInfo { + + Impl(LauncherStartupInfo target, Path jarPath, boolean isClassNameFromMainJar) { + super(target); + this.jarPath = jarPath; + this.isClassNameFromMainJar = isClassNameFromMainJar; + } + + @Override + public Path jarPath() { + return jarPath; + } + + @Override + public boolean isClassNameFromMainJar() { + return isClassNameFromMainJar; + } + + private final Path jarPath; + private final boolean isClassNameFromMainJar; + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherModularStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherModularStartupInfo.java index 241e3c3fd26e3..332adb70945fc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherModularStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherModularStartupInfo.java @@ -28,7 +28,32 @@ import java.util.List; interface LauncherModularStartupInfo extends LauncherStartupInfo { + String moduleName(); List modulePath(); + + final static class Impl extends LauncherStartupInfo.Proxy + implements LauncherModularStartupInfo { + + Impl(LauncherStartupInfo target, String moduleName, + List modulePath) { + super(target); + this.moduleName = moduleName; + this.modulePath = modulePath; + } + + @Override + public String moduleName() { + return moduleName; + } + + @Override + public List modulePath() { + return modulePath; + } + + private final String moduleName; + private final List modulePath; + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java index 951cd800adf75..7e93e2a0f974f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java @@ -26,11 +26,9 @@ import java.nio.file.Path; import java.util.List; -import java.util.Map; -import static jdk.jpackage.internal.StandardBundlerParam.ARGUMENTS; -import static jdk.jpackage.internal.StandardBundlerParam.JAVA_OPTIONS; interface LauncherStartupInfo { + String qualifiedClassName(); default String packageName() { @@ -47,74 +45,59 @@ default String packageName() { List classPath(); - static LauncherStartupInfo createFromParams(Map params) { - var inputDir = StandardBundlerParam.SOURCE_DIR.fetchFrom(params); - var launcherData = StandardBundlerParam.LAUNCHER_DATA.fetchFrom(params); - var javaOptions = JAVA_OPTIONS.fetchFrom(params); - var arguments = ARGUMENTS.fetchFrom(params); - var classpath = launcherData.classPath().stream().map(p -> { - return inputDir.resolve(p).toAbsolutePath(); - }).toList(); - - if (launcherData.isModular()) { - return new LauncherModularStartupInfo() { - @Override - public String moduleName() { - return launcherData.moduleName(); - } - - @Override - public List modulePath() { - return launcherData.modulePath().stream().map(Path::toAbsolutePath).toList(); - } - - @Override - public String qualifiedClassName() { - return launcherData.qualifiedClassName(); - } - - @Override - public List javaOptions() { - return javaOptions; - } - - @Override - public List defaultParameters() { - return arguments; - } - - @Override - public List classPath() { - return classpath; - } - }; - } else { - return new LauncherJarStartupInfo() { - @Override - public Path jarPath() { - return inputDir.resolve(launcherData.mainJarName()); - } - - @Override - public String qualifiedClassName() { - return launcherData.qualifiedClassName(); - } - - @Override - public List javaOptions() { - return javaOptions; - } - - @Override - public List defaultParameters() { - return arguments; - } - - @Override - public List classPath() { - return classpath; - } - }; + record Impl(String qualifiedClassName, List javaOptions, + List defaultParameters, List classPath) implements + LauncherStartupInfo { + } + + static class Proxy extends ProxyBase + implements LauncherStartupInfo { + + Proxy(T target) { + super(target); + } + + @Override + public String qualifiedClassName() { + return target.qualifiedClassName(); + } + + @Override + public List javaOptions() { + return target.javaOptions(); + } + + @Override + public List defaultParameters() { + return target.defaultParameters(); + } + + @Override + public List classPath() { + return target.classPath(); + } + } + + static class Unsupported implements LauncherStartupInfo { + + @Override + public String qualifiedClassName() { + throw new UnsupportedOperationException(); + } + + @Override + public List javaOptions() { + throw new UnsupportedOperationException(); + } + + @Override + public List defaultParameters() { + throw new UnsupportedOperationException(); + } + + @Override + public List classPath() { + throw new UnsupportedOperationException(); } } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java new file mode 100644 index 0000000000000..c1171da601d56 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.Map; +import static jdk.jpackage.internal.StandardBundlerParam.ARGUMENTS; +import static jdk.jpackage.internal.StandardBundlerParam.JAVA_OPTIONS; + +final class LauncherStartupInfoFromParams { + + static LauncherStartupInfo create(Map params) { + var inputDir = StandardBundlerParam.SOURCE_DIR.fetchFrom(params); + var launcherData = StandardBundlerParam.LAUNCHER_DATA.fetchFrom(params); + var javaOptions = JAVA_OPTIONS.fetchFrom(params); + var arguments = ARGUMENTS.fetchFrom(params); + var classpath = launcherData.classPath().stream().map(p -> { + return inputDir.resolve(p).toAbsolutePath(); + }).toList(); + + var startupInfo = new LauncherStartupInfo.Impl( + launcherData.qualifiedClassName(), javaOptions, arguments, + classpath); + + if (launcherData.isModular()) { + return new LauncherModularStartupInfo.Impl(startupInfo, + launcherData.moduleName(), launcherData.modulePath()); + } else { + return new LauncherJarStartupInfo.Impl(startupInfo, + inputDir.resolve(launcherData.mainJarName()), + launcherData.isClassNameFromMainJar()); + } + } +} From c50f783037c8d48a0c9f39337b843727fc1bd16e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 04:14:38 -0400 Subject: [PATCH 0028/1101] Use absolute paths when filtering module paths --- .../share/classes/jdk/jpackage/internal/RuntimeBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilder.java index 01138b679614c..b93b8398cf8d4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilder.java @@ -58,7 +58,7 @@ static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, Path... modul Path dest = appLayout.appModsDirectory(); for (Path mp : modulePath) { - if (!defaultModulePath.contains(mp)) { + if (!defaultModulePath.contains(mp.toAbsolutePath())) { IOUtils.copyRecursive(mp, dest); } } From ec7b61c70a34b0860213a461862292787de2e815 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 04:17:47 -0400 Subject: [PATCH 0029/1101] Add `thpws IOException` as ApplicationFromParams.create() can throw exceptions of this type --- .../jdk/jpackage/internal/LinuxApplicationFromParams.java | 3 ++- .../jdk/jpackage/internal/WinApplicationFromParams.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java index 26c661e9f2674..31e3cca5e74d2 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import java.io.IOException; import java.util.Map; import java.util.stream.Stream; import static jdk.jpackage.internal.ApplicationFromParams.createBundlerParam; @@ -32,7 +33,7 @@ final class LinuxApplicationFromParams { - private static LinuxApplication create(Map params) throws ConfigException { + private static LinuxApplication create(Map params) throws ConfigException, IOException { var app = ApplicationFromParams.create(params, launcherParams -> { var launcher = LauncherFromParams.create(launcherParams); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java index 0ed602a7f3f49..49bf8723c5e1d 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import java.io.IOException; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,7 +37,7 @@ final class WinApplicationFromParams { - private static WinApplication create(Map params) throws ConfigException { + private static WinApplication create(Map params) throws ConfigException, IOException { var app = ApplicationFromParams.create(params, launcherParams -> { var launcher = LauncherFromParams.create(launcherParams); boolean isConsole = CONSOLE_HINT.fetchFrom(launcherParams); From 40b82c1be92214faf12318964c7cd83b2c8f11cf Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 13:42:58 -0400 Subject: [PATCH 0030/1101] Get rid of `params` in CfgFile.java --- .../internal/AbstractAppImageBuilder.java | 28 ++++-- .../jdk/jpackage/internal/CfgFile.java | 88 ++++++++----------- .../internal/StandardBundlerParam.java | 6 +- 3 files changed, 60 insertions(+), 62 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java index 4e46d9a59cc52..eab984f1084ca 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java @@ -31,10 +31,11 @@ import java.util.Map; import java.util.List; import static jdk.jpackage.internal.OverridableResource.createResource; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.SOURCE_DIR; import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; +import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import jdk.jpackage.internal.resources.ResourceLocator; /* @@ -62,7 +63,22 @@ public abstract void prepareApplicationFiles( protected void writeCfgFile(Map params) throws IOException { - new CfgFile().initFromParams(params).create(root); + new CfgFile(new Application.Unsupported() { + @Override + public String version() { + return VERSION.fetchFrom(params); + } + }, new Launcher.Unsupported() { + @Override + public LauncherStartupInfo startupInfo() { + return LauncherStartupInfoFromParams.create(params); + } + + @Override + public String name() { + return APP_NAME.fetchFrom(params); + } + }).create(ApplicationLayout.platformAppImage(), appLayout); } ApplicationLayout getAppLayout() { @@ -79,10 +95,10 @@ protected void copyApplication(Map params) AppImageFile.save(root, params); - List items = APP_CONTENT.fetchFrom(params); - for (String item : items) { - IOUtils.copyRecursive(Path.of(item), - appLayout.contentDirectory().resolve(Path.of(item).getFileName())); + List items = APP_CONTENT.fetchFrom(params); + for (Path item : items) { + IOUtils.copyRecursive(item, + appLayout.contentDirectory().resolve(item.getFileName())); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java index 9ab3151121bba..fdf45e4865027 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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,72 +25,57 @@ package jdk.jpackage.internal; import java.io.IOException; -import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Stream; -import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_DATA; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.JAVA_OPTIONS; -import static jdk.jpackage.internal.StandardBundlerParam.ARGUMENTS; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; + /** * App launcher's config file. */ final class CfgFile { - CfgFile() { - appLayout = ApplicationLayout.platformAppImage(); - } - - CfgFile initFromParams(Map params) { - launcherData = LAUNCHER_DATA.fetchFrom(params); - launcherName = APP_NAME.fetchFrom(params); - javaOptions = JAVA_OPTIONS.fetchFrom(params); - arguments = ARGUMENTS.fetchFrom(params); - version = VERSION.fetchFrom(params); - return this; + CfgFile(Application app, Launcher launcher) { + startupInfo = launcher.startupInfo(); + executableName = launcher.executableName(); + version = app.version(); } - void create(Path appImage) throws IOException { + void create(ApplicationLayout unresolvedAppLayout, ApplicationLayout appLayout) throws IOException { List> content = new ArrayList<>(); - ApplicationLayout appCfgLayout = createAppCfgLayout(); + ApplicationLayout appCfgLayout = createAppCfgLayout(unresolvedAppLayout); content.add(Map.entry("[Application]", SECTION_TAG)); - if (launcherData.isModular()) { - content.add(Map.entry("app.mainmodule", launcherData.moduleName() - + "/" + launcherData.qualifiedClassName())); - } else { - if (launcherData.mainJarName() != null) { - Path mainJarPath = appCfgLayout.appDirectory().resolve( - launcherData.mainJarName()); - - if (launcherData.isClassNameFromMainJar()) { - content.add(Map.entry("app.mainjar", mainJarPath)); - } else { - content.add(Map.entry("app.classpath", mainJarPath)); - } + if (startupInfo instanceof LauncherModularStartupInfo modularStartupInfo) { + content.add(Map.entry("app.mainmodule", modularStartupInfo.moduleName() + + "/" + startupInfo.qualifiedClassName())); + } else if (startupInfo instanceof LauncherJarStartupInfo jarStartupInfo) { + Path mainJarPath = appCfgLayout.appDirectory().resolve( + jarStartupInfo.jarPath().getFileName()); + + if (jarStartupInfo.isClassNameFromMainJar()) { + content.add(Map.entry("app.mainjar", mainJarPath)); + } else { + content.add(Map.entry("app.classpath", mainJarPath)); } - if (!launcherData.isClassNameFromMainJar()) { - content.add(Map.entry("app.mainclass", - launcherData.qualifiedClassName())); + if (!jarStartupInfo.isClassNameFromMainJar()) { + content.add(Map.entry("app.mainclass", startupInfo.qualifiedClassName())); } + } else { + throw new UnsupportedOperationException(); } - for (var value : launcherData.classPath()) { + for (var value : Optional.ofNullable(startupInfo.classPath()).orElseGet(List::of)) { content.add(Map.entry("app.classpath", appCfgLayout.appDirectory().resolve(value).toString())); } - ApplicationLayout appImagelayout = appLayout.resolveAt(appImage); - Path modsDir = appImagelayout.appModsDirectory(); - content.add(Map.entry("[JavaOptions]", SECTION_TAG)); // always let app know it's version @@ -98,17 +83,17 @@ void create(Path appImage) throws IOException { "java-options", "-Djpackage.app-version=" + version)); // add user supplied java options if there are any - for (var value : javaOptions) { + for (var value : Optional.ofNullable(startupInfo.javaOptions()).orElseGet(List::of)) { content.add(Map.entry("java-options", value)); } // add module path if there is one - if (Files.isDirectory(modsDir)) { + if (Files.isDirectory(appLayout.appModsDirectory())) { content.add(Map.entry("java-options", "--module-path")); - content.add(Map.entry("java-options", - appCfgLayout.appModsDirectory())); + content.add(Map.entry("java-options", appCfgLayout.appModsDirectory())); } + var arguments = Optional.ofNullable(startupInfo.defaultParameters()).orElseGet(List::of); if (!arguments.isEmpty()) { content.add(Map.entry("[ArgOptions]", SECTION_TAG)); for (var value : arguments) { @@ -116,8 +101,8 @@ void create(Path appImage) throws IOException { } } - Path cfgFile = appImagelayout.appDirectory().resolve(launcherName + ".cfg"); - Files.createDirectories(IOUtils.getParent(cfgFile)); + Path cfgFile = appLayout.appDirectory().resolve(IOUtils.replaceSuffix(executableName, ".cfg")); + Files.createDirectories(cfgFile.getParent()); boolean[] addLineBreakAtSection = new boolean[1]; Stream lines = content.stream().map(entry -> { @@ -133,7 +118,7 @@ void create(Path appImage) throws IOException { Files.write(cfgFile, (Iterable) lines::iterator); } - private ApplicationLayout createAppCfgLayout() { + private ApplicationLayout createAppCfgLayout(ApplicationLayout appLayout) { ApplicationLayout appCfgLayout = appLayout.resolveAt(Path.of("$ROOTDIR")); appCfgLayout.pathGroup().setPath(ApplicationLayout.PathRole.APP, Path.of("$APPDIR")); @@ -142,12 +127,9 @@ private ApplicationLayout createAppCfgLayout() { return appCfgLayout; } - private String launcherName; - private String version; - private LauncherData launcherData; - List arguments; - List javaOptions; - private final ApplicationLayout appLayout; + private final LauncherStartupInfo startupInfo; + private final String version; + private final Path executableName; private static final Object SECTION_TAG = new Object(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index d82c4dcdfdc09..48824869d8dba 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -414,12 +414,12 @@ final class StandardBundlerParam { ); @SuppressWarnings("unchecked") - static final BundlerParamInfo> APP_CONTENT = + static final BundlerParamInfo> APP_CONTENT = new BundlerParamInfo<>( Arguments.CLIOptions.APP_CONTENT.getId(), - (Class>) (Object)List.class, + (Class>) (Object)List.class, p->Collections.emptyList(), - (s, p) -> Arrays.asList(s.split(",")) + (s, p) -> Stream.of(s.split(",")).map(Path::of).toList() ); @SuppressWarnings("unchecked") From c228af7350b17995ab3c3a5a80ea3a4edd129441 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 13:44:50 -0400 Subject: [PATCH 0031/1101] Fix failed InstallDirTest.testLinuxInvalid(/) test --- .../share/classes/jdk/jpackage/internal/Package.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index f22def824f30b..c4927cfbf9612 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -328,6 +328,10 @@ static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigExc var ex = new ConfigException(MessageFormat.format(I18N.getString("error.invalid-install-dir"), installDir), null); + if (installDir.getNameCount() == 0) { + throw ex; + } + if (installDir.getFileName().equals(Path.of(""))) { // Trailing '/' or '\\'. Strip them away. installDir = installDir.getParent(); From 6389ca5d6f622343ee0bc571aec82a49869f4269 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 13:46:20 -0400 Subject: [PATCH 0032/1101] Fix for `--app-image` scenario. More strict checks of the values of `Icon` and `Exec` keys --- .../jdk/jpackage/test/LinuxHelper.java | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index 6e3354a040cce..402b409788248 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -40,6 +40,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.internal.IOUtils; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.PackageTest.PackageHandlers; @@ -403,8 +404,10 @@ private static void verifyDesktopFile(JPackageCommand cmd, Path desktopFile) var launcherName = Stream.of(List.of(cmd.name()), cmd.addLauncherNames()).flatMap(List::stream).filter(name -> { return getDesktopFile(cmd, name).equals(desktopFile); }).findAny(); - TKit.assertTrue(launcherName.isPresent(), - "Check the desktop file corresponds to one of app launchers"); + if (!cmd.hasArgument("--app-image")) { + TKit.assertTrue(launcherName.isPresent(), + "Check the desktop file corresponds to one of app launchers"); + } List lines = Files.readAllLines(desktopFile); TKit.assertEquals("[Desktop Entry]", lines.get(0), "Check file header"); @@ -444,16 +447,25 @@ private static void verifyDesktopFile(JPackageCommand cmd, Path desktopFile) launcherPath = launcherPath.substring(1, launcherPath.length() - 1); } - TKit.assertEquals(launcherPath.toString(), cmd.pathToPackageFile( - cmd.appLauncherPath(launcherName.get())).toString(), - String.format( - "Check the value of [Exec] key references [%s] app launcher", - launcherName.get())); + if (launcherName.isPresent()) { + TKit.assertEquals(launcherPath, cmd.pathToPackageFile( + cmd.appLauncherPath(launcherName.get())).toString(), + String.format( + "Check the value of [Exec] key references [%s] app launcher", + launcherName.get())); + } - Stream.of(launcherPath, data.get("Icon")) - .map(Path::of) - .map(cmd::pathToUnpackedPackageFile) - .forEach(TKit::assertFileExists); + for (var e : List.>, Function>>of( + Map.entry(Map.entry("Exec", Optional.of(launcherPath)), ApplicationLayout::launchersDirectory), + Map.entry(Map.entry("Icon", Optional.empty()), ApplicationLayout::destktopIntegrationDirectory))) { + var path = e.getKey().getValue().or(() -> Optional.of(data.get( + e.getKey().getKey()))).map(Path::of).get(); + TKit.assertFileExists(cmd.pathToUnpackedPackageFile(path)); + Path expectedDir = cmd.pathToPackageFile(e.getValue().apply(cmd.appLayout())); + TKit.assertTrue(path.getParent().equals(expectedDir), String.format( + "Check the value of [%s] key references a file in [%s] folder", + e.getKey().getKey(), expectedDir)); + } TKit.trace(String.format("Check [%s] file END", desktopFile)); } From 6c25915bc2a4b1ab900612c5efe49ccc8a60a389 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 14:17:21 -0400 Subject: [PATCH 0033/1101] - All rpm tests pass. - Added AppImageFile2 with the same functionality as AppImageFile but without `params` and hardcoded specifics of OSX (signing). It should eventually replace AppImageFile. - Added AppImageBuilder to build app image without `params`. LinuxAppImageBuilder2 is derived from AppImageBuilder and shoudl eventually replace LinuxAppImageBuilder. - Added missing Unsupported classes. - Added missing properties to Launcher and Application interfaces. - renamed Application.allLaunchers() into Application.launchers(). - default implementation of Application.additionalLaunchers() will never return `null`. --- .../internal/LinuxAppImageBuilder2.java | 71 ++++ .../jdk/jpackage/internal/LinuxLauncher.java | 7 + .../internal/LinuxPackageBundler.java | 51 ++- .../jdk/jpackage/internal/MacApplication.java | 40 ++ .../jpackage/internal/AppImageBuilder.java | 107 ++++++ .../jdk/jpackage/internal/AppImageFile2.java | 347 ++++++++++++++++++ .../jdk/jpackage/internal/Application.java | 107 +++++- .../internal/ApplicationFromParams.java | 35 +- .../jdk/jpackage/internal/Launcher.java | 53 ++- .../internal/StandardBundlerParam.java | 9 +- .../internal/UnixLaunchersAsServices.java | 3 +- .../jdk/jpackage/internal/WinLauncher.java | 8 + .../internal/WixAppImageFragmentBuilder.java | 6 +- 13 files changed, 772 insertions(+), 72 deletions(-) create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder2.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplication.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder2.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder2.java new file mode 100644 index 0000000000000..b776204794e29 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder2.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import static jdk.jpackage.internal.LinuxAppImageBuilder.DEFAULT_ICON; +import jdk.jpackage.internal.resources.ResourceLocator; + +final class LinuxAppImageBuilder2 extends AppImageBuilder { + + LinuxAppImageBuilder2(Application app) { + super(app); + } + + LinuxAppImageBuilder2(Package pkg) { + super(pkg); + } + + @Override + void execute(Workshop workshop) throws IOException, PackagerException { + super.execute(workshop); + + if (app.isRuntime()) { + return; + } + + var resolvedAppLayout = appLayout.resolveAt(workshop.appImageDir()); + + var launcherLib = resolvedAppLayout.pathGroup().getPath( + ApplicationLayout.PathRole.LINUX_APPLAUNCHER_LIB); + try (var in = ResourceLocator.class.getResourceAsStream("libjpackageapplauncheraux.so")) { + Files.createDirectories(launcherLib.getParent()); + Files.copy(in, launcherLib); + } + + for (var launcher : app.launchers()) { + var iconResource = app.createLauncherIconResource(launcher, + DEFAULT_ICON, workshop::createResource); + if (iconResource != null) { + Path iconTarget = resolvedAppLayout.destktopIntegrationDirectory().resolve( + IOUtils.replaceSuffix(launcher.executableName(), + IOUtils.getSuffix(Path.of(DEFAULT_ICON)))); + iconResource.saveToFile(iconTarget); + } + } + } +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java index 301e99bae8490..a9345e78b80e2 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java @@ -24,12 +24,19 @@ */ package jdk.jpackage.internal; +import java.util.Map; import java.util.Optional; interface LinuxLauncher extends Launcher { Optional shortcut(); + default Map extraAppImageData() { + return shortcut().map(v -> { + return Map.of("shortcut", Boolean.toString(v)); + }).orElseGet(Map::of); + } + static class Impl extends Launcher.Proxy implements LinuxLauncher { Impl(Launcher launcher, Optional shortcut) { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 59718af7a90c2..d631c0c68b876 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -26,7 +26,6 @@ import java.io.IOException; import java.nio.file.Path; -import java.nio.file.Files; import java.text.MessageFormat; import java.util.Collections; import java.util.HashMap; @@ -34,7 +33,6 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; @@ -42,7 +40,6 @@ abstract class LinuxPackageBundler extends AbstractBundler { LinuxPackageBundler(BundlerParamInfo pkgParam) { this.pkgParam = pkgParam; - appImageBundler = new LinuxAppBundler().setDependentTask(true); customActions = List.of(new CustomActionInstance( DesktopIntegration::create), new CustomActionInstance( LinuxLaunchersAsServices::create)); @@ -56,10 +53,6 @@ public final boolean validate(Map params) LinuxPackage pkg = pkgParam.fetchFrom(params); var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); - // run basic validation to ensure requirements are met - // we are not interested in return code, only possible exception - appImageBundler.validate(params); - FileAssociation.verify(FileAssociation.fetchFrom(params)); for (var validator: getToolValidators()) { @@ -118,30 +111,29 @@ public Path appImageDir() { params.put(WorkshopFromParams.WORKSHOP.getID(), pkgWorkshop); - Function initAppImageLayout = imageRoot -> { - ApplicationLayout layout = pkg.appLayout(); - layout.pathGroup().setPath(new Object(), - AppImageFile.getPathInAppImage(Path.of(""))); - return layout.resolveAt(imageRoot); - }; - try { - Path srcAppImageDir = pkg.predefinedAppImage(); - - // we either have an application image or need to build one - boolean moveLayout = (srcAppImageDir == null); - if (moveLayout) { - srcAppImageDir = workshop.appImageDir(); - Files.createDirectories(srcAppImageDir.getParent()); - appImageBundler.execute(params, srcAppImageDir.getParent()); - } - - var srcLayout = initAppImageLayout.apply(srcAppImageDir); - var dstLayout = pkg.packageLayout().resolveAt(pkgWorkshop.appImageDir()); - if (moveLayout) { - srcLayout.move(dstLayout); + // We either have an application image or need to build one. + if (pkg.app().runtimeBuilder() != null) { + // Runtime builder is present, build app image. + new LinuxAppImageBuilder2(pkg).execute(pkgWorkshop); } else { - srcLayout.copy(dstLayout); + Path srcAppImageDir = pkg.predefinedAppImage(); + if (srcAppImageDir == null) { + // No predefined app image and no runtime builder. + // This should be runtime packaging. + if (pkg.app().isRuntime()) { + srcAppImageDir = workshop.appImageDir(); + } else { + // Can't create app image without runtime builder. + throw new UnsupportedOperationException(); + } + } + + // Copy app layout omitting application image info file. + ApplicationLayout srcLayout = pkg.appLayout().resolveAt(srcAppImageDir); + srcLayout.pathGroup().setPath(new Object(), + AppImageFile.getPathInAppImage(srcAppImageDir)); + srcLayout.copy(pkg.packageLayout().resolveAt(pkgWorkshop.appImageDir())); } for (var ca : customActions) { @@ -239,7 +231,6 @@ protected abstract Path buildPackageBundle( PackagerException, IOException; private final BundlerParamInfo pkgParam; - private final Bundler appImageBundler; private boolean withFindNeededPackages; private final List customActions; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplication.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplication.java new file mode 100644 index 0000000000000..ef7b3bfe506ae --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplication.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.Map; + +interface MacApplication extends Application { + + boolean signed(); + + boolean appStore(); + + @Override + default Map extraAppImageData() { + return Map.of("signed", Boolean.toString(signed()), "app-store", + Boolean.toString(appStore())); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java new file mode 100644 index 0000000000000..c1b4f69cb74ab --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + + +class AppImageBuilder { + + AppImageBuilder(Application app) { + this.app = app; + this.appLayout = app.appLayout(); + this.withAppImageFile = true; + } + + AppImageBuilder(Package pkg) { + this.app = pkg.app(); + this.appLayout = pkg.packageLayout(); + this.withAppImageFile = false; + } + + private static void copyRecursive(Path srcDir, Path dstDir, Workshop workshop) throws IOException { + srcDir = srcDir.toAbsolutePath(); + + List excludes = new ArrayList<>(); + + for (var path : List.of(workshop.buildRoot(), workshop.appImageDir())) { + if (Files.isDirectory(path)) { + path = path.toAbsolutePath(); + if (path.startsWith(srcDir) && !Files.isSameFile(path, srcDir)) { + excludes.add(path); + } + } + } + + IOUtils.copyRecursive(srcDir, dstDir.toAbsolutePath() /*, excludes */); + } + + void execute(Workshop workshop) throws IOException, PackagerException { + var resolvedAppLayout = appLayout.resolveAt(workshop.appImageDir()); + + app.runtimeBuilder().createRuntime(resolvedAppLayout); + if (app.isRuntime()) { + return; + } + + copyRecursive(app.mainSrcDir(), resolvedAppLayout.appDirectory(), workshop); + + for (var srcDir : Optional.ofNullable(app.additionalSrcDirs()).orElseGet(List::of)) { + copyRecursive(srcDir, + resolvedAppLayout.contentDirectory().resolve(srcDir.getFileName()), + workshop); + } + + if (withAppImageFile) { + new AppImageFile2(app).save(workshop.appImageDir()); + } + + for (var launcher : app.launchers()) { + // Copy executable to launchers folder + Path executableFile = resolvedAppLayout.launchersDirectory().resolve(launcher.executableName()); + try (var in = launcher.executableResource()) { + Files.createDirectories(executableFile.getParent()); + Files.copy(in, executableFile); + } + + var asFile = executableFile.toFile(); + + asFile.setExecutable(true, false); + + // Create corresponding .cfg file + new CfgFile(app, launcher).create(appLayout, resolvedAppLayout); + } + } + + private final boolean withAppImageFile; + protected final Application app; + protected final ApplicationLayout appLayout; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java new file mode 100644 index 0000000000000..471937ace6df1 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.NoSuchFileException; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import static java.util.stream.Collectors.toMap; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import jdk.internal.util.OperatingSystem; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + + +public final class AppImageFile2 { + + AppImageFile2(Application app) { + appVersion = app.version(); + launcherName = app.mainLauncher().name(); + mainClass = app.mainLauncher().startupInfo().qualifiedClassName(); + extra = app.extraAppImageData(); + creatorVersion = getVersion(); + creatorPlatform = getPlatform(); + addLauncherInfos = app.additionalLaunchers().stream().map(launcher -> { + return new LauncherInfo(launcher.name(), launcher.isService(), + launcher.extraAppImageData()); + }).toList(); + + for (var str : List.of(appVersion, launcherName, mainClass)) { + if (str == null || str.isBlank()) { + throw new InavlidAppImageFileException(); + } + } + } + + /** + * Returns list of additional launchers configured for the application. + * + * Returns empty list for application without additional launchers. + */ + List getAddLaunchers() { + return addLauncherInfos; + } + + /** + * Returns application version. Never returns null or empty value. + */ + String getAppVersion() { + return appVersion; + } + + /** + * Returns main application launcher name. Never returns null or empty value. + */ + String getLauncherName() { + return launcherName; + } + + /** + * Returns main class name. Never returns null or empty value. + */ + String getMainClass() { + return mainClass; + } + + /** + * Saves file with application image info in application image using values + * from this instance. + * @param appImageDir - path to application image + * @throws IOException + */ + void save(Path appImageDir) throws IOException { + IOUtils.createXml(getPathInAppImage(appImageDir), xml -> { + xml.writeStartElement("jpackage-state"); + xml.writeAttribute("version", creatorVersion); + xml.writeAttribute("platform", creatorPlatform); + + xml.writeStartElement("app-version"); + xml.writeCharacters(appVersion); + xml.writeEndElement(); + + xml.writeStartElement("main-launcher"); + xml.writeCharacters(launcherName); + xml.writeEndElement(); + + xml.writeStartElement("main-class"); + xml.writeCharacters(launcherName); + xml.writeEndElement(); + + for (var extraKey : extra.keySet().stream().sorted().toList()) { + xml.writeStartElement(extraKey); + xml.writeCharacters(extra.get(extraKey)); + xml.writeEndElement(); + } + + for (var li : addLauncherInfos) { + xml.writeStartElement("add-launcher"); + xml.writeAttribute("name", li.name()); + xml.writeAttribute("service", Boolean.toString(li.service())); + for (var extraKey : li.extra().keySet().stream().sorted().toList()) { + xml.writeStartElement(extraKey); + xml.writeCharacters(li.extra().get(extraKey)); + xml.writeEndElement(); + } + xml.writeEndElement(); + } + }); + } + + /** + * Returns path to application image info file. + * @param appImageDir - path to application image + */ + public static Path getPathInAppImage(Path appImageDir) { + return ApplicationLayout.platformAppImage() + .resolveAt(appImageDir) + .appDirectory() + .resolve(FILENAME); + } + + /** + * Loads application image info from application image. + * @param appImageDir - path to application image + * @return valid info about application image or null + * @throws IOException + */ + public static AppImageFile2 load(Path appImageDir) throws ConfigException, IOException { + try { + Document doc = IOUtils.initDocumentBuilder().parse( + Files.newInputStream(getPathInAppImage(appImageDir))); + + XPath xPath = XPathFactory.newInstance().newXPath(); + + String platform = queryNodes(doc, xPath, "/jpackage-state/@platform").findFirst().map( + Node::getNodeValue).orElse(null); + + String version = queryNodes(doc, xPath, "/jpackage-state/@version").findFirst().map( + Node::getNodeValue).orElse(null); + + if (!platform.equals(getPlatform()) || !version.equals(getVersion())) { + throw new InavlidAppImageFileException(); + } + + var props = AppImageProperties.main(doc, xPath); + + Launcher mainLauncher = new Launcher.Unsupported() { + @Override + public String name() { + return props.get("main-launcher"); + } + + @Override + public LauncherStartupInfo startupInfo() { + return startupInfo; + } + + private final LauncherStartupInfo startupInfo = new LauncherStartupInfo.Unsupported() { + @Override + public String qualifiedClassName() { + return props.get("main-class"); + } + }; + }; + + List additionalLaunchers = AppImageProperties.launchers(doc, xPath).stream().map(launcherProps -> { + Launcher launcher = new Launcher.Unsupported() { + @Override + public String name() { + return launcherProps.get("name"); + } + + @Override + public boolean isService() { + return Boolean.parseBoolean(launcherProps.get("service")); + } + + @Override + public Map extraAppImageData() { + return launcherProps.getExtra(); + } + }; + return launcher; + }).toList(); + + return new AppImageFile2(new Application.Unsupported() { + @Override + public String version() { + return props.get("app-version"); + } + + @Override + public List launchers() { + return Stream.concat(Stream.of(mainLauncher), additionalLaunchers.stream()).toList(); + } + + @Override + public Map extraAppImageData() { + return props.getExtra(); + } + }); + } catch (XPathExpressionException ex) { + // This should never happen as XPath expressions should be correct + throw new RuntimeException(ex); + } catch (SAXException ex) { + // Exception reading input XML (probably malformed XML) + throw new IOException(ex); + } catch (NoSuchFileException ex) { + throw new ConfigException(MessageFormat.format(I18N.getString( + "error.foreign-app-image"), appImageDir), null); + } catch (InavlidAppImageFileException ex) { + // Invalid input XML + throw new ConfigException(MessageFormat.format(I18N.getString( + "error.invalid-app-image"), appImageDir), null); + } + } + + static Stream queryNodes(Node xml, XPath xPath, String xpathExpr) throws XPathExpressionException { + NodeList nodes = (NodeList) xPath.evaluate(xpathExpr, xml, XPathConstants.NODESET); + return Optional.ofNullable(nodes).map(AppImageFile2::toStream).orElseGet(Stream::of); + } + + static Stream toStream(NodeList nodes) { + return Optional.ofNullable(nodes).map(v -> { + return IntStream.range(0, v.getLength()).mapToObj(v::item); + }).orElseGet(Stream::of); + } + + static Stream toStream(NamedNodeMap nodes) { + return Optional.ofNullable(nodes).map(v -> { + return IntStream.range(0, v.getLength()).mapToObj(v::item); + }).orElseGet(Stream::of); + } + + private static String getVersion() { + return System.getProperty("java.version"); + } + + private static String getPlatform() { + return PLATFORM_LABELS.get(OperatingSystem.current()); + } + + private final static class AppImageProperties { + private AppImageProperties(Map data, Set stdKeys) { + this.data = data; + this.stdKeys = stdKeys; + } + + static AppImageProperties main(Document xml, XPath xPath) throws XPathExpressionException { + var data = queryNodes(xml, xPath, "/jpackage-state/*/text()").map(node -> { + return Map.entry(node.getParentNode().getNodeName(), node.getNodeValue()); + }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a)); + return new AppImageProperties(data, Set.of("app-version", "main-launcher", "main-class")); + } + + static AppImageProperties launcher(Node node) { + var data = toStream(node.getAttributes()).map(attrNode -> { + return Map.entry(attrNode.getNodeName(), attrNode.getNodeValue()); + }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); + return new AppImageProperties(data, Set.of("name", "service")); + } + + static List launchers(Document xml, XPath xPath) + throws XPathExpressionException { + return queryNodes(xml, xPath, "/jpackage-state/add-launcher").map( + AppImageProperties::launcher).toList(); + } + + String get(String name) { + return Optional.ofNullable(data.get(name)).orElseThrow( + InavlidAppImageFileException::new); + } + + Map getExtra() { + Map extra = new HashMap<>(data); + stdKeys.forEach(extra::remove); + return extra; + } + + private final Map data; + private final Set stdKeys; + } + + static record LauncherInfo(String name, boolean service, Map extra) { + LauncherInfo { + if (name == null || name.isBlank()) { + throw new InavlidAppImageFileException(); + } + } + } + + private static class InavlidAppImageFileException extends RuntimeException { + private static final long serialVersionUID = 1L; + } + + private final String appVersion; + private final String launcherName; + private final String mainClass; + private final Map extra; + private final List addLauncherInfos; + private final String creatorVersion; + private final String creatorPlatform; + + private static final String FILENAME = ".jpackage.xml"; + + private static final Map PLATFORM_LABELS = Map.of( + OperatingSystem.LINUX, "linux", + OperatingSystem.WINDOWS, "windows", + OperatingSystem.MACOS, "macOS"); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java index 3edb7de4540a1..b8085ba260a98 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java @@ -28,9 +28,9 @@ import java.text.MessageFormat; import java.util.Date; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.function.Function; -import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; @@ -46,6 +46,17 @@ interface Application { String copyright(); + List srcDirs(); + + default Path mainSrcDir() { + return srcDirs().getFirst(); + } + + default List additionalSrcDirs() { + var srcDirs = srcDirs(); + return srcDirs.subList(1, srcDirs.size()); + } + RuntimeBuilder runtimeBuilder(); default Path appImageDirName() { @@ -59,16 +70,33 @@ default Path appImageDirName() { } } - Launcher mainLauncher(); + List launchers(); + + default Launcher mainLauncher() { + return Optional.ofNullable(launchers()).map(launchers -> { + Launcher launcher; + if (launchers.isEmpty()) { + launcher = null; + } else { + launcher = launchers.getFirst(); + } + return launcher; + }).orElse(null); + } + + default List additionalLaunchers() { + return Optional.ofNullable(launchers()).map(launchers -> { + return launchers.subList(1, launchers.size()); + }).orElseGet(List::of); + } default boolean isRuntime() { return mainLauncher() == null; } - List additionalLaunchers(); - default boolean isService() { - return allLaunchers().stream().filter(Launcher::isService).findAny().isPresent(); + return Optional.ofNullable(launchers()).orElseGet(List::of).stream().filter( + Launcher::isService).findAny().isPresent(); } default ApplicationLayout appLayout() { @@ -79,10 +107,8 @@ default ApplicationLayout appLayout() { } } - default List allLaunchers() { - return Optional.ofNullable(mainLauncher()).map(main -> { - return Stream.concat(Stream.of(main), additionalLaunchers().stream()).toList(); - }).orElse(List.of()); + default Map extraAppImageData() { + return Map.of(); } default OverridableResource createLauncherIconResource(Launcher launcher, String defaultIconName, @@ -115,11 +141,13 @@ default OverridableResource createLauncherIconResource(Launcher launcher, String return resource; } - static record Impl(String name, String description, String version, String vendor, - String copyright, RuntimeBuilder runtimeBuilder, Launcher mainLauncher, - List additionalLaunchers) implements Application { - public Impl { - name = Optional.ofNullable(name).orElseGet(mainLauncher::name); + static record Impl(String name, String description, String version, + String vendor, String copyright, List srcDirs, + RuntimeBuilder runtimeBuilder, List launchers) implements Application { + public Impl { + name = Optional.ofNullable(name).orElseGet(() -> { + return mainLauncher().name(); + }); description = Optional.ofNullable(description).orElseGet(Defaults.INSTANCE::description); version = Optional.ofNullable(version).orElseGet(Defaults.INSTANCE::version); vendor = Optional.ofNullable(vendor).orElseGet(Defaults.INSTANCE::vendor); @@ -166,19 +194,62 @@ public String copyright() { return target.copyright(); } + @Override + public List srcDirs() { + return target.srcDirs(); + } + @Override public RuntimeBuilder runtimeBuilder() { return target.runtimeBuilder(); } @Override - public Launcher mainLauncher() { - return target.mainLauncher(); + public List launchers() { + return target.launchers(); + } + } + + static class Unsupported implements Application { + + @Override + public String name() { + throw new UnsupportedOperationException(); + } + + @Override + public String description() { + throw new UnsupportedOperationException(); + } + + @Override + public String version() { + throw new UnsupportedOperationException(); + } + + @Override + public String vendor() { + throw new UnsupportedOperationException(); + } + + @Override + public String copyright() { + throw new UnsupportedOperationException(); + } + + @Override + public List srcDirs() { + throw new UnsupportedOperationException(); + } + + @Override + public RuntimeBuilder runtimeBuilder() { + throw new UnsupportedOperationException(); } @Override - public List additionalLaunchers() { - return target.additionalLaunchers(); + public List launchers() { + throw new UnsupportedOperationException(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java index 9c5f79dc4de44..9c5b1fb4be980 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java @@ -24,7 +24,7 @@ */ package jdk.jpackage.internal; -import java.util.Collections; +import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -33,14 +33,14 @@ import java.util.stream.Stream; import jdk.jpackage.internal.Functional.ThrowingFunction; import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; +import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.COPYRIGHT; import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; -import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; -import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; +import static jdk.jpackage.internal.StandardBundlerParam.SOURCE_DIR; import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; @@ -49,12 +49,14 @@ final class ApplicationFromParams { static Application create(Map params, - Function, Launcher> launcherSupplier) throws ConfigException { + Function, Launcher> launcherSupplier) throws ConfigException, IOException { var name = APP_NAME.fetchFrom(params); var description = DESCRIPTION.fetchFrom(params); var version = VERSION.fetchFrom(params); var vendor = VENDOR.fetchFrom(params); var copyright = COPYRIGHT.fetchFrom(params); + var srcDir = SOURCE_DIR.fetchFrom(params); + var additionalContent = APP_CONTENT.fetchFrom(params); var predefinedAppImage = getPredefinedAppImage(params); if (name == null && predefinedAppImage == null) { @@ -74,20 +76,21 @@ static Application create(Map params, } else if (predefinedAppImage != null) { runtimeBuilder = null; - AppImageFile appImage = AppImageFile.load(predefinedAppImage); + var appImage = AppImageFile2.load(predefinedAppImage); version = appImage.getAppVersion(); mainLauncher = launcherSupplier.apply(mergeParams(params, Map.of(APP_NAME.getID(), appImage.getLauncherName(), DESCRIPTION.getID(), description))); additionalLaunchers = appImage.getAddLaunchers().stream().map(li -> { - return launcherSupplier.apply(mergeParams(params, Map.of(APP_NAME.getID(), li - .getName(), SHORTCUT_HINT.getID(), li.isShortcut(), MENU_HINT.getID(), li - .isMenu(), LAUNCHER_AS_SERVICE.getID(), li.isService()))); + Map launcherParams = new HashMap<>(); + launcherParams.put(APP_NAME.getID(), li.name()); + launcherParams.put(LAUNCHER_AS_SERVICE.getID(), Boolean.toString(li.service())); + launcherParams.putAll(li.extra()); + return launcherSupplier.apply(mergeParams(params, launcherParams)); }).toList(); } else { - var launchers = Optional.ofNullable(ADD_LAUNCHERS.fetchFrom(params)).orElseGet( - Collections::emptyList); + var launchers = Optional.ofNullable(ADD_LAUNCHERS.fetchFrom(params)).orElseGet(List::of); mainLauncher = launcherSupplier.apply(params); additionalLaunchers = launchers.stream().map(launcherParams -> { return launcherSupplier.apply(mergeParams(params, launcherParams)); @@ -99,15 +102,21 @@ static Application create(Map params, runtimeBuilder = RuntimeBuilderFromParams.create(params, startupInfos); } - return new Application.Impl(name, description, version, vendor, copyright, runtimeBuilder, - mainLauncher, additionalLaunchers); + List launchers = Optional.ofNullable(mainLauncher).map(v -> { + return Stream.concat(Stream.of(v), additionalLaunchers.stream()).toList(); + }).orElse(null); + + return new Application.Impl(name, description, version, vendor, + copyright, Stream.concat(Stream.of(srcDir), + additionalContent.stream()).toList(), runtimeBuilder, + launchers); } private static Map mergeParams(Map mainParams, Map launcherParams) { if (!launcherParams.containsKey(DESCRIPTION.getID())) { launcherParams = new HashMap<>(launcherParams); -// FIXME: this is a good improvement but it fails existing tests +// FIXME: this is a good improvement but it fails existing tests // launcherParams.put(DESCRIPTION.getID(), String.format("%s (%s)", DESCRIPTION.fetchFrom( // mainParams), APP_NAME.fetchFrom(launcherParams))); launcherParams.put(DESCRIPTION.getID(), DESCRIPTION.fetchFrom(mainParams)); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java index 884dcd1e623d0..5e14d166e94fa 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java @@ -24,8 +24,11 @@ */ package jdk.jpackage.internal; +import java.io.InputStream; import java.nio.file.Path; import java.util.List; +import java.util.Map; +import jdk.jpackage.internal.resources.ResourceLocator; interface Launcher { @@ -43,14 +46,25 @@ default Path executableName() { String description(); + default InputStream executableResource() { + return ResourceLocator.class.getResourceAsStream("jpackageapplauncher"); + } + + default Map extraAppImageData() { + return Map.of(); + } + /** - * Null for the default or resource directory icon, empty path for no icon, other value for - * custom icon. + * Returns path to icon to assign for the launcher. + * + * Null for the default or resource directory icon, empty path for no icon, + * other value for custom icon. */ Path icon(); static record Impl(String name, LauncherStartupInfo startupInfo, - List fileAssociations, boolean isService, String description, Path icon) implements Launcher { + List fileAssociations, boolean isService, + String description, Path icon) implements Launcher { } @@ -90,4 +104,37 @@ public Path icon() { return target.icon(); } } + + static class Unsupported implements Launcher { + + @Override + public String name() { + throw new UnsupportedOperationException(); + } + + @Override + public LauncherStartupInfo startupInfo() { + throw new UnsupportedOperationException(); + } + + @Override + public List fileAssociations() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isService() { + throw new UnsupportedOperationException(); + } + + @Override + public String description() { + throw new UnsupportedOperationException(); + } + + @Override + public Path icon() { + throw new UnsupportedOperationException(); + } + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index 48824869d8dba..98a52b604f259 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -40,6 +40,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Stream; +import jdk.jpackage.internal.Functional.ThrowingFunction; import static jdk.jpackage.internal.RuntimeBuilder.getDefaultModulePath; /** @@ -102,8 +103,9 @@ final class StandardBundlerParam { if (isRuntimeInstaller(params)) { return null; } else if (hasPredefinedAppImage(params)) { - return AppImageFile.extractMainClass( - getPredefinedAppImage(params)); + return ThrowingFunction.toFunction( + AppImageFile2::load).apply( + getPredefinedAppImage(params)).getMainClass(); } return LAUNCHER_DATA.fetchFrom(params).qualifiedClassName(); }, @@ -144,7 +146,8 @@ final class StandardBundlerParam { Path appImage = PREDEFINED_APP_IMAGE.fetchFrom(params); String appName = NAME.fetchFrom(params); if (appImage != null) { - String name = AppImageFile.extractAppName(appImage); + String name = ThrowingFunction.toFunction( + AppImageFile2::load).apply(appImage).getLauncherName(); appName = (name != null) ? name : appName; } else if (appName == null) { String s = MAIN_CLASS.fetchFrom(params); diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java index e717e0b46c42c..233603291390c 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java @@ -46,8 +46,7 @@ class UnixLaunchersAsServices extends ShellCustomAction { this.requiredPackages = requiredPackages; // Read launchers information - launchers = app.allLaunchers().stream().filter(Launcher::isService).map(factory::apply) - .toList(); + launchers = app.launchers().stream().filter(Launcher::isService).map(factory::apply).toList(); } @Override diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java index 18ae547f16995..6c2178838515e 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java @@ -24,8 +24,10 @@ */ package jdk.jpackage.internal; +import java.io.InputStream; import java.nio.file.Path; import java.util.Set; +import jdk.jpackage.internal.resources.ResourceLocator; interface WinLauncher extends Launcher { @@ -36,6 +38,12 @@ default Path executableName() { boolean isConsole(); + @Override + default InputStream executableResource() { + return ResourceLocator.class.getResourceAsStream( + isConsole() ? "jpackageapplauncher.exe" : "jpackageapplauncherw.exe"); + } + enum WinShortcut { WinShortcutDesktop, WinShortcutStartMenu diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index 227f6b6e7ca63..df50461a67712 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -95,7 +95,7 @@ void initFromParams(Workshop workshop, WinMsiPackage pkg) { installedAppImage = pkg.appLayout().resolveAt(INSTALLDIR); - launchers = toCollection(pkg.app().allLaunchers()); + launchers = toCollection(pkg.app().launchers()); shortcutFolders = ShortcutsFolder.getForPackage(pkg); @@ -187,7 +187,7 @@ private Path getInstalledFaIcoPath(FileAssociation fa) { } private void initFileAssociations(WinMsiPackage pkg) { - var allFileAssociations = pkg.app().allLaunchers().stream().map(Launcher::fileAssociations) + var allFileAssociations = pkg.app().launchers().stream().map(Launcher::fileAssociations) .flatMap(List::stream).toList(); associations = allFileAssociations.stream() .peek(this::normalizeFileAssociation) @@ -929,7 +929,7 @@ String getWixVariableName() { } static Set getForPackage(WinMsiPackage pkg) { - return pkg.app().allLaunchers().stream().map(launcher -> { + return pkg.app().launchers().stream().map(launcher -> { return Stream.of(ShortcutsFolder.values()).filter(shortcutsFolder -> { return shortcutsFolder.isRequestedFor((WinLauncher)launcher); }); From 6e35a77b95c18e57277aa7c452df2c25eeee6165 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 16:44:05 -0400 Subject: [PATCH 0034/1101] Fix BasicTest.testTemp() rpm test --- .../linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index 778110066670e..ec4ef9f07025d 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -191,7 +191,7 @@ private Path buildRPM(Workshop workshop, Package pkg, Path outdir) throws IOExce TOOL_RPMBUILD, "-bb", specFile(workshop, pkg).toAbsolutePath().toString(), "--define", String.format("%%_sourcedir %s", - workshop.appImageDir()), + workshop.appImageDir().toAbsolutePath()), // save result to output dir "--define", String.format("%%_rpmdir %s", rpmFile.getParent()), // do not use other system directories to build as current user From e6e514dc93e3655c134733a0510209df26e03f2f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 16:58:37 -0400 Subject: [PATCH 0035/1101] Split Launcher.executableName() into Launcher.executableName(), Launcher.executableSuffix(), and Launcher.executableNameWithSuffix(). Fix DotInNameTest.java test --- .../jdk/jpackage/internal/DesktopIntegration.java | 6 +++--- .../jpackage/internal/LinuxAppImageBuilder2.java | 5 +++-- .../jpackage/internal/LinuxLaunchersAsServices.java | 3 +-- .../jdk/jpackage/internal/AppImageBuilder.java | 3 ++- .../classes/jdk/jpackage/internal/CfgFile.java | 6 +++--- .../classes/jdk/jpackage/internal/Launcher.java | 13 +++++++++++-- .../classes/jdk/jpackage/internal/WinLauncher.java | 5 ++--- .../jdk/jpackage/internal/WinMsiBundler.java | 4 ++-- .../internal/WixAppImageFragmentBuilder.java | 5 +++-- 9 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 0811fa935294f..cf23f0e0a2f85 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -233,9 +233,9 @@ private Map createDataForDesktopFile() { data.put("APPLICATION_ICON", Optional.ofNullable(iconFile).map( f -> f.installPath().toString()).orElse(null)); data.put("DEPLOY_BUNDLE_CATEGORY", pkg.category()); - data.put("APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo(pkg - .installedPackageLayout().launchersDirectory().resolve(launcher.executableName()) - .toString())); + data.put("APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo( + pkg.installedPackageLayout().launchersDirectory().resolve( + launcher.executableNameWithSuffix()).toString())); return data; } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder2.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder2.java index b776204794e29..0ecbe859bbcb3 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder2.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder2.java @@ -61,9 +61,10 @@ void execute(Workshop workshop) throws IOException, PackagerException { var iconResource = app.createLauncherIconResource(launcher, DEFAULT_ICON, workshop::createResource); if (iconResource != null) { + String iconFileName = launcher.executableName() + IOUtils.getSuffix( + Path.of(DEFAULT_ICON)); Path iconTarget = resolvedAppLayout.destktopIntegrationDirectory().resolve( - IOUtils.replaceSuffix(launcher.executableName(), - IOUtils.getSuffix(Path.of(DEFAULT_ICON)))); + iconFileName); iconResource.saveToFile(iconTarget); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java index 8720c594d6944..f32c488339f3f 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java @@ -75,8 +75,7 @@ private static class LauncherImpl extends UnixLauncherAsService { workshop.createResource("unit-template.service").setCategory( I18N.getString("resource.systemd-unit-file"))); - unitFilename = getServiceUnitFileName(pkg.packageName(), - launcher.executableName().toString()); + unitFilename = getServiceUnitFileName(pkg.packageName(), launcher.executableName()); getResource().setPublicName(unitFilename).addSubstitutionDataEntry( "APPLICATION_LAUNCHER", diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java index c1b4f69cb74ab..4643e2506fc8f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -86,7 +86,8 @@ void execute(Workshop workshop) throws IOException, PackagerException { for (var launcher : app.launchers()) { // Copy executable to launchers folder - Path executableFile = resolvedAppLayout.launchersDirectory().resolve(launcher.executableName()); + Path executableFile = resolvedAppLayout.launchersDirectory().resolve( + launcher.executableNameWithSuffix()); try (var in = launcher.executableResource()) { Files.createDirectories(executableFile.getParent()); Files.copy(in, executableFile); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java index fdf45e4865027..54e0c4d2ead87 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java @@ -40,7 +40,7 @@ final class CfgFile { CfgFile(Application app, Launcher launcher) { startupInfo = launcher.startupInfo(); - executableName = launcher.executableName(); + outputFileName = launcher.executableName() + ".cfg"; version = app.version(); } @@ -101,7 +101,7 @@ void create(ApplicationLayout unresolvedAppLayout, ApplicationLayout appLayout) } } - Path cfgFile = appLayout.appDirectory().resolve(IOUtils.replaceSuffix(executableName, ".cfg")); + Path cfgFile = appLayout.appDirectory().resolve(outputFileName); Files.createDirectories(cfgFile.getParent()); boolean[] addLineBreakAtSection = new boolean[1]; @@ -129,7 +129,7 @@ private ApplicationLayout createAppCfgLayout(ApplicationLayout appLayout) { private final LauncherStartupInfo startupInfo; private final String version; - private final Path executableName; + private final String outputFileName; private static final Object SECTION_TAG = new Object(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java index 5e14d166e94fa..f6845e3df925d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java @@ -28,14 +28,23 @@ import java.nio.file.Path; import java.util.List; import java.util.Map; +import java.util.Optional; import jdk.jpackage.internal.resources.ResourceLocator; interface Launcher { String name(); - default Path executableName() { - return Path.of(name()); + default String executableName() { + return name(); + } + + default String executableSuffix() { + return null; + } + + default String executableNameWithSuffix() { + return executableName() + Optional.ofNullable(executableSuffix()).orElse(""); } LauncherStartupInfo startupInfo(); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java index 6c2178838515e..58fbbfd17388c 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java @@ -25,15 +25,14 @@ package jdk.jpackage.internal; import java.io.InputStream; -import java.nio.file.Path; import java.util.Set; import jdk.jpackage.internal.resources.ResourceLocator; interface WinLauncher extends Launcher { @Override - default Path executableName() { - return Path.of(name() + ".exe"); + default String executableSuffix() { + return ".exe"; } boolean isConsole(); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 2827dca550c8f..e0ee2ff9b01d5 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -228,8 +228,8 @@ private void prepareProto(Map params) // Java Runtime image. installerIcon = pkgLayout.runtimeDirectory().resolve(Path.of("bin", "java.exe")); } else { - installerIcon = pkgLayout.launchersDirectory().resolve(pkg.app().mainLauncher() - .executableName()); + installerIcon = pkgLayout.launchersDirectory().resolve( + pkg.app().mainLauncher().executableNameWithSuffix()); new PackageFile(pkg.packageName()).save(pkgLayout); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index df50461a67712..62b80c2184a85 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -102,7 +102,8 @@ void initFromParams(Workshop workshop, WinMsiPackage pkg) { launchersAsServices = launchers.stream() .filter(Launcher::isService) .map(launcher -> { - var launcherPath = installedAppImage.launchersDirectory().resolve(launcher.executableName()); + var launcherPath = installedAppImage.launchersDirectory().resolve( + launcher.executableNameWithSuffix()); var id = Id.File.of(launcherPath); return new WixLauncherAsService(launcher, workshop::createResource) .setLauncherInstallPath(toWixPath(launcherPath)) @@ -456,7 +457,7 @@ private void addShortcutComponentGroup(XMLStreamWriter xml) throws for (var launcher : launchers) { for (var folder : shortcutFolders) { Path launcherPath = installedAppImage.launchersDirectory().resolve( - launcher.executableName()); + launcher.executableNameWithSuffix()); if (folder.isRequestedFor(launcher)) { String componentId = addShortcutComponent(xml, launcherPath, folder); From fdf5b77c88a85b04a35c3ba0a40c0b0c2dccbbfb Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 16:59:02 -0400 Subject: [PATCH 0036/1101] Add missing @Override --- .../linux/classes/jdk/jpackage/internal/LinuxLauncher.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java index a9345e78b80e2..fcf9a2ff87654 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java @@ -31,6 +31,7 @@ interface LinuxLauncher extends Launcher { Optional shortcut(); + @Override default Map extraAppImageData() { return shortcut().map(v -> { return Map.of("shortcut", Boolean.toString(v)); From ae55cbe021abe00c71329d52928091db1a66a13a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 20:15:27 -0400 Subject: [PATCH 0037/1101] Check main jar is added to the app image at the correct location --- .../jpackage/helpers/jdk/jpackage/test/JPackageCommand.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index fd62d6c7d8820..70019dfde7016 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -830,6 +830,11 @@ JPackageCommand assertAppLayout() { TKit.assertFileExists(appRuntimeDirectory().resolve( "Contents/MacOS/libjli.dylib")); } + + var mainJar = getArgumentValue("--main-jar"); + if (mainJar != null) { + TKit.assertFileExists(appLayout().appDirectory().resolve(mainJar)); + } } return this; From 0e7d045e4b2494e973b434697e50282a865b6126 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 20:17:21 -0400 Subject: [PATCH 0038/1101] Rework InstallableFile --- .../internal/LinuxPackageBundler.java | 8 ++-- .../jpackage/internal/InstallableFile.java | 41 ++++--------------- .../jdk/jpackage/internal/PathGroup.java | 4 ++ .../internal/WixAppImageFragmentBuilder.java | 5 +-- 4 files changed, 18 insertions(+), 40 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index d631c0c68b876..9575199e8ca1a 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -119,7 +119,7 @@ public Path appImageDir() { } else { Path srcAppImageDir = pkg.predefinedAppImage(); if (srcAppImageDir == null) { - // No predefined app image and no runtime builder. + // No predefined app image and no runtime builder. // This should be runtime packaging. if (pkg.app().isRuntime()) { srcAppImageDir = workshop.appImageDir(); @@ -130,9 +130,9 @@ public Path appImageDir() { } // Copy app layout omitting application image info file. - ApplicationLayout srcLayout = pkg.appLayout().resolveAt(srcAppImageDir); - srcLayout.pathGroup().setPath(new Object(), - AppImageFile.getPathInAppImage(srcAppImageDir)); + var srcLayout = pkg.appLayout().resolveAt(srcAppImageDir); + srcLayout.pathGroup().ghostPath(AppImageFile.getPathInAppImage( + srcAppImageDir)); srcLayout.copy(pkg.packageLayout().resolveAt(pkgWorkshop.appImageDir())); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java index c5128fa5dd017..52d15c9881775 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java @@ -25,38 +25,13 @@ package jdk.jpackage.internal; import java.nio.file.Path; -import java.util.Objects; -final class InstallableFile { - - InstallableFile(Path srcPath, Path installPath) { - Objects.requireNonNull(srcPath); - - this.srcPath = srcPath; - this.installPath = installPath; - } - - Path installPath() { - return installPath; - } - - Path srcPath() { - return srcPath; - } - - void applyToApplicationLayouts(ApplicationLayout src, - ApplicationLayout install) { - var key = new Object(); - src.pathGroup().setPath(key, srcPath); - if (installPath != null && install != null) { - install.pathGroup().setPath(key, installPath); - } - } - - void excludeFromApplicationLayout(ApplicationLayout layout) { - applyToApplicationLayouts(layout, null); - } - - private final Path installPath; - private final Path srcPath; +/** + * Source file that should be copied somewhere in application image tree. + * + * Has two paths: + * - path where it should be picked from; + * - path where it should be copied in application image; + */ +record InstallableFile(Path srcPath, Path installPath) { } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java index c32e0b5248075..58e23b5a6a2be 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java @@ -62,6 +62,10 @@ void setPath(Object id, Path path) { } } + void ghostPath(Path path) { + setPath(new Object(), path); + } + /** * All configured IDs. */ diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index 62b80c2184a85..fc55cd55a9e5a 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -83,9 +83,8 @@ void initFromParams(Workshop workshop, WinMsiPackage pkg) { do { ApplicationLayout layout = pkg.appLayout(); - // Don't want AppImageFile.FILENAME in installed application. - new InstallableFile(AppImageFile.getPathInAppImage(Path.of("")), - null).excludeFromApplicationLayout(layout); + // Don't want app image info file in installed application. + layout.pathGroup().ghostPath(AppImageFile.getPathInAppImage(Path.of(""))); // Want absolute paths to source files in generated WiX sources. // This is to handle scenario if sources would be processed from From b31c28f47f60f2e9d61d1f64ca9f7c630adc5e96 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 20:18:42 -0400 Subject: [PATCH 0039/1101] Remove DesktopFile class --- .../jpackage/internal/DesktopIntegration.java | 54 +++++++------------ 1 file changed, 20 insertions(+), 34 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index cf23f0e0a2f85..01fe1e1708810 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -102,11 +102,11 @@ private DesktopIntegration(Workshop workshop, LinuxPackage pkg, LinuxLauncher la final String mimeInfoFileName = String.format("%s-%s-MimeInfo.xml", pkg.packageName(), escapedAppFileName); - mimeInfoFile = new DesktopFile(mimeInfoFileName); + mimeInfoFile = createDesktopFile(mimeInfoFileName); if (withDesktopFile) { - desktopFile = new DesktopFile(desktopFileName); - iconFile = new DesktopFile(escapedAppFileName + desktopFile = createDesktopFile(desktopFileName); + iconFile = createDesktopFile(escapedAppFileName + IOUtils.getSuffix(Path.of(DEFAULT_ICON))); if (curIconResource == null) { @@ -170,7 +170,7 @@ protected Map createImpl() throws IOException { final ShellCommands shellCommands; if (desktopFile != null) { // Create application desktop description file. - createDesktopFile(data); + saveDesktopFile(data); // Shell commands will be created only if desktop file // should be installed. @@ -328,32 +328,18 @@ void applyTo(Map data) { } /** - * Desktop integration file. xml, icon, etc. - * Resides somewhere in application installation tree. - * Has two paths: - * - path where it should be placed at package build time; - * - path where it should be installed by package manager; + * Creates desktop integration file. xml, icon, etc. + * + * Returned instance: + * - srcPath(): path where it should be placed at package build time; + * - installPath(): path where it should be installed by package manager; */ - private class DesktopFile { - - DesktopFile(String fileName) { - var installPath = pkg.installedPackageLayout() - .destktopIntegrationDirectory().resolve(fileName); - var srcPath = pkg.packageLayout().resolveAt(workshop.appImageDir()) - .destktopIntegrationDirectory().resolve(fileName); - - impl = new InstallableFile(srcPath, installPath); - } - - Path installPath() { - return impl.installPath(); - } - - Path srcPath() { - return impl.srcPath(); - } - - private final InstallableFile impl; + private InstallableFile createDesktopFile(String fileName) { + var srcPath = pkg.packageLayout().resolveAt(workshop.appImageDir()).destktopIntegrationDirectory().resolve( + fileName); + var installPath = pkg.installedPackageLayout().destktopIntegrationDirectory().resolve( + fileName); + return new InstallableFile(srcPath, installPath); } private void appendFileAssociation(XMLStreamWriter xml, @@ -411,7 +397,7 @@ private void addFileAssociationIconFiles(ShellCommands shellCommands) processedMimeTypes.add(mimeType); // Create icon name for mime type from mime type. - DesktopFile faIconFile = new DesktopFile(mimeType.replace( + var faIconFile = createDesktopFile(mimeType.replace( File.separatorChar, '-') + IOUtils.getSuffix( assoc.data.iconPath)); @@ -424,7 +410,7 @@ private void addFileAssociationIconFiles(ShellCommands shellCommands) } } - private void createDesktopFile(Map data) throws IOException { + private void saveDesktopFile(Map data) throws IOException { List mimeTypes = getMimeTypeNamesFromFileAssociations(); data.put("DESKTOP_MIMES", "MimeType=" + String.join(";", mimeTypes)); @@ -500,9 +486,9 @@ private static class LinuxFileAssociation { private final OverridableResource iconResource; private final OverridableResource desktopFileResource; - private final DesktopFile mimeInfoFile; - private final DesktopFile desktopFile; - private final DesktopFile iconFile; + private final InstallableFile mimeInfoFile; + private final InstallableFile desktopFile; + private final InstallableFile iconFile; private final List nestedIntegrations; From ab7269415c5f0037b2407fd9d2a5cb69cca34408 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 20:21:21 -0400 Subject: [PATCH 0040/1101] Fix BasicTest.testWhitespaceInPaths() test --- .../share/classes/jdk/jpackage/internal/CfgFile.java | 4 ++-- .../jdk/jpackage/internal/LauncherJarStartupInfo.java | 10 ++++------ .../jdk/jpackage/internal/LauncherStartupInfo.java | 11 ++++++----- .../internal/LauncherStartupInfoFromParams.java | 6 ++++-- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java index 54e0c4d2ead87..c61b2f5a1e7a0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java @@ -56,7 +56,7 @@ void create(ApplicationLayout unresolvedAppLayout, ApplicationLayout appLayout) + "/" + startupInfo.qualifiedClassName())); } else if (startupInfo instanceof LauncherJarStartupInfo jarStartupInfo) { Path mainJarPath = appCfgLayout.appDirectory().resolve( - jarStartupInfo.jarPath().getFileName()); + jarStartupInfo.jarPath().installPath()); if (jarStartupInfo.isClassNameFromMainJar()) { content.add(Map.entry("app.mainjar", mainJarPath)); @@ -73,7 +73,7 @@ void create(ApplicationLayout unresolvedAppLayout, ApplicationLayout appLayout) for (var value : Optional.ofNullable(startupInfo.classPath()).orElseGet(List::of)) { content.add(Map.entry("app.classpath", - appCfgLayout.appDirectory().resolve(value).toString())); + appCfgLayout.appDirectory().resolve(value.installPath()).toString())); } content.add(Map.entry("[JavaOptions]", SECTION_TAG)); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java index 464ba7f9f8785..5456c2334c962 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java @@ -24,24 +24,22 @@ */ package jdk.jpackage.internal; -import java.nio.file.Path; - interface LauncherJarStartupInfo extends LauncherStartupInfo { - Path jarPath(); + InstallableFile jarPath(); boolean isClassNameFromMainJar(); final static class Impl extends LauncherStartupInfo.Proxy implements LauncherJarStartupInfo { - Impl(LauncherStartupInfo target, Path jarPath, boolean isClassNameFromMainJar) { + Impl(LauncherStartupInfo target, InstallableFile jarPath, boolean isClassNameFromMainJar) { super(target); this.jarPath = jarPath; this.isClassNameFromMainJar = isClassNameFromMainJar; } @Override - public Path jarPath() { + public InstallableFile jarPath() { return jarPath; } @@ -50,7 +48,7 @@ public boolean isClassNameFromMainJar() { return isClassNameFromMainJar; } - private final Path jarPath; + private final InstallableFile jarPath; private final boolean isClassNameFromMainJar; } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java index 7e93e2a0f974f..a013ad6f63ce3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java @@ -43,11 +43,12 @@ default String packageName() { List defaultParameters(); - List classPath(); + List classPath(); record Impl(String qualifiedClassName, List javaOptions, - List defaultParameters, List classPath) implements - LauncherStartupInfo { + List defaultParameters, List classPath) + implements LauncherStartupInfo { + } static class Proxy extends ProxyBase @@ -73,7 +74,7 @@ public List defaultParameters() { } @Override - public List classPath() { + public List classPath() { return target.classPath(); } } @@ -96,7 +97,7 @@ public List defaultParameters() { } @Override - public List classPath() { + public List classPath() { throw new UnsupportedOperationException(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java index c1171da601d56..14df460647a65 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java @@ -36,7 +36,7 @@ static LauncherStartupInfo create(Map params) { var javaOptions = JAVA_OPTIONS.fetchFrom(params); var arguments = ARGUMENTS.fetchFrom(params); var classpath = launcherData.classPath().stream().map(p -> { - return inputDir.resolve(p).toAbsolutePath(); + return new InstallableFile(inputDir.resolve(p), p); }).toList(); var startupInfo = new LauncherStartupInfo.Impl( @@ -48,7 +48,9 @@ static LauncherStartupInfo create(Map params) { launcherData.moduleName(), launcherData.modulePath()); } else { return new LauncherJarStartupInfo.Impl(startupInfo, - inputDir.resolve(launcherData.mainJarName()), + new InstallableFile(inputDir.resolve( + launcherData.mainJarName()), + launcherData.mainJarName()), launcherData.isClassNameFromMainJar()); } } From 148fb8ef591c7edf086c9cd50525dcbe01e1aef2 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 22:42:43 -0400 Subject: [PATCH 0041/1101] Bugfix --- .../jdk/jpackage/test/JPackageCommand.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 70019dfde7016..b4ffae0bff29b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -224,7 +224,7 @@ public String installerName() { String installerName = getArgumentValue("--name", () -> getArgumentValue("--main-class", () -> null)); if (installerName == null) { - String appImage = getArgumentValue("--app-image"); + String appImage = getArgumentValue("--app-image", () -> null); if (appImage != null) { installerName = AppImageFile.extractAppName(Path.of(appImage)); } @@ -301,12 +301,9 @@ public JPackageCommand setFakeRuntime() { public void createJPackageXMLFile(String mainLauncher, String mainClass) throws IOException { - Path jpackageXMLFile = AppImageFile.getPathInAppImage( - Optional.ofNullable(getArgumentValue("--app-image")).map( - Path::of).orElseThrow(() -> { - return new RuntimeException( - "Error: --app-image expected"); - })); + Path jpackageXMLFile = AppImageFile.getPathInAppImage(getArgumentValue("--app-image", () -> { + throw new RuntimeException("Error: --app-image expected"); + }, Path::of)); IOUtils.createXml(jpackageXMLFile, xml -> { xml.writeStartElement("jpackage-state"); @@ -831,7 +828,7 @@ JPackageCommand assertAppLayout() { "Contents/MacOS/libjli.dylib")); } - var mainJar = getArgumentValue("--main-jar"); + var mainJar = getArgumentValue("--main-jar", () -> null); if (mainJar != null) { TKit.assertFileExists(appLayout().appDirectory().resolve(mainJar)); } @@ -843,7 +840,7 @@ JPackageCommand assertAppLayout() { private void assertAppImageFile() { Path appImageDir = Path.of(""); if (isImagePackageType() && hasArgument("--app-image")) { - appImageDir = Path.of(getArgumentValue("--app-image", () -> null)); + appImageDir = Path.of(getArgumentValue("--app-image")); } final Path lookupPath = AppImageFile.getPathInAppImage(appImageDir); @@ -883,8 +880,7 @@ private void assertPackageFile() { assertFileInAppImage(lookupPath, null); } else { if (TKit.isOSX() && hasArgument("--app-image")) { - String appImage = getArgumentValue("--app-image", - () -> null); + String appImage = getArgumentValue("--app-image"); if (AppImageFile.load(Path.of(appImage)).isSigned()) { assertFileInAppImage(lookupPath, null); } else { From 4bb7aff1794b7ef25f0a53c6a88c0485d9761a09 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Oct 2024 23:22:49 -0400 Subject: [PATCH 0042/1101] - extraAppImageData() -> extraAppImageFileData() - trailing whitespaces removed --- .../classes/jdk/jpackage/internal/LinuxLauncher.java | 2 +- .../jdk/jpackage/internal/LinuxRpmPackage.java | 2 +- .../jdk/jpackage/internal/MacApplication.java | 2 +- .../jdk/jpackage/internal/AppImageBundler.java | 2 +- .../classes/jdk/jpackage/internal/AppImageFile2.java | 12 ++++++------ .../classes/jdk/jpackage/internal/Application.java | 2 +- .../jdk/jpackage/internal/BundlerParamInfo.java | 4 ++-- .../jdk/jpackage/internal/InstallableFile.java | 4 ++-- .../classes/jdk/jpackage/internal/Launcher.java | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java index fcf9a2ff87654..59b2f0470f184 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java @@ -32,7 +32,7 @@ interface LinuxLauncher extends Launcher { Optional shortcut(); @Override - default Map extraAppImageData() { + default Map extraAppImageFileData() { return shortcut().map(v -> { return Map.of("shortcut", Boolean.toString(v)); }).orElseGet(Map::of); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java index 737fa71b0bf61..086ad2ce63ce8 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java @@ -45,7 +45,7 @@ public String licenseType() { private final String licenseType; } - + static record Defaults(String licenseType) { private final static Defaults INSTANCE = new Defaults(I18N.getString( diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplication.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplication.java index ef7b3bfe506ae..17a97dae080c6 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplication.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplication.java @@ -33,7 +33,7 @@ interface MacApplication extends Application { boolean appStore(); @Override - default Map extraAppImageData() { + default Map extraAppImageFileData() { return Map.of("signed", Boolean.toString(signed()), "app-store", Boolean.toString(appStore())); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java index 3a07d995a3cda..8aed59fbccafc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java @@ -177,7 +177,7 @@ private Path createAppBundle(Map params, AbstractAppImageBuilder appBuilder = appImageSupplier.apply(rootDirectory); if (!hasAppImage) { - app.runtimeBuilder().createRuntime(appBuilder.getAppLayout()); + app.runtimeBuilder().createRuntime(appBuilder.getAppLayout()); } appBuilder.prepareApplicationFiles(params); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index 471937ace6df1..3f597158f5a7a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -56,12 +56,12 @@ public final class AppImageFile2 { appVersion = app.version(); launcherName = app.mainLauncher().name(); mainClass = app.mainLauncher().startupInfo().qualifiedClassName(); - extra = app.extraAppImageData(); + extra = app.extraAppImageFileData(); creatorVersion = getVersion(); creatorPlatform = getPlatform(); addLauncherInfos = app.additionalLaunchers().stream().map(launcher -> { return new LauncherInfo(launcher.name(), launcher.isService(), - launcher.extraAppImageData()); + launcher.extraAppImageFileData()); }).toList(); for (var str : List.of(appVersion, launcherName, mainClass)) { @@ -213,7 +213,7 @@ public boolean isService() { } @Override - public Map extraAppImageData() { + public Map extraAppImageFileData() { return launcherProps.getExtra(); } }; @@ -232,7 +232,7 @@ public List launchers() { } @Override - public Map extraAppImageData() { + public Map extraAppImageFileData() { return props.getExtra(); } }); @@ -262,7 +262,7 @@ static Stream toStream(NodeList nodes) { return IntStream.range(0, v.getLength()).mapToObj(v::item); }).orElseGet(Stream::of); } - + static Stream toStream(NamedNodeMap nodes) { return Optional.ofNullable(nodes).map(v -> { return IntStream.range(0, v.getLength()).mapToObj(v::item); @@ -293,7 +293,7 @@ static AppImageProperties main(Document xml, XPath xPath) throws XPathExpression static AppImageProperties launcher(Node node) { var data = toStream(node.getAttributes()).map(attrNode -> { return Map.entry(attrNode.getNodeName(), attrNode.getNodeValue()); - }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); + }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); return new AppImageProperties(data, Set.of("name", "service")); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java index b8085ba260a98..47edfd8c17ebb 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java @@ -107,7 +107,7 @@ default ApplicationLayout appLayout() { } } - default Map extraAppImageData() { + default Map extraAppImageFileData() { return Map.of(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java index 26316a20d3dc6..73653cd9b2706 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java @@ -46,11 +46,11 @@ record BundlerParamInfo(String id, Class valueType, Function, T> defaultValueFunction, BiFunction, T> stringConverter) { - + static BundlerParamInfo createStringBundlerParam(String id) { return new BundlerParamInfo<>(id, String.class, null, null); } - + @SuppressWarnings({"unchecked", "rawtypes"}) static BundlerParamInfo createBundlerParam(String id, Functional.ThrowingFunction, T2> valueFunc) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java index 52d15c9881775..0cbbdcb427809 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java @@ -28,10 +28,10 @@ /** * Source file that should be copied somewhere in application image tree. - * + * * Has two paths: * - path where it should be picked from; * - path where it should be copied in application image; */ -record InstallableFile(Path srcPath, Path installPath) { +record InstallableFile(Path srcPath, Path installPath) { } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java index f6845e3df925d..ae7a93e70718f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java @@ -59,7 +59,7 @@ default InputStream executableResource() { return ResourceLocator.class.getResourceAsStream("jpackageapplauncher"); } - default Map extraAppImageData() { + default Map extraAppImageFileData() { return Map.of(); } From dea0f0f285d77871da7d3349231a8d6ee0cd2dcc Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 16:12:38 -0400 Subject: [PATCH 0043/1101] Fix formatting --- .../classes/jdk/jpackage/internal/LinuxPackage.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java index 597323d1fd6f6..c30b2617cf228 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java @@ -74,10 +74,12 @@ default boolean isInstallDirInUsrTree() { static class Impl extends Package.Proxy implements LinuxPackage { - Impl(Package target, String menuGroupName, String category, String additionalDependencies, - String release) throws ConfigException { - this(target, menuGroupName, category, additionalDependencies, release, LinuxPackageArch - .getValue(target.asStandardPackageType())); + Impl(Package target, String menuGroupName, String category, + String additionalDependencies, String release) throws + ConfigException { + this(target, menuGroupName, category, additionalDependencies, + release, LinuxPackageArch.getValue( + target.asStandardPackageType())); } Impl(Package target, String menuGroupName, String category, From c64f417af9b41f8b5ddbc42a92755f4531fc8a9f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 16:15:21 -0400 Subject: [PATCH 0044/1101] Added `ConfigException.build()` to simplify building ConfigException instances --- .../jpackage/internal/ConfigException.java | 32 ++++++++++++++++++- .../classes/jdk/jpackage/internal/I18N.java | 12 ++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ConfigException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ConfigException.java index 5a43fbe93fee4..3f4e46aacc6c9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ConfigException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ConfigException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 @@ -47,4 +47,34 @@ public ConfigException(Exception cause) { public String getAdvice() { return advice; } + + public static Builder build() { + return new Builder(); + } + + static final class Builder { + + ConfigException create() { + return new ConfigException(msg, advice, cause); + } + + public Builder msg(String msgId, Object ... args) { + msg = I18N.format(msgId, args); + return this; + } + + public Builder advice(String adviceId, Object ... args) { + advice = I18N.format(adviceId, args); + return this; + } + + public Builder cause(Exception v) { + cause = v; + return this; + } + + private String msg; + private String advice; + private Exception cause; + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java index 2e37a5c91af32..e872b400f0334 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import java.util.ListResourceBundle; @@ -34,11 +35,20 @@ import static java.util.stream.Collectors.toMap; import java.util.stream.Stream; -class I18N { +final class I18N { static String getString(String key) { return BUNDLE.getString(key); } + + static String format(String key, Object ... args) { + var str = getString(key); + if (args.length != 0) { + return MessageFormat.format(str, args); + } else { + return str; + } + } private static class MultiResourceBundle extends ListResourceBundle { From 4c4130b1e2605c65fa7bc496e506b52572445c42 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 16:17:20 -0400 Subject: [PATCH 0045/1101] Added Launcher.defaultIconResourceName() and static Launcher.validateIcon() to validate launcher icon --- .../jdk/jpackage/internal/LinuxLauncher.java | 4 +++ .../jdk/jpackage/internal/Launcher.java | 32 ++++++++++++++++++- .../jdk/jpackage/internal/WinLauncher.java | 4 +++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java index 59b2f0470f184..73e45cc7cc13b 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java @@ -37,6 +37,10 @@ default Map extraAppImageFileData() { return Map.of("shortcut", Boolean.toString(v)); }).orElseGet(Map::of); } + + default String defaultIconResourceName() { + return "JavaApp.png"; + } static class Impl extends Launcher.Proxy implements LinuxLauncher { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java index ae7a93e70718f..4596dc5378673 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java @@ -29,6 +29,10 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import jdk.internal.util.OperatingSystem; +import static jdk.internal.util.OperatingSystem.LINUX; +import static jdk.internal.util.OperatingSystem.WINDOWS; +import static jdk.jpackage.internal.Functional.ThrowingConsumer.toConsumer; import jdk.jpackage.internal.resources.ResourceLocator; interface Launcher { @@ -70,11 +74,37 @@ default Map extraAppImageFileData() { * other value for custom icon. */ Path icon(); + + default String defaultIconResourceName() { + return null; + } static record Impl(String name, LauncherStartupInfo startupInfo, List fileAssociations, boolean isService, String description, Path icon) implements Launcher { - + public Impl { + Optional.ofNullable(icon).ifPresent(toConsumer(Launcher::validateIcon)); + } + } + + static void validateIcon(Path icon) throws ConfigException { + switch (OperatingSystem.current()) { + case WINDOWS -> { + if (!icon.getFileName().toString().toLowerCase().endsWith(".ico")) { + throw ConfigException.build().msg("message.icon-not-ico", icon).create(); + } + } + case LINUX -> { + if (!icon.getFileName().toString().endsWith(".png")) { + throw ConfigException.build().msg("message.icon-not-png", icon).create(); + } + } + case MACOS -> { + if (!icon.getFileName().toString().endsWith(".icns")) { + throw ConfigException.build().msg("message.icon-not-icns", icon).create(); + } + } + } } static class Proxy extends ProxyBase implements Launcher { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java index 58fbbfd17388c..cacdc4db322d1 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java @@ -43,6 +43,10 @@ default InputStream executableResource() { isConsole() ? "jpackageapplauncher.exe" : "jpackageapplauncherw.exe"); } + default String defaultIconResourceName() { + return "JavaApp.ico"; + } + enum WinShortcut { WinShortcutDesktop, WinShortcutStartMenu From db647f8c056458dce411c40ea14d13649e4ba3f8 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 16:20:27 -0400 Subject: [PATCH 0046/1101] Added WinApplication.winVersion(), WinMsiPackage.msiVersion(), and WinExePackage --- .../jdk/jpackage/internal/WinApplication.java | 5 ++ .../jdk/jpackage/internal/WinExePackage.java | 62 +++++++++++++++++++ .../jdk/jpackage/internal/WinMsiPackage.java | 4 ++ 3 files changed, 71 insertions(+) create mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java index 1541b5cce4986..da9c4d1ddaafa 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java @@ -25,6 +25,11 @@ package jdk.jpackage.internal; interface WinApplication extends Application { + + default DottedVersion winVersion() { + return DottedVersion.lazy(version()); + } + static class Impl extends Application.Proxy implements WinApplication { Impl(Application app) { super(app); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java new file mode 100644 index 0000000000000..5b48cb087f996 --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; + +interface WinExePackage extends Package { + + WinMsiPackage msiPackage(); + + Path icon(); + + @Override + default PackageType type() { + return StandardPackageType.WinExe; + } + + static class Impl extends Package.Proxy implements WinExePackage { + + Impl(WinMsiPackage msiPackage, Path icon) throws ConfigException { + super(msiPackage); + this.icon = icon; + if (icon != null) { + Launcher.validateIcon(icon); + } + } + + @Override + public WinMsiPackage msiPackage() { + return target; + } + + @Override + public Path icon() { + return icon; + } + + private final Path icon; + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java index b2ac220c7ee58..33798acbff156 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java @@ -32,6 +32,10 @@ interface WinMsiPackage extends Package { + default DottedVersion msiVersion() { + return MsiVersion.of(version()); + } + boolean withInstallDirChooser(); boolean withShortcutPrompt(); From 495e91cb9dfc84303903a32df92f4360a048e6bf Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 16:22:39 -0400 Subject: [PATCH 0047/1101] Don't use InstallableFile in LauncherStartupInfo --- .../classes/jdk/jpackage/internal/CfgFile.java | 5 ++--- .../jpackage/internal/LauncherJarStartupInfo.java | 15 +++++++++++---- .../jpackage/internal/LauncherStartupInfo.java | 15 +++++++++++---- .../internal/LauncherStartupInfoFromParams.java | 9 ++------- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java index c61b2f5a1e7a0..3093231eaaee8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java @@ -55,8 +55,7 @@ void create(ApplicationLayout unresolvedAppLayout, ApplicationLayout appLayout) content.add(Map.entry("app.mainmodule", modularStartupInfo.moduleName() + "/" + startupInfo.qualifiedClassName())); } else if (startupInfo instanceof LauncherJarStartupInfo jarStartupInfo) { - Path mainJarPath = appCfgLayout.appDirectory().resolve( - jarStartupInfo.jarPath().installPath()); + Path mainJarPath = appCfgLayout.appDirectory().resolve(jarStartupInfo.jarPath()); if (jarStartupInfo.isClassNameFromMainJar()) { content.add(Map.entry("app.mainjar", mainJarPath)); @@ -73,7 +72,7 @@ void create(ApplicationLayout unresolvedAppLayout, ApplicationLayout appLayout) for (var value : Optional.ofNullable(startupInfo.classPath()).orElseGet(List::of)) { content.add(Map.entry("app.classpath", - appCfgLayout.appDirectory().resolve(value.installPath()).toString())); + appCfgLayout.appDirectory().resolve(value).toString())); } content.add(Map.entry("[JavaOptions]", SECTION_TAG)); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java index 5456c2334c962..1a54e9f19d7ff 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java @@ -24,22 +24,29 @@ */ package jdk.jpackage.internal; +import java.nio.file.Path; + interface LauncherJarStartupInfo extends LauncherStartupInfo { - InstallableFile jarPath(); + /** + * Returns path to the main jar relative to app's main source directory. + * + * @see jdk.jpackage.internal.Application#mainSrcDir() + */ + Path jarPath(); boolean isClassNameFromMainJar(); final static class Impl extends LauncherStartupInfo.Proxy implements LauncherJarStartupInfo { - Impl(LauncherStartupInfo target, InstallableFile jarPath, boolean isClassNameFromMainJar) { + Impl(LauncherStartupInfo target, Path jarPath, boolean isClassNameFromMainJar) { super(target); this.jarPath = jarPath; this.isClassNameFromMainJar = isClassNameFromMainJar; } @Override - public InstallableFile jarPath() { + public Path jarPath() { return jarPath; } @@ -48,7 +55,7 @@ public boolean isClassNameFromMainJar() { return isClassNameFromMainJar; } - private final InstallableFile jarPath; + private final Path jarPath; private final boolean isClassNameFromMainJar; } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java index a013ad6f63ce3..0c4afe54f7bbb 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java @@ -43,10 +43,17 @@ default String packageName() { List defaultParameters(); - List classPath(); + /** + * Returns list of paths to add to the classath. + * + * Every path in the list is relative to app's main source directory. + * + * @see jdk.jpackage.internal.Application#mainSrcDir() + */ + List classPath(); record Impl(String qualifiedClassName, List javaOptions, - List defaultParameters, List classPath) + List defaultParameters, List classPath) implements LauncherStartupInfo { } @@ -74,7 +81,7 @@ public List defaultParameters() { } @Override - public List classPath() { + public List classPath() { return target.classPath(); } } @@ -97,7 +104,7 @@ public List defaultParameters() { } @Override - public List classPath() { + public List classPath() { throw new UnsupportedOperationException(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java index 14df460647a65..b13a6dff64907 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java @@ -35,22 +35,17 @@ static LauncherStartupInfo create(Map params) { var launcherData = StandardBundlerParam.LAUNCHER_DATA.fetchFrom(params); var javaOptions = JAVA_OPTIONS.fetchFrom(params); var arguments = ARGUMENTS.fetchFrom(params); - var classpath = launcherData.classPath().stream().map(p -> { - return new InstallableFile(inputDir.resolve(p), p); - }).toList(); var startupInfo = new LauncherStartupInfo.Impl( launcherData.qualifiedClassName(), javaOptions, arguments, - classpath); + launcherData.classPath()); if (launcherData.isModular()) { return new LauncherModularStartupInfo.Impl(startupInfo, launcherData.moduleName(), launcherData.modulePath()); } else { return new LauncherJarStartupInfo.Impl(startupInfo, - new InstallableFile(inputDir.resolve( - launcherData.mainJarName()), - launcherData.mainJarName()), + launcherData.mainJarName(), launcherData.isClassNameFromMainJar()); } } From 5a0de1309ea9f2a609bba3d8b54e16f8a4eeee7c Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 16:23:17 -0400 Subject: [PATCH 0048/1101] Fix formatting --- .../share/classes/jdk/jpackage/internal/Package.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index c4927cfbf9612..46c7db7d47ec4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -131,8 +131,8 @@ default Path packageFileName() { if (type() instanceof StandardPackageType type) { switch (type) { case WinMsi, WinExe -> { - return Path - .of(String.format("%s-%s%s", packageName(), version(), type.suffix())); + return Path.of(String.format("%s-%s%s", packageName(), + version(), type.suffix())); } } } @@ -203,7 +203,7 @@ static record Impl(Application app, PackageType type, String packageName, String description, String version, String aboutURL, Path licenseFile, Path predefinedAppImage, Path configuredInstallBaseDir) implements Package { - public Impl { + public Impl { description = Optional.ofNullable(description).orElseGet(app::description); version = Optional.ofNullable(version).orElseGet(app::version); packageName = Optional.ofNullable(packageName).orElseGet(app::name); From f5e1cdedff5722c6d0544697656d6776870a2378 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 22:58:56 -0400 Subject: [PATCH 0049/1101] - Added AppImageFile test helper; - Fix wrong assert message in TKit.assertStringListEquals(); - Reference ExecutableRebrander.iconSwap() instead of ExecutableRebrander.iconSwapWrapper() from LauncherIconVerifier. --- .../jdk/jpackage/test/AppImageFile.java | 128 ++++++++++++++++++ .../jdk/jpackage/test/JPackageCommand.java | 47 +------ .../jpackage/test/LauncherIconVerifier.java | 18 ++- .../helpers/jdk/jpackage/test/TKit.java | 2 +- .../jpackage/share/AppImagePackageTest.java | 6 +- .../jdk/jpackage/tests/AppVersionTest.java | 13 +- .../jdk/jpackage/tests/ModulePathTest3.java | 11 +- .../tests/PredefinedAppImageErrorTest.java | 8 +- 8 files changed, 160 insertions(+), 73 deletions(-) create mode 100644 test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java new file mode 100644 index 0000000000000..6560c06b76fcf --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.Map; +import java.util.Optional; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.ApplicationLayout; +import jdk.jpackage.internal.IOUtils; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +public record AppImageFile(String mainLauncherName, String mainLauncherClassName, + String version, boolean macSigned, boolean macAppStore) { + + public static Path getPathInAppImage(Path appImageDir) { + return ApplicationLayout.platformAppImage() + .resolveAt(appImageDir) + .appDirectory() + .resolve(FILENAME); + } + + public AppImageFile(String mainLauncherName, String mainLauncherClassName) { + this(mainLauncherName, mainLauncherClassName, "1.0", false, false); + } + + public void save(Path appImageDir) throws IOException { + IOUtils.createXml(getPathInAppImage(appImageDir), xml -> { + xml.writeStartElement("jpackage-state"); + xml.writeAttribute("version", getVersion()); + xml.writeAttribute("platform", getPlatform()); + + xml.writeStartElement("app-version"); + xml.writeCharacters(version); + xml.writeEndElement(); + + xml.writeStartElement("main-launcher"); + xml.writeCharacters(mainLauncherName); + xml.writeEndElement(); + + xml.writeStartElement("main-class"); + xml.writeCharacters(mainLauncherClassName); + xml.writeEndElement(); + + xml.writeStartElement("signed"); + xml.writeCharacters(Boolean.toString(macSigned)); + xml.writeEndElement(); + + xml.writeStartElement("app-store"); + xml.writeCharacters(Boolean.toString(macAppStore)); + xml.writeEndElement(); + }); + } + + public static AppImageFile load(Path appImageDir) { + try { + Document doc = IOUtils.initDocumentBuilder().parse( + Files.newInputStream(getPathInAppImage(appImageDir))); + + XPath xPath = XPathFactory.newInstance().newXPath(); + + var version = xPath.evaluate("/jpackage-state/app-version/text()", doc); + + var mainLauncherName = xPath.evaluate( + "/jpackage-state/main-launcher/text()", doc); + + var mainLauncherClassName = xPath.evaluate( + "/jpackage-state/main-class/text()", doc); + + var macSigned = Optional.ofNullable(xPath.evaluate( + "/jpackage-state/signed/text()", doc)).map( + Boolean::parseBoolean).orElse(false); + + var macAppStore = Optional.ofNullable(xPath.evaluate( + "/jpackage-state/app-store/text()", doc)).map( + Boolean::parseBoolean).orElse(false); + + return new AppImageFile(mainLauncherName, mainLauncherClassName, + version, macSigned, macAppStore); + + } catch (XPathExpressionException | SAXException | IOException ex) { + // This should never happen as XPath expressions should be correct + throw new RuntimeException(ex); + } + } + + private static String getVersion() { + return System.getProperty("java.version"); + } + + private static String getPlatform() { + return PLATFORM_LABELS.get(OperatingSystem.current()); + } + + private static final Map PLATFORM_LABELS = Map.of( + OperatingSystem.LINUX, "linux", + OperatingSystem.WINDOWS, "windows", + OperatingSystem.MACOS, "macOS"); + + private static final String FILENAME = ".jpackage.xml"; +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index b4ffae0bff29b..e86d1e4d5a233 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -45,8 +45,6 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.IOUtils; -import jdk.jpackage.internal.AppImageFile; import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.internal.PackageFile; import static jdk.jpackage.test.AdditionalLauncher.forEachAdditionalLauncher; @@ -212,7 +210,7 @@ public String version() { public String name() { String appImage = getArgumentValue("--app-image", () -> null); if (appImage != null) { - String name = AppImageFile.extractAppName(Path.of(appImage)); + String name = AppImageFile.load(Path.of(appImage)).mainLauncherName(); // can be null if using foreign app-image return ((name != null) ? name : getArgumentValue("--name")); } @@ -226,7 +224,7 @@ public String installerName() { if (installerName == null) { String appImage = getArgumentValue("--app-image", () -> null); if (appImage != null) { - installerName = AppImageFile.extractAppName(Path.of(appImage)); + installerName = AppImageFile.load(Path.of(appImage)).mainLauncherName(); } } return installerName; @@ -299,39 +297,6 @@ public JPackageCommand setFakeRuntime() { return this; } - public void createJPackageXMLFile(String mainLauncher, String mainClass) - throws IOException { - Path jpackageXMLFile = AppImageFile.getPathInAppImage(getArgumentValue("--app-image", () -> { - throw new RuntimeException("Error: --app-image expected"); - }, Path::of)); - - IOUtils.createXml(jpackageXMLFile, xml -> { - xml.writeStartElement("jpackage-state"); - xml.writeAttribute("version", AppImageFile.getVersion()); - xml.writeAttribute("platform", AppImageFile.getPlatform()); - - xml.writeStartElement("app-version"); - xml.writeCharacters("1.0"); - xml.writeEndElement(); - - xml.writeStartElement("main-launcher"); - xml.writeCharacters(mainLauncher); - xml.writeEndElement(); - - xml.writeStartElement("main-class"); - xml.writeCharacters(mainClass); - xml.writeEndElement(); - - xml.writeStartElement("signed"); - xml.writeCharacters("false"); - xml.writeEndElement(); - - xml.writeStartElement("app-store"); - xml.writeCharacters("false"); - xml.writeEndElement(); - }); - } - JPackageCommand addPrerequisiteAction(ThrowingConsumer action) { verifyMutable(); prerequisiteActions.add(action); @@ -861,12 +826,12 @@ private void assertAppImageFile() { AppImageFile aif = AppImageFile.load(rootDir); boolean expectedValue = hasArgument("--mac-sign"); - boolean actualValue = aif.isSigned(); + boolean actualValue = aif.macSigned(); TKit.assertEquals(Boolean.toString(expectedValue), Boolean.toString(actualValue), "Check for unexptected value in app image file for "); expectedValue = hasArgument("--mac-app-store"); - actualValue = aif.isAppStore(); + actualValue = aif.macAppStore(); TKit.assertEquals(Boolean.toString(expectedValue), Boolean.toString(actualValue), "Check for unexptected value in app image file for "); } @@ -881,7 +846,7 @@ private void assertPackageFile() { } else { if (TKit.isOSX() && hasArgument("--app-image")) { String appImage = getArgumentValue("--app-image"); - if (AppImageFile.load(Path.of(appImage)).isSigned()) { + if (AppImageFile.load(Path.of(appImage)).macSigned()) { assertFileInAppImage(lookupPath, null); } else { assertFileInAppImage(lookupPath, lookupPath); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java index 2de2e002a9470..abc9b89ffd50a 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -171,9 +171,9 @@ private WinIconVerifier() { "unlockResource", long.class); unlockResource.setAccessible(true); - iconSwapWrapper = executableRebranderClass.getDeclaredMethod( - "iconSwapWrapper", long.class, String.class); - iconSwapWrapper.setAccessible(true); + iconSwap = executableRebranderClass.getDeclaredMethod( + "iconSwap", long.class, String.class); + iconSwap.setAccessible(true); } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) { throw Functional.rethrowUnchecked(ex); @@ -246,8 +246,14 @@ private void setIcon(Path iconPath, Path launcherPath) { "Failed to lock [%s] executable", launcherPath)); } - iconSwapWrapper.invoke(null, new Object[]{lock, + var exitCode = (Integer) iconSwap.invoke(null, new Object[]{ + lock, iconPath.toAbsolutePath().normalize().toString()}); + if (exitCode != 0) { + throw new RuntimeException(String.format( + "Failed to swap icon of [%s] executable", + launcherPath)); + } } finally { if (lock != 0) { unlockResource.invoke(null, new Object[]{lock}); @@ -266,7 +272,7 @@ private void setIcon(Path iconPath, Path launcherPath) { private final Class executableRebranderClass; private final Method lockResource; private final Method unlockResource; - private final Method iconSwapWrapper; + private final Method iconSwap; } private String launcherName; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index cd32f32f63d24..dcec290d5f760 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -768,7 +768,7 @@ public static void assertStringListEquals(List expected, if (actual.size() < expected.size()) { // Actual string list is shorter than expected error(concatMessages(String.format( - "Actual list is longer than expected by %d elements", + "Actual list is shorter than expected by %d elements", expected.size() - actual.size()), msg)); } } diff --git a/test/jdk/tools/jpackage/share/AppImagePackageTest.java b/test/jdk/tools/jpackage/share/AppImagePackageTest.java index 949e68faae2ee..f582b018c9374 100644 --- a/test/jdk/tools/jpackage/share/AppImagePackageTest.java +++ b/test/jdk/tools/jpackage/share/AppImagePackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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,7 +25,7 @@ import java.nio.file.Files; import java.io.IOException; import java.util.List; -import jdk.jpackage.internal.AppImageFile; +import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.TKit; import jdk.jpackage.test.JPackageCommand; @@ -88,7 +88,7 @@ public static void testEmpty(boolean withIcon) throws IOException { cmd.addArguments("--icon", iconPath("icon")); } cmd.removeArgumentWithValue("--input"); - cmd.createJPackageXMLFile("EmptyAppImagePackageTest", "Hello"); + new AppImageFile("EmptyAppImagePackageTest", "Hello").save(appImageDir); // on mac, with --app-image and without --mac-package-identifier, // will try to infer it from the image, so foreign image needs it. diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/AppVersionTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/AppVersionTest.java index f137fabf3d629..8ea52c9d4bca9 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/AppVersionTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/AppVersionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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,17 +27,13 @@ import java.util.Collection; import java.util.ArrayList; import java.util.List; -import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.AppImageFile; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.TKit; -import jdk.jpackage.internal.AppImageFile; -import org.w3c.dom.Document; /* * @test @@ -118,10 +114,7 @@ public void test() throws XPathExpressionException, IOException { } cmd.executeAndAssertHelloAppImageCreated(); - Document xml = AppImageFile.readXml(cmd.outputBundle()); - String actualVersion = XPathFactory.newInstance().newXPath().evaluate( - "/jpackage-state/app-version/text()", xml, XPathConstants.STRING).toString(); - + String actualVersion = AppImageFile.load(cmd.outputBundle()).version(); TKit.assertEquals(expectedVersion, actualVersion, "Check application version"); } diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest3.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest3.java index 662b2633207a7..77d0d1a1ac6e4 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest3.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ModulePathTest3.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,11 +32,10 @@ import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.AppImageFile; +import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.HelloApp; import jdk.jpackage.test.JavaAppDesc; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Executor; import jdk.jpackage.test.JPackageCommand; @@ -107,11 +106,7 @@ private void testIt(String mainAppDesc) throws XPathExpressionException, cmd.executeAndAssertHelloAppImageCreated(); if (appDesc.moduleVersion() != null) { - Document xml = AppImageFile.readXml(cmd.outputBundle()); - String actualVersion = XPathFactory.newInstance().newXPath().evaluate( - "/jpackage-state/app-version/text()", xml, - XPathConstants.STRING).toString(); - + String actualVersion = AppImageFile.load(cmd.outputBundle()).version(); TKit.assertEquals(appDesc.moduleVersion(), actualVersion, "Check application version"); } diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java index d03c7cf28df96..637bc186f0619 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.TKit; @@ -112,8 +113,7 @@ private void getDummyAppImage(JPackageCommand cmd) throws IOException { = dummyAppFolder.resolve("DummyAppFile").toAbsolutePath(); Files.createFile(dummyAppFile); - cmd.addArguments("--app-image", dummyAppFolder.toString()); - cmd.createJPackageXMLFile("PredefinedAppImageErrorTest", "Hello"); + cmd.addArguments("--app-image", dummyAppFolder.toString()); + new AppImageFile("PredefinedAppImageErrorTest", "Hello").save(dummyAppFolder); } - } From 035fceee9688a8736f598fe51b1415feebbf4b01 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 23:01:06 -0400 Subject: [PATCH 0050/1101] Simplified --- .../jdk/jpackage/internal/PackageFile.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java index 87935a9287c39..2c2e8a3165779 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; -import java.util.Optional; public final class PackageFile { @@ -38,10 +37,16 @@ public final class PackageFile { * @param appImageDir - path to application image */ public static Path getPathInAppImage(Path appImageDir) { - return ApplicationLayout.platformAppImage() - .resolveAt(appImageDir) - .appDirectory() - .resolve(FILENAME); + return getPathInAppImage(ApplicationLayout.platformAppImage().resolveAt( + appImageDir)); + } + + /** + * Returns path to package file. + * @param appLayout - application layout + */ + public static Path getPathInAppImage(ApplicationLayout appLayout) { + return appLayout.appDirectory().resolve(FILENAME); } PackageFile(String packageName) { @@ -50,13 +55,10 @@ public static Path getPathInAppImage(Path appImageDir) { } void save(ApplicationLayout appLayout) throws IOException { - Path dst = Optional.ofNullable(appLayout.appDirectory()).map(appDir -> { - return appDir.resolve(FILENAME); - }).orElse(null); - - if (dst != null) { - Files.createDirectories(dst.getParent()); - Files.writeString(dst, packageName); + Path dstDir = appLayout.appDirectory(); + if (dstDir != null) { + Files.createDirectories(dstDir); + Files.writeString(dstDir.resolve(FILENAME), packageName); } } From 36d449db4d00250eada68f89cdfc5d69e91707a9 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 23:01:55 -0400 Subject: [PATCH 0051/1101] Made Package.defaultInstallDir() static --- .../jdk/jpackage/internal/Package.java | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index 46c7db7d47ec4..b668385e29787 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -161,7 +161,7 @@ default Path relativeInstallDir() { } } return v.resolve(packageName()); - }).orElseGet(this::defaultInstallDir); + }).orElseGet(() -> defaultInstallDir(this)); switch (asStandardPackageType()) { case WinExe, WinMsi -> { @@ -175,30 +175,6 @@ default Path relativeInstallDir() { Path configuredInstallBaseDir(); - default Path defaultInstallDir() { - Path base; - switch (asStandardPackageType()) { - case WinExe, WinMsi -> { - base = Path.of(""); - } - case LinuxDeb, LinuxRpm -> { - base = Path.of("/opt"); - } - case MacDmg, MacPkg -> { - if (isRuntimeInstaller()) { - base = Path.of("/Library/Java/JavaVirtualMachines"); - } else { - base = Path.of("/Applications"); - } - } - default -> { - throw new UnsupportedOperationException(); - } - } - - return base.resolve(packageName()); - } - static record Impl(Application app, PackageType type, String packageName, String description, String version, String aboutURL, Path licenseFile, Path predefinedAppImage, Path configuredInstallBaseDir) implements Package { @@ -361,4 +337,28 @@ static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigExc return installDir; } + + private static Path defaultInstallDir(Package pkg) { + Path base; + switch (pkg.asStandardPackageType()) { + case WinExe, WinMsi -> { + base = Path.of(""); + } + case LinuxDeb, LinuxRpm -> { + base = Path.of("/opt"); + } + case MacDmg, MacPkg -> { + if (pkg.isRuntimeInstaller()) { + base = Path.of("/Library/Java/JavaVirtualMachines"); + } else { + base = Path.of("/Applications"); + } + } + default -> { + throw new UnsupportedOperationException(); + } + } + + return base.resolve(pkg.packageName()); + } } From 860b2aa9278390785adeb914b19577ae8639b91e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 23:02:41 -0400 Subject: [PATCH 0052/1101] Don't validate empty string icons --- .../share/classes/jdk/jpackage/internal/Launcher.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java index 4596dc5378673..f9a4ff7059ccc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java @@ -83,7 +83,9 @@ static record Impl(String name, LauncherStartupInfo startupInfo, List fileAssociations, boolean isService, String description, Path icon) implements Launcher { public Impl { - Optional.ofNullable(icon).ifPresent(toConsumer(Launcher::validateIcon)); + if (icon != null && !icon.toString().isEmpty()) { + toConsumer(Launcher::validateIcon).accept(icon); + } } } From 58473a4e53ee2211bc80ecd7da9b7763f6c7e462 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 23:04:30 -0400 Subject: [PATCH 0053/1101] Make AppImageFile class package private --- .../jdk/jpackage/internal/AppImageFile.java | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index 31228a8f5a3e4..0c1787fd25dfb 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -60,7 +60,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; -public final class AppImageFile { +final class AppImageFile { // These values will be loaded from AppImage xml file. private final String appVersion; @@ -167,11 +167,11 @@ String getMainClass() { return mainClass; } - public boolean isSigned() { + boolean isSigned() { return signed; } - public boolean isAppStore() { + boolean isAppStore() { return appStore; } @@ -179,7 +179,7 @@ public boolean isAppStore() { * Returns path to application image info file. * @param appImageDir - path to application image */ - public static Path getPathInAppImage(Path appImageDir) { + static Path getPathInAppImage(Path appImageDir) { return ApplicationLayout.platformAppImage() .resolveAt(appImageDir) .appDirectory() @@ -304,7 +304,7 @@ static void addLauncherInfo(XMLStreamWriter xml, LauncherInfo li) * @return valid info about application image or null * @throws IOException */ - public static AppImageFile load(Path appImageDir) { + static AppImageFile load(Path appImageDir) { try { Document doc = readXml(appImageDir); @@ -361,7 +361,7 @@ public static AppImageFile load(Path appImageDir) { * is not marked as signed. If AppImageFile already signed it will return * instance to itself. */ - public AppImageFile copyAsSigned() { + AppImageFile copyAsSigned() { if (isSigned()) { return this; } @@ -374,7 +374,7 @@ public AppImageFile copyAsSigned() { getVersion(), getPlatform(), "true", String.valueOf(isAppStore())); } - public static Document readXml(Path appImageDir) throws IOException { + static Document readXml(Path appImageDir) throws IOException { try { Path path = getPathInAppImage(appImageDir); @@ -414,14 +414,6 @@ static List getLaunchers(Path appImageDir, return launchers; } - public static String extractAppName(Path appImageDir) { - return AppImageFile.load(appImageDir).getLauncherName(); - } - - public static String extractMainClass(Path appImageDir) { - return AppImageFile.load(appImageDir).getMainClass(); - } - private static String xpathQueryNullable(XPath xPath, String xpathExpr, Document xml) throws XPathExpressionException { NodeList nodes = (NodeList) xPath.evaluate(xpathExpr, xml, @@ -432,11 +424,11 @@ private static String xpathQueryNullable(XPath xPath, String xpathExpr, return null; } - public static String getVersion() { + static String getVersion() { return System.getProperty("java.version"); } - public static String getPlatform() { + static String getPlatform() { return PLATFORM_LABELS.get(OperatingSystem.current()); } From 3f6aae326b03f9683683e4d161489b2d62daee9d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 23:05:28 -0400 Subject: [PATCH 0054/1101] Make AppImageFile2 class package private and add function to get path to the file in the application layout --- .../jdk/jpackage/internal/AppImageFile2.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index 3f597158f5a7a..316b90a31ecbf 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -50,7 +50,7 @@ import org.xml.sax.SAXException; -public final class AppImageFile2 { +final class AppImageFile2 { AppImageFile2(Application app) { appVersion = app.version(); @@ -149,11 +149,17 @@ void save(Path appImageDir) throws IOException { * Returns path to application image info file. * @param appImageDir - path to application image */ - public static Path getPathInAppImage(Path appImageDir) { - return ApplicationLayout.platformAppImage() - .resolveAt(appImageDir) - .appDirectory() - .resolve(FILENAME); + static Path getPathInAppImage(Path appImageDir) { + return getPathInAppImage(ApplicationLayout.platformAppImage().resolveAt( + appImageDir)); + } + + /** + * Returns path to application image info file. + * @param appLayout - application layout + */ + static Path getPathInAppImage(ApplicationLayout appLayout) { + return appLayout.appDirectory().resolve(FILENAME); } /** @@ -162,7 +168,7 @@ public static Path getPathInAppImage(Path appImageDir) { * @return valid info about application image or null * @throws IOException */ - public static AppImageFile2 load(Path appImageDir) throws ConfigException, IOException { + static AppImageFile2 load(Path appImageDir) throws ConfigException, IOException { try { Document doc = IOUtils.initDocumentBuilder().parse( Files.newInputStream(getPathInAppImage(appImageDir))); From 1c4f69356586b9aaa6e75d380c0f8b7a6223a2c0 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 23:06:19 -0400 Subject: [PATCH 0055/1101] Fix formatting --- .../linux/classes/jdk/jpackage/internal/LinuxDebBundler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index 9ab75ab95b5ca..44332177fc972 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -343,8 +343,8 @@ protected Map createReplacementData(Workshop workshop, LinuxPack data.put("APPLICATION_COPYRIGHT", pkg.app().copyright()); data.put("APPLICATION_LICENSE_TEXT", licenseText); data.put("APPLICATION_ARCH", pkg.arch()); - data.put("APPLICATION_INSTALLED_SIZE", Long.toString(pkg.appLayout().resolveAt(workshop - .appImageDir()).sizeInBytes() >> 10)); + data.put("APPLICATION_INSTALLED_SIZE", Long.toString(pkg.packageLayout().resolveAt( + workshop.appImageDir()).sizeInBytes() >> 10)); data.put("APPLICATION_HOMEPAGE", Optional.ofNullable(pkg.aboutURL()).map( value -> "Homepage: " + value).orElse("")); data.put("APPLICATION_VERSION_WITH_RELEASE", ((LinuxDebPackage) pkg).versionWithRelease()); From 5e905ed64824298d96163833c567a70addd872a4 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 23:06:43 -0400 Subject: [PATCH 0056/1101] Add missing @Override --- .../linux/classes/jdk/jpackage/internal/LinuxLauncher.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java index 73e45cc7cc13b..05c06b5cd0947 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java @@ -38,6 +38,7 @@ default Map extraAppImageFileData() { }).orElseGet(Map::of); } + @Override default String defaultIconResourceName() { return "JavaApp.png"; } From f1ded1ea8dbd8ceb31cbf7a9ec0573acafe189a4 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 23:08:03 -0400 Subject: [PATCH 0057/1101] Added handy Workshop.withAppImageDir() --- .../share/classes/jdk/jpackage/internal/Workshop.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java index 983e52db01788..6b272d2187fdc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java @@ -54,6 +54,15 @@ record Impl(Path buildRoot, Path resourceDir) implements Workshop { } + static Workshop withAppImageDir(Workshop workshop, Path appImageDir) { + return new Proxy(workshop) { + @Override + public Path appImageDir() { + return appImageDir; + } + }; + } + static class Proxy implements Workshop { Proxy(Workshop target) { From 7af24a350ddff8901574b73a9b70825bdec142f4 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 23:08:36 -0400 Subject: [PATCH 0058/1101] Use Workshop.withAppImageDir() --- .../jdk/jpackage/internal/WorkshopFromParams.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java index 9686797e12ad4..5749151a21134 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java @@ -28,7 +28,7 @@ import java.util.Map; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import jdk.jpackage.internal.Workshop.Impl; -import jdk.jpackage.internal.Workshop.Proxy; +import static jdk.jpackage.internal.Workshop.withAppImageDir; final class WorkshopFromParams { @@ -48,12 +48,7 @@ static Workshop create(Map params) throws ConfigExceptio appImageDir = defaultWorkshop.buildRoot().resolve("image").resolve(dir); } - return new Proxy(defaultWorkshop) { - @Override - public Path appImageDir() { - return appImageDir; - } - }; + return withAppImageDir(defaultWorkshop, appImageDir); } static final BundlerParamInfo WORKSHOP = BundlerParamInfo.createBundlerParam( From e6f21dc4a10fa1291f90685e39f4a034a42857ec Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 23:09:24 -0400 Subject: [PATCH 0059/1101] Moved CONSOLE_HINT param to WinApplicationFromParams --- .../jpackage/internal/WinApplicationFromParams.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java index 49bf8723c5e1d..e5d6ba6fa4fc8 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java @@ -33,7 +33,6 @@ import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; import static jdk.jpackage.internal.WinLauncher.WinShortcut.WinShortcutDesktop; import static jdk.jpackage.internal.WinLauncher.WinShortcut.WinShortcutStartMenu; -import static jdk.jpackage.internal.WindowsAppImageBuilder.CONSOLE_HINT; final class WinApplicationFromParams { @@ -78,4 +77,13 @@ private static WinApplication create(Map params) throws // valueOf(null) is false, // and we actually do want null in some cases (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); + + public static final BundlerParamInfo CONSOLE_HINT = new BundlerParamInfo<>( + Arguments.CLIOptions.WIN_CONSOLE_HINT.getId(), + Boolean.class, + params -> false, + // valueOf(null) is false, + // and we actually do want null in some cases + (s, p) -> (s == null + || "null".equalsIgnoreCase(s)) ? true : Boolean.valueOf(s)); } From 171349cf97f3fd2bc5241d38f777d978f7840512 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 23:11:51 -0400 Subject: [PATCH 0060/1101] - Add default implementation to PathGroup.TransformHandler interface - Don't create .package file in app image when bundling msi. Create it in config dir. This lets keep app image R/O --- .../jdk/jpackage/internal/PathGroup.java | 9 +++++++-- .../internal/WixAppImageFragmentBuilder.java | 19 ++++++++++--------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java index 58e23b5a6a2be..75008fd677069 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java @@ -161,8 +161,13 @@ default void transform(Facade dst, TransformHandler handler) throws } static interface TransformHandler { - public void copyFile(Path src, Path dst) throws IOException; - public void createDirectory(Path dir) throws IOException; + default public void copyFile(Path src, Path dst) throws IOException { + + } + + default public void createDirectory(Path dir) throws IOException { + + } } private static void copy(PathGroup src, PathGroup dst, diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index fc55cd55a9e5a..fb1372b4c165d 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -84,7 +84,7 @@ void initFromParams(Workshop workshop, WinMsiPackage pkg) { do { ApplicationLayout layout = pkg.appLayout(); // Don't want app image info file in installed application. - layout.pathGroup().ghostPath(AppImageFile.getPathInAppImage(Path.of(""))); + layout.pathGroup().ghostPath(AppImageFile2.getPathInAppImage(layout)); // Want absolute paths to source files in generated WiX sources. // This is to handle scenario if sources would be processed from @@ -119,6 +119,8 @@ void initFromParams(Workshop workshop, WinMsiPackage pkg) { programMenuFolderName = pkg.startMenuGroupName(); + packageFile = new PackageFile(pkg.packageName()); + initFileAssociations(pkg); } @@ -126,6 +128,7 @@ void initFromParams(Workshop workshop, WinMsiPackage pkg) { void addFilesToConfigRoot() throws IOException { removeFolderItems = new HashMap<>(); defaultedMimes = new HashSet<>(); + packageFile.save(ApplicationLayout.windowsAppImage().resolveAt(getConfigRoot())); super.addFilesToConfigRoot(); } @@ -705,10 +708,6 @@ private void addFilesComponentGroup(XMLStreamWriter xml) public void copyFile(Path src, Path dst) throws IOException { files.add(Map.entry(src, dst)); } - - @Override - public void createDirectory(final Path dir) throws IOException { - } }); if (serviceInstaller != null) { @@ -716,6 +715,10 @@ public void createDirectory(final Path dir) throws IOException { serviceInstaller.installPath())); } + files.add(Map.entry(PackageFile.getPathInAppImage( + getConfigRoot().toAbsolutePath().normalize()), + PackageFile.getPathInAppImage(installedAppImage))); + List componentIds = new ArrayList<>(); for (var file : files) { Path src = file.getKey(); @@ -795,10 +798,6 @@ public void copyFile(Path src, Path dst) throws IOException { icoFiles.add(Map.entry(src, dst)); } } - - @Override - public void createDirectory(Path dst) throws IOException { - } }); for (var icoFile : icoFiles) { @@ -966,6 +965,8 @@ static Set getForPackage(WinMsiPackage pkg) { private Map removeFolderItems; private Set defaultedMimes; + private PackageFile packageFile; + private static final Path TARGETDIR = Path.of("TARGETDIR"); private static final Path INSTALLDIR = Path.of("INSTALLDIR"); From c0475aeebbacc5b7979ac22db0522a79e0809ced Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 23:17:30 -0400 Subject: [PATCH 0061/1101] - Get rid of `params` in Windows and Linux code. Only marginal usages are left to clean. - Make AppImageBuilder class final. Its behavior is still configurable. - Use AppImageBuilder in all Windows and Linux bundlers. - Get rid of copying app image when building Windows and Linux packages. --- .../jpackage/internal/DesktopIntegration.java | 10 +- .../jpackage/internal/LinuxAppBundler.java | 10 +- .../internal/LinuxAppImageBuilder.java | 122 ++------- .../internal/LinuxAppImageBuilder2.java | 72 ------ .../internal/LinuxPackageBundler.java | 18 +- .../jdk/jpackage/internal/MacAppBundler.java | 14 +- .../internal/AbstractAppImageBuilder.java | 59 ----- .../jpackage/internal/AppImageBuilder.java | 75 ++++-- .../jpackage/internal/AppImageBundler.java | 48 ++-- .../jdk/jpackage/internal/Application.java | 39 +-- .../internal/ApplicationFromParams.java | 6 +- .../jdk/jpackage/internal/ScriptRunner.java | 19 -- .../internal/ExecutableRebrander.java | 241 ++++++++---------- .../jdk/jpackage/internal/WinAppBundler.java | 10 +- .../jpackage/internal/WinAppImageBuilder.java | 60 +++++ .../jdk/jpackage/internal/WinExeBundler.java | 65 ++--- .../jdk/jpackage/internal/WinMsiBundler.java | 55 ++-- .../internal/WindowsAppImageBuilder.java | 145 ----------- 18 files changed, 374 insertions(+), 694 deletions(-) delete mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder2.java create mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java delete mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsAppImageBuilder.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 01fe1e1708810..a22cbca190c69 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -44,7 +44,6 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; -import static jdk.jpackage.internal.LinuxAppImageBuilder.DEFAULT_ICON; /** * Helper to create files for desktop integration. @@ -74,7 +73,7 @@ private DesktopIntegration(Workshop workshop, LinuxPackage pkg, LinuxLauncher la // - user explicitly requested to create a shortcut boolean withDesktopFile = !associations.isEmpty() || launcher.shortcut().orElse(false); - var curIconResource = pkg.app().createLauncherIconResource(launcher, DEFAULT_ICON, + var curIconResource = pkg.app().createLauncherIconResource(launcher, workshop::createResource); if (curIconResource == null) { // This is additional launcher with explicit `no icon` configuration. @@ -106,13 +105,12 @@ private DesktopIntegration(Workshop workshop, LinuxPackage pkg, LinuxLauncher la if (withDesktopFile) { desktopFile = createDesktopFile(desktopFileName); - iconFile = createDesktopFile(escapedAppFileName - + IOUtils.getSuffix(Path.of(DEFAULT_ICON))); + iconFile = createDesktopFile(escapedAppFileName + ".png"); if (curIconResource == null) { // Create default icon. - curIconResource = pkg.app().createLauncherIconResource(pkg.app().mainLauncher(), - DEFAULT_ICON, workshop::createResource); + curIconResource = pkg.app().createLauncherIconResource( + pkg.app().mainLauncher(), workshop::createResource); } } else { desktopFile = null; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java index 9a308155f78de..40fa50287ccfb 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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,6 +27,12 @@ public class LinuxAppBundler extends AppImageBundler { public LinuxAppBundler() { - setAppImageSupplier(LinuxAppImageBuilder::new); + setAppImageSupplier((params, output) -> { + // Order is important! + var app = LinuxApplicationFromParams.APPLICATION.fetchFrom(params); + var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); + LinuxAppImageBuilder.build().create(app).execute( + Workshop.withAppImageDir(workshop, output)); + }); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index f4754dc236724..76fe4f259db53 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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,114 +22,42 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.jpackage.internal; import java.io.IOException; -import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.List; -import java.util.Map; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.ICON; -import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; - -public class LinuxAppImageBuilder extends AbstractAppImageBuilder { - - static final BundlerParamInfo ICON_PNG = - new BundlerParamInfo<>( - "icon.png", - Path.class, - params -> { - Path f = ICON.fetchFrom(params); - if (f != null && f.getFileName() != null && !f.getFileName() - .toString().toLowerCase().endsWith(".png")) { - Log.error(MessageFormat.format( - I18N.getString("message.icon-not-png"), f)); - return null; - } - return f; - }, - (s, p) -> Path.of(s)); - - static final String DEFAULT_ICON = "JavaApp.png"; +import jdk.jpackage.internal.resources.ResourceLocator; - LinuxAppImageBuilder(Path imageOutDir) { - super(imageOutDir); - } +final class LinuxAppImageBuilder { - private void writeEntry(InputStream in, Path dstFile) throws IOException { - Files.createDirectories(dstFile.getParent()); - Files.copy(in, dstFile); + static AppImageBuilder.Builder build() { + return new AppImageBuilder.Builder().launcherCallback(new LauncherCallbackImpl()); } - public static String getLauncherName(Map params) { - return APP_NAME.fetchFrom(params); - } - - @Override - public void prepareApplicationFiles(Map params) - throws IOException { - appLayout.roots().stream().forEach(dir -> { - try { - IOUtils.writableOutputDir(dir); - } catch (PackagerException pe) { - throw new RuntimeException(pe); + private final static class LauncherCallbackImpl implements AppImageBuilder.LauncherCallback { + + @Override + public void onLauncher(Application app, + AppImageBuilder.LauncherContext ctx) throws IOException, PackagerException { + if (ctx.launcher() == app.mainLauncher()) { + var launcherLib = ctx.resolvedAppLayout().pathGroup().getPath( + ApplicationLayout.PathRole.LINUX_APPLAUNCHER_LIB); + try (var in = ResourceLocator.class.getResourceAsStream("libjpackageapplauncheraux.so")) { + Files.createDirectories(launcherLib.getParent()); + Files.copy(in, launcherLib); + } } - }); - - // create the primary launcher - createLauncherForEntryPoint(params, null); - - // create app launcher shared library - createLauncherLib(); - - // create the additional launchers, if any - List> entryPoints - = ADD_LAUNCHERS.fetchFrom(params); - for (Map entryPoint : entryPoints) { - createLauncherForEntryPoint(AddLauncherArguments.merge(params, - entryPoint, ICON.getID(), ICON_PNG.getID()), params); - } - - // Copy class path entries to Java folder - copyApplication(params); - } - - private void createLauncherLib() throws IOException { - Path path = appLayout.pathGroup().getPath( - ApplicationLayout.PathRole.LINUX_APPLAUNCHER_LIB); - try (InputStream resource = getResourceAsStream("libjpackageapplauncheraux.so")) { - writeEntry(resource, path); + AppImageBuilder.LauncherCallback.super.onLauncher(app, ctx); } - path.toFile().setExecutable(true, false); - path.toFile().setWritable(true, true); - } - - private void createLauncherForEntryPoint(Map params, - Map mainParams) throws IOException { - // Copy executable to launchers folder - Path executableFile = appLayout.launchersDirectory().resolve(getLauncherName(params)); - try (InputStream is_launcher = - getResourceAsStream("jpackageapplauncher")) { - writeEntry(is_launcher, executableFile); - } - - executableFile.toFile().setExecutable(true, false); - executableFile.toFile().setWritable(true, true); - - writeCfgFile(params); - - var iconResource = createIconResource(DEFAULT_ICON, ICON_PNG, params, - mainParams); - if (iconResource != null) { - Path iconTarget = appLayout.destktopIntegrationDirectory().resolve( - APP_NAME.fetchFrom(params) + IOUtils.getSuffix(Path.of( - DEFAULT_ICON))); - iconResource.saveToFile(iconTarget); + @Override + public void onLauncher(Application app, + AppImageBuilder.LauncherContext ctx, + OverridableResource launcherIcon) throws IOException, PackagerException { + String iconFileName = ctx.launcher().executableName() + ".png"; + Path iconTarget = ctx.resolvedAppLayout().destktopIntegrationDirectory().resolve(iconFileName); + launcherIcon.saveToFile(iconTarget); } } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder2.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder2.java deleted file mode 100644 index 0ecbe859bbcb3..0000000000000 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder2.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import static jdk.jpackage.internal.LinuxAppImageBuilder.DEFAULT_ICON; -import jdk.jpackage.internal.resources.ResourceLocator; - -final class LinuxAppImageBuilder2 extends AppImageBuilder { - - LinuxAppImageBuilder2(Application app) { - super(app); - } - - LinuxAppImageBuilder2(Package pkg) { - super(pkg); - } - - @Override - void execute(Workshop workshop) throws IOException, PackagerException { - super.execute(workshop); - - if (app.isRuntime()) { - return; - } - - var resolvedAppLayout = appLayout.resolveAt(workshop.appImageDir()); - - var launcherLib = resolvedAppLayout.pathGroup().getPath( - ApplicationLayout.PathRole.LINUX_APPLAUNCHER_LIB); - try (var in = ResourceLocator.class.getResourceAsStream("libjpackageapplauncheraux.so")) { - Files.createDirectories(launcherLib.getParent()); - Files.copy(in, launcherLib); - } - - for (var launcher : app.launchers()) { - var iconResource = app.createLauncherIconResource(launcher, - DEFAULT_ICON, workshop::createResource); - if (iconResource != null) { - String iconFileName = launcher.executableName() + IOUtils.getSuffix( - Path.of(DEFAULT_ICON)); - Path iconTarget = resolvedAppLayout.destktopIntegrationDirectory().resolve( - iconFileName); - iconResource.saveToFile(iconTarget); - } - } - } -} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 9575199e8ca1a..fb8151d7aa17d 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -102,26 +102,20 @@ public final Path execute(Map params, LinuxPackage pkg = pkgParam.fetchFrom(params); var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); - Workshop pkgWorkshop = new Workshop.Proxy(workshop) { - @Override - public Path appImageDir() { - return buildRoot().resolve("pkg-image"); - } - }; - - params.put(WorkshopFromParams.WORKSHOP.getID(), pkgWorkshop); + Workshop pkgWorkshop = Workshop.withAppImageDir(workshop, + workshop.buildRoot().resolve("image")); try { // We either have an application image or need to build one. if (pkg.app().runtimeBuilder() != null) { // Runtime builder is present, build app image. - new LinuxAppImageBuilder2(pkg).execute(pkgWorkshop); + LinuxAppImageBuilder.build().create(pkg).execute(pkgWorkshop); } else { Path srcAppImageDir = pkg.predefinedAppImage(); if (srcAppImageDir == null) { // No predefined app image and no runtime builder. // This should be runtime packaging. - if (pkg.app().isRuntime()) { + if (pkg.isRuntimeInstaller()) { srcAppImageDir = workshop.appImageDir(); } else { // Can't create app image without runtime builder. @@ -131,8 +125,8 @@ public Path appImageDir() { // Copy app layout omitting application image info file. var srcLayout = pkg.appLayout().resolveAt(srcAppImageDir); - srcLayout.pathGroup().ghostPath(AppImageFile.getPathInAppImage( - srcAppImageDir)); + srcLayout.pathGroup().ghostPath(AppImageFile2.getPathInAppImage( + srcLayout)); srcLayout.copy(pkg.packageLayout().resolveAt(pkgWorkshop.appImageDir())); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index 06814bd5fe914..f925d87181b01 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -38,21 +38,13 @@ public class MacAppBundler extends AppImageBundler { public MacAppBundler() { - setAppImageSupplier(imageOutDir -> { - return new MacAppImageBuilder(imageOutDir, isDependentTask()); + setAppImageSupplier((params, imageOutDir) -> { + var builder = new MacAppImageBuilder(imageOutDir, isDependentTask()); + builder.prepareApplicationFiles(params); }); setParamsValidator(MacAppBundler::doValidate); } - private static final String TEMPLATE_BUNDLE_ICON = "JavaApp.icns"; - - public static final BundlerParamInfo DEFAULT_ICNS_ICON = - new BundlerParamInfo<>( - ".mac.default.icns", - String.class, - params -> TEMPLATE_BUNDLE_ICON, - (s, p) -> s); - public static final BundlerParamInfo DEVELOPER_ID_APP_SIGNING_KEY = new BundlerParamInfo<>( "mac.signing-key-developer-id-app", diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java index eab984f1084ca..2a3ccbaa0cde5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java @@ -30,8 +30,6 @@ import java.nio.file.Path; import java.util.Map; import java.util.List; -import static jdk.jpackage.internal.OverridableResource.createResource; -import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.SOURCE_DIR; import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; @@ -81,10 +79,6 @@ public String name() { }).create(ApplicationLayout.platformAppImage(), appLayout); } - ApplicationLayout getAppLayout() { - return appLayout; - } - protected void copyApplication(Map params) throws IOException { Path inputPath = SOURCE_DIR.fetchFrom(params); @@ -101,57 +95,4 @@ protected void copyApplication(Map params) appLayout.contentDirectory().resolve(item.getFileName())); } } - - public static OverridableResource createIconResource(String defaultIconName, - BundlerParamInfo iconParam, Map params, - Map mainParams) throws IOException { - - if (mainParams != null) { - params = AddLauncherArguments.merge(mainParams, params, ICON.getID(), - iconParam.getID()); - } - - final String resourcePublicName = APP_NAME.fetchFrom(params) - + IOUtils.getSuffix(Path.of(defaultIconName)); - - IconType iconType = getLauncherIconType(params); - if (iconType == IconType.NoIcon) { - return null; - } - - OverridableResource resource = createResource(defaultIconName, params) - .setCategory("icon") - .setExternal(iconParam.fetchFrom(params)) - .setPublicName(resourcePublicName); - - if (iconType == IconType.DefaultOrResourceDirIcon && mainParams != null) { - // No icon explicitly configured for this launcher. - // Dry-run resource creation to figure out its source. - final Path nullPath = null; - if (resource.saveToFile(nullPath) - != OverridableResource.Source.ResourceDir) { - // No icon in resource dir for this launcher, inherit icon - // configured for the main launcher. - resource = createIconResource(defaultIconName, iconParam, - mainParams, null).setLogPublicName(resourcePublicName); - } - } - - return resource; - } - - private enum IconType { DefaultOrResourceDirIcon, CustomIcon, NoIcon }; - - private static IconType getLauncherIconType(Map params) { - Path launcherIcon = ICON.fetchFrom(params); - if (launcherIcon == null) { - return IconType.DefaultOrResourceDirIcon; - } - - if (launcherIcon.toFile().getName().isEmpty()) { - return IconType.NoIcon; - } - - return IconType.CustomIcon; - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java index 4643e2506fc8f..59c6257f26de7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -33,18 +33,39 @@ import java.util.Optional; -class AppImageBuilder { +final class AppImageBuilder { - AppImageBuilder(Application app) { + static final class Builder { + + Builder launcherCallback(LauncherCallback v) { + launcherCallback = v; + return this; + } + + AppImageBuilder create(Application app) { + return new AppImageBuilder(app, app.appLayout(), launcherCallback); + } + + AppImageBuilder create(Package pkg) { + return new AppImageBuilder(pkg, launcherCallback); + } + + private LauncherCallback launcherCallback; + } + + static Builder build() { + return new Builder(); + } + + private AppImageBuilder(Application app, ApplicationLayout appLayout, LauncherCallback launcherCallback) { this.app = app; - this.appLayout = app.appLayout(); + this.appLayout = appLayout; this.withAppImageFile = true; + this.launcherCallback = launcherCallback; } - AppImageBuilder(Package pkg) { - this.app = pkg.app(); - this.appLayout = pkg.packageLayout(); - this.withAppImageFile = false; + private AppImageBuilder(Package pkg, LauncherCallback launcherCallback) { + this(pkg.app(), pkg.packageLayout(), launcherCallback); } private static void copyRecursive(Path srcDir, Path dstDir, Workshop workshop) throws IOException { @@ -72,9 +93,11 @@ void execute(Workshop workshop) throws IOException, PackagerException { return; } - copyRecursive(app.mainSrcDir(), resolvedAppLayout.appDirectory(), workshop); + if (app.srcDir() != null) { + copyRecursive(app.srcDir(), resolvedAppLayout.appDirectory(), workshop); + } - for (var srcDir : Optional.ofNullable(app.additionalSrcDirs()).orElseGet(List::of)) { + for (var srcDir : Optional.ofNullable(app.contentDirs()).orElseGet(List::of)) { copyRecursive(srcDir, resolvedAppLayout.contentDirectory().resolve(srcDir.getFileName()), workshop); @@ -85,6 +108,9 @@ void execute(Workshop workshop) throws IOException, PackagerException { } for (var launcher : app.launchers()) { + // Create corresponding .cfg file + new CfgFile(app, launcher).create(appLayout, resolvedAppLayout); + // Copy executable to launchers folder Path executableFile = resolvedAppLayout.launchersDirectory().resolve( launcher.executableNameWithSuffix()); @@ -93,16 +119,35 @@ void execute(Workshop workshop) throws IOException, PackagerException { Files.copy(in, executableFile); } - var asFile = executableFile.toFile(); + if (launcherCallback != null) { + launcherCallback.onLauncher(app, new LauncherContext(launcher, + workshop, resolvedAppLayout, executableFile)); + } - asFile.setExecutable(true, false); + executableFile.toFile().setExecutable(true); + } + } - // Create corresponding .cfg file - new CfgFile(app, launcher).create(appLayout, resolvedAppLayout); + static interface LauncherCallback { + default public void onLauncher(Application app, LauncherContext ctx) throws IOException, PackagerException { + var iconResource = app.createLauncherIconResource(ctx.launcher, + ctx.workshop::createResource); + if (iconResource != null) { + onLauncher(app, ctx, iconResource); + } + } + + default public void onLauncher(Application app, LauncherContext ctx, + OverridableResource launcherIcon) throws IOException, PackagerException { } } + static record LauncherContext(Launcher launcher, Workshop workshop, + ApplicationLayout resolvedAppLayout, Path launcherExecutable) { + } + private final boolean withAppImageFile; - protected final Application app; - protected final ApplicationLayout appLayout; + private final Application app; + private final ApplicationLayout appLayout; + private final LauncherCallback launcherCallback; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java index 8aed59fbccafc..b351b88dc8174 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java @@ -33,7 +33,6 @@ import java.text.MessageFormat; import java.util.Map; import java.util.Objects; -import java.util.function.Function; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_DATA; @@ -89,11 +88,19 @@ public final Path execute(Map params, return PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); } + var predefinedAppImage = PREDEFINED_APP_IMAGE.fetchFrom(params); + if (predefinedAppImage != null) { + return predefinedAppImage; + } + try { - return createAppBundle(params, outputParentDir); + Path rootDirectory = createRoot(params, outputParentDir); + appImageSupplier.prepareApplicationFiles(params, rootDirectory); + return rootDirectory; + } catch (PackagerException pe) { throw pe; - } catch (RuntimeException|IOException|ConfigException ex) { + } catch (RuntimeException|IOException ex) { Log.verbose(ex); throw new PackagerException(ex); } @@ -118,8 +125,14 @@ final boolean isDependentTask() { return dependentTask; } - final AppImageBundler setAppImageSupplier( - Function v) { + @FunctionalInterface + static interface AppImageSupplier { + + void prepareApplicationFiles(Map params, + Path root) throws PackagerException, IOException; + } + + final AppImageBundler setAppImageSupplier(AppImageSupplier v) { appImageSupplier = v; return this; } @@ -162,30 +175,7 @@ private Path createRoot(Map params, return rootDirectory; } - private Path createAppBundle(Map params, - Path outputDirectory) throws PackagerException, IOException, - ConfigException { - - var app = ApplicationFromParams.APPLICATION.fetchFrom(params); - - boolean hasAppImage = - PREDEFINED_APP_IMAGE.fetchFrom(params) != null; - - Path rootDirectory = hasAppImage ? - PREDEFINED_APP_IMAGE.fetchFrom(params) : - createRoot(params, outputDirectory); - - AbstractAppImageBuilder appBuilder = appImageSupplier.apply(rootDirectory); - if (!hasAppImage) { - app.runtimeBuilder().createRuntime(appBuilder.getAppLayout()); - } - - appBuilder.prepareApplicationFiles(params); - - return rootDirectory; - } - private boolean dependentTask; private ParamsValidator paramsValidator; - private Function appImageSupplier; + private AppImageSupplier appImageSupplier; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java index 47edfd8c17ebb..bccefa5a30e14 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Optional; import java.util.function.Function; +import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; @@ -46,16 +47,9 @@ interface Application { String copyright(); - List srcDirs(); + Path srcDir(); - default Path mainSrcDir() { - return srcDirs().getFirst(); - } - - default List additionalSrcDirs() { - var srcDirs = srcDirs(); - return srcDirs.subList(1, srcDirs.size()); - } + List contentDirs(); RuntimeBuilder runtimeBuilder(); @@ -111,9 +105,10 @@ default Map extraAppImageFileData() { return Map.of(); } - default OverridableResource createLauncherIconResource(Launcher launcher, String defaultIconName, + default OverridableResource createLauncherIconResource(Launcher launcher, Function resourceSupplier) { - final String resourcePublicName = launcher.name() + IOUtils.getSuffix(Path.of( + final String defaultIconName = launcher.defaultIconResourceName(); + final String resourcePublicName = launcher.executableName() + IOUtils.getSuffix(Path.of( defaultIconName)); var iconType = Internal.getLauncherIconType(launcher.icon()); @@ -133,8 +128,8 @@ default OverridableResource createLauncherIconResource(Launcher launcher, String if (toSupplier(() -> resource.saveToFile(nullPath)).get() != OverridableResource.Source.ResourceDir) { // No icon in resource dir for this launcher, inherit icon // configured for the main launcher. - return createLauncherIconResource(mainLauncher(), defaultIconName, resourceSupplier) - .setLogPublicName(resourcePublicName); + return createLauncherIconResource(mainLauncher(), + resourceSupplier).setLogPublicName(resourcePublicName); } } @@ -142,7 +137,7 @@ default OverridableResource createLauncherIconResource(Launcher launcher, String } static record Impl(String name, String description, String version, - String vendor, String copyright, List srcDirs, + String vendor, String copyright, Path srcDir, List contentDirs, RuntimeBuilder runtimeBuilder, List launchers) implements Application { public Impl { name = Optional.ofNullable(name).orElseGet(() -> { @@ -195,8 +190,13 @@ public String copyright() { } @Override - public List srcDirs() { - return target.srcDirs(); + public Path srcDir() { + return target.srcDir(); + } + + @Override + public List contentDirs() { + return target.contentDirs(); } @Override @@ -238,7 +238,12 @@ public String copyright() { } @Override - public List srcDirs() { + public Path srcDir() { + throw new UnsupportedOperationException(); + } + + @Override + public List contentDirs() { throw new UnsupportedOperationException(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java index 9c5b1fb4be980..b94675fd770a8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java @@ -56,7 +56,7 @@ static Application create(Map params, var vendor = VENDOR.fetchFrom(params); var copyright = COPYRIGHT.fetchFrom(params); var srcDir = SOURCE_DIR.fetchFrom(params); - var additionalContent = APP_CONTENT.fetchFrom(params); + var contentDirs = APP_CONTENT.fetchFrom(params); var predefinedAppImage = getPredefinedAppImage(params); if (name == null && predefinedAppImage == null) { @@ -107,9 +107,7 @@ static Application create(Map params, }).orElse(null); return new Application.Impl(name, description, version, vendor, - copyright, Stream.concat(Stream.of(srcDir), - additionalContent.stream()).toList(), runtimeBuilder, - launchers); + copyright, srcDir, contentDirs, runtimeBuilder, launchers); } private static Map mergeParams(Map mainParams, diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java index bff71c81fec0f..0aecba3d83e53 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java @@ -96,25 +96,6 @@ public void run(Workshop workshop, String name) throws IOException { Executor.of(pb).executeExpectSuccess(); } - public void run(Map params) throws IOException { - run(new Workshop() { - @Override - public Path buildRoot() { - throw new UnsupportedOperationException(); - } - - @Override - public Path resourceDir() { - return StandardBundlerParam.RESOURCE_DIR.fetchFrom(params); - } - - @Override - public Path configDir() { - return StandardBundlerParam.CONFIG_ROOT.fetchFrom(params); - } - }, StandardBundlerParam.APP_NAME.fetchFrom(params)); - } - private static String shell() { if (OperatingSystem.isWindows()) { return "cscript"; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java index a297f507da84a..85e5f53d55561 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java @@ -32,90 +32,82 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.text.MessageFormat; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Properties; import java.util.ResourceBundle; -import java.util.function.Supplier; -import static jdk.jpackage.internal.OverridableResource.createResource; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.COPYRIGHT; -import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; -import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; -import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.WindowsAppImageBuilder.ICON_ICO; +import java.util.function.Function; +import java.util.stream.Stream; @SuppressWarnings("restricted") final class ExecutableRebrander { - private static final ResourceBundle I18N = ResourceBundle.getBundle( - "jdk.jpackage.internal.resources.WinResources"); - private static final String LAUNCHER_PROPERTIES_TEMPLATE = - "WinLauncher.template"; + ExecutableRebrander(WinExePackage pkg, + Function resourceSupplier, + UpdateResourceAction... extraActions) { + this(ExecutableProperties.create(pkg), resourceSupplier.apply( + "WinInstaller.template").setPublicName("WinInstaller.properties"), + extraActions); + } - private static final String INSTALLER_PROPERTIES_TEMPLATE = - "WinInstaller.template"; + ExecutableRebrander(WinApplication app, WinLauncher launcher, + Function resourceSupplier, + UpdateResourceAction... extraActions) { + this(ExecutableProperties.create(app, launcher), resourceSupplier.apply( + "WinLauncher.template").setPublicName( + launcher.executableName() + ".properties"), extraActions); + } - private static final String INSTALLER_PROPERTIES_RESOURE_DIR_ID = - "WinInstaller.properties"; + private ExecutableRebrander(ExecutableProperties props, + OverridableResource propertiesFileResource, + UpdateResourceAction... extraActions) { + this.extraActions = List.of(extraActions); + this.propertiesFileResource = propertiesFileResource; + this.props = new HashMap<>(); - void rebrandInstaller(Map params, Path target) - throws IOException { - Path icon = ICON_ICO.fetchFrom(params); - rebrandExecutable(params, icon, () -> { - return createResource(INSTALLER_PROPERTIES_TEMPLATE, params).setPublicName( - INSTALLER_PROPERTIES_RESOURE_DIR_ID); - }, target); - } + validateValueAndPut(this.props, Map.entry("COMPANY_NAME", props.vendor), "vendor"); + validateValueAndPut(this.props, Map.entry("FILE_DESCRIPTION",props.description), "description"); + validateValueAndPut(this.props, Map.entry("FILE_VERSION", props.version.toString()), "version"); + validateValueAndPut(this.props, Map.entry("LEGAL_COPYRIGHT", props.copyright), "copyright"); + validateValueAndPut(this.props, Map.entry("PRODUCT_NAME", props.name), "name"); - void rebrandLauncher(Map params, Path icon, - Path target) throws IOException { - rebrandExecutable(params, icon, () -> { - return createResource( - LAUNCHER_PROPERTIES_TEMPLATE, params).setPublicName( - APP_NAME.fetchFrom(params) + ".properties"); - }, target); + this.props.put("FIXEDFILEINFO_FILE_VERSION", toFixedFileVersion(props.version)); + this.props.put("INTERNAL_NAME", props.executableName); + this.props.put("ORIGINAL_FILENAME", props.executableName); } - private void rebrandExecutable(Map params, Path icon, - Supplier resourceSupplier, Path target) throws - IOException { - if (!target.isAbsolute() || (icon != null && !icon.isAbsolute())) { - Path absIcon = null; - if (icon != null) { - absIcon = icon.toAbsolutePath(); - } - rebrandExecutable(params, absIcon, resourceSupplier, - target.toAbsolutePath()); - return; - } - rebrandExecutable(params, target, (resourceLock) -> { - rebrandProperties(resourceLock, resourceSupplier.get(), - createSubstituteData( - params), target); - if (icon != null) { - iconSwapWrapper(resourceLock, icon.toString()); - } - }); - } + void execute(Workshop workshop, Path target, Path icon) throws IOException { + String[] propsArray = toStringArray(propertiesFileResource, props); - ExecutableRebrander addAction(UpdateResourceAction action) { - if (extraActions == null) { - extraActions = new ArrayList<>(); + UpdateResourceAction versionSwapper = resourceLock -> { + if (versionSwap(resourceLock, propsArray) != 0) { + throw new RuntimeException(MessageFormat.format(I18N.getString( + "error.version-swap"), target)); + } + }; + + var absIcon = Optional.ofNullable(icon).map(Path::toAbsolutePath).orElse( + null); + if (absIcon == null) { + rebrandExecutable(workshop, target, versionSwapper); + } else { + rebrandExecutable(workshop, target, versionSwapper, + resourceLock -> { + if (iconSwap(resourceLock, absIcon.toString()) != 0) { + throw new RuntimeException(MessageFormat.format( + I18N.getString("error.icon-swap"), absIcon)); + } + }); } - extraActions.add(action); - return this; } - private void rebrandExecutable(Map params, - Path target, UpdateResourceAction action) throws IOException { + private static void rebrandExecutable(Workshop workshop, + Path target, UpdateResourceAction ... actions) throws IOException { try { - String tempDirectory = TEMP_ROOT.fetchFrom(params) - .toAbsolutePath().toString(); + String tempDirectory = workshop.buildRoot().toAbsolutePath().toString(); if (WindowsDefender.isThereAPotentialWindowsDefenderIssue( tempDirectory)) { Log.verbose(MessageFormat.format(I18N.getString( @@ -133,11 +125,8 @@ private void rebrandExecutable(Map params, final boolean resourceUnlockedSuccess; try { - action.editResource(resourceLock); - if (extraActions != null) { - for (UpdateResourceAction extraAction : extraActions) { - extraAction.editResource(resourceLock); - } + for (var action : actions) { + action.editResource(resourceLock); } } finally { if (resourceLock == 0) { @@ -156,101 +145,77 @@ private void rebrandExecutable(Map params, } } - @FunctionalInterface - static interface UpdateResourceAction { - public void editResource(long resourceLock) throws IOException; - } - - private static String getFixedFileVersion(String value) { - int addComponentsCount = 4 - - DottedVersion.greedy(value).getComponents().length; + private static String toFixedFileVersion(DottedVersion value) { + int addComponentsCount = 4 - value.getComponents().length; if (addComponentsCount > 0) { - StringBuilder sb = new StringBuilder(value); + StringBuilder sb = new StringBuilder(value.toComponentsString()); do { sb.append('.'); sb.append(0); } while (--addComponentsCount > 0); return sb.toString(); } - return value; + return value.toComponentsString(); } - private Map createSubstituteData( - Map params) { - Map data = new HashMap<>(); - - String fixedFileVersion = getFixedFileVersion(VERSION.fetchFrom(params)); - - // mapping Java parameters in strings for version resource - validateValueAndPut(data, "COMPANY_NAME", VENDOR, params); - validateValueAndPut(data, "FILE_DESCRIPTION", DESCRIPTION, params); - validateValueAndPut(data, "FILE_VERSION", VERSION, params); - validateValueAndPut(data, "LEGAL_COPYRIGHT", COPYRIGHT, params); - validateValueAndPut(data, "PRODUCT_NAME", APP_NAME, params); - data.put("FIXEDFILEINFO_FILE_VERSION", fixedFileVersion); - - return data; - } - - private void rebrandProperties(long resourceLock, OverridableResource properties, - Map data, Path target) throws IOException { - - String targetExecutableName = IOUtils.getFileName(target).toString(); - data.put("INTERNAL_NAME", targetExecutableName); - data.put("ORIGINAL_FILENAME", targetExecutableName); - + private static String[] toStringArray( + OverridableResource propertiesFileResource, + Map props) throws IOException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - properties - .setSubstitutionData(data) - .setCategory(I18N.getString("resource.executable-properties-template")) - .saveToStream(buffer); + propertiesFileResource + .setSubstitutionData(props) + .setCategory(I18N.getString( + "resource.executable-properties-template")) + .saveToStream(buffer); - final List propList = new ArrayList<>(); try (Reader reader = new InputStreamReader(new ByteArrayInputStream( buffer.toByteArray()), StandardCharsets.UTF_8)) { - final Properties configProp = new Properties(); + var configProp = new Properties(); configProp.load(reader); - configProp.forEach((k, v) -> { - propList.add(k.toString()); - propList.add(v.toString()); - }); + return configProp.entrySet().stream().flatMap(e -> Stream.of( + e.getKey().toString(), e.getValue().toString())).toArray( + String[]::new); } - - versionSwapWrapper(resourceLock, propList.toArray(String[]::new), - target.toString()); } - private static void validateValueAndPut( - Map data, String key, - BundlerParamInfo param, - Map params) { - String value = param.fetchFrom(params); - if (value.contains("\r") || value.contains("\n")) { - Log.error("Configuration Parameter " + param.getID() + private static void validateValueAndPut(Map target, + Map.Entry e, String label) { + if (e.getValue().contains("\r") || e.getValue().contains("\n")) { + Log.error("Configuration parameter " + label + " contains multiple lines of text, ignore it"); - data.put(key, ""); - return; + e = Map.entry(e.getKey(), ""); } - data.put(key, value); + target.put(e.getKey(), e.getValue()); } - private static void iconSwapWrapper(long resourceLock, - String iconTarget) { - if (iconSwap(resourceLock, iconTarget) != 0) { - throw new RuntimeException(MessageFormat.format(I18N.getString( - "error.icon-swap"), iconTarget)); - } + @FunctionalInterface + static interface UpdateResourceAction { + public void editResource(long resourceLock) throws IOException; } - private static void versionSwapWrapper(long resourceLock, - String[] executableProperties, String target) { - if (versionSwap(resourceLock, executableProperties) != 0) { - throw new RuntimeException(MessageFormat.format(I18N.getString( - "error.version-swap"), target)); + private static record ExecutableProperties(String vendor, String description, + DottedVersion version, String copyright, String name, String executableName) { + static ExecutableProperties create(WinApplication app, + WinLauncher launcher) { + return new ExecutableProperties(app.vendor(), launcher.description(), + app.winVersion(), app.copyright(), launcher.name(), + launcher.executableNameWithSuffix()); + } + + static ExecutableProperties create(WinExePackage pkg) { + return new ExecutableProperties(pkg.app().vendor(), + pkg.description(), DottedVersion.lazy(pkg.version()), + pkg.app().copyright(), pkg.packageName(), + pkg.packageFileName().getFileName().toString()); } } - private List extraActions; + private final Map props; + private final List extraActions; + private final OverridableResource propertiesFileResource; + + private static final ResourceBundle I18N = ResourceBundle.getBundle( + "jdk.jpackage.internal.resources.WinResources"); static { System.loadLibrary("jpackage"); @@ -260,7 +225,7 @@ private static void versionSwapWrapper(long resourceLock, private static native boolean unlockResource(long resourceLock); - private static native int iconSwap(long resourceLock, String iconTarget); + private static native int iconSwap(long resourceLock, String newIcon); private static native int versionSwap(long resourceLock, String[] executableProperties); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java index 16ae11e1f4a4e..799c198f61d38 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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,6 +27,12 @@ public class WinAppBundler extends AppImageBundler { public WinAppBundler() { - setAppImageSupplier(WindowsAppImageBuilder::new); + setAppImageSupplier((params, output) -> { + // Order is important! + var app = WinApplicationFromParams.APPLICATION.fetchFrom(params); + var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); + WinAppImageBuilder.build().create(app).execute( + Workshop.withAppImageDir(workshop, output)); + }); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java new file mode 100644 index 0000000000000..bfb01d95b97a0 --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.io.IOException; +import java.nio.file.Path; + +final class WinAppImageBuilder { + + static AppImageBuilder.Builder build() { + return new AppImageBuilder.Builder().launcherCallback(new LauncherCallbackImpl()); + } + + private final static class LauncherCallbackImpl implements + AppImageBuilder.LauncherCallback { + + @Override + public void onLauncher(Application app, + AppImageBuilder.LauncherContext ctx) throws IOException, PackagerException { + Path iconTarget = null; + var iconResource = app.createLauncherIconResource(ctx.launcher(), + name -> ctx.workshop().createResource(name)); + if (iconResource != null) { + var iconDir = ctx.workshop().buildRoot().resolve("icons"); + iconTarget = iconDir.resolve(ctx.launcher().executableName() + ".ico"); + if (null == iconResource.saveToFile(iconTarget)) { + iconTarget = null; + } + } + + // Update branding of launcher executable + new ExecutableRebrander((WinApplication) app, + (WinLauncher) ctx.launcher(), + name -> ctx.workshop().createResource(name)).execute( + ctx.workshop(), ctx.launcherExecutable(), iconTarget); + } + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java index f3cdec72f96bd..1a85e1c5f1a7e 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java @@ -28,8 +28,11 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.text.MessageFormat; import java.util.Map; +import static jdk.jpackage.internal.Functional.ThrowingRunnable.toRunnable; +import static jdk.jpackage.internal.StandardBundlerParam.ICON; @SuppressWarnings("restricted") public class WinExeBundler extends AbstractBundler { @@ -38,25 +41,6 @@ public class WinExeBundler extends AbstractBundler { System.loadLibrary("jpackage"); } - public static final BundlerParamInfo EXE_IMAGE_DIR - = new BundlerParamInfo<>( - "win.exe.imageDir", - Path.class, - params -> { - Path imagesRoot = IMAGES_ROOT.fetchFrom(params); - if (!Files.exists(imagesRoot)) { - try { - Files.createDirectories(imagesRoot); - } catch (IOException ioe) { - return null; - } - } - return imagesRoot.resolve("win-exe.image"); - }, - (s, p) -> null); - - private static final String EXE_WRAPPER_NAME = "msiwrapper.exe"; - @Override public String getName() { return I18N.getString("exe.bundler.name"); @@ -72,12 +56,6 @@ public String getBundleType() { return "INSTALLER"; } - @Override - public Path execute(Map params, - Path outputParentDir) throws PackagerException { - return bundle(params, outputParentDir); - } - @Override public boolean supported(boolean platformInstaller) { return msiBundler.supported(platformInstaller); @@ -94,32 +72,40 @@ public boolean validate(Map params) return msiBundler.validate(params); } - public Path bundle(Map params, Path outdir) + @Override + public Path execute(Map params, Path outdir) throws PackagerException { + // Order is important! + var pkg = WinMsiPackageFromParams.PACKAGE.fetchFrom(params); + var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); + IOUtils.writableOutputDir(outdir); - Path exeImageDir = EXE_IMAGE_DIR.fetchFrom(params); + Path msiDir = workshop.buildRoot().resolve("msi"); + toRunnable(() -> Files.createDirectories(msiDir)).run(); // Write msi to temporary directory. - Path msi = msiBundler.execute(params, exeImageDir); + Path msi = msiBundler.execute(params, msiDir); try { + var exePkg = new WinExePackage.Impl(pkg, ICON.fetchFrom(params)); + new ScriptRunner() .setDirectory(msi.getParent()) .setResourceCategoryId("resource.post-msi-script") .setScriptNameSuffix("post-msi") .setEnvironmentVariable("JpMsiFile", msi.toAbsolutePath().toString()) - .run(params); + .run(workshop, IOUtils.replaceSuffix(pkg.packageFileName(), "").getFileName().toString()); - return buildEXE(params, msi, outdir); - } catch (IOException ex) { + return buildEXE(workshop, exePkg, msi, outdir); + } catch (IOException|ConfigException ex) { Log.verbose(ex); throw new PackagerException(ex); } } - private Path buildEXE(Map params, Path msi, + private Path buildEXE(Workshop workshop, WinExePackage pkg, Path msi, Path outdir) throws IOException { Log.verbose(MessageFormat.format( @@ -127,22 +113,21 @@ private Path buildEXE(Map params, Path msi, outdir.toAbsolutePath().toString())); // Copy template msi wrapper next to msi file - final Path exePath = IOUtils.replaceSuffix(msi, ".exe"); - try (InputStream is = OverridableResource.readDefault(EXE_WRAPPER_NAME)) { + final Path exePath = msi.getParent().resolve(pkg.packageFileName()); + try (InputStream is = OverridableResource.readDefault("msiwrapper.exe")) { Files.copy(is, exePath); } - new ExecutableRebrander().addAction((resourceLock) -> { + new ExecutableRebrander(pkg, workshop::createResource, resourceLock -> { // Embed msi in msi wrapper exe. embedMSI(resourceLock, msi.toAbsolutePath().toString()); - }).rebrandInstaller(params, exePath); + }).execute(workshop, exePath, pkg.icon()); - Path dstExePath = outdir.toAbsolutePath().resolve(exePath.getFileName()); - Files.deleteIfExists(dstExePath); + Path dstExePath = outdir.resolve(exePath.getFileName()); - Files.copy(exePath, dstExePath); + Files.copy(exePath, dstExePath, StandardCopyOption.REPLACE_EXISTING); - dstExePath.toFile().setWritable(true, true); + dstExePath.toFile().setExecutable(true); Log.verbose(MessageFormat.format( I18N.getString("message.output-location"), diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index e0ee2ff9b01d5..e850f638ef368 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -119,7 +119,6 @@ public class WinMsiBundler extends AbstractBundler { public WinMsiBundler() { - appImageBundler = new WinAppBundler().setDependentTask(true); wixFragments = Stream.of( Map.entry("bundle.wxf", new WixAppImageFragmentBuilder()), Map.entry("ui.wxf", new WixUiFragmentBuilder()) @@ -171,7 +170,9 @@ public boolean isDefault() { public boolean validate(Map params) throws ConfigException { try { - appImageBundler.validate(params); + // Order is important! + WinApplicationFromParams.APPLICATION.fetchFrom(params); + WorkshopFromParams.WORKSHOP.fetchFrom(params); if (wixToolset == null) { wixToolset = WixTool.createToolset(); @@ -201,24 +202,31 @@ public boolean validate(Map params) } } - private void prepareProto(Map params) - throws PackagerException, IOException { + private void prepareProto(WinMsiPackage pkg, Workshop workshop) throws + PackagerException, IOException { - // Order is important! - var pkg = WinMsiPackageFromParams.PACKAGE.fetchFrom(params); - var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); - - Path appImage = pkg.predefinedAppImage(); + ApplicationLayout appLayout; - // we either have an application image or need to build one - if (appImage != null) { - IOUtils.copyRecursive(appImage, workshop.appImageDir()); + // We either have an application image or need to build one. + if (pkg.app().runtimeBuilder() != null) { + // Runtime builder is present, build app image. + WinAppImageBuilder.build().create(pkg.app()).execute(workshop); + appLayout = pkg.appLayout().resolveAt(workshop.appImageDir()); } else { - Files.createDirectories(workshop.appImageDir().getParent()); - appImageBundler.execute(params, workshop.appImageDir().getParent()); - } + Path srcAppImageDir = pkg.predefinedAppImage(); + if (srcAppImageDir == null) { + // No predefined app image and no runtime builder. + // This should be runtime packaging. + if (pkg.isRuntimeInstaller()) { + srcAppImageDir = workshop.appImageDir(); + } else { + // Can't create app image without runtime builder. + throw new UnsupportedOperationException(); + } + } - var pkgLayout = pkg.packageLayout().resolveAt(workshop.appImageDir()); + appLayout = pkg.appLayout().resolveAt(srcAppImageDir); + } // Configure installer icon if (pkg.isRuntimeInstaller()) { @@ -226,12 +234,10 @@ private void prepareProto(Map params) // Assume java.exe exists in Java Runtime being packed. // Ignore custom icon if any as we don't want to copy anything in // Java Runtime image. - installerIcon = pkgLayout.runtimeDirectory().resolve(Path.of("bin", "java.exe")); + installerIcon = appLayout.runtimeDirectory().resolve(Path.of("bin", "java.exe")); } else { - installerIcon = pkgLayout.launchersDirectory().resolve( + installerIcon = appLayout.launchersDirectory().resolve( pkg.app().mainLauncher().executableNameWithSuffix()); - - new PackageFile(pkg.packageName()).save(pkgLayout); } installerIcon = installerIcon.toAbsolutePath(); @@ -251,15 +257,15 @@ private void prepareProto(Map params) public Path execute(Map params, Path outputParentDir) throws PackagerException { + IOUtils.writableOutputDir(outputParentDir); + // Order is important! var pkg = WinMsiPackageFromParams.PACKAGE.fetchFrom(params); var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); - IOUtils.writableOutputDir(outputParentDir); - Path imageDir = workshop.appImageDir(); try { - prepareProto(params); + prepareProto(pkg, workshop); for (var wixFragment : wixFragments) { wixFragment.initFromParams(workshop, pkg); wixFragment.addFilesToConfigRoot(); @@ -500,8 +506,6 @@ private static String getCultureFromWxlFile(Path wxlPath) throws IOException { } private static void ensureByMutationFileIsRTF(Path f) { - if (f == null || !Files.isRegularFile(f)) return; - try { boolean existingLicenseIsRTF = false; @@ -571,6 +575,5 @@ private static void ensureByMutationFileIsRTF(Path f) { private Path installerIcon; private WixToolset wixToolset; - private AppImageBundler appImageBundler; private final List wixFragments; } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsAppImageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsAppImageBuilder.java deleted file mode 100644 index 0ed3650fbc299..0000000000000 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsAppImageBuilder.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.List; -import java.util.Map; -import java.util.ResourceBundle; - -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.ICON; -import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; - -public class WindowsAppImageBuilder extends AbstractAppImageBuilder { - private static final ResourceBundle I18N = ResourceBundle.getBundle( - "jdk.jpackage.internal.resources.WinResources"); - - private static final String TEMPLATE_APP_ICON ="JavaApp.ico"; - - public static final BundlerParamInfo ICON_ICO = - new BundlerParamInfo<>( - "icon.ico", - Path.class, - params -> { - Path f = ICON.fetchFrom(params); - if (f != null && f.getFileName() != null && !f.getFileName() - .toString().toLowerCase().endsWith(".ico")) { - Log.error(MessageFormat.format( - I18N.getString("message.icon-not-ico"), f)); - return null; - } - return f; - }, - (s, p) -> Path.of(s)); - - public static final BundlerParamInfo CONSOLE_HINT = - new BundlerParamInfo<>( - Arguments.CLIOptions.WIN_CONSOLE_HINT.getId(), - Boolean.class, - params -> false, - // valueOf(null) is false, - // and we actually do want null in some cases - (s, p) -> (s == null - || "null".equalsIgnoreCase(s)) ? true : Boolean.valueOf(s)); - - WindowsAppImageBuilder(Path imageOutDir) { - super(imageOutDir); - } - - private void writeEntry(InputStream in, Path dstFile) throws IOException { - Files.createDirectories(IOUtils.getParent(dstFile)); - Files.copy(in, dstFile); - } - - private static String getLauncherName(Map params) { - return APP_NAME.fetchFrom(params) + ".exe"; - } - - // Returns launcher resource name for launcher we need to use. - public static String getLauncherResourceName( - Map params) { - if (CONSOLE_HINT.fetchFrom(params)) { - return "jpackageapplauncher.exe"; - } else { - return "jpackageapplauncherw.exe"; - } - } - - @Override - public void prepareApplicationFiles(Map params) - throws IOException { - // create the .exe launchers - createLauncherForEntryPoint(params, null); - - // copy the jars - copyApplication(params); - - // create the additional launcher(s), if any - List> entryPoints = ADD_LAUNCHERS.fetchFrom(params); - for (Map entryPoint : entryPoints) { - createLauncherForEntryPoint(AddLauncherArguments.merge(params, - entryPoint, ICON.getID(), ICON_ICO.getID()), params); - } - } - - private void createLauncherForEntryPoint(Map params, - Map mainParams) throws IOException { - - var iconResource = createIconResource(TEMPLATE_APP_ICON, ICON_ICO, params, - mainParams); - Path iconTarget = null; - if (iconResource != null) { - Path iconDir = StandardBundlerParam.TEMP_ROOT.fetchFrom(params).resolve( - "icons"); - iconTarget = iconDir.resolve(APP_NAME.fetchFrom(params) + ".ico"); - if (null == iconResource.saveToFile(iconTarget)) { - iconTarget = null; - } - } - - writeCfgFile(params); - - // Copy executable to bin folder - Path executableFile = appLayout.launchersDirectory().resolve( - getLauncherName(params)); - - try (InputStream is_launcher = - getResourceAsStream(getLauncherResourceName(params))) { - writeEntry(is_launcher, executableFile); - } - - // Update branding of launcher executable - new ExecutableRebrander().rebrandLauncher(params, iconTarget, executableFile); - - executableFile.toFile().setExecutable(true); - executableFile.toFile().setReadOnly(); - } -} From 705fb2d3ee64fecd0c1aef2fb7b859c26dbe49dc Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 23 Oct 2024 23:17:49 -0400 Subject: [PATCH 0062/1101] Bugfix --- .../windows/classes/jdk/jpackage/internal/WinMsiPackage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java index 33798acbff156..7ef73a6eb049f 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java @@ -72,7 +72,7 @@ static class Impl extends Package.Proxy implements WinMsiPackage { "error.version-string-wrong-format.advice"), ex); } - if (pkg.app().isService() && serviceInstaller == null || !Files.exists(serviceInstaller)) { + if (pkg.app().isService() && (serviceInstaller == null || !Files.exists(serviceInstaller))) { throw new ConfigException(I18N.getString("error.missing-service-installer"), I18N .getString("error.missing-service-installer.advice")); } From dcbb158ed702cd280a45c47c5d797332d5ee887d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 24 Oct 2024 08:42:57 -0400 Subject: [PATCH 0063/1101] Get rid of dependency on jdk.internal.util.OperatingSystem. --- .../jdk/jpackage/test/AppImageFile.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java index 6560c06b76fcf..518d6a9584b21 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java @@ -24,14 +24,11 @@ import java.io.IOException; import java.nio.file.Files; -import java.nio.file.NoSuchFileException; import java.nio.file.Path; -import java.util.Map; import java.util.Optional; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.internal.IOUtils; import org.w3c.dom.Document; @@ -116,13 +113,16 @@ private static String getVersion() { } private static String getPlatform() { - return PLATFORM_LABELS.get(OperatingSystem.current()); + if (TKit.isLinux()) { + return "linux"; + } else if (TKit.isOSX()) { + return "macOS"; + } else if (TKit.isWindows()) { + return "windows"; + } else { + throw new UnsupportedOperationException(); + } } - private static final Map PLATFORM_LABELS = Map.of( - OperatingSystem.LINUX, "linux", - OperatingSystem.WINDOWS, "windows", - OperatingSystem.MACOS, "macOS"); - private static final String FILENAME = ".jpackage.xml"; } From b97f8cdadd42979c8c92980679ad6f7b750cc57e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 24 Oct 2024 08:43:53 -0400 Subject: [PATCH 0064/1101] ConfigException.Builder.msg() -> ConfigException.Builder.message() --- .../classes/jdk/jpackage/internal/ConfigException.java | 2 +- .../share/classes/jdk/jpackage/internal/Launcher.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ConfigException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ConfigException.java index 3f4e46aacc6c9..8fc105c69f716 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ConfigException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ConfigException.java @@ -58,7 +58,7 @@ ConfigException create() { return new ConfigException(msg, advice, cause); } - public Builder msg(String msgId, Object ... args) { + public Builder message(String msgId, Object ... args) { msg = I18N.format(msgId, args); return this; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java index f9a4ff7059ccc..c2e4857f36eb7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java @@ -93,17 +93,17 @@ static void validateIcon(Path icon) throws ConfigException { switch (OperatingSystem.current()) { case WINDOWS -> { if (!icon.getFileName().toString().toLowerCase().endsWith(".ico")) { - throw ConfigException.build().msg("message.icon-not-ico", icon).create(); + throw ConfigException.build().message("message.icon-not-ico", icon).create(); } } case LINUX -> { if (!icon.getFileName().toString().endsWith(".png")) { - throw ConfigException.build().msg("message.icon-not-png", icon).create(); + throw ConfigException.build().message("message.icon-not-png", icon).create(); } } case MACOS -> { if (!icon.getFileName().toString().endsWith(".icns")) { - throw ConfigException.build().msg("message.icon-not-icns", icon).create(); + throw ConfigException.build().message("message.icon-not-icns", icon).create(); } } } From 715c5aeb5cab619e2d35e5b1e82ca74157daab86 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 24 Oct 2024 08:44:29 -0400 Subject: [PATCH 0065/1101] Fix InstallDirTest failure on windows --- .../share/classes/jdk/jpackage/internal/Package.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index b668385e29787..32ff83b2c7fcc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -159,6 +159,9 @@ default Path relativeInstallDir() { } } } + case WinExe, WinMsi -> { + return v; + } } return v.resolve(packageName()); }).orElseGet(() -> defaultInstallDir(this)); @@ -301,8 +304,8 @@ static Package override(Package base, Package overrides) { } static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigException { - var ex = new ConfigException(MessageFormat.format(I18N.getString("error.invalid-install-dir"), - installDir), null); + var ex = ConfigException.build().message("error.invalid-install-dir", + installDir).create(); if (installDir.getNameCount() == 0) { throw ex; From 95ec46faa4906f322f1f663ad4f6a9061ce3d3d3 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 24 Oct 2024 08:45:37 -0400 Subject: [PATCH 0066/1101] Move `error.invalid-install-dir` key from LinuxResources.properties to shared MainResources.properties --- .../jdk/jpackage/internal/resources/LinuxResources.properties | 4 +--- .../jdk/jpackage/internal/resources/MainResources.properties | 4 +++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties index 8bc11a4f054e2..6b570b0947c4f 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2024, 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 @@ -44,8 +44,6 @@ resource.systemd-unit-file=systemd unit file error.tool-not-found.advice=Please install required packages error.tool-old-version.advice=Please install required packages -error.invalid-install-dir=Invalid installation directory "{0}" - error.invalid-value-for-package-name=Invalid value "{0}" for the bundle name. error.invalid-value-for-package-name.advice=Set the "linux-bundle-name" option to a valid Debian package name. Note that the package names must consist only of lower case letters (a-z), digits (0-9), plus (+) and minus (-) signs, and periods (.). They must be at least two characters long and must start with an alphanumeric character. diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index 53f012b0e950e..68d84b973bd43 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2024, 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 @@ -82,6 +82,8 @@ warning.no.jdk.modules.found=Warning: No JDK Modules found error.foreign-app-image=Error: Missing .jpackage.xml file in app-image dir "{0}" error.invalid-app-image=Error: app-image dir "{0}" generated by another jpackage version or malformed "{1}" +error.invalid-install-dir=Invalid installation directory "{0}" + MSG_BundlerFailed=Error: Bundler "{1}" ({0}) failed to produce a package MSG_BundlerConfigException=Bundler {0} skipped because of a configuration problem: {1} \n\ Advice to fix: {2} From e0cffce072719885e82469610df07b27e99b3719 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 24 Oct 2024 09:44:40 -0400 Subject: [PATCH 0067/1101] Fix exe package --- .../classes/jdk/jpackage/internal/WinExePackage.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java index 5b48cb087f996..4a6807c07ecec 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java @@ -32,11 +32,6 @@ interface WinExePackage extends Package { Path icon(); - @Override - default PackageType type() { - return StandardPackageType.WinExe; - } - static class Impl extends Package.Proxy implements WinExePackage { Impl(WinMsiPackage msiPackage, Path icon) throws ConfigException { @@ -47,6 +42,11 @@ static class Impl extends Package.Proxy implements WinExePackage } } + @Override + public PackageType type() { + return StandardPackageType.WinExe; + } + @Override public WinMsiPackage msiPackage() { return target; From 55e5ebc1fee58b2c0901ab921b7c7a8a5a87576f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 24 Oct 2024 12:34:08 -0400 Subject: [PATCH 0068/1101] Make PackagerException use I18N class to access l10n data. Fixes the issue that PackagerException can pull values from `jdk.jpackage.internal.resources.MainResources` resource bundle only instead of all jpackage resource bundles --- .../jpackage/internal/PackagerException.java | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerException.java index b5f514ae1ab68..2483e9706ab21 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, 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,38 +22,30 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.jpackage.internal; -import java.text.MessageFormat; -import java.util.ResourceBundle; - public class PackagerException extends Exception { + private static final long serialVersionUID = 1L; - private static final ResourceBundle bundle = ResourceBundle.getBundle( - "jdk.jpackage.internal.resources.MainResources"); public PackagerException(Throwable cause) { super(cause); } public PackagerException(String key, Throwable cause) { - super(bundle.getString(key), cause); + super(I18N.getString(key), cause); } public PackagerException(String key) { - super(bundle.getString(key)); + super(I18N.getString(key)); } - public PackagerException(String key, String ... arguments) { - super(MessageFormat.format( - bundle.getString(key), (Object[]) arguments)); + public PackagerException(String key, Object... arguments) { + super(I18N.format(key, arguments)); } - public PackagerException( - Throwable cause, String key, String ... arguments) { - super(MessageFormat.format(bundle.getString(key), - (Object[]) arguments), cause); + public PackagerException(Throwable cause, String key, Object... arguments) { + super(I18N.format(key, arguments), cause); } } From 5b33aeb859eab7c05b5ddafa5fc7c77c00649710 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 24 Oct 2024 12:35:51 -0400 Subject: [PATCH 0069/1101] PackageFile.getPathInAppImage() and AppImageFile2.getPathInAppImage() will return null if called on app layout without `app` subdirectory (runtime image) --- .../share/classes/jdk/jpackage/internal/AppImageFile2.java | 3 ++- .../share/classes/jdk/jpackage/internal/PackageFile.java | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index 316b90a31ecbf..c57abf58c8332 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -159,7 +159,8 @@ static Path getPathInAppImage(Path appImageDir) { * @param appLayout - application layout */ static Path getPathInAppImage(ApplicationLayout appLayout) { - return appLayout.appDirectory().resolve(FILENAME); + return Optional.ofNullable(appLayout.appDirectory()).map( + path -> path.resolve(FILENAME)).orElse(null); } /** diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java index 2c2e8a3165779..9d956c3fcc9de 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java @@ -29,6 +29,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; +import java.util.Optional; public final class PackageFile { @@ -46,7 +47,8 @@ public static Path getPathInAppImage(Path appImageDir) { * @param appLayout - application layout */ public static Path getPathInAppImage(ApplicationLayout appLayout) { - return appLayout.appDirectory().resolve(FILENAME); + return Optional.ofNullable(appLayout.appDirectory()).map( + path -> path.resolve(FILENAME)).orElse(null); } PackageFile(String packageName) { From e2bb391eef7aa7ce2bcb2664f2d141a057922937 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 24 Oct 2024 12:37:00 -0400 Subject: [PATCH 0070/1101] Get rid of Linux-specific `LINUX_APPLAUNCHER_LIB` in ApplicationLayout --- .../jdk/jpackage/internal/LinuxAppImageBuilder.java | 4 ++-- .../jdk/jpackage/internal/ApplicationLayout.java | 10 +--------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index 76fe4f259db53..0149d0ef9bb44 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -41,8 +41,8 @@ private final static class LauncherCallbackImpl implements AppImageBuilder.Launc public void onLauncher(Application app, AppImageBuilder.LauncherContext ctx) throws IOException, PackagerException { if (ctx.launcher() == app.mainLauncher()) { - var launcherLib = ctx.resolvedAppLayout().pathGroup().getPath( - ApplicationLayout.PathRole.LINUX_APPLAUNCHER_LIB); + var launcherLib = ctx.workshop().appImageDir().resolve(Path.of( + "lib/libapplauncher.so")); try (var in = ResourceLocator.class.getResourceAsStream("libjpackageapplauncheraux.so")) { Files.createDirectories(launcherLib.getParent()); Files.copy(in, launcherLib); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java index e96b6b72de2c0..1b455d61c98ba 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -65,11 +65,6 @@ enum PathRole { */ MODULES, - /** - * Linux app launcher shared library. - */ - LINUX_APPLAUNCHER_LIB, - /** * Location of additional application content */ @@ -151,7 +146,6 @@ static ApplicationLayout linuxAppImage() { PathRole.RUNTIME_HOME, Path.of("lib/runtime"), PathRole.DESKTOP, Path.of("lib"), PathRole.MODULES, Path.of("lib/app/mods"), - PathRole.LINUX_APPLAUNCHER_LIB, Path.of("lib/libapplauncher.so"), PathRole.CONTENT, Path.of("lib") )); } @@ -210,8 +204,6 @@ public static ApplicationLayout linuxUsrTreePackageImage(Path prefix, PathRole.RUNTIME_HOME, lib.resolve("runtime"), PathRole.DESKTOP, lib, PathRole.MODULES, lib.resolve("app/mods"), - PathRole.LINUX_APPLAUNCHER_LIB, lib.resolve( - "lib/libapplauncher.so"), PathRole.CONTENT, lib )); } From 46eb697a961c4716a5a3b355df8f7439680b8d64 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 24 Oct 2024 13:27:45 -0400 Subject: [PATCH 0071/1101] Fix runtime package building --- .../internal/WixAppImageFragmentBuilder.java | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index fb1372b4c165d..18a975649e1b4 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -84,7 +84,8 @@ void initFromParams(Workshop workshop, WinMsiPackage pkg) { do { ApplicationLayout layout = pkg.appLayout(); // Don't want app image info file in installed application. - layout.pathGroup().ghostPath(AppImageFile2.getPathInAppImage(layout)); + Optional.ofNullable(AppImageFile2.getPathInAppImage(layout)).ifPresent( + appImageFile -> layout.pathGroup().ghostPath(appImageFile)); // Want absolute paths to source files in generated WiX sources. // This is to handle scenario if sources would be processed from @@ -94,7 +95,7 @@ void initFromParams(Workshop workshop, WinMsiPackage pkg) { installedAppImage = pkg.appLayout().resolveAt(INSTALLDIR); - launchers = toCollection(pkg.app().launchers()); + launchers = toCollection(Optional.ofNullable(pkg.app().launchers()).orElseGet(List::of)); shortcutFolders = ShortcutsFolder.getForPackage(pkg); @@ -119,16 +120,23 @@ void initFromParams(Workshop workshop, WinMsiPackage pkg) { programMenuFolderName = pkg.startMenuGroupName(); - packageFile = new PackageFile(pkg.packageName()); + if (!pkg.isRuntimeInstaller()) { + packageFile = new PackageFile(pkg.packageName()); + } else { + packageFile = null; + } - initFileAssociations(pkg); + initFileAssociations(); } @Override void addFilesToConfigRoot() throws IOException { removeFolderItems = new HashMap<>(); defaultedMimes = new HashSet<>(); - packageFile.save(ApplicationLayout.windowsAppImage().resolveAt(getConfigRoot())); + if (packageFile != null) { + packageFile.save(ApplicationLayout.windowsAppImage().resolveAt( + getConfigRoot())); + } super.addFilesToConfigRoot(); } @@ -189,9 +197,9 @@ private Path getInstalledFaIcoPath(FileAssociation fa) { return installedAppImage.destktopIntegrationDirectory().resolve(fname); } - private void initFileAssociations(WinMsiPackage pkg) { - var allFileAssociations = pkg.app().launchers().stream().map(Launcher::fileAssociations) - .flatMap(List::stream).toList(); + private void initFileAssociations() { + var allFileAssociations = launchers.stream().map(Launcher::fileAssociations).flatMap( + List::stream).toList(); associations = allFileAssociations.stream() .peek(this::normalizeFileAssociation) // Filter out file associations without extensions. @@ -715,9 +723,11 @@ public void copyFile(Path src, Path dst) throws IOException { serviceInstaller.installPath())); } - files.add(Map.entry(PackageFile.getPathInAppImage( - getConfigRoot().toAbsolutePath().normalize()), - PackageFile.getPathInAppImage(installedAppImage))); + if (packageFile != null) { + files.add(Map.entry(PackageFile.getPathInAppImage( + getConfigRoot().toAbsolutePath().normalize()), + PackageFile.getPathInAppImage(installedAppImage))); + } List componentIds = new ArrayList<>(); for (var file : files) { @@ -928,7 +938,9 @@ String getWixVariableName() { } static Set getForPackage(WinMsiPackage pkg) { - return pkg.app().launchers().stream().map(launcher -> { + var launchers = Optional.ofNullable(pkg.app().launchers()).map( + List::stream).orElseGet(Stream::of); + return launchers.map(launcher -> { return Stream.of(ShortcutsFolder.values()).filter(shortcutsFolder -> { return shortcutsFolder.isRequestedFor((WinLauncher)launcher); }); From 9478b59cad4673e55f2c1735e30088a4366744f8 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 24 Oct 2024 14:54:32 -0400 Subject: [PATCH 0072/1101] Revert "Get rid of Linux-specific `LINUX_APPLAUNCHER_LIB` in ApplicationLayout" This reverts commit e2bb391eef7aa7ce2bcb2664f2d141a057922937. --- .../jdk/jpackage/internal/LinuxAppImageBuilder.java | 4 ++-- .../jdk/jpackage/internal/ApplicationLayout.java | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index 0149d0ef9bb44..76fe4f259db53 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -41,8 +41,8 @@ private final static class LauncherCallbackImpl implements AppImageBuilder.Launc public void onLauncher(Application app, AppImageBuilder.LauncherContext ctx) throws IOException, PackagerException { if (ctx.launcher() == app.mainLauncher()) { - var launcherLib = ctx.workshop().appImageDir().resolve(Path.of( - "lib/libapplauncher.so")); + var launcherLib = ctx.resolvedAppLayout().pathGroup().getPath( + ApplicationLayout.PathRole.LINUX_APPLAUNCHER_LIB); try (var in = ResourceLocator.class.getResourceAsStream("libjpackageapplauncheraux.so")) { Files.createDirectories(launcherLib.getParent()); Files.copy(in, launcherLib); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java index 1b455d61c98ba..e96b6b72de2c0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, 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 @@ -65,6 +65,11 @@ enum PathRole { */ MODULES, + /** + * Linux app launcher shared library. + */ + LINUX_APPLAUNCHER_LIB, + /** * Location of additional application content */ @@ -146,6 +151,7 @@ static ApplicationLayout linuxAppImage() { PathRole.RUNTIME_HOME, Path.of("lib/runtime"), PathRole.DESKTOP, Path.of("lib"), PathRole.MODULES, Path.of("lib/app/mods"), + PathRole.LINUX_APPLAUNCHER_LIB, Path.of("lib/libapplauncher.so"), PathRole.CONTENT, Path.of("lib") )); } @@ -204,6 +210,8 @@ public static ApplicationLayout linuxUsrTreePackageImage(Path prefix, PathRole.RUNTIME_HOME, lib.resolve("runtime"), PathRole.DESKTOP, lib, PathRole.MODULES, lib.resolve("app/mods"), + PathRole.LINUX_APPLAUNCHER_LIB, lib.resolve( + "lib/libapplauncher.so"), PathRole.CONTENT, lib )); } From de0ec7116421c993c65e15c78346b96ad84f7c11 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 24 Oct 2024 15:22:32 -0400 Subject: [PATCH 0073/1101] Add null check to PathGroup.ghostPath() --- .../share/classes/jdk/jpackage/internal/PathGroup.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java index 75008fd677069..cec9e5c2eb2dc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java @@ -32,6 +32,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.function.BiFunction; import java.util.stream.Collectors; @@ -63,6 +64,7 @@ void setPath(Object id, Path path) { } void ghostPath(Path path) { + Objects.requireNonNull(path); setPath(new Object(), path); } From d05b291229c437f26002badd56092574ba8e4182 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 24 Oct 2024 15:28:20 -0400 Subject: [PATCH 0074/1101] - split Package.packageFileName() into Package.packageFileName(), Package.packageFileSuffix(), and Package.packageFileNameWithSuffix(). - fix bug in Package.defaultInstallDir() on windows. - Use I18N.format(). - Fix WinScriptTest for exe installer. --- .../jpackage/internal/LinuxDebBundler.java | 9 ++-- .../jdk/jpackage/internal/LinuxPackage.java | 8 ++-- .../jpackage/internal/LinuxRpmBundler.java | 11 ++--- .../jdk/jpackage/internal/Package.java | 30 +++++++++---- .../internal/ExecutableRebrander.java | 2 +- .../jdk/jpackage/internal/WinExeBundler.java | 16 +++---- .../jdk/jpackage/internal/WinMsiBundler.java | 42 ++++++++----------- 7 files changed, 54 insertions(+), 64 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index 44332177fc972..bfc896d45e934 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -34,7 +34,6 @@ import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermissions; -import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -353,9 +352,8 @@ protected Map createReplacementData(Workshop workshop, LinuxPack } private Path buildDeb(Workshop workshop, LinuxPackage pkg, Path outdir) throws IOException { - Path outFile = pkg.packageFileName(); - Log.verbose(MessageFormat.format(I18N.getString( - "message.outputting-to-location"), outFile.toAbsolutePath().toString())); + Path outFile = outdir.resolve(pkg.packageFileNameWithSuffix()); + Log.verbose(I18N.format("message.outputting-to-location", outFile.toAbsolutePath())); List cmdline = new ArrayList<>(); cmdline.addAll(List.of(TOOL_FAKEROOT, TOOL_DPKG_DEB)); @@ -370,8 +368,7 @@ private Path buildDeb(Workshop workshop, LinuxPackage pkg, Path outdir) throws I "semop(1): encountered an error: Invalid argument").execute( cmdline.toArray(String[]::new)); - Log.verbose(MessageFormat.format(I18N.getString( - "message.output-to-location"), outFile.toAbsolutePath().toString())); + Log.verbose(I18N.format("message.output-to-location", outFile.toAbsolutePath())); return outFile; } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java index c30b2617cf228..b32f3e83cd3d6 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java @@ -51,21 +51,21 @@ default ApplicationLayout packageLayout() { } @Override - default Path packageFileName() { + default String packageFileName() { String packageFileNameTemlate; switch (asStandardPackageType()) { case LinuxDeb -> { - packageFileNameTemlate = "%s_%s-%s_%s.deb"; + packageFileNameTemlate = "%s_%s-%s_%s"; } case LinuxRpm -> { - packageFileNameTemlate = "%s-%s-%s.%s.rpm"; + packageFileNameTemlate = "%s-%s-%s.%s"; } default -> { throw new UnsupportedOperationException(); } } - return Path.of(String.format(packageFileNameTemlate, packageName(), version(), release(), arch())); + return String.format(packageFileNameTemlate, packageName(), version(), release(), arch()); } default boolean isInstallDirInUsrTree() { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index ec4ef9f07025d..60aebe84ca1f6 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -27,7 +27,6 @@ import java.io.IOException; import java.nio.file.Path; -import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -180,11 +179,9 @@ private Path specFile(Workshop workshop, Package pkg) { private Path buildRPM(Workshop workshop, Package pkg, Path outdir) throws IOException { - Path rpmFile = outdir.toAbsolutePath().resolve(pkg.packageFileName()); + Path rpmFile = outdir.toAbsolutePath().resolve(pkg.packageFileNameWithSuffix()); - Log.verbose(MessageFormat.format(I18N.getString( - "message.outputting-bundle-location"), - rpmFile.getParent())); + Log.verbose(I18N.format("message.outputting-bundle-location", rpmFile.getParent())); //run rpmbuild Executor.of( @@ -200,9 +197,7 @@ private Path buildRPM(Workshop workshop, Package pkg, Path outdir) throws IOExce "--define", String.format("%%_rpmfilename %s", rpmFile.getFileName()) ).executeExpectSuccess(); - Log.verbose(MessageFormat.format( - I18N.getString("message.output-bundle-location"), - rpmFile.getParent())); + Log.verbose(I18N.format("message.output-bundle-location", rpmFile.getParent())); return rpmFile; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index 32ff83b2c7fcc..ac65cbd93377a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal; import java.nio.file.Path; -import java.text.MessageFormat; import java.util.Optional; import java.util.stream.Stream; import static jdk.jpackage.internal.Getter.getValueOrDefault; @@ -74,6 +73,9 @@ default StandardPackageType asStandardPackageType() { /** * Returns platform-specific package name. + * + * The value should be valid file system name as it will be used to create + * files/directories in the file system. */ String packageName(); @@ -127,18 +129,29 @@ default ApplicationLayout installedPackageLayout() { /** * Returns package file name. */ - default Path packageFileName() { + default String packageFileName() { if (type() instanceof StandardPackageType type) { switch (type) { case WinMsi, WinExe -> { - return Path.of(String.format("%s-%s%s", packageName(), - version(), type.suffix())); + return String.format("%s-%s", packageName(), version()); } } } throw new UnsupportedOperationException(); } + default String packageFileSuffix() { + if (type() instanceof StandardPackageType type) { + return type.suffix(); + } else { + throw new UnsupportedOperationException(); + } + } + + default String packageFileNameWithSuffix() { + return packageFileName() + Optional.ofNullable(packageFileSuffix()).orElse(""); + } + default boolean isRuntimeInstaller() { return app().isRuntime(); } @@ -342,26 +355,25 @@ static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigExc } private static Path defaultInstallDir(Package pkg) { - Path base; switch (pkg.asStandardPackageType()) { case WinExe, WinMsi -> { - base = Path.of(""); + return Path.of(pkg.app().name()); } case LinuxDeb, LinuxRpm -> { - base = Path.of("/opt"); + return Path.of("/opt").resolve(pkg.packageName()); } case MacDmg, MacPkg -> { + Path base; if (pkg.isRuntimeInstaller()) { base = Path.of("/Library/Java/JavaVirtualMachines"); } else { base = Path.of("/Applications"); } + return base.resolve(pkg.packageName()); } default -> { throw new UnsupportedOperationException(); } } - - return base.resolve(pkg.packageName()); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java index 85e5f53d55561..1e2d68d8f17bf 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java @@ -206,7 +206,7 @@ static ExecutableProperties create(WinExePackage pkg) { return new ExecutableProperties(pkg.app().vendor(), pkg.description(), DottedVersion.lazy(pkg.version()), pkg.app().copyright(), pkg.packageName(), - pkg.packageFileName().getFileName().toString()); + pkg.packageFileNameWithSuffix()); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java index 1a85e1c5f1a7e..3dd1c1f500867 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java @@ -29,7 +29,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.text.MessageFormat; import java.util.Map; import static jdk.jpackage.internal.Functional.ThrowingRunnable.toRunnable; import static jdk.jpackage.internal.StandardBundlerParam.ICON; @@ -89,15 +88,14 @@ public Path execute(Map params, Path outdir) Path msi = msiBundler.execute(params, msiDir); try { - var exePkg = new WinExePackage.Impl(pkg, ICON.fetchFrom(params)); - new ScriptRunner() .setDirectory(msi.getParent()) .setResourceCategoryId("resource.post-msi-script") .setScriptNameSuffix("post-msi") .setEnvironmentVariable("JpMsiFile", msi.toAbsolutePath().toString()) - .run(workshop, IOUtils.replaceSuffix(pkg.packageFileName(), "").getFileName().toString()); + .run(workshop, pkg.packageName()); + var exePkg = new WinExePackage.Impl(pkg, ICON.fetchFrom(params)); return buildEXE(workshop, exePkg, msi, outdir); } catch (IOException|ConfigException ex) { Log.verbose(ex); @@ -108,12 +106,10 @@ public Path execute(Map params, Path outdir) private Path buildEXE(Workshop workshop, WinExePackage pkg, Path msi, Path outdir) throws IOException { - Log.verbose(MessageFormat.format( - I18N.getString("message.outputting-to-location"), - outdir.toAbsolutePath().toString())); + Log.verbose(I18N.format("message.outputting-to-location", outdir.toAbsolutePath())); // Copy template msi wrapper next to msi file - final Path exePath = msi.getParent().resolve(pkg.packageFileName()); + final Path exePath = msi.getParent().resolve(pkg.packageFileNameWithSuffix()); try (InputStream is = OverridableResource.readDefault("msiwrapper.exe")) { Files.copy(is, exePath); } @@ -129,9 +125,7 @@ private Path buildEXE(Workshop workshop, WinExePackage pkg, Path msi, dstExePath.toFile().setExecutable(true); - Log.verbose(MessageFormat.format( - I18N.getString("message.output-location"), - outdir.toAbsolutePath().toString())); + Log.verbose(I18N.format("message.output-location", outdir.toAbsolutePath())); return dstExePath; } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index e850f638ef368..0a5cce5a29434 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -33,7 +33,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; -import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -179,9 +178,9 @@ public boolean validate(Map params) } for (var tool : wixToolset.getType().getTools()) { - Log.verbose(MessageFormat.format(I18N.getString( - "message.tool-version"), wixToolset.getToolPath(tool). - getFileName(), wixToolset.getVersion())); + Log.verbose(I18N.format("message.tool-version", + wixToolset.getToolPath(tool).getFileName(), + wixToolset.getVersion())); } wixFragments.forEach(wixFragment -> wixFragment.setWixVersion(wixToolset.getVersion(), @@ -293,10 +292,8 @@ private Map prepareMainProjectFile(Workshop workshop, WinMsiPack data.put("JpProductCode", pkg.productCode().toString()); data.put("JpProductUpgradeCode", pkg.upgradeCode().toString()); - Log.verbose(MessageFormat.format(I18N.getString("message.product-code"), - pkg.productCode())); - Log.verbose(MessageFormat.format(I18N.getString("message.upgrade-code"), - pkg.upgradeCode())); + Log.verbose(I18N.format("message.product-code", pkg.productCode())); + Log.verbose(I18N.format("message.upgrade-code", pkg.upgradeCode())); data.put("JpAllowUpgrades", "yes"); if (!pkg.isRuntimeInstaller()) { @@ -339,11 +336,9 @@ private Path buildMSI(Workshop workshop, WinMsiPackage pkg, Map wixVars, Path outdir) throws IOException { - Path msiOut = outdir.resolve(pkg.packageFileName()); + Path msiOut = outdir.resolve(pkg.packageFileNameWithSuffix()); - Log.verbose(MessageFormat.format(I18N.getString( - "message.preparing-msi-config"), msiOut.toAbsolutePath() - .toString())); + Log.verbose(I18N.format("message.preparing-msi-config", msiOut.toAbsolutePath())); WixPipeline wixPipeline = new WixPipeline() .setToolset(wixToolset) @@ -355,8 +350,7 @@ private Path buildMSI(Workshop workshop, WinMsiPackage pkg, wixFragment.configureWixPipeline(wixPipeline); } - Log.verbose(MessageFormat.format(I18N.getString( - "message.generating-msi"), msiOut.toAbsolutePath().toString())); + Log.verbose(I18N.format("message.generating-msi", msiOut.toAbsolutePath())); switch (wixToolset.getType()) { case Wix3 -> { @@ -402,11 +396,10 @@ private Path buildMSI(Workshop workshop, WinMsiPackage pkg, .filter(custom -> primaryWxlFiles.stream().noneMatch(primary -> primary.getFileName().toString().equalsIgnoreCase( custom.getFileName().toString()))) - .peek(custom -> Log.verbose(MessageFormat.format( - I18N.getString("message.using-custom-resource"), - String.format("[%s]", I18N.getString("resource.wxl-file")), - custom.getFileName().toString()))) - .toList(); + .peek(custom -> Log.verbose(I18N.format( + "message.using-custom-resource", String.format("[%s]", + I18N.getString("resource.wxl-file")), + custom.getFileName()))).toList(); // Copy custom l10n files. for (var path : customWxlFiles) { @@ -489,19 +482,18 @@ private static String getCultureFromWxlFile(Path wxlPath) throws IOException { XPath xPath = XPathFactory.newInstance().newXPath(); NodeList nodes = (NodeList) xPath.evaluate( - "//WixLocalization/@Culture", doc, - XPathConstants.NODESET); + "//WixLocalization/@Culture", doc, XPathConstants.NODESET); if (nodes.getLength() != 1) { - throw new IOException(MessageFormat.format(I18N.getString( - "error.extract-culture-from-wix-l10n-file"), + throw new IOException(I18N.format( + "error.extract-culture-from-wix-l10n-file", wxlPath.toAbsolutePath())); } return nodes.item(0).getNodeValue(); } catch (XPathExpressionException | ParserConfigurationException | SAXException ex) { - throw new IOException(MessageFormat.format(I18N.getString( - "error.read-wix-l10n-file"), wxlPath.toAbsolutePath()), ex); + throw new IOException(I18N.format("error.read-wix-l10n-file", + wxlPath.toAbsolutePath()), ex); } } From fde3792b947e6d33d6dfe880953786e528e92943 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 24 Oct 2024 15:28:50 -0400 Subject: [PATCH 0075/1101] Fix for runtime packaging --- .../classes/jdk/jpackage/internal/LinuxPackageBundler.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index fb8151d7aa17d..f3e2b166443d0 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -125,8 +125,9 @@ public final Path execute(Map params, // Copy app layout omitting application image info file. var srcLayout = pkg.appLayout().resolveAt(srcAppImageDir); - srcLayout.pathGroup().ghostPath(AppImageFile2.getPathInAppImage( - srcLayout)); + Optional.ofNullable(AppImageFile2.getPathInAppImage(srcLayout)).ifPresent( + appImageFile -> srcLayout.pathGroup().ghostPath( + appImageFile)); srcLayout.copy(pkg.packageLayout().resolveAt(pkgWorkshop.appImageDir())); } From 761de3027d014bcc270e6fb67065eee41300f83f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 26 Oct 2024 21:40:33 -0400 Subject: [PATCH 0076/1101] Drop unused import --- .../share/classes/jdk/jpackage/internal/Application.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java index bccefa5a30e14..4a9fa283aa1ec 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java @@ -31,7 +31,6 @@ import java.util.Map; import java.util.Optional; import java.util.function.Function; -import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; From 33e18f8712409d66ff6a278fe19bfe98f675bd5c Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 26 Oct 2024 21:41:10 -0400 Subject: [PATCH 0077/1101] Rename values of StandardPackageType enum --- .../jpackage/internal/LinuxDebBundler.java | 4 +-- .../internal/LinuxDebPackageFromParams.java | 4 +-- .../jdk/jpackage/internal/LinuxPackage.java | 10 +++---- .../jpackage/internal/LinuxPackageArch.java | 4 +-- .../internal/LinuxRpmPackageFromParams.java | 4 +-- .../jdk/jpackage/internal/Package.java | 30 +++++++++---------- .../jdk/jpackage/internal/WinExePackage.java | 2 +- .../internal/WinMsiPackageFromParams.java | 4 +-- 8 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index bfc896d45e934..cb6f9d9930fa3 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -48,7 +48,7 @@ import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; -import static jdk.jpackage.internal.Package.StandardPackageType.LinuxDeb; +import static jdk.jpackage.internal.Package.StandardPackageType.LINUX_DEB; public class LinuxDebBundler extends LinuxPackageBundler { @@ -152,7 +152,7 @@ private static Stream findProvidingPackages(Path file) throws IOExceptio Set archPackages = new HashSet<>(); Set otherPackages = new HashSet<>(); - var debArch = LinuxPackageArch.getValue(LinuxDeb); + var debArch = LinuxPackageArch.getValue(LINUX_DEB); Executor.of(TOOL_DPKG, "-S", file.toString()) .saveOutput(true).executeExpectSuccess() diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java index 00e6b3f14a136..6ec27171008e9 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java @@ -26,13 +26,13 @@ import java.util.Map; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; -import static jdk.jpackage.internal.Package.StandardPackageType.LinuxDeb; import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; +import static jdk.jpackage.internal.Package.StandardPackageType.LINUX_DEB; final class LinuxDebPackageFromParams { private static LinuxDebPackage create(Map params) throws ConfigException { - var pkg = LinuxPackageFromParams.create(params, LinuxDeb); + var pkg = LinuxPackageFromParams.create(params, LINUX_DEB); var maintainerEmail = MAINTAINER_EMAIL.fetchFrom(params); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java index b32f3e83cd3d6..c17732879889f 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java @@ -54,10 +54,10 @@ default ApplicationLayout packageLayout() { default String packageFileName() { String packageFileNameTemlate; switch (asStandardPackageType()) { - case LinuxDeb -> { + case LINUX_DEB -> { packageFileNameTemlate = "%s_%s-%s_%s"; } - case LinuxRpm -> { + case LINUX_RPM -> { packageFileNameTemlate = "%s-%s-%s.%s"; } default -> { @@ -90,7 +90,7 @@ public String packageName() { var packageName = target.packageName(); if (target.type() instanceof StandardPackageType type) { switch (type) { - case LinuxDeb, LinuxRpm -> { + case LINUX_DEB, LINUX_RPM -> { // make sure to lower case and spaces/underscores become dashes packageName = packageName.toLowerCase().replaceAll("[ _]", "-"); } @@ -184,7 +184,7 @@ static record Defaults(String release, String menuGroupName, String category) { private static void validatePackageName(String packageName, StandardPackageType pkgType) throws ConfigException { switch (pkgType) { - case LinuxDeb -> { + case LINUX_DEB -> { // // Debian rules for package naming are used here // https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Source @@ -201,7 +201,7 @@ private static void validatePackageName(String packageName, .getString("error.deb-invalid-value-for-package-name.advice")); } } - case LinuxRpm -> { + case LINUX_RPM -> { // // Fedora rules for package naming are used here // https://fedoraproject.org/wiki/Packaging:NamingGuidelines?rd=Packaging/NamingGuidelines diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java index 411ba88506720..6936bcec941d9 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java @@ -32,10 +32,10 @@ final class LinuxPackageArch { static String getValue(StandardPackageType pkgType) { switch (pkgType) { - case LinuxRpm -> { + case LINUX_RPM -> { return RpmPackageArch.VALUE; } - case LinuxDeb -> { + case LINUX_DEB -> { return DebPackageArch.VALUE; } default -> { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java index 388d16c165af8..7bc795e78fb3a 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java @@ -27,13 +27,13 @@ import java.util.Map; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import jdk.jpackage.internal.LinuxRpmPackage.Impl; -import static jdk.jpackage.internal.Package.StandardPackageType.LinuxRpm; import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; +import static jdk.jpackage.internal.Package.StandardPackageType.LINUX_RPM; final class LinuxRpmPackageFromParams { private static LinuxRpmPackage create(Map params) throws ConfigException { - var pkg = LinuxPackageFromParams.create(params, LinuxRpm); + var pkg = LinuxPackageFromParams.create(params, LINUX_RPM); var licenseType = LICENSE_TYPE.fetchFrom(params); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index ac65cbd93377a..a57b20d84413b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -35,12 +35,12 @@ interface PackageType { } enum StandardPackageType implements PackageType { - WinMsi(".msi"), - WinExe(".exe"), - LinuxDeb(".deb"), - LinuxRpm(".rpm"), - MacPkg(".pkg"), - MacDmg(".dmg"); + WIN_MSI(".msi"), + WIN_EXE(".exe"), + LINUX_DEB(".deb"), + LINUX_RPM(".rpm"), + MAC_PKG(".pkg"), + MAC_DMG(".dmg"); StandardPackageType(String suffix) { this.suffix = suffix; @@ -118,7 +118,7 @@ default ApplicationLayout installedPackageLayout() { Path root = relativeInstallDir(); if (type() instanceof StandardPackageType type) { switch (type) { - case LinuxDeb, LinuxRpm, MacDmg, MacPkg -> { + case LINUX_DEB, LINUX_RPM, MAC_DMG, MAC_PKG -> { root = Path.of("/").resolve(root); } } @@ -132,7 +132,7 @@ default ApplicationLayout installedPackageLayout() { default String packageFileName() { if (type() instanceof StandardPackageType type) { switch (type) { - case WinMsi, WinExe -> { + case WIN_MSI, WIN_EXE -> { return String.format("%s-%s", packageName(), version()); } } @@ -165,14 +165,14 @@ default boolean isRuntimeInstaller() { default Path relativeInstallDir() { var path = Optional.ofNullable(configuredInstallBaseDir()).map(v -> { switch (asStandardPackageType()) { - case LinuxDeb, LinuxRpm -> { + case LINUX_DEB, LINUX_RPM -> { switch (v.toString()) { case "/usr", "/usr/local" -> { return v; } } } - case WinExe, WinMsi -> { + case WIN_EXE, WIN_MSI -> { return v; } } @@ -180,7 +180,7 @@ default Path relativeInstallDir() { }).orElseGet(() -> defaultInstallDir(this)); switch (asStandardPackageType()) { - case WinExe, WinMsi -> { + case WIN_EXE, WIN_MSI -> { return path; } default -> { @@ -334,7 +334,7 @@ static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigExc } switch (pkgType) { - case StandardPackageType.WinExe, StandardPackageType.WinMsi -> { + case StandardPackageType.WIN_EXE, StandardPackageType.WIN_MSI -> { if (installDir.isAbsolute()) { throw ex; } @@ -356,13 +356,13 @@ static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigExc private static Path defaultInstallDir(Package pkg) { switch (pkg.asStandardPackageType()) { - case WinExe, WinMsi -> { + case WIN_EXE, WIN_MSI -> { return Path.of(pkg.app().name()); } - case LinuxDeb, LinuxRpm -> { + case LINUX_DEB, LINUX_RPM -> { return Path.of("/opt").resolve(pkg.packageName()); } - case MacDmg, MacPkg -> { + case MAC_DMG, MAC_PKG -> { Path base; if (pkg.isRuntimeInstaller()) { base = Path.of("/Library/Java/JavaVirtualMachines"); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java index 4a6807c07ecec..fb65b88d72db4 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java @@ -44,7 +44,7 @@ static class Impl extends Package.Proxy implements WinExePackage @Override public PackageType type() { - return StandardPackageType.WinExe; + return StandardPackageType.WIN_EXE; } @Override diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java index b773918dec827..48a42387e219a 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java @@ -29,15 +29,15 @@ import java.util.Optional; import java.util.UUID; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; -import static jdk.jpackage.internal.Package.StandardPackageType.WinMsi; import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; import jdk.jpackage.internal.WinMsiPackage.Impl; +import static jdk.jpackage.internal.Package.StandardPackageType.WIN_MSI; final class WinMsiPackageFromParams { private static WinMsiPackage create(Map params) throws ConfigException { - var pkg = PackageFromParams.create(params, WinApplicationFromParams.APPLICATION, WinMsi); + var pkg = PackageFromParams.create(params, WinApplicationFromParams.APPLICATION, WIN_MSI); var withInstallDirChooser = INSTALLDIR_CHOOSER.fetchFrom(params); var withShortcutPrompt = SHORTCUT_PROMPT.fetchFrom(params); var helpURL = HELP_URL.fetchFrom(params); From 9efcdfa5e66737427b7403c4ec589b90084f26e8 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 26 Oct 2024 21:57:39 -0400 Subject: [PATCH 0078/1101] Workshop -> BuildEnv --- .../jpackage/internal/DesktopIntegration.java | 23 ++++---- .../jpackage/internal/LinuxAppBundler.java | 5 +- .../jpackage/internal/LinuxDebBundler.java | 27 +++++----- .../internal/LinuxLaunchersAsServices.java | 21 ++++---- .../internal/LinuxPackageBundler.java | 46 ++++++++-------- .../jpackage/internal/LinuxRpmBundler.java | 31 ++++++----- .../internal/MacLaunchersAsServices.java | 14 ++--- .../jpackage/internal/AppImageBuilder.java | 20 +++---- .../internal/{Workshop.java => BuildEnv.java} | 14 ++--- ...romParams.java => BuildEnvFromParams.java} | 17 +++--- .../jpackage/internal/PackageFromParams.java | 2 +- .../jdk/jpackage/internal/ScriptRunner.java | 6 +-- .../internal/ShellCustomActionFactory.java | 2 +- .../internal/UnixLaunchersAsServices.java | 4 +- .../internal/ExecutableRebrander.java | 10 ++-- .../jdk/jpackage/internal/WinAppBundler.java | 4 +- .../jpackage/internal/WinAppImageBuilder.java | 8 +-- .../jdk/jpackage/internal/WinExeBundler.java | 14 ++--- .../jdk/jpackage/internal/WinMsiBundler.java | 54 +++++++++---------- .../internal/WixAppImageFragmentBuilder.java | 8 +-- .../jpackage/internal/WixFragmentBuilder.java | 6 +-- .../internal/WixUiFragmentBuilder.java | 8 +-- 22 files changed, 168 insertions(+), 176 deletions(-) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{Workshop.java => BuildEnv.java} (87%) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{WorkshopFromParams.java => BuildEnvFromParams.java} (79%) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index a22cbca190c69..61e4864a6cdf0 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -58,13 +58,13 @@ final class DesktopIntegration extends ShellCustomAction { private static final List REPLACEMENT_STRING_IDS = List.of( COMMANDS_INSTALL, COMMANDS_UNINSTALL, SCRIPTS, COMMON_SCRIPTS); - private DesktopIntegration(Workshop workshop, LinuxPackage pkg, LinuxLauncher launcher) throws IOException { + private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launcher) throws IOException { associations = launcher.fileAssociations().stream() .filter(fa -> !fa.mimeTypes.isEmpty()) .map(LinuxFileAssociation::new).toList(); - this.workshop = workshop; + this.env = env; this.pkg = pkg; this.launcher = launcher; @@ -74,7 +74,7 @@ private DesktopIntegration(Workshop workshop, LinuxPackage pkg, LinuxLauncher la boolean withDesktopFile = !associations.isEmpty() || launcher.shortcut().orElse(false); var curIconResource = pkg.app().createLauncherIconResource(launcher, - workshop::createResource); + env::createResource); if (curIconResource == null) { // This is additional launcher with explicit `no icon` configuration. withDesktopFile = false; @@ -87,7 +87,7 @@ private DesktopIntegration(Workshop workshop, LinuxPackage pkg, LinuxLauncher la } } - desktopFileResource = workshop.createResource("template.desktop") + desktopFileResource = env.createResource("template.desktop") .setCategory(I18N.getString("resource.menu-shortcut-descriptor")) .setPublicName(launcher.name() + ".desktop"); @@ -109,8 +109,7 @@ private DesktopIntegration(Workshop workshop, LinuxPackage pkg, LinuxLauncher la if (curIconResource == null) { // Create default icon. - curIconResource = pkg.app().createLauncherIconResource( - pkg.app().mainLauncher(), workshop::createResource); + curIconResource = pkg.app().createLauncherIconResource(pkg.app().mainLauncher(), env::createResource); } } else { desktopFile = null; @@ -129,17 +128,17 @@ private DesktopIntegration(Workshop workshop, LinuxPackage pkg, LinuxLauncher la }).filter(l -> { return l.shortcut().orElse(true); }).map(toFunction(l -> { - return new DesktopIntegration(workshop, pkg, l); + return new DesktopIntegration(env, pkg, l); })).toList(); } } - static ShellCustomAction create(Workshop workshop, Package pkg) throws IOException { + static ShellCustomAction create(BuildEnv env, Package pkg) throws IOException { if (pkg.isRuntimeInstaller()) { return ShellCustomAction.nop(REPLACEMENT_STRING_IDS); } - return new DesktopIntegration(workshop, (LinuxPackage) pkg, (LinuxLauncher) pkg.app() - .mainLauncher()); + return new DesktopIntegration(env, (LinuxPackage) pkg, + (LinuxLauncher) pkg.app().mainLauncher()); } @Override @@ -333,7 +332,7 @@ void applyTo(Map data) { * - installPath(): path where it should be installed by package manager; */ private InstallableFile createDesktopFile(String fileName) { - var srcPath = pkg.packageLayout().resolveAt(workshop.appImageDir()).destktopIntegrationDirectory().resolve( + var srcPath = pkg.packageLayout().resolveAt(env.appImageDir()).destktopIntegrationDirectory().resolve( fileName); var installPath = pkg.installedPackageLayout().destktopIntegrationDirectory().resolve( fileName); @@ -475,7 +474,7 @@ private static class LinuxFileAssociation { final int iconSize; } - private final Workshop workshop; + private final BuildEnv env; private final LinuxPackage pkg; private final Launcher launcher; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java index 40fa50287ccfb..affdc1bca88df 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java @@ -30,9 +30,8 @@ public LinuxAppBundler() { setAppImageSupplier((params, output) -> { // Order is important! var app = LinuxApplicationFromParams.APPLICATION.fetchFrom(params); - var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); - LinuxAppImageBuilder.build().create(app).execute( - Workshop.withAppImageDir(workshop, output)); + var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + LinuxAppImageBuilder.build().create(app).execute(BuildEnv.withAppImageDir(env, output)); }); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index cb6f9d9930fa3..ac3e01d6985bb 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -61,7 +61,7 @@ public LinuxDebBundler() { } @Override - protected void doValidate(Workshop workshop, LinuxPackage pkg) throws ConfigException { + protected void doValidate(BuildEnv env, LinuxPackage pkg) throws ConfigException { // Show warning if license file is missing if (pkg.licenseFile() == null) { @@ -76,12 +76,12 @@ protected List getToolValidators() { } @Override - protected Path buildPackageBundle(Map replacementData, Workshop workshop, + protected Path buildPackageBundle(Map replacementData, BuildEnv env, LinuxPackage pkg, Path outputParentDir) throws PackagerException, IOException { - prepareProjectConfig(replacementData, workshop, pkg); - adjustPermissionsRecursive(workshop.appImageDir()); - return buildDeb(workshop, pkg, outputParentDir); + prepareProjectConfig(replacementData, env, pkg); + adjustPermissionsRecursive(env.appImageDir()); + return buildDeb(env, pkg, outputParentDir); } private static final Pattern PACKAGE_NAME_REGEX = Pattern.compile("^(^\\S+):"); @@ -178,7 +178,7 @@ private static Stream findProvidingPackages(Path file) throws IOExceptio } @Override - protected List verifyOutputBundle(Workshop workshop, LinuxPackage pkg, + protected List verifyOutputBundle(BuildEnv env, LinuxPackage pkg, Path packageBundle) { List errors = new ArrayList<>(); @@ -301,9 +301,9 @@ void create(Map data, Function reso private String permissions; } - private void prepareProjectConfig(Map data, Workshop workshop, LinuxPackage pkg) throws IOException { + private void prepareProjectConfig(Map data, BuildEnv env, LinuxPackage pkg) throws IOException { - Path configDir = workshop.appImageDir().resolve("DEBIAN"); + Path configDir = env.appImageDir().resolve("DEBIAN"); List debianFiles = new ArrayList<>(); debianFiles.add(new DebianFile( configDir.resolve("control"), @@ -327,12 +327,12 @@ private void prepareProjectConfig(Map data, Workshop workshop, L }); for (DebianFile debianFile : debianFiles) { - debianFile.create(data, workshop::createResource); + debianFile.create(data, env::createResource); } } @Override - protected Map createReplacementData(Workshop workshop, LinuxPackage pkg) throws IOException { + protected Map createReplacementData(BuildEnv env, LinuxPackage pkg) throws IOException { Map data = new HashMap<>(); String licenseText = Optional.ofNullable(pkg.licenseFile()).map(toFunction(Files::readString)).orElse("Unknown"); @@ -342,8 +342,7 @@ protected Map createReplacementData(Workshop workshop, LinuxPack data.put("APPLICATION_COPYRIGHT", pkg.app().copyright()); data.put("APPLICATION_LICENSE_TEXT", licenseText); data.put("APPLICATION_ARCH", pkg.arch()); - data.put("APPLICATION_INSTALLED_SIZE", Long.toString(pkg.packageLayout().resolveAt( - workshop.appImageDir()).sizeInBytes() >> 10)); + data.put("APPLICATION_INSTALLED_SIZE", Long.toString(pkg.packageLayout().resolveAt(env.appImageDir()).sizeInBytes() >> 10)); data.put("APPLICATION_HOMEPAGE", Optional.ofNullable(pkg.aboutURL()).map( value -> "Homepage: " + value).orElse("")); data.put("APPLICATION_VERSION_WITH_RELEASE", ((LinuxDebPackage) pkg).versionWithRelease()); @@ -351,7 +350,7 @@ protected Map createReplacementData(Workshop workshop, LinuxPack return data; } - private Path buildDeb(Workshop workshop, LinuxPackage pkg, Path outdir) throws IOException { + private Path buildDeb(BuildEnv env, LinuxPackage pkg, Path outdir) throws IOException { Path outFile = outdir.resolve(pkg.packageFileNameWithSuffix()); Log.verbose(I18N.format("message.outputting-to-location", outFile.toAbsolutePath())); @@ -360,7 +359,7 @@ private Path buildDeb(Workshop workshop, LinuxPackage pkg, Path outdir) throws I if (Log.isVerbose()) { cmdline.add("--verbose"); } - cmdline.addAll(List.of("-b", workshop.appImageDir().toString(), + cmdline.addAll(List.of("-b", env.appImageDir().toString(), outFile.toAbsolutePath().toString())); // run dpkg diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java index f32c488339f3f..1f9bfbff662cd 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java @@ -36,9 +36,9 @@ */ public final class LinuxLaunchersAsServices extends UnixLaunchersAsServices { - private LinuxLaunchersAsServices(Workshop workshop, Package pkg) throws IOException { - super(workshop, pkg.app(), REQUIRED_PACKAGES, launcher -> { - return new LauncherImpl(workshop, pkg, launcher); + private LinuxLaunchersAsServices(BuildEnv env, Package pkg) throws IOException { + super(env, pkg.app(), REQUIRED_PACKAGES, launcher -> { + return new LauncherImpl(env, pkg, launcher); }); } @@ -56,11 +56,11 @@ protected Map createImpl() throws IOException { return data; } - static ShellCustomAction create(Workshop workshop, Package pkg) throws IOException { + static ShellCustomAction create(BuildEnv env, Package pkg) throws IOException { if (pkg.isRuntimeInstaller()) { return ShellCustomAction.nop(LINUX_REPLACEMENT_STRING_IDS); } - return new LinuxLaunchersAsServices(workshop, pkg); + return new LinuxLaunchersAsServices(env, pkg); } public static Path getServiceUnitFileName(String packageName, String launcherName) { @@ -70,18 +70,15 @@ public static Path getServiceUnitFileName(String packageName, String launcherNam private static class LauncherImpl extends UnixLauncherAsService { - LauncherImpl(Workshop workshop, Package pkg, Launcher launcher) { + LauncherImpl(BuildEnv env, Package pkg, Launcher launcher) { super(launcher, - workshop.createResource("unit-template.service").setCategory( + env.createResource("unit-template.service").setCategory( I18N.getString("resource.systemd-unit-file"))); unitFilename = getServiceUnitFileName(pkg.packageName(), launcher.executableName()); - getResource().setPublicName(unitFilename).addSubstitutionDataEntry( - "APPLICATION_LAUNCHER", - Enquoter.forPropertyValues().applyTo( - pkg.installedPackageLayout().resolveAt( - workshop.appImageDir()).launchersDirectory().resolve( + getResource().setPublicName(unitFilename).addSubstitutionDataEntry("APPLICATION_LAUNCHER", + Enquoter.forPropertyValues().applyTo(pkg.installedPackageLayout().resolveAt(env.appImageDir()).launchersDirectory().resolve( getName()).toString())); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index f3e2b166443d0..954a89401618c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -51,7 +51,7 @@ public final boolean validate(Map params) // Order is important! LinuxPackage pkg = pkgParam.fetchFrom(params); - var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); + var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); FileAssociation.verify(FileAssociation.fetchFrom(params)); @@ -83,7 +83,7 @@ public final boolean validate(Map params) } // Packaging specific validation - doValidate(workshop, pkg); + doValidate(env, pkg); return true; } @@ -100,23 +100,23 @@ public final Path execute(Map params, // Order is important! LinuxPackage pkg = pkgParam.fetchFrom(params); - var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); + var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - Workshop pkgWorkshop = Workshop.withAppImageDir(workshop, - workshop.buildRoot().resolve("image")); + BuildEnv pkgEnv = BuildEnv.withAppImageDir(env, + env.buildRoot().resolve("image")); try { // We either have an application image or need to build one. if (pkg.app().runtimeBuilder() != null) { // Runtime builder is present, build app image. - LinuxAppImageBuilder.build().create(pkg).execute(pkgWorkshop); + LinuxAppImageBuilder.build().create(pkg).execute(pkgEnv); } else { Path srcAppImageDir = pkg.predefinedAppImage(); if (srcAppImageDir == null) { // No predefined app image and no runtime builder. // This should be runtime packaging. if (pkg.isRuntimeInstaller()) { - srcAppImageDir = workshop.appImageDir(); + srcAppImageDir = env.appImageDir(); } else { // Can't create app image without runtime builder. throw new UnsupportedOperationException(); @@ -128,25 +128,25 @@ public final Path execute(Map params, Optional.ofNullable(AppImageFile2.getPathInAppImage(srcLayout)).ifPresent( appImageFile -> srcLayout.pathGroup().ghostPath( appImageFile)); - srcLayout.copy(pkg.packageLayout().resolveAt(pkgWorkshop.appImageDir())); + srcLayout.copy(pkg.packageLayout().resolveAt(pkgEnv.appImageDir())); } for (var ca : customActions) { - ca.init(pkgWorkshop, pkg); + ca.init(pkgEnv, pkg); } - Map data = createDefaultReplacementData(pkgWorkshop, pkg); + Map data = createDefaultReplacementData(pkgEnv, pkg); for (var ca : customActions) { ShellCustomAction.mergeReplacementData(data, ca.instance.create()); } - data.putAll(createReplacementData(pkgWorkshop, pkg)); + data.putAll(createReplacementData(pkgEnv, pkg)); Path packageBundle = buildPackageBundle(Collections.unmodifiableMap( - data), pkgWorkshop, pkg, outputParentDir); + data), pkgEnv, pkg, outputParentDir); - verifyOutputBundle(pkgWorkshop, pkg, packageBundle).stream() + verifyOutputBundle(pkgEnv, pkg, packageBundle).stream() .filter(Objects::nonNull) .forEachOrdered(ex -> { Log.verbose(ex.getLocalizedMessage()); @@ -160,7 +160,7 @@ public final Path execute(Map params, } } - private List getListOfNeededPackages(Workshop workshop) throws IOException { + private List getListOfNeededPackages(BuildEnv env) throws IOException { final List caPackages = customActions.stream() .map(ca -> ca.instance) @@ -172,7 +172,7 @@ private List getListOfNeededPackages(Workshop workshop) throws IOExcepti LibProvidersLookup lookup = new LibProvidersLookup(); initLibProvidersLookup(lookup); - neededLibPackages = lookup.execute(workshop.appImageDir()); + neededLibPackages = lookup.execute(env.appImageDir()); } else { neededLibPackages = Collections.emptyList(); Log.info(I18N.getString("warning.foreign-app-image")); @@ -188,7 +188,7 @@ private List getListOfNeededPackages(Workshop workshop) throws IOExcepti return result; } - private Map createDefaultReplacementData(Workshop workshop, LinuxPackage pkg) throws IOException { + private Map createDefaultReplacementData(BuildEnv env, LinuxPackage pkg) throws IOException { Map data = new HashMap<>(); data.put("APPLICATION_PACKAGE", pkg.packageName()); @@ -196,7 +196,7 @@ private Map createDefaultReplacementData(Workshop workshop, Linu data.put("APPLICATION_VERSION", pkg.version()); data.put("APPLICATION_DESCRIPTION", pkg.description()); - String defaultDeps = String.join(", ", getListOfNeededPackages(workshop)); + String defaultDeps = String.join(", ", getListOfNeededPackages(env)); String customDeps = Optional.ofNullable(pkg.additionalDependencies()).orElse(""); if (!customDeps.isEmpty() && !defaultDeps.isEmpty()) { customDeps = ", " + customDeps; @@ -208,21 +208,21 @@ private Map createDefaultReplacementData(Workshop workshop, Linu } protected abstract List verifyOutputBundle( - Workshop workshop, LinuxPackage pkg, Path packageBundle); + BuildEnv env, LinuxPackage pkg, Path packageBundle); protected abstract void initLibProvidersLookup(LibProvidersLookup libProvidersLookup); protected abstract List getToolValidators(); - protected abstract void doValidate(Workshop workshop, LinuxPackage pkg) + protected abstract void doValidate(BuildEnv env, LinuxPackage pkg) throws ConfigException; protected abstract Map createReplacementData( - Workshop workshop, LinuxPackage pkg) throws IOException; + BuildEnv env, LinuxPackage pkg) throws IOException; protected abstract Path buildPackageBundle( Map replacementData, - Workshop workshop, LinuxPackage pkg, Path outputParentDir) throws + BuildEnv env, LinuxPackage pkg, Path outputParentDir) throws PackagerException, IOException; private final BundlerParamInfo pkgParam; @@ -235,8 +235,8 @@ private static final class CustomActionInstance { this.factory = factory; } - void init(Workshop workshop, Package pkg) throws IOException { - instance = factory.create(workshop, pkg); + void init(BuildEnv env, Package pkg) throws IOException { + instance = factory.create(env, pkg); Objects.requireNonNull(instance); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index 60aebe84ca1f6..1fffc749c15b0 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -64,7 +64,7 @@ public LinuxRpmBundler() { } @Override - protected void doValidate(Workshop workshop, LinuxPackage pkg) throws ConfigException { + protected void doValidate(BuildEnv env, LinuxPackage pkg) throws ConfigException { } private static ToolValidator createRpmbuildToolValidator() { @@ -87,18 +87,18 @@ protected List getToolValidators() { } @Override - protected Path buildPackageBundle(Map replacementData, Workshop workshop, + protected Path buildPackageBundle(Map replacementData, BuildEnv env, LinuxPackage pkg, Path outputParentDir) throws PackagerException, IOException { - Path specFile = specFile(workshop, pkg); + Path specFile = specFile(env, pkg); // prepare spec file - workshop.createResource(DEFAULT_SPEC_TEMPLATE) + env.createResource(DEFAULT_SPEC_TEMPLATE) .setCategory(I18N.getString("resource.rpm-spec-file")) .setSubstitutionData(replacementData) .saveToFile(specFile); - return buildRPM(workshop, pkg, outputParentDir); + return buildRPM(env, pkg, outputParentDir); } private static Path installPrefix(LinuxPackage pkg) { @@ -110,7 +110,7 @@ private static Path installPrefix(LinuxPackage pkg) { } @Override - protected Map createReplacementData(Workshop workshop, LinuxPackage pkg) throws IOException { + protected Map createReplacementData(BuildEnv env, LinuxPackage pkg) throws IOException { Map data = new HashMap<>(); data.put("APPLICATION_RELEASE", pkg.release()); @@ -141,11 +141,11 @@ protected void initLibProvidersLookup(LibProvidersLookup libProvidersLookup) { } @Override - protected List verifyOutputBundle(Workshop workshop, LinuxPackage pkg, + protected List verifyOutputBundle(BuildEnv env, LinuxPackage pkg, Path packageBundle) { List errors = new ArrayList<>(); - String specFileName = specFile(workshop, pkg).getFileName().toString(); + String specFileName = specFile(env, pkg).getFileName().toString(); try { List properties = List.of( @@ -173,27 +173,26 @@ protected List verifyOutputBundle(Workshop workshop, LinuxPacka return errors; } - private Path specFile(Workshop workshop, Package pkg) { - return workshop.buildRoot().resolve(Path.of("SPECS", pkg.packageName() + ".spec")); + private Path specFile(BuildEnv env, Package pkg) { + return env.buildRoot().resolve(Path.of("SPECS", pkg.packageName() + ".spec")); } - private Path buildRPM(Workshop workshop, Package pkg, Path outdir) throws IOException { + private Path buildRPM(BuildEnv env, Package pkg, Path outdir) throws IOException { Path rpmFile = outdir.toAbsolutePath().resolve(pkg.packageFileNameWithSuffix()); Log.verbose(I18N.format("message.outputting-bundle-location", rpmFile.getParent())); //run rpmbuild - Executor.of( - TOOL_RPMBUILD, - "-bb", specFile(workshop, pkg).toAbsolutePath().toString(), + Executor.of(TOOL_RPMBUILD, + "-bb", specFile(env, pkg).toAbsolutePath().toString(), "--define", String.format("%%_sourcedir %s", - workshop.appImageDir().toAbsolutePath()), + env.appImageDir().toAbsolutePath()), // save result to output dir "--define", String.format("%%_rpmdir %s", rpmFile.getParent()), // do not use other system directories to build as current user "--define", String.format("%%_topdir %s", - workshop.buildRoot().toAbsolutePath()), + env.buildRoot().toAbsolutePath()), "--define", String.format("%%_rpmfilename %s", rpmFile.getFileName()) ).executeExpectSuccess(); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index db0a866a4dd41..420dd2b519eba 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -36,9 +36,9 @@ */ public final class MacLaunchersAsServices extends UnixLaunchersAsServices { - private MacLaunchersAsServices(Workshop workshop, Package pkg) throws IOException { - super(workshop, pkg.app(), List.of(), launcher -> { - return new MacLauncherAsService(workshop, pkg, launcher); + private MacLaunchersAsServices(BuildEnv env, Package pkg) throws IOException { + super(env, pkg.app(), List.of(), launcher -> { + return new MacLauncherAsService(env, pkg, launcher); }); } @@ -47,12 +47,12 @@ static ShellCustomAction create(Map params, // Order is important! var pkg = PackageFromParams.PACKAGE.fetchFrom(params); - var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); + var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); if (pkg.isRuntimeInstaller()) { return null; } - return Optional.of(new MacLaunchersAsServices(workshop, pkg)).filter(Predicate.not( + return Optional.of(new MacLaunchersAsServices(env, pkg)).filter(Predicate.not( MacLaunchersAsServices::isEmpty)).orElse(null); } @@ -64,8 +64,8 @@ public static Path getServicePListFileName(String packageName, private static class MacLauncherAsService extends UnixLauncherAsService { - MacLauncherAsService(Workshop workshop, Package pkg, Launcher launcher) { - super(launcher, workshop.createResource("launchd.plist.template").setCategory(I18N + MacLauncherAsService(BuildEnv env, Package pkg, Launcher launcher) { + super(launcher, env.createResource("launchd.plist.template").setCategory(I18N .getString("resource.launchd-plist-file"))); plistFilename = getServicePListFileName(pkg.packageName(), getName()); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java index 59c6257f26de7..3ef2080244ba3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -68,12 +68,12 @@ private AppImageBuilder(Package pkg, LauncherCallback launcherCallback) { this(pkg.app(), pkg.packageLayout(), launcherCallback); } - private static void copyRecursive(Path srcDir, Path dstDir, Workshop workshop) throws IOException { + private static void copyRecursive(Path srcDir, Path dstDir, BuildEnv env) throws IOException { srcDir = srcDir.toAbsolutePath(); List excludes = new ArrayList<>(); - for (var path : List.of(workshop.buildRoot(), workshop.appImageDir())) { + for (var path : List.of(env.buildRoot(), env.appImageDir())) { if (Files.isDirectory(path)) { path = path.toAbsolutePath(); if (path.startsWith(srcDir) && !Files.isSameFile(path, srcDir)) { @@ -85,8 +85,8 @@ private static void copyRecursive(Path srcDir, Path dstDir, Workshop workshop) t IOUtils.copyRecursive(srcDir, dstDir.toAbsolutePath() /*, excludes */); } - void execute(Workshop workshop) throws IOException, PackagerException { - var resolvedAppLayout = appLayout.resolveAt(workshop.appImageDir()); + void execute(BuildEnv env) throws IOException, PackagerException { + var resolvedAppLayout = appLayout.resolveAt(env.appImageDir()); app.runtimeBuilder().createRuntime(resolvedAppLayout); if (app.isRuntime()) { @@ -94,17 +94,17 @@ void execute(Workshop workshop) throws IOException, PackagerException { } if (app.srcDir() != null) { - copyRecursive(app.srcDir(), resolvedAppLayout.appDirectory(), workshop); + copyRecursive(app.srcDir(), resolvedAppLayout.appDirectory(), env); } for (var srcDir : Optional.ofNullable(app.contentDirs()).orElseGet(List::of)) { copyRecursive(srcDir, resolvedAppLayout.contentDirectory().resolve(srcDir.getFileName()), - workshop); + env); } if (withAppImageFile) { - new AppImageFile2(app).save(workshop.appImageDir()); + new AppImageFile2(app).save(env.appImageDir()); } for (var launcher : app.launchers()) { @@ -121,7 +121,7 @@ void execute(Workshop workshop) throws IOException, PackagerException { if (launcherCallback != null) { launcherCallback.onLauncher(app, new LauncherContext(launcher, - workshop, resolvedAppLayout, executableFile)); + env, resolvedAppLayout, executableFile)); } executableFile.toFile().setExecutable(true); @@ -131,7 +131,7 @@ void execute(Workshop workshop) throws IOException, PackagerException { static interface LauncherCallback { default public void onLauncher(Application app, LauncherContext ctx) throws IOException, PackagerException { var iconResource = app.createLauncherIconResource(ctx.launcher, - ctx.workshop::createResource); + ctx.env::createResource); if (iconResource != null) { onLauncher(app, ctx, iconResource); } @@ -142,7 +142,7 @@ default public void onLauncher(Application app, LauncherContext ctx, } } - static record LauncherContext(Launcher launcher, Workshop workshop, + static record LauncherContext(Launcher launcher, BuildEnv env, ApplicationLayout resolvedAppLayout, Path launcherExecutable) { } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java similarity index 87% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java index 6b272d2187fdc..d70c1126fa4b6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Workshop.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java @@ -26,7 +26,7 @@ import java.nio.file.Path; -interface Workshop { +interface BuildEnv { Path buildRoot(); @@ -50,12 +50,12 @@ default OverridableResource createResource(String defaultName) { return new OverridableResource(defaultName).setResourceDir(resourceDir()); } - record Impl(Path buildRoot, Path resourceDir) implements Workshop { + record Impl(Path buildRoot, Path resourceDir) implements BuildEnv { } - static Workshop withAppImageDir(Workshop workshop, Path appImageDir) { - return new Proxy(workshop) { + static BuildEnv withAppImageDir(BuildEnv env, Path appImageDir) { + return new Proxy(env) { @Override public Path appImageDir() { return appImageDir; @@ -63,9 +63,9 @@ public Path appImageDir() { }; } - static class Proxy implements Workshop { + static class Proxy implements BuildEnv { - Proxy(Workshop target) { + Proxy(BuildEnv target) { this.target = target; } @@ -79,6 +79,6 @@ public Path resourceDir() { return target.resourceDir(); } - private final Workshop target; + private final BuildEnv target; } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java similarity index 79% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java index 5749151a21134..9f70d050a7c9e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/WorkshopFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java @@ -27,16 +27,16 @@ import java.nio.file.Path; import java.util.Map; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; -import jdk.jpackage.internal.Workshop.Impl; -import static jdk.jpackage.internal.Workshop.withAppImageDir; +import jdk.jpackage.internal.BuildEnv.Impl; +import static jdk.jpackage.internal.BuildEnv.withAppImageDir; -final class WorkshopFromParams { +final class BuildEnvFromParams { - static Workshop create(Map params) throws ConfigException { + static BuildEnv create(Map params) throws ConfigException { var root = StandardBundlerParam.TEMP_ROOT.fetchFrom(params); var resourceDir = StandardBundlerParam.RESOURCE_DIR.fetchFrom(params); - var defaultWorkshop = new Impl(root, resourceDir); + var defaultEnv = new Impl(root, resourceDir); Path appImageDir; if (StandardBundlerParam.isRuntimeInstaller(params)) { @@ -45,14 +45,13 @@ static Workshop create(Map params) throws ConfigExceptio appImageDir = StandardBundlerParam.getPredefinedAppImage(params); } else { Path dir = ApplicationFromParams.APPLICATION.fetchFrom(params).appImageDirName(); - appImageDir = defaultWorkshop.buildRoot().resolve("image").resolve(dir); + appImageDir = defaultEnv.buildRoot().resolve("image").resolve(dir); } - return withAppImageDir(defaultWorkshop, appImageDir); + return withAppImageDir(defaultEnv, appImageDir); } - static final BundlerParamInfo WORKSHOP = BundlerParamInfo.createBundlerParam( - "workshop", WorkshopFromParams::create); + static final BundlerParamInfo BUILD_ENV = BundlerParamInfo.createBundlerParam("env", BuildEnvFromParams::create); static final BundlerParamInfo PACKAGE_TYPE = createStringBundlerParam( Arguments.CLIOptions.PACKAGE_TYPE.getId()); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java index 948171c835939..60e0e4cea860a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java @@ -70,7 +70,7 @@ static BundlerParamInfo createBundlerParam( static final BundlerParamInfo PACKAGE = createBundlerParam(params -> { return PackageFromParams.create(params, ApplicationFromParams.APPLICATION, - StandardPackageType.fromCmdLineType(WorkshopFromParams.PACKAGE_TYPE + StandardPackageType.fromCmdLineType(BuildEnvFromParams.PACKAGE_TYPE .fetchFrom(params))); }); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java index 0aecba3d83e53..10fd9f87c9b70 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java @@ -72,11 +72,11 @@ ScriptRunner setEnvironmentVariable(String envVarName, String envVarValue) { return this; } - public void run(Workshop workshop, String name) throws IOException { + public void run(BuildEnv env, String name) throws IOException { String scriptName = String.format("%s-%s%s", name, scriptNameSuffix, scriptSuffix()); - Path scriptPath = workshop.configDir().resolve(scriptName); - workshop.createResource(null) + Path scriptPath = env.configDir().resolve(scriptName); + env.createResource(null) .setCategory(I18N.getString(resourceCategoryId)) .saveToFile(scriptPath); if (!Files.exists(scriptPath)) { diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java index 35dfb564a4f8e..fd3ee7e45921d 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java @@ -28,5 +28,5 @@ interface ShellCustomActionFactory { - ShellCustomAction create(Workshop workshop, Package pkg) throws IOException; + ShellCustomAction create(BuildEnv env, Package pkg) throws IOException; } diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java index 233603291390c..be75e02f36399 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java @@ -39,10 +39,10 @@ */ class UnixLaunchersAsServices extends ShellCustomAction { - UnixLaunchersAsServices(Workshop workshop, Application app, List requiredPackages, + UnixLaunchersAsServices(BuildEnv env, Application app, List requiredPackages, Function factory) throws IOException { - this.appImageDir = workshop.appImageDir(); + this.appImageDir = env.appImageDir(); this.requiredPackages = requiredPackages; // Read launchers information diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java index 1e2d68d8f17bf..ee41a487f92fd 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java @@ -79,7 +79,7 @@ private ExecutableRebrander(ExecutableProperties props, this.props.put("ORIGINAL_FILENAME", props.executableName); } - void execute(Workshop workshop, Path target, Path icon) throws IOException { + void execute(BuildEnv env, Path target, Path icon) throws IOException { String[] propsArray = toStringArray(propertiesFileResource, props); UpdateResourceAction versionSwapper = resourceLock -> { @@ -92,9 +92,9 @@ void execute(Workshop workshop, Path target, Path icon) throws IOException { var absIcon = Optional.ofNullable(icon).map(Path::toAbsolutePath).orElse( null); if (absIcon == null) { - rebrandExecutable(workshop, target, versionSwapper); + rebrandExecutable(env, target, versionSwapper); } else { - rebrandExecutable(workshop, target, versionSwapper, + rebrandExecutable(env, target, versionSwapper, resourceLock -> { if (iconSwap(resourceLock, absIcon.toString()) != 0) { throw new RuntimeException(MessageFormat.format( @@ -104,10 +104,10 @@ void execute(Workshop workshop, Path target, Path icon) throws IOException { } } - private static void rebrandExecutable(Workshop workshop, + private static void rebrandExecutable(BuildEnv env, Path target, UpdateResourceAction ... actions) throws IOException { try { - String tempDirectory = workshop.buildRoot().toAbsolutePath().toString(); + String tempDirectory = env.buildRoot().toAbsolutePath().toString(); if (WindowsDefender.isThereAPotentialWindowsDefenderIssue( tempDirectory)) { Log.verbose(MessageFormat.format(I18N.getString( diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java index 799c198f61d38..12518f65eca6c 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java @@ -30,9 +30,9 @@ public WinAppBundler() { setAppImageSupplier((params, output) -> { // Order is important! var app = WinApplicationFromParams.APPLICATION.fetchFrom(params); - var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); + var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); WinAppImageBuilder.build().create(app).execute( - Workshop.withAppImageDir(workshop, output)); + BuildEnv.withAppImageDir(env, output)); }); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java index bfb01d95b97a0..7512c44229a5a 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java @@ -41,9 +41,9 @@ public void onLauncher(Application app, AppImageBuilder.LauncherContext ctx) throws IOException, PackagerException { Path iconTarget = null; var iconResource = app.createLauncherIconResource(ctx.launcher(), - name -> ctx.workshop().createResource(name)); + name -> ctx.env().createResource(name)); if (iconResource != null) { - var iconDir = ctx.workshop().buildRoot().resolve("icons"); + var iconDir = ctx.env().buildRoot().resolve("icons"); iconTarget = iconDir.resolve(ctx.launcher().executableName() + ".ico"); if (null == iconResource.saveToFile(iconTarget)) { iconTarget = null; @@ -53,8 +53,8 @@ public void onLauncher(Application app, // Update branding of launcher executable new ExecutableRebrander((WinApplication) app, (WinLauncher) ctx.launcher(), - name -> ctx.workshop().createResource(name)).execute( - ctx.workshop(), ctx.launcherExecutable(), iconTarget); + name -> ctx.env().createResource(name)).execute( + ctx.env(), ctx.launcherExecutable(), iconTarget); } } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java index 3dd1c1f500867..943e0b46bfd2e 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java @@ -77,11 +77,11 @@ public Path execute(Map params, Path outdir) // Order is important! var pkg = WinMsiPackageFromParams.PACKAGE.fetchFrom(params); - var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); + var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); IOUtils.writableOutputDir(outdir); - Path msiDir = workshop.buildRoot().resolve("msi"); + Path msiDir = env.buildRoot().resolve("msi"); toRunnable(() -> Files.createDirectories(msiDir)).run(); // Write msi to temporary directory. @@ -93,17 +93,17 @@ public Path execute(Map params, Path outdir) .setResourceCategoryId("resource.post-msi-script") .setScriptNameSuffix("post-msi") .setEnvironmentVariable("JpMsiFile", msi.toAbsolutePath().toString()) - .run(workshop, pkg.packageName()); + .run(env, pkg.packageName()); var exePkg = new WinExePackage.Impl(pkg, ICON.fetchFrom(params)); - return buildEXE(workshop, exePkg, msi, outdir); + return buildEXE(env, exePkg, msi, outdir); } catch (IOException|ConfigException ex) { Log.verbose(ex); throw new PackagerException(ex); } } - private Path buildEXE(Workshop workshop, WinExePackage pkg, Path msi, + private Path buildEXE(BuildEnv env, WinExePackage pkg, Path msi, Path outdir) throws IOException { Log.verbose(I18N.format("message.outputting-to-location", outdir.toAbsolutePath())); @@ -114,10 +114,10 @@ private Path buildEXE(Workshop workshop, WinExePackage pkg, Path msi, Files.copy(is, exePath); } - new ExecutableRebrander(pkg, workshop::createResource, resourceLock -> { + new ExecutableRebrander(pkg, env::createResource, resourceLock -> { // Embed msi in msi wrapper exe. embedMSI(resourceLock, msi.toAbsolutePath().toString()); - }).execute(workshop, exePath, pkg.icon()); + }).execute(env, exePath, pkg.icon()); Path dstExePath = outdir.resolve(exePath.getFileName()); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 0a5cce5a29434..5267a086f330e 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -171,7 +171,7 @@ public boolean validate(Map params) try { // Order is important! WinApplicationFromParams.APPLICATION.fetchFrom(params); - WorkshopFromParams.WORKSHOP.fetchFrom(params); + BuildEnvFromParams.BUILD_ENV.fetchFrom(params); if (wixToolset == null) { wixToolset = WixTool.createToolset(); @@ -201,7 +201,7 @@ public boolean validate(Map params) } } - private void prepareProto(WinMsiPackage pkg, Workshop workshop) throws + private void prepareProto(WinMsiPackage pkg, BuildEnv env) throws PackagerException, IOException { ApplicationLayout appLayout; @@ -209,15 +209,15 @@ private void prepareProto(WinMsiPackage pkg, Workshop workshop) throws // We either have an application image or need to build one. if (pkg.app().runtimeBuilder() != null) { // Runtime builder is present, build app image. - WinAppImageBuilder.build().create(pkg.app()).execute(workshop); - appLayout = pkg.appLayout().resolveAt(workshop.appImageDir()); + WinAppImageBuilder.build().create(pkg.app()).execute(env); + appLayout = pkg.appLayout().resolveAt(env.appImageDir()); } else { Path srcAppImageDir = pkg.predefinedAppImage(); if (srcAppImageDir == null) { // No predefined app image and no runtime builder. // This should be runtime packaging. if (pkg.isRuntimeInstaller()) { - srcAppImageDir = workshop.appImageDir(); + srcAppImageDir = env.appImageDir(); } else { // Can't create app image without runtime builder. throw new UnsupportedOperationException(); @@ -244,7 +244,7 @@ private void prepareProto(WinMsiPackage pkg, Workshop workshop) throws if (licenseFile != null) { // need to copy license file to the working directory // and convert to rtf if needed - Path destFile = workshop.configDir().resolve(licenseFile.getFileName()); + Path destFile = env.configDir().resolve(licenseFile.getFileName()); IOUtils.copyFile(licenseFile, destFile); destFile.toFile().setWritable(true); @@ -260,33 +260,33 @@ public Path execute(Map params, // Order is important! var pkg = WinMsiPackageFromParams.PACKAGE.fetchFrom(params); - var workshop = WorkshopFromParams.WORKSHOP.fetchFrom(params); + var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - Path imageDir = workshop.appImageDir(); + Path imageDir = env.appImageDir(); try { - prepareProto(pkg, workshop); + prepareProto(pkg, env); for (var wixFragment : wixFragments) { - wixFragment.initFromParams(workshop, pkg); + wixFragment.initFromParams(env, pkg); wixFragment.addFilesToConfigRoot(); } - Map wixVars = prepareMainProjectFile(workshop, pkg); + Map wixVars = prepareMainProjectFile(env, pkg); new ScriptRunner() .setDirectory(imageDir) .setResourceCategoryId("resource.post-app-image-script") .setScriptNameSuffix("post-image") .setEnvironmentVariable("JpAppImageDir", imageDir.toAbsolutePath().toString()) - .run(workshop, pkg.packageName()); + .run(env, pkg.packageName()); - return buildMSI(workshop, pkg, wixVars, outputParentDir); + return buildMSI(env, pkg, wixVars, outputParentDir); } catch (IOException ex) { Log.verbose(ex); throw new PackagerException(ex); } } - private Map prepareMainProjectFile(Workshop workshop, WinMsiPackage pkg) throws IOException { + private Map prepareMainProjectFile(BuildEnv env, WinMsiPackage pkg) throws IOException { Map data = new HashMap<>(); data.put("JpProductCode", pkg.productCode().toString()); @@ -321,9 +321,9 @@ private Map prepareMainProjectFile(Workshop workshop, WinMsiPack }); data.put("JpAppSizeKb", Long.toString(pkg.packageLayout().resolveAt( - workshop.appImageDir()).sizeInBytes() >> 10)); + env.appImageDir()).sizeInBytes() >> 10)); - data.put("JpConfigDir", workshop.configDir().toAbsolutePath().toString()); + data.put("JpConfigDir", env.configDir().toAbsolutePath().toString()); if (pkg.isSystemWideInstall()) { data.put("JpIsSystemWide", "yes"); @@ -332,7 +332,7 @@ private Map prepareMainProjectFile(Workshop workshop, WinMsiPack return data; } - private Path buildMSI(Workshop workshop, WinMsiPackage pkg, + private Path buildMSI(BuildEnv env, WinMsiPackage pkg, Map wixVars, Path outdir) throws IOException { @@ -342,9 +342,9 @@ private Path buildMSI(Workshop workshop, WinMsiPackage pkg, WixPipeline wixPipeline = new WixPipeline() .setToolset(wixToolset) - .setWixObjDir(workshop.buildRoot().resolve("wixobj")) - .setWorkDir(workshop.appImageDir()) - .addSource(workshop.configDir().resolve("main.wxs"), wixVars); + .setWixObjDir(env.buildRoot().resolve("wixobj")) + .setWorkDir(env.appImageDir()) + .addSource(env.configDir().resolve("main.wxs"), wixVars); for (var wixFragment : wixFragments) { wixFragment.configureWixPipeline(wixPipeline); @@ -367,7 +367,7 @@ private Path buildMSI(Workshop workshop, WinMsiPackage pkg, } } - final Path configDir = workshop.configDir(); + final Path configDir = env.configDir(); var primaryWxlFiles = Stream.of("de", "en", "ja", "zh_CN").map(loc -> { return configDir.resolve("MsiInstallerStrings_" + loc + ".wxl"); @@ -378,21 +378,21 @@ private Path buildMSI(Workshop workshop, WinMsiPackage pkg, // Copy standard l10n files. for (var path : primaryWxlFiles) { var name = path.getFileName().toString(); - wixResources.addResource(workshop.createResource(name).setPublicName(name).setCategory( + wixResources.addResource(env.createResource(name).setPublicName(name).setCategory( I18N.getString("resource.wxl-file")), path); } - wixResources.addResource(workshop.createResource("main.wxs").setPublicName("main.wxs"). + wixResources.addResource(env.createResource("main.wxs").setPublicName("main.wxs"). setCategory(I18N.getString("resource.main-wix-file")), configDir.resolve("main.wxs")); - wixResources.addResource(workshop.createResource("overrides.wxi").setPublicName( + wixResources.addResource(env.createResource("overrides.wxi").setPublicName( "overrides.wxi").setCategory(I18N.getString("resource.overrides-wix-file")), configDir.resolve("overrides.wxi")); // Filter out custom l10n files that were already used to // override primary l10n files. Ignore case filename comparison, // both lists are expected to be short. - List customWxlFiles = getWxlFilesFromDir(workshop.resourceDir()).stream() + List customWxlFiles = getWxlFilesFromDir(env.resourceDir()).stream() .filter(custom -> primaryWxlFiles.stream().noneMatch(primary -> primary.getFileName().toString().equalsIgnoreCase( custom.getFileName().toString()))) @@ -404,7 +404,7 @@ private Path buildMSI(Workshop workshop, WinMsiPackage pkg, // Copy custom l10n files. for (var path : customWxlFiles) { var name = path.getFileName().toString(); - wixResources.addResource(workshop.createResource(name).setPublicName(name). + wixResources.addResource(env.createResource(name).setPublicName(name). setSourceOrder(OverridableResource.Source.ResourceDir).setCategory(I18N. getString("resource.wxl-file")), configDir.resolve(name)); } @@ -427,7 +427,7 @@ private Path buildMSI(Workshop workshop, WinMsiPackage pkg, } // Append a primary culture bases on runtime locale. - final Path primaryWxlFile = workshop.configDir().resolve( + final Path primaryWxlFile = env.configDir().resolve( I18N.getString("resource.wxl-file-name")); cultures.add(getCultureFromWxlFile(primaryWxlFile)); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index 18a975649e1b4..d46957bf3d6d3 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -66,10 +66,10 @@ final class WixAppImageFragmentBuilder extends WixFragmentBuilder { @Override - void initFromParams(Workshop workshop, WinMsiPackage pkg) { - super.initFromParams(workshop, pkg); + void initFromParams(BuildEnv env, WinMsiPackage pkg) { + super.initFromParams(env, pkg); - Path appImageRoot = workshop.appImageDir(); + Path appImageRoot = env.appImageDir(); systemWide = pkg.isSystemWideInstall(); @@ -105,7 +105,7 @@ void initFromParams(Workshop workshop, WinMsiPackage pkg) { var launcherPath = installedAppImage.launchersDirectory().resolve( launcher.executableNameWithSuffix()); var id = Id.File.of(launcherPath); - return new WixLauncherAsService(launcher, workshop::createResource) + return new WixLauncherAsService(launcher, env::createResource) .setLauncherInstallPath(toWixPath(launcherPath)) .setLauncherInstallPathId(id); }).toList(); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java index ef1d0e4d2aecd..500724db13982 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java @@ -59,11 +59,11 @@ final void setOutputFileName(String v) { outputFileName = v; } - void initFromParams(Workshop workshop, WinMsiPackage pkg) { + void initFromParams(BuildEnv env, WinMsiPackage pkg) { wixVariables = null; additionalResources = null; - configRoot = workshop.configDir(); - fragmentResource = workshop.createResource(outputFileName).setSourceOrder(Source.ResourceDir); + configRoot = env.configDir(); + fragmentResource = env.createResource(outputFileName).setSourceOrder(Source.ResourceDir); } List getLoggableWixFeatures() { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java index f6ee0c564c623..bb85aa9f58e49 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java @@ -48,8 +48,8 @@ final class WixUiFragmentBuilder extends WixFragmentBuilder { @Override - void initFromParams(Workshop workshop, WinMsiPackage pkg) { - super.initFromParams(workshop, pkg); + void initFromParams(BuildEnv env, WinMsiPackage pkg) { + super.initFromParams(env, pkg); Path licenseFile = pkg.licenseFile(); withLicenseDlg = licenseFile != null; @@ -68,7 +68,7 @@ void initFromParams(Workshop workshop, WinMsiPackage pkg) { customDialogs = new ArrayList<>(); if (withShortcutPromptDlg) { - CustomDialog dialog = new CustomDialog(workshop::createResource, I18N.getString( + CustomDialog dialog = new CustomDialog(env::createResource, I18N.getString( "resource.shortcutpromptdlg-wix-file"), "ShortcutPromptDlg.wxs"); for (var shortcutFolder : shortcutFolders) { @@ -79,7 +79,7 @@ void initFromParams(Workshop workshop, WinMsiPackage pkg) { } if (withInstallDirChooserDlg) { - CustomDialog dialog = new CustomDialog(workshop::createResource, I18N.getString( + CustomDialog dialog = new CustomDialog(env::createResource, I18N.getString( "resource.installdirnotemptydlg-wix-file"), "InstallDirNotEmptyDlg.wxs"); List dialogIds = getUI().dialogIdsSupplier.apply(this); From f6041f0b98f82eb247768b218f67e01889ed4ac4 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 28 Oct 2024 00:50:19 -0400 Subject: [PATCH 0079/1101] - move Package to jpk.jpackage.model package - move Package.StandardPackageType and Package.PackageType to outer level --- .../jpackage/internal/LinuxDebBundler.java | 2 +- .../internal/LinuxDebPackageFromParams.java | 2 +- .../jdk/jpackage/internal/LinuxPackage.java | 1 + .../jpackage/internal/LinuxPackageArch.java | 2 +- .../internal/LinuxPackageFromParams.java | 2 +- .../internal/LinuxRpmPackageFromParams.java | 2 +- .../jdk/jpackage/internal/Package.java | 32 ++----------------- .../jpackage/internal/PackageFromParams.java | 4 +-- .../jdk/jpackage/internal/WinExePackage.java | 2 ++ .../internal/WinMsiPackageFromParams.java | 2 +- 10 files changed, 14 insertions(+), 37 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index ac3e01d6985bb..84d362dbe023a 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -48,7 +48,7 @@ import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; -import static jdk.jpackage.internal.Package.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.model.StandardPackageType.LINUX_DEB; public class LinuxDebBundler extends LinuxPackageBundler { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java index 6ec27171008e9..91190b23a325d 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java @@ -27,7 +27,7 @@ import java.util.Map; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; -import static jdk.jpackage.internal.Package.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.model.StandardPackageType.LINUX_DEB; final class LinuxDebPackageFromParams { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java index c17732879889f..f018f1395727c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.model.StandardPackageType; import java.nio.file.Path; import java.text.MessageFormat; import java.util.Optional; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java index 6936bcec941d9..734a680a37f53 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java @@ -26,7 +26,7 @@ import java.io.IOException; import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; -import jdk.jpackage.internal.Package.StandardPackageType; +import jdk.jpackage.model.StandardPackageType; final class LinuxPackageArch { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java index a7836d649a7b7..3aa389f0b0f48 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java @@ -27,7 +27,7 @@ import java.util.Map; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import jdk.jpackage.internal.LinuxPackage.Impl; -import jdk.jpackage.internal.Package.StandardPackageType; +import jdk.jpackage.model.StandardPackageType; final class LinuxPackageFromParams { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java index 7bc795e78fb3a..8a2a7a63a0a3a 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java @@ -28,7 +28,7 @@ import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import jdk.jpackage.internal.LinuxRpmPackage.Impl; import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; -import static jdk.jpackage.internal.Package.StandardPackageType.LINUX_RPM; +import static jdk.jpackage.model.StandardPackageType.LINUX_RPM; final class LinuxRpmPackageFromParams { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java index a57b20d84413b..11b0cc9e98329 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java @@ -24,40 +24,14 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.model.StandardPackageType; +import jdk.jpackage.model.PackageType; import java.nio.file.Path; import java.util.Optional; -import java.util.stream.Stream; import static jdk.jpackage.internal.Getter.getValueOrDefault; -interface Package { +public interface Package { - interface PackageType { - } - - enum StandardPackageType implements PackageType { - WIN_MSI(".msi"), - WIN_EXE(".exe"), - LINUX_DEB(".deb"), - LINUX_RPM(".rpm"), - MAC_PKG(".pkg"), - MAC_DMG(".dmg"); - - StandardPackageType(String suffix) { - this.suffix = suffix; - } - - String suffix() { - return suffix; - } - - static StandardPackageType fromCmdLineType(String type) { - return Stream.of(values()).filter(pt -> { - return pt.suffix().substring(1).equals(type); - }).findAny().get(); - } - - private final String suffix; - } Application app(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java index 60e0e4cea860a..71c0efa9c52be 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java @@ -30,8 +30,8 @@ import jdk.jpackage.internal.Functional.ThrowingFunction; import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; import jdk.jpackage.internal.Package.Impl; -import jdk.jpackage.internal.Package.PackageType; -import jdk.jpackage.internal.Package.StandardPackageType; +import jdk.jpackage.model.PackageType; +import jdk.jpackage.model.StandardPackageType; import static jdk.jpackage.internal.Package.mapInstallDir; import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java index fb65b88d72db4..eeb3e0b69c915 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.model.StandardPackageType; +import jdk.jpackage.model.PackageType; import java.nio.file.Path; interface WinExePackage extends Package { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java index 48a42387e219a..0011776000b56 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java @@ -32,7 +32,7 @@ import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; import jdk.jpackage.internal.WinMsiPackage.Impl; -import static jdk.jpackage.internal.Package.StandardPackageType.WIN_MSI; +import static jdk.jpackage.model.StandardPackageType.WIN_MSI; final class WinMsiPackageFromParams { From 45d852416645b80c3f7aad13acfdb1bd29948469 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 28 Oct 2024 00:51:15 -0400 Subject: [PATCH 0080/1101] Add a package with jackage CLI. Ready for JOpt integration --- .../jdk/jpackage/cli/AdditionalLauncher.java | 32 +++ .../classes/jdk/jpackage/cli/Option.java | 31 +++ .../classes/jdk/jpackage/cli/OptionSpec.java | 41 ++++ .../jdk/jpackage/cli/OptionSpecBuilder.java | 122 ++++++++++ .../jdk/jpackage/cli/PackageTypeGroup.java | 72 ++++++ .../jdk/jpackage/cli/ParsedOptions.java | 33 +++ .../jdk/jpackage/cli/StandardOption.java | 210 ++++++++++++++++++ .../jpackage/cli/StandardValueConverter.java | 83 +++++++ .../jpackage/cli/StandardValueValidator.java | 53 +++++ .../jdk/jpackage/cli/ValueConverter.java | 46 ++++ .../jpackage/model/AppImagePackageType.java | 35 +++ .../jdk/jpackage/model/PackageType.java | 29 +++ .../jpackage/model/StandardPackageType.java | 52 +++++ 13 files changed, 839 insertions(+) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/cli/AdditionalLauncher.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/cli/Option.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/cli/OptionSpec.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/cli/OptionSpecBuilder.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/cli/PackageTypeGroup.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/cli/ParsedOptions.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardOption.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardValueConverter.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardValueValidator.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/cli/ValueConverter.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/model/AppImagePackageType.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/model/PackageType.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/model/StandardPackageType.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/AdditionalLauncher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/AdditionalLauncher.java new file mode 100644 index 0000000000000..a282b04dab011 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/AdditionalLauncher.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.cli; + +import java.nio.file.Path; + + +public record AdditionalLauncher(String name, Path propertyFile) { +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/Option.java b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/Option.java new file mode 100644 index 0000000000000..57b1b507e75d6 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/Option.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.cli; + + +public interface Option { + OptionSpec getSpec(); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/OptionSpec.java b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/OptionSpec.java new file mode 100644 index 0000000000000..f065438ddfe86 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/OptionSpec.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.cli; + +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; +import jdk.jpackage.model.PackageType; + + +public record OptionSpec(String name, ValueConverter valueConverter, String shortName, Set supportedPackageTypes, Consumer valueValidator) { + public OptionSpec { + Objects.requireNonNull(name); + if (supportedPackageTypes.isEmpty()) { + throw new IllegalArgumentException("At least one package type must be set"); + } + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/OptionSpecBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/OptionSpecBuilder.java new file mode 100644 index 0000000000000..309951f8377e0 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/OptionSpecBuilder.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.cli; + +import java.util.Set; +import java.util.function.Consumer; +import jdk.jpackage.model.PackageType; +import static jdk.jpackage.cli.StandardValueConverter.IDENTITY_CONV; +import static jdk.jpackage.cli.StandardValueConverter.PATH_ARRAY_CONV; +import static jdk.jpackage.cli.StandardValueConverter.PATH_CONV; +import static jdk.jpackage.cli.StandardValueConverter.STRING_ARRAY_CONV; + +final class OptionSpecBuilder { + OptionSpec create() { + return new OptionSpec(name, valueConverter, shortName, supportedPackageTypes, valueValidator); + } + + OptionSpecBuilder ofString() { + return valueConverter(IDENTITY_CONV); + } + + OptionSpecBuilder ofPath() { + return valueConverter(PATH_CONV); + } + + OptionSpecBuilder ofDirectory() { + return ofPath().valueValidator(StandardValueValidator::validateDirectory); + } + + OptionSpecBuilder ofStringArray() { + return valueConverter(STRING_ARRAY_CONV); + } + + OptionSpecBuilder ofPathArray() { + return valueConverter(PATH_ARRAY_CONV); + } + + OptionSpecBuilder ofDirectoryArray() { + return ofPathArray().valueValidator(StandardValueValidator::validateDirectoryArray); + } + + OptionSpecBuilder ofUrl() { + return ofString().valueValidator(StandardValueValidator::validateUrl); + } + + OptionSpecBuilder name(String v) { + name = v; + return this; + } + + OptionSpecBuilder valueConverter(ValueConverter v) { + valueConverter = v; + return this; + } + + OptionSpecBuilder valueValidator(Consumer v) { + valueValidator = v; + return this; + } + + OptionSpecBuilder shortName(String v) { + shortName = v; + return this; + } + + final OptionSpecBuilder supportedPackageTypes(PackageType... v) { + return supportedPackageTypes(Set.of(v)); + } + + OptionSpecBuilder supportedPackageTypes(Set v) { + supportedPackageTypes = v; + return this; + } + + String getName() { + return name; + } + + ValueConverter getValueConverter() { + return valueConverter; + } + + Consumer getValueValidator() { + return valueValidator; + } + + String getShortName() { + return shortName; + } + + Set getSupportedPackageTypes() { + return supportedPackageTypes; + } + + private String name; + private ValueConverter valueConverter; + private Consumer valueValidator; + private String shortName; + private Set supportedPackageTypes; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/PackageTypeGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/PackageTypeGroup.java new file mode 100644 index 0000000000000..6d0e7b09e03e0 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/PackageTypeGroup.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.cli; + +import java.util.Set; +import java.util.function.Function; +import static java.util.stream.Collectors.toSet; +import java.util.stream.Stream; +import jdk.jpackage.model.AppImagePackageType; +import jdk.jpackage.model.PackageType; +import jdk.jpackage.model.StandardPackageType; +import static jdk.jpackage.model.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.model.StandardPackageType.LINUX_RPM; +import static jdk.jpackage.model.StandardPackageType.MAC_DMG; +import static jdk.jpackage.model.StandardPackageType.MAC_PKG; +import static jdk.jpackage.model.StandardPackageType.WIN_EXE; +import static jdk.jpackage.model.StandardPackageType.WIN_MSI; + +enum PackageTypeGroup { + APP_IMAGE(name -> Set.of(AppImagePackageType.APP_IMAGE)), + NATIVE_PACKAGE(name -> { + if (name == null) { + return Set.of(StandardPackageType.values()); + } else if (name.startsWith("win")) { + return Set.of(WIN_EXE, WIN_MSI); + } else if (name.startsWith("linux")) { + return Set.of(LINUX_DEB, LINUX_RPM); + } else if (name.startsWith("mac")) { + return Set.of(MAC_DMG, MAC_PKG); + } else { + throw new IllegalArgumentException("Unsupported name"); + } + }), + ALL_PACKAGE_TYPES(name -> { + return Stream.of( + APP_IMAGE.forForOptionName(name), + NATIVE_PACKAGE.forForOptionName(name) + ).flatMap(Set::stream).collect(toSet()); + }); + + PackageTypeGroup(Function> conv) { + this.conv = conv; + } + + Set forForOptionName(String name) { + return conv.apply(name); + } + + private final Function> conv; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/ParsedOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/ParsedOptions.java new file mode 100644 index 0000000000000..cdb1eb5c95309 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/ParsedOptions.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.cli; + +import java.util.Optional; + + +public interface ParsedOptions { + public Optional get(Option id); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardOption.java new file mode 100644 index 0000000000000..63a20626193c4 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardOption.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.cli; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; +import jdk.jpackage.model.AppImagePackageType; +import jdk.jpackage.model.PackageType; +import jdk.jpackage.model.StandardPackageType; +import static jdk.jpackage.model.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.model.StandardPackageType.LINUX_RPM; +import static jdk.jpackage.model.StandardPackageType.MAC_DMG; +import static jdk.jpackage.model.StandardPackageType.MAC_PKG; +import static jdk.jpackage.model.StandardPackageType.WIN_EXE; +import static jdk.jpackage.model.StandardPackageType.WIN_MSI; +import static jdk.jpackage.cli.PackageTypeGroup.ALL_PACKAGE_TYPES; +import static jdk.jpackage.cli.PackageTypeGroup.APP_IMAGE; +import static jdk.jpackage.cli.PackageTypeGroup.NATIVE_PACKAGE; + +public enum StandardOption implements Option { + TYPE(build().name("type").shortName("t").valueConverter(new ValueConverter() { + @Override + public PackageType convert(String value) { + if ("app-image".equals(value)) { + return AppImagePackageType.APP_IMAGE; + } else { + return StandardPackageType.fromCmdLineType(value); + } + } + + @Override + public Class valueType() { + return PackageType.class; + } + + })), + INPUT(build().name("input").shortName("i").ofDirectory(), APP_IMAGE), + DEST(build().name("dest").shortName("d").ofDirectory()), + DESCRIPTION("description"), + VENDOR("vendor"), + APPCLASS("main-class"), + NAME(build().name("input").shortName("i").ofString()), + VERBOSE(build().name("verbose").valueConverter(null)), + RESOURCE_DIR("resource-dir", OptionSpecBuilder::ofDirectory), + ARGUMENTS("arguments", OptionSpecBuilder::ofStringArray), + JLINK_OPTIONS("arguments", OptionSpecBuilder::ofStringArray), + ICON("icon", OptionSpecBuilder::ofPath), + COPYRIGHT("copyright"), + LICENSE_FILE("license-file", OptionSpecBuilder::ofPath), + VERSION("app-version"), + ABOUT_URL("about-url", OptionSpecBuilder::ofUrl), + JAVA_OPTIONS("java-options", OptionSpecBuilder::ofStringArray), + APP_CONTENT("app-content", OptionSpecBuilder::ofPathArray), + FILE_ASSOCIATIONS("file-associations", OptionSpecBuilder::ofPath), + ADD_LAUNCHER(build().name("add-launcher").valueConverter(new ValueConverter() { + @Override + public jdk.jpackage.cli.AdditionalLauncher convert(String value) { + var components = value.split("=", 2); + if (components.length == 1) { + return new AdditionalLauncher(null, + StandardValueConverter.PATH_CONV.convert(components[0])); + } else { + return new AdditionalLauncher(components[0], + StandardValueConverter.PATH_CONV.convert(components[1])); + } + } + + @Override + public Class valueType() { + return AdditionalLauncher.class; + } + })), + TEMP_ROOT("temp", OptionSpecBuilder::ofDirectory), + INSTALL_DIR("install-dir", OptionSpecBuilder::ofPath), + PREDEFINED_APP_IMAGE("app-image", OptionSpecBuilder::ofDirectory, NATIVE_PACKAGE), + PREDEFINED_RUNTIME_IMAGE("runtime-image", OptionSpecBuilder::ofDirectory), + MAIN_JAR("main-jar", OptionSpecBuilder::ofPath), + MODULE(build().name("module").shortName("m").ofString()), + ADD_MODULES("add-modules", OptionSpecBuilder::ofStringArray), + MODULE_PATH(build().name("module-path").shortName("p").ofDirectoryArray()), + LAUNCHER_AS_SERVICE(build().name("launcher-as-service").valueConverter(null)), + // Linux-specific + LINUX_RELEASE("linux-app-release", NATIVE_PACKAGE), + LINUX_BUNDLE_NAME("linux-package-name", NATIVE_PACKAGE), + LINUX_DEB_MAINTAINER("linux-deb-maintainer", NATIVE_PACKAGE), + LINUX_CATEGORY("linux-app-category", NATIVE_PACKAGE), + LINUX_RPM_LICENSE_TYPE("linux-rpm-license-type", NATIVE_PACKAGE), + LINUX_PACKAGE_DEPENDENCIES("linux-package-deps", NATIVE_PACKAGE), + LINUX_SHORTCUT_HINT(build().name("linux-shortcut").valueConverter(null), NATIVE_PACKAGE), + LINUX_MENU_GROUP("linux-package-deps", NATIVE_PACKAGE), + // MacOS-specific + DMG_CONTENT(build().name("mac-dmg-content").ofPathArray()), + MAC_SIGN(build().name("mac-sign").shortName("s").valueConverter(null)), + MAC_APP_STORE(build().name("mac-app-store").shortName("s").valueConverter(null), NATIVE_PACKAGE), + MAC_CATEGORY("mac-app-category"), + MAC_BUNDLE_NAME("mac-package-name"), + MAC_BUNDLE_IDENTIFIER("mac-package-identifier"), + MAC_BUNDLE_SIGNING_PREFIX("mac-package-signing-prefix"), + MAC_SIGNING_KEY_NAME("mac-signing-key-user-name"), + MAC_APP_IMAGE_SIGN_IDENTITY("mac-app-image-sign-identity", APP_IMAGE), + MAC_INSTALLER_SIGN_IDENTITY("mac-installer-sign-identity", NATIVE_PACKAGE), + MAC_SIGNING_KEYCHAIN("mac-signing-keychain", OptionSpecBuilder::ofPath), + MAC_ENTITLEMENTS("mac-entitlements"), + // Windows-specific + WIN_HELP_URL("win-help-url", OptionSpecBuilder::ofUrl, NATIVE_PACKAGE), + WIN_UPDATE_URL("win-update-url", OptionSpecBuilder::ofUrl, NATIVE_PACKAGE), + WIN_MENU_HINT(build().name("win-menu").valueConverter(null), NATIVE_PACKAGE), + WIN_MENU_GROUP("win-menu-group", NATIVE_PACKAGE), + WIN_SHORTCUT_HINT(build().name("win-shortcut").valueConverter(null), NATIVE_PACKAGE), + WIN_SHORTCUT_PROMPT("win-shortcut-prompt", NATIVE_PACKAGE), + WIN_PER_USER_INSTALLATION(build().name("win-per-user-install").valueConverter(null), NATIVE_PACKAGE), + WIN_DIR_CHOOSER(build().name("win-dir-chooser").valueConverter(null), NATIVE_PACKAGE), + WIN_UPGRADE_UUID("win-upgrade-uuid", NATIVE_PACKAGE), + WIN_CONSOLE_HINT(build().name("win-console").valueConverter(null)), + ; + + StandardOption(OptionSpecBuilder builder) { + this(builder, ALL_PACKAGE_TYPES); + } + + StandardOption(OptionSpecBuilder builder, PackageTypeGroup packageTypeGroup) { + this.spec = createOptionSpec(builder, packageTypeGroup); + } + + StandardOption(String name) { + this(name, ALL_PACKAGE_TYPES); + } + + StandardOption(String name, PackageTypeGroup packageTypeGroup) { + this(name, OptionSpecBuilder::ofString, ALL_PACKAGE_TYPES); + } + + StandardOption(String name, UnaryOperator conv) { + this(name, conv, ALL_PACKAGE_TYPES); + } + + StandardOption(String name, UnaryOperator conv, + PackageTypeGroup packageTypeGroup) { + this(conv.apply(build()).name(name)); + } + + @Override + public OptionSpec getSpec() { + return spec; + } + + public static List filterOptions(PackageType... packageTypes) { + return Stream.of(values()).filter(option -> { + return Stream.of(packageTypes).anyMatch( + option.spec.supportedPackageTypes()::contains); + }).toList(); + } + + private static OptionSpecBuilder build() { + return new OptionSpecBuilder(); + } + + private static OptionSpec createOptionSpec(OptionSpecBuilder builder, + PackageTypeGroup packageTypeGroup) { + Objects.requireNonNull(packageTypeGroup); + if (Optional.ofNullable(builder.getSupportedPackageTypes()).map( + Collection::isEmpty).orElse(false)) { + var name = builder.getName(); + if (name.startsWith("win-exe")) { + builder.supportedPackageTypes(WIN_EXE); + } else if (name.startsWith("win-msi")) { + builder.supportedPackageTypes(WIN_MSI); + } else if (name.startsWith("linux-deb")) { + builder.supportedPackageTypes(LINUX_DEB); + } else if (name.startsWith("linux-rpm")) { + builder.supportedPackageTypes(LINUX_RPM); + } else if (name.startsWith("mac-dmg")) { + builder.supportedPackageTypes(MAC_DMG); + } else if (name.startsWith("mac-pkg")) { + builder.supportedPackageTypes(MAC_PKG); + } else { + builder.supportedPackageTypes(packageTypeGroup.forForOptionName(name)); + } + } + return builder.create(); + } + + private final OptionSpec spec; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardValueConverter.java new file mode 100644 index 0000000000000..fa371a117aee1 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardValueConverter.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.cli; + +import java.io.File; +import java.nio.file.Path; +import java.util.Objects; +import java.util.stream.Stream; + + +final class StandardValueConverter { + final static ValueConverter IDENTITY_CONV = new ValueConverter<>() { + @Override + public String convert(String value) { + Objects.requireNonNull(value); + return value; + } + + @Override + public Class valueType() { + return String.class; + } + }; + + final static ValueConverter PATH_CONV = new ValueConverter<>() { + @Override + public Path convert(String value) { + return Path.of(value); + } + + @Override + public Class valueType() { + return Path.class; + } + }; + + final static ValueConverter STRING_ARRAY_CONV = new ValueConverter<>() { + @Override + public String[] convert(String value) { + return value.split("[,\\s]"); + } + + @Override + public Class valueType() { + return String[].class; + } + }; + + final static ValueConverter PATH_ARRAY_CONV = new ValueConverter<>() { + @Override + public Path[] convert(String value) { + return Stream.of(value.split(File.pathSeparator)).map(Path::of).toArray(Path[]::new); + } + + @Override + public Class valueType() { + return Path[].class; + } + }; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardValueValidator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardValueValidator.java new file mode 100644 index 0000000000000..4b60baaead748 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardValueValidator.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.cli; + +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; + +final class StandardValueValidator { + + static void validateDirectory(Path path) { + if (!Files.isDirectory(path)) { + throw new IllegalArgumentException(); + } + } + + static void validateDirectoryArray(Path[] paths) { + for (var path : paths) { + validateDirectory(path); + } + } + + static void validateUrl(String str) { + try { + new URI(str); + } catch (URISyntaxException ex) { + throw new IllegalArgumentException(ex); + } + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/ValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/ValueConverter.java new file mode 100644 index 0000000000000..c2f03ba8b05bf --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/cli/ValueConverter.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.cli; + +public interface ValueConverter { + + /** + * Converts the given string value into a Java type. + * + * @param value the string to convert + * @return the converted value + * @throws ValueConversionException if a problem occurs while converting the + * value + */ + T convert(String value); + + /** + * Gives the class of the type of values this converter converts to. + * + * @return the target class for conversion + */ + Class valueType(); + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/model/AppImagePackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/model/AppImagePackageType.java new file mode 100644 index 0000000000000..8f2a46400d9a3 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/model/AppImagePackageType.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.model; + + +public final class AppImagePackageType implements PackageType { + private AppImagePackageType() { + + } + + public final static AppImagePackageType APP_IMAGE = new AppImagePackageType(); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/model/PackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/model/PackageType.java new file mode 100644 index 0000000000000..1c36c075bf5a7 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/model/PackageType.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.model; + + +public interface PackageType {} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/model/StandardPackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/model/StandardPackageType.java new file mode 100644 index 0000000000000..5e062f33d903f --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/model/StandardPackageType.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.model; + +import java.util.stream.Stream; + +public enum StandardPackageType implements PackageType { + WIN_MSI(".msi"), + WIN_EXE(".exe"), + LINUX_DEB(".deb"), + LINUX_RPM(".rpm"), + MAC_PKG(".pkg"), + MAC_DMG(".dmg"); + + StandardPackageType(String suffix) { + this.suffix = suffix; + } + + public String suffix() { + return suffix; + } + + public static StandardPackageType fromCmdLineType(String type) { + return Stream.of(values()).filter(pt -> { + return pt.suffix().substring(1).equals(type); + }).findAny().get(); + } + final String suffix; + +} From fb2586080d4795d81184066b533b8e2baaa35419 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 29 Oct 2024 00:30:36 -0400 Subject: [PATCH 0081/1101] - Clustered classes from jdk.jpackage.internal package into jdk.jpackage.internal.cli, jdk.jpackage.internal.util, jdk.jpackage.internal.util.function, jdk.jpackage.internal.util.xml, and jdk.jpackage.internal.model packages - Reworked file associations initialization --- .../jpackage/internal/DesktopIntegration.java | 94 +++--- .../internal/LinuxAppImageBuilder.java | 4 + .../internal/LinuxApplicationFromParams.java | 31 +- .../jpackage/internal/LinuxDebBundler.java | 9 +- .../internal/LinuxDebPackageFromParams.java | 4 +- .../internal/LinuxLaunchersAsServices.java | 2 + .../jpackage/internal/LinuxPackageArch.java | 4 +- .../internal/LinuxPackageBundler.java | 6 +- .../internal/LinuxPackageFromParams.java | 10 +- .../jpackage/internal/LinuxRpmBundler.java | 6 + .../internal/LinuxRpmPackageFromParams.java | 6 +- .../jpackage/internal/PackageProperty.java | 1 + .../{ => model}/LinuxApplication.java | 8 +- .../internal/{ => model}/LinuxDebPackage.java | 4 +- .../internal/{ => model}/LinuxLauncher.java | 8 +- .../internal/{ => model}/LinuxPackage.java | 17 +- .../internal/{ => model}/LinuxRpmPackage.java | 6 +- .../jpackage/internal/CFBundleVersion.java | 3 +- .../jdk/jpackage/internal/MacAppBundler.java | 1 + .../jpackage/internal/MacAppImageBuilder.java | 4 +- .../internal/MacBaseInstallerBundler.java | 6 +- .../jdk/jpackage/internal/MacDmgBundler.java | 14 +- .../internal/MacLaunchersAsServices.java | 5 +- .../jdk/jpackage/internal/MacPkgBundler.java | 10 +- .../internal/MacPkgInstallerScripts.java | 1 + .../internal/AbstractAppImageBuilder.java | 9 +- .../jpackage/internal/AbstractBundler.java | 3 +- .../jpackage/internal/AppImageBuilder.java | 9 +- .../jpackage/internal/AppImageBundler.java | 2 + .../jdk/jpackage/internal/AppImageFile.java | 4 +- .../jdk/jpackage/internal/AppImageFile2.java | 10 +- .../internal/ApplicationFromParams.java | 38 ++- .../jdk/jpackage/internal/Arguments.java | 29 +- .../jdk/jpackage/internal/BuildEnv.java | 30 +- .../jpackage/internal/BuildEnvFromParams.java | 4 +- .../jdk/jpackage/internal/Bundler.java | 2 + .../jpackage/internal/BundlerParamInfo.java | 5 +- .../jdk/jpackage/internal/CfgFile.java | 6 + .../jdk/jpackage/internal/DeployParams.java | 1 + .../jpackage/internal/FileAssociation.java | 106 ------- .../jdk/jpackage/internal/Functional.java | 208 -------------- .../classes/jdk/jpackage/internal/Getter.java | 4 +- .../classes/jdk/jpackage/internal/I18N.java | 61 +--- .../jdk/jpackage/internal/IOUtils.java | 271 +----------------- .../internal/JLinkRuntimeBuilder.java | 6 + .../jpackage/internal/LauncherAsService.java | 3 + .../jdk/jpackage/internal/LauncherData.java | 1 + .../jpackage/internal/LauncherFromParams.java | 72 ++++- .../LauncherStartupInfoFromParams.java | 3 + .../jdk/jpackage/internal/PackageFile.java | 1 + .../jpackage/internal/PackageFromParams.java | 15 +- .../jpackage/internal/PlatformPackage.java | 1 + .../internal/RuntimeBuilderFromParams.java | 3 + .../internal/StandardBundlerParam.java | 13 +- .../jdk/jpackage/internal/ToolValidator.java | 2 + .../cli/AdditionalLauncher.java | 2 +- .../jpackage/{ => internal}/cli/Option.java | 2 +- .../{ => internal}/cli/OptionSpec.java | 4 +- .../{ => internal}/cli/OptionSpecBuilder.java | 12 +- .../{ => internal}/cli/PackageTypeGroup.java | 20 +- .../{ => internal}/cli/ParsedOptions.java | 2 +- .../{ => internal}/cli/StandardOption.java | 30 +- .../cli/StandardValueConverter.java | 2 +- .../cli/StandardValueValidator.java | 2 +- .../{ => internal}/cli/ValueConverter.java | 2 +- .../model/AppImagePackageType.java | 2 +- .../internal/{ => model}/Application.java | 34 +-- .../{ => model}/ApplicationLayout.java | 13 +- .../internal/{ => model}/ConfigException.java | 10 +- .../internal/{ => model}/DottedVersion.java | 20 +- .../internal/model/FileAssociation.java | 111 +++++++ .../jdk/jpackage/internal/model/I18N.java | 62 ++++ .../jdk/jpackage/internal/model/IconType.java | 41 +++ .../internal/{ => model}/Launcher.java | 6 +- .../{ => model}/LauncherJarStartupInfo.java | 6 +- .../LauncherModularStartupInfo.java | 6 +- .../{ => model}/LauncherStartupInfo.java | 4 +- .../internal/model}/MacApplication.java | 4 +- .../{ => model}/OverridableResource.java | 96 ++++--- .../internal/{ => model}/Package.java | 4 +- .../{ => internal}/model/PackageType.java | 2 +- .../{ => model}/PackagerException.java | 2 +- .../internal/{ => model}/ProxyBase.java | 4 +- .../internal/{ => model}/RuntimeBuilder.java | 31 +- .../model/StandardPackageType.java | 2 +- .../internal/util/CollectionUtils.java | 34 +++ .../jdk/jpackage/internal/util/FileUtils.java | 116 ++++++++ .../internal/util/MultiResourceBundle.java | 75 +++++ .../internal/{ => util}/PathGroup.java | 41 +-- .../jdk/jpackage/internal/util/PathUtils.java | 31 ++ .../jdk/jpackage/internal/util/XmlUtils.java | 111 +++++++ .../util/function/ExceptionWrapper.java | 46 +++ .../util/function/ThrowingBiConsumer.java | 43 +++ .../util/function/ThrowingBiFunction.java | 43 +++ .../util/function/ThrowingConsumer.java | 42 +++ .../util/function/ThrowingFunction.java | 42 +++ .../util/function/ThrowingRunnable.java | 40 +++ .../util/function/ThrowingSupplier.java | 42 +++ .../util/function/ThrowingUnaryOperator.java | 43 +++ .../internal/util/xml/PrettyPrintHandler.java | 89 ++++++ .../util/xml/SkipDocumentHandler.java | 48 ++++ .../jdk/jpackage/internal/PackageScripts.java | 5 +- .../jpackage/internal/ShellCustomAction.java | 4 +- .../internal/ShellCustomActionFactory.java | 1 + .../internal/ShellScriptResource.java | 1 + .../internal/UnixLaunchersAsServices.java | 3 + .../internal/ExecutableRebrander.java | 5 + .../jpackage/internal/WinAppImageBuilder.java | 4 + .../internal/WinApplicationFromParams.java | 51 ++-- .../jdk/jpackage/internal/WinExeBundler.java | 9 +- .../jdk/jpackage/internal/WinMsiBundler.java | 7 +- .../internal/WinMsiPackageFromParams.java | 6 +- .../internal/WixAppImageFragmentBuilder.java | 143 ++++----- .../jpackage/internal/WixFragmentBuilder.java | 10 +- .../internal/WixLauncherAsService.java | 7 +- .../jdk/jpackage/internal/WixPipeline.java | 3 +- .../jpackage/internal/WixSourceConverter.java | 7 +- .../jdk/jpackage/internal/WixTool.java | 5 +- .../jdk/jpackage/internal/WixToolset.java | 1 + .../internal/WixUiFragmentBuilder.java | 7 +- .../internal/{ => model}/MsiVersion.java | 9 +- .../internal/{ => model}/WinApplication.java | 8 +- .../internal/{ => model}/WinExePackage.java | 10 +- .../internal/{ => model}/WinLauncher.java | 13 +- .../internal/{ => model}/WinMsiPackage.java | 23 +- .../jdk/jpackage/test/AppImageFile.java | 7 +- .../jdk/jpackage/test/ApplicationLayout.java | 126 ++++++++ .../jdk/jpackage/test/FileAssociations.java | 4 +- .../jdk/jpackage/test/JPackageCommand.java | 2 - .../test/LauncherAsServiceVerifier.java | 4 +- .../jdk/jpackage/test/LinuxHelper.java | 5 +- .../helpers/jdk/jpackage/test/MacHelper.java | 4 +- .../jdk/jpackage/test/PackageFile.java | 37 +++ .../jdk/jpackage/test/PackageTest.java | 2 - .../jpackage/internal/DeployParamsTest.java | 1 + .../internal/PlatformVersionTest.java | 1 + .../jpackage/internal/ToolValidatorTest.java | 10 +- .../{ => model}/ApplicationLayoutTest.java | 3 +- .../{ => model}/CompareDottedVersionTest.java | 2 +- .../{ => model}/DottedVersionTest.java | 3 +- .../{ => model}/InvalidDottedVersionTest.java | 5 +- .../{ => model}/OverridableResourceTest.java | 17 +- .../internal/{ => util}/PathGroupTest.java | 2 +- ...SigningPackageFromTwoStepAppImageTest.java | 2 +- .../jpackage/macosx/SigningPackageTest.java | 2 +- .../macosx/SigningPackageTwoStepTest.java | 2 +- .../jpackage/macosx/base/SigningCheck.java | 4 - .../tools/jpackage/share/AppContentTest.java | 15 +- .../share/EmptyFolderPackageTest.java | 2 +- .../tools/jpackage/share/EmptyFolderTest.java | 2 +- .../share/RuntimeImageSymbolicLinksTest.java | 11 +- .../jpackage/windows/WinLongVersionTest.java | 9 +- .../tools/jpackage/windows/WinScriptTest.java | 7 +- 153 files changed, 2032 insertions(+), 1211 deletions(-) rename src/jdk.jpackage/linux/classes/jdk/jpackage/internal/{ => model}/LinuxApplication.java (84%) rename src/jdk.jpackage/linux/classes/jdk/jpackage/internal/{ => model}/LinuxDebPackage.java (96%) rename src/jdk.jpackage/linux/classes/jdk/jpackage/internal/{ => model}/LinuxLauncher.java (88%) rename src/jdk.jpackage/linux/classes/jdk/jpackage/internal/{ => model}/LinuxPackage.java (92%) rename src/jdk.jpackage/linux/classes/jdk/jpackage/internal/{ => model}/LinuxRpmPackage.java (90%) delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociation.java delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/Functional.java rename src/jdk.jpackage/share/classes/jdk/jpackage/{ => internal}/cli/AdditionalLauncher.java (95%) rename src/jdk.jpackage/share/classes/jdk/jpackage/{ => internal}/cli/Option.java (95%) rename src/jdk.jpackage/share/classes/jdk/jpackage/{ => internal}/cli/OptionSpec.java (93%) rename src/jdk.jpackage/share/classes/jdk/jpackage/{ => internal}/cli/OptionSpecBuilder.java (86%) rename src/jdk.jpackage/share/classes/jdk/jpackage/{ => internal}/cli/PackageTypeGroup.java (79%) rename src/jdk.jpackage/share/classes/jdk/jpackage/{ => internal}/cli/ParsedOptions.java (95%) rename src/jdk.jpackage/share/classes/jdk/jpackage/{ => internal}/cli/StandardOption.java (87%) rename src/jdk.jpackage/share/classes/jdk/jpackage/{ => internal}/cli/StandardValueConverter.java (95%) rename src/jdk.jpackage/share/classes/jdk/jpackage/{ => internal}/cli/StandardValueValidator.java (95%) rename src/jdk.jpackage/share/classes/jdk/jpackage/{ => internal}/cli/ValueConverter.java (95%) rename src/jdk.jpackage/share/classes/jdk/jpackage/{ => internal}/model/AppImagePackageType.java (97%) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/Application.java (90%) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/ApplicationLayout.java (95%) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/ConfigException.java (90%) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/DottedVersion.java (94%) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/IconType.java rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/Launcher.java (97%) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/LauncherJarStartupInfo.java (90%) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/LauncherModularStartupInfo.java (91%) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/LauncherStartupInfo.java (97%) rename src/jdk.jpackage/{macosx/classes/jdk/jpackage/internal => share/classes/jdk/jpackage/internal/model}/MacApplication.java (94%) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/OverridableResource.java (81%) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/Package.java (98%) rename src/jdk.jpackage/share/classes/jdk/jpackage/{ => internal}/model/PackageType.java (97%) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/PackagerException.java (98%) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/ProxyBase.java (94%) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/RuntimeBuilder.java (72%) rename src/jdk.jpackage/share/classes/jdk/jpackage/{ => internal}/model/StandardPackageType.java (97%) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => util}/PathGroup.java (88%) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionWrapper.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiConsumer.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/PrettyPrintHandler.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/SkipDocumentHandler.java rename src/jdk.jpackage/windows/classes/jdk/jpackage/internal/{ => model}/MsiVersion.java (90%) rename src/jdk.jpackage/windows/classes/jdk/jpackage/internal/{ => model}/WinApplication.java (85%) rename src/jdk.jpackage/windows/classes/jdk/jpackage/internal/{ => model}/WinExePackage.java (84%) rename src/jdk.jpackage/windows/classes/jdk/jpackage/internal/{ => model}/WinLauncher.java (86%) rename src/jdk.jpackage/windows/classes/jdk/jpackage/internal/{ => model}/WinMsiPackage.java (83%) create mode 100644 test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java create mode 100644 test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageFile.java rename test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/{ => model}/ApplicationLayoutTest.java (97%) rename test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/{ => model}/CompareDottedVersionTest.java (99%) rename test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/{ => model}/DottedVersionTest.java (98%) rename test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/{ => model}/InvalidDottedVersionTest.java (94%) rename test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/{ => model}/OverridableResourceTest.java (94%) rename test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/{ => util}/PathGroupTest.java (99%) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 61e4864a6cdf0..ca9ba8d7c4276 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -24,6 +24,11 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.LinuxLauncher; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.OverridableResource; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; @@ -43,7 +48,10 @@ import javax.imageio.ImageIO; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; +import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.util.PathUtils; +import jdk.jpackage.internal.util.XmlUtils; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; /** * Helper to create files for desktop integration. @@ -60,9 +68,8 @@ final class DesktopIntegration extends ShellCustomAction { private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launcher) throws IOException { - associations = launcher.fileAssociations().stream() - .filter(fa -> !fa.mimeTypes.isEmpty()) - .map(LinuxFileAssociation::new).toList(); + associations = launcher.fileAssociations().stream().map( + LinuxFileAssociation::new).toList(); this.env = env; this.pkg = pkg; @@ -155,8 +162,6 @@ protected List replacementStringIds() { @Override protected Map createImpl() throws IOException { - associations.forEach(assoc -> assoc.data.verify()); - if (iconFile != null) { // Create application icon file. iconResource.saveToFile(iconFile.srcPath()); @@ -340,37 +345,33 @@ private InstallableFile createDesktopFile(String fileName) { } private void appendFileAssociation(XMLStreamWriter xml, - FileAssociation assoc) throws XMLStreamException { + LinuxFileAssociation fa) throws XMLStreamException { - for (var mimeType : assoc.mimeTypes) { xml.writeStartElement("mime-type"); - xml.writeAttribute("type", mimeType); + xml.writeAttribute("type", fa.mimeType()); - final String description = assoc.description; + final String description = fa.description(); if (description != null && !description.isEmpty()) { xml.writeStartElement("comment"); xml.writeCharacters(description); xml.writeEndElement(); } - for (String ext : assoc.extensions) { - xml.writeStartElement("glob"); - xml.writeAttribute("pattern", "*." + ext); - xml.writeEndElement(); - } + xml.writeStartElement("glob"); + xml.writeAttribute("pattern", "*." + fa.extension()); + xml.writeEndElement(); xml.writeEndElement(); - } } private void createFileAssociationsMimeInfoFile() throws IOException { - IOUtils.createXml(mimeInfoFile.srcPath(), xml -> { + XmlUtils.createXml(mimeInfoFile.srcPath(), xml -> { xml.writeStartElement("mime-info"); xml.writeDefaultNamespace( "http://www.freedesktop.org/standards/shared-mime-info"); - for (var assoc : associations) { - appendFileAssociation(xml, assoc.data); + for (var fa : associations) { + appendFileAssociation(xml, fa); } xml.writeEndElement(); @@ -380,30 +381,27 @@ private void createFileAssociationsMimeInfoFile() throws IOException { private void addFileAssociationIconFiles(ShellCommands shellCommands) throws IOException { Set processedMimeTypes = new HashSet<>(); - for (var assoc : associations) { - if (assoc.iconSize <= 0) { + for (var fa : associations) { + if (fa.icon() == null) { // No icon. continue; } - for (var mimeType : assoc.data.mimeTypes) { - if (processedMimeTypes.contains(mimeType)) { - continue; - } + var mimeType = fa.mimeType(); + if (processedMimeTypes.contains(mimeType)) { + continue; + } - processedMimeTypes.add(mimeType); + processedMimeTypes.add(mimeType); - // Create icon name for mime type from mime type. - var faIconFile = createDesktopFile(mimeType.replace( - File.separatorChar, '-') + IOUtils.getSuffix( - assoc.data.iconPath)); + // Create icon name for mime type from mime type. + var faIconFile = createDesktopFile(mimeType.replace(File.separatorChar, + '-') + PathUtils.getSuffix(fa.icon())); - IOUtils.copyFile(assoc.data.iconPath, - faIconFile.srcPath()); + IOUtils.copyFile(fa.icon(), faIconFile.srcPath()); - shellCommands.addIcon(mimeType, faIconFile.installPath(), - assoc.iconSize); - } + shellCommands.addIcon(mimeType, faIconFile.installPath(), + fa.iconSize); } } @@ -418,10 +416,7 @@ private void saveDesktopFile(Map data) throws IOException { } private List getMimeTypeNamesFromFileAssociations() { - return associations.stream() - .map(fa -> fa.data.mimeTypes) - .flatMap(List::stream) - .collect(Collectors.toUnmodifiableList()); + return associations.stream().map(FileAssociation::mimeType).toList(); } private static int getSquareSizeOfImage(File f) { @@ -460,18 +455,27 @@ private static int normalizeIconSize(int iconSize) { return commonIconSize; } - private static class LinuxFileAssociation { + private static class LinuxFileAssociation extends FileAssociation.Proxy { LinuxFileAssociation(FileAssociation fa) { - this.data = fa; - if (fa.iconPath != null && Files.isReadable(fa.iconPath)) { - iconSize = getSquareSizeOfImage(fa.iconPath.toFile()); + super(fa); + var icon = fa.icon(); + if (icon != null && Files.isReadable(icon)) { + iconSize = getSquareSizeOfImage(icon.toFile()); } else { iconSize = -1; } } - final FileAssociation data; - final int iconSize; + @Override + public Path icon() { + if (iconSize < 0) { + return null; + } else { + return super.icon(); + } + } + + private final int iconSize; } private final BuildEnv env; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index 76fe4f259db53..2ed79857aa5d3 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -24,6 +24,10 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.OverridableResource; +import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java index 31e3cca5e74d2..2c0ce4628cee5 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java @@ -24,31 +24,30 @@ */ package jdk.jpackage.internal; -import java.io.IOException; +import jdk.jpackage.internal.model.LinuxApplication; +import jdk.jpackage.internal.model.LinuxLauncher; import java.util.Map; import java.util.stream.Stream; import static jdk.jpackage.internal.ApplicationFromParams.createBundlerParam; -import jdk.jpackage.internal.LinuxApplication.Impl; +import jdk.jpackage.internal.model.LinuxApplication.Impl; import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; final class LinuxApplicationFromParams { - private static LinuxApplication create(Map params) throws ConfigException, IOException { - var app = ApplicationFromParams.create(params, launcherParams -> { - var launcher = LauncherFromParams.create(launcherParams); - - var shortcut = Stream.of(SHORTCUT_HINT, LINUX_SHORTCUT_HINT).filter(param -> { - return launcherParams.containsKey(param.getID()); - }).map(param -> { - return param.fetchFrom(launcherParams); - }).findFirst(); - return new LinuxLauncher.Impl(launcher, shortcut); - }); - return new Impl(app); + private static LinuxLauncher createLauncher(Map params) { + var launcher = new LauncherFromParams().create(params); + var shortcut = Stream.of(SHORTCUT_HINT, LINUX_SHORTCUT_HINT).filter(param -> { + return params.containsKey(param.getID()); + }).map(param -> { + return param.fetchFrom(params); + }).findFirst(); + return new LinuxLauncher.Impl(launcher, shortcut); } - static final BundlerParamInfo APPLICATION = createBundlerParam( - LinuxApplicationFromParams::create); + static final BundlerParamInfo APPLICATION = createBundlerParam(params -> { + var app = new ApplicationFromParams(LinuxApplicationFromParams::createLauncher).create(params); + return new Impl(app); + }); private static final BundlerParamInfo LINUX_SHORTCUT_HINT = new BundlerParamInfo<>( Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(), diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index 84d362dbe023a..cf0b8d0556fd5 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -25,6 +25,11 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LinuxDebPackage; +import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.nio.file.FileVisitResult; import java.nio.file.Files; @@ -47,8 +52,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; -import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; -import static jdk.jpackage.model.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; public class LinuxDebBundler extends LinuxPackageBundler { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java index 91190b23a325d..345079db38254 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java @@ -24,10 +24,12 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LinuxDebPackage; import java.util.Map; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; -import static jdk.jpackage.model.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; final class LinuxDebPackageFromParams { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java index 1f9bfbff662cd..a90b23ffdff6e 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.Launcher; import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java index 734a680a37f53..bb016e8d56530 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java @@ -25,8 +25,8 @@ package jdk.jpackage.internal; import java.io.IOException; -import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; -import jdk.jpackage.model.StandardPackageType; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; +import jdk.jpackage.internal.model.StandardPackageType; final class LinuxPackageArch { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 954a89401618c..d478bf1b177fa 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -24,6 +24,10 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.ConfigException; import java.io.IOException; import java.nio.file.Path; import java.text.MessageFormat; @@ -53,8 +57,6 @@ public final boolean validate(Map params) LinuxPackage pkg = pkgParam.fetchFrom(params); var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - FileAssociation.verify(FileAssociation.fetchFrom(params)); - for (var validator: getToolValidators()) { ConfigException ex = validator.validate(); if (ex != null) { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java index 3aa389f0b0f48..de23f9ee60832 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java @@ -24,10 +24,13 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.ConfigException; import java.util.Map; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; -import jdk.jpackage.internal.LinuxPackage.Impl; -import jdk.jpackage.model.StandardPackageType; +import jdk.jpackage.internal.model.LinuxPackage.Impl; +import jdk.jpackage.internal.model.StandardPackageType; final class LinuxPackageFromParams { @@ -48,7 +51,8 @@ public String packageName() { }); } - return new Impl(pkg, menuGroupName, category, additionalDependencies, release); + return new Impl(pkg, menuGroupName, category, additionalDependencies, + release, LinuxPackageArch.getValue(pkg.asStandardPackageType())); } private static final BundlerParamInfo LINUX_CATEGORY = createStringBundlerParam( diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index 1fffc749c15b0..8d2672a1e86ac 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -25,6 +25,12 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LinuxRpmPackage; +import jdk.jpackage.internal.model.DottedVersion; import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java index 8a2a7a63a0a3a..c69a68194e9b1 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java @@ -24,11 +24,13 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LinuxRpmPackage; import java.util.Map; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; -import jdk.jpackage.internal.LinuxRpmPackage.Impl; +import jdk.jpackage.internal.model.LinuxRpmPackage.Impl; import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; -import static jdk.jpackage.model.StandardPackageType.LINUX_RPM; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; final class LinuxRpmPackageFromParams { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java index b9f43b93742aa..5f7b072171987 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; import java.text.MessageFormat; final class PackageProperty { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplication.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java similarity index 84% rename from src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplication.java rename to src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java index 21c17c61bcf40..041913d65a5fe 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplication.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java @@ -23,11 +23,11 @@ * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; -interface LinuxApplication extends Application { - static class Impl extends Application.Proxy implements LinuxApplication { - Impl(Application app) { +public interface LinuxApplication extends Application { + public static class Impl extends Application.Proxy implements LinuxApplication { + public Impl(Application app) { super(app); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java similarity index 96% rename from src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java rename to src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java index 3057df281f97a..2f5ca2f0f5ebd 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java @@ -22,12 +22,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.nio.file.Path; import java.util.Optional; -interface LinuxDebPackage extends LinuxPackage { +public interface LinuxDebPackage extends LinuxPackage { String maintainerEmail(); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java similarity index 88% rename from src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java rename to src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java index 05c06b5cd0947..2140d7b8789a9 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java @@ -22,12 +22,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.util.Map; import java.util.Optional; -interface LinuxLauncher extends Launcher { +public interface LinuxLauncher extends Launcher { Optional shortcut(); @@ -43,9 +43,9 @@ default String defaultIconResourceName() { return "JavaApp.png"; } - static class Impl extends Launcher.Proxy implements LinuxLauncher { + public static class Impl extends Launcher.Proxy implements LinuxLauncher { - Impl(Launcher launcher, Optional shortcut) { + public Impl(Launcher launcher, Optional shortcut) { super(launcher); this.shortcut = shortcut; } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java similarity index 92% rename from src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java rename to src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java index f018f1395727c..41e94fcee0f13 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java @@ -22,15 +22,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; -import jdk.jpackage.model.StandardPackageType; import java.nio.file.Path; import java.text.MessageFormat; import java.util.Optional; import java.util.regex.Pattern; -interface LinuxPackage extends Package { +public interface LinuxPackage extends Package { String menuGroupName(); @@ -73,17 +72,9 @@ default boolean isInstallDirInUsrTree() { return !relativeInstallDir().getFileName().equals(Path.of(packageName())); } - static class Impl extends Package.Proxy implements LinuxPackage { + public static class Impl extends Package.Proxy implements LinuxPackage { - Impl(Package target, String menuGroupName, String category, - String additionalDependencies, String release) throws - ConfigException { - this(target, menuGroupName, category, additionalDependencies, - release, LinuxPackageArch.getValue( - target.asStandardPackageType())); - } - - Impl(Package target, String menuGroupName, String category, + public Impl(Package target, String menuGroupName, String category, String additionalDependencies, String release, String arch) throws ConfigException { super(Package.override(target, new Package.Unsupported() { @Override diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java similarity index 90% rename from src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java rename to src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java index 086ad2ce63ce8..9bf3235a0dd6e 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java @@ -22,15 +22,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.util.Optional; -interface LinuxRpmPackage extends LinuxPackage { +public interface LinuxRpmPackage extends LinuxPackage { String licenseType(); - static class Impl extends LinuxPackage.Proxy implements LinuxRpmPackage { + public static class Impl extends LinuxPackage.Proxy implements LinuxRpmPackage { public Impl(LinuxPackage target, String licenseType) { super(target); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java index 61bedfb8e67ca..181f7aa1dc008 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.DottedVersion; import java.math.BigInteger; @@ -38,7 +39,7 @@ final class CFBundleVersion { * @throws IllegalArgumentException */ static DottedVersion of(String value) { - DottedVersion ver = new DottedVersion(value); + DottedVersion ver = DottedVersion.greedy(value); BigInteger[] components = ver.getComponents(); if (components.length > 3) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index a8bd042ecd19b..3c564cf88222c 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; import java.text.MessageFormat; import java.util.Map; import java.util.Optional; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java index d1455a58316d3..66550ef749f76 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ApplicationLayout; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -58,7 +59,7 @@ import static jdk.jpackage.internal.MacAppBundler.APP_IMAGE_SIGN_IDENTITY; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; import static jdk.jpackage.internal.MacBaseInstallerBundler.INSTALLER_SIGN_IDENTITY; -import static jdk.jpackage.internal.OverridableResource.createResource; +import static jdk.jpackage.internal.StandardBundlerParam.createResource; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT; import static jdk.jpackage.internal.StandardBundlerParam.COPYRIGHT; @@ -75,6 +76,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; +import static jdk.jpackage.internal.StandardBundlerParam.createResource; public class MacAppImageBuilder extends AbstractAppImageBuilder { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index a4a73515d5555..0f1996f217ddf 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -25,6 +25,9 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.nio.file.Files; import java.nio.file.LinkOption; @@ -38,6 +41,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; +import jdk.jpackage.internal.util.FileUtils; public abstract class MacBaseInstallerBundler extends AbstractBundler { @@ -181,7 +185,7 @@ protected Path prepareAppBundle(Map params) StandardBundlerParam.getPredefinedAppImage(params); if (predefinedImage != null) { appDir = appImageRoot.resolve(APP_NAME.fetchFrom(params) + ".app"); - IOUtils.copyRecursive(predefinedImage, appDir, + FileUtils.copyRecursive(predefinedImage, appDir, LinkOption.NOFOLLOW_LINKS); // Create PackageFile if predefined app image is not signed diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java index 04a3dffa95ff4..8f71d6e9b58e8 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java @@ -25,6 +25,9 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.util.PathGroup; import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -40,7 +43,7 @@ import java.util.ResourceBundle; import static jdk.jpackage.internal.MacAppImageBuilder.ICON_ICNS; import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; -import static jdk.jpackage.internal.OverridableResource.createResource; +import static jdk.jpackage.internal.StandardBundlerParam.createResource; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT; @@ -48,6 +51,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; import static jdk.jpackage.internal.StandardBundlerParam.VERBOSE; import static jdk.jpackage.internal.StandardBundlerParam.DMG_CONTENT; +import jdk.jpackage.internal.util.FileUtils; public class MacDmgBundler extends MacBaseInstallerBundler { @@ -294,7 +298,7 @@ private Path buildDMG( Map params, MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params)); Path dest = root.resolve("Contents/Home"); - IOUtils.copyRecursive(source, dest); + FileUtils.copyRecursive(source, dest); srcFolder = newRoot; } @@ -319,7 +323,7 @@ private Path buildDMG( Map params, List dmgContent = DMG_CONTENT.fetchFrom(params); for (String content : dmgContent) { Path path = Path.of(content); - IOUtils.copyRecursive(path, srcFolder.resolve(path.getFileName())); + FileUtils.copyRecursive(path, srcFolder.resolve(path.getFileName())); } // create temp image ProcessBuilder pb = new ProcessBuilder( @@ -381,9 +385,9 @@ private Path buildDMG( Map params, Path destPath = mountedRoot .resolve(srcFolder.getFileName()); Files.createDirectory(destPath); - IOUtils.copyRecursive(srcFolder, destPath); + FileUtils.copyRecursive(srcFolder, destPath); } else { - IOUtils.copyRecursive(srcFolder, mountedRoot); + FileUtils.copyRecursive(srcFolder, mountedRoot); } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index 420dd2b519eba..ceb40945684f5 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -24,12 +24,15 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.Launcher; import java.io.IOException; import java.nio.file.Path; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Predicate; +import jdk.jpackage.internal.util.PathUtils; /** * Helper to install launchers as services using "launchd". @@ -72,7 +75,7 @@ private static class MacLauncherAsService extends UnixLauncherAsService { // It is recommended to set value of "label" property in launchd // .plist file equal to the name of this .plist file without the suffix. - String label = IOUtils.replaceSuffix(plistFilename.getFileName(), "").toString(); + String label = PathUtils.replaceSuffix(plistFilename.getFileName(), "").toString(); getResource() .setPublicName(plistFilename) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 1dc21c1065d2e..a4c7e69699004 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -25,6 +25,8 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; import jdk.internal.util.Architecture; import jdk.internal.util.OSVersion; @@ -60,8 +62,10 @@ import static jdk.jpackage.internal.MacAppBundler.APP_IMAGE_SIGN_IDENTITY; import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; -import static jdk.jpackage.internal.OverridableResource.createResource; +import static jdk.jpackage.internal.StandardBundlerParam.createResource; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; +import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.XmlUtils; public class MacPkgBundler extends MacBaseInstallerBundler { @@ -267,7 +271,7 @@ private void prepareDistributionXMLFile(Map params) Log.verbose(MessageFormat.format(I18N.getString( "message.preparing-distribution-dist"), f.toAbsolutePath().toString())); - IOUtils.createXml(f, xml -> { + XmlUtils.createXml(f, xml -> { xml.writeStartElement("installer-gui-script"); xml.writeAttribute("minSpecVersion", "1"); @@ -452,7 +456,7 @@ private String getRoot(Map params, source = appLocation; dest = newRoot.resolve(appLocation.getFileName()); } - IOUtils.copyRecursive(source, dest); + FileUtils.copyRecursive(source, dest); return newRoot.toString(); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java index a1e153dd7fe89..cd0457b0ec170 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.OverridableResource; import java.util.function.Supplier; import jdk.jpackage.internal.PackageScripts.ResourceConfig; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java index 2a3ccbaa0cde5..08b96802d982d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java @@ -25,6 +25,10 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.LauncherStartupInfo; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; @@ -35,6 +39,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import jdk.jpackage.internal.resources.ResourceLocator; +import jdk.jpackage.internal.util.FileUtils; /* * AbstractAppImageBuilder @@ -83,7 +88,7 @@ protected void copyApplication(Map params) throws IOException { Path inputPath = SOURCE_DIR.fetchFrom(params); if (inputPath != null) { - IOUtils.copyRecursive(SOURCE_DIR.fetchFrom(params), + FileUtils.copyRecursive(SOURCE_DIR.fetchFrom(params), appLayout.appDirectory()); } @@ -91,7 +96,7 @@ protected void copyApplication(Map params) List items = APP_CONTENT.fetchFrom(params); for (Path item : items) { - IOUtils.copyRecursive(item, + FileUtils.copyRecursive(item, appLayout.contentDirectory().resolve(item.getFileName())); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java index 17d43b90213e1..caa1b1bea4e8b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.nio.file.Path; import java.util.Map; +import jdk.jpackage.internal.util.FileUtils; /** @@ -55,7 +56,7 @@ public String toString() { @Override public void cleanup(Map params) { try { - IOUtils.deleteRecursive( + FileUtils.deleteRecursive( StandardBundlerParam.TEMP_ROOT.fetchFrom(params)); } catch (IOException e) { Log.verbose(e.getMessage()); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java index 3ef2080244ba3..03e292c0d34fa 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -25,12 +25,19 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.OverridableResource; +import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import jdk.jpackage.internal.util.FileUtils; final class AppImageBuilder { @@ -82,7 +89,7 @@ private static void copyRecursive(Path srcDir, Path dstDir, BuildEnv env) throws } } - IOUtils.copyRecursive(srcDir, dstDir.toAbsolutePath() /*, excludes */); + FileUtils.copyRecursive(srcDir, dstDir.toAbsolutePath() /*, excludes */); } void execute(BuildEnv env) throws IOException, PackagerException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java index b351b88dc8174..5892b128a23d7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java @@ -25,6 +25,8 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; import jdk.internal.util.OperatingSystem; import java.io.IOException; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index 0c1787fd25dfb..04959928e23f9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -59,6 +60,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; +import jdk.jpackage.internal.util.XmlUtils; final class AppImageFile { @@ -247,7 +249,7 @@ private static void save(Path appImageDir, addLauncherInfoSave = appImage.getAddLaunchers(); } - IOUtils.createXml(getPathInAppImage(appImageDir), xml -> { + XmlUtils.createXml(getPathInAppImage(appImageDir), xml -> { xml.writeStartElement("jpackage-state"); xml.writeAttribute("version", getVersion()); xml.writeAttribute("platform", getPlatform()); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index c57abf58c8332..26da22c785248 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -24,6 +24,11 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LauncherStartupInfo; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -43,6 +48,7 @@ import javax.xml.xpath.XPathFactory; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -108,7 +114,7 @@ String getMainClass() { * @throws IOException */ void save(Path appImageDir) throws IOException { - IOUtils.createXml(getPathInAppImage(appImageDir), xml -> { + XmlUtils.createXml(getPathInAppImage(appImageDir), xml -> { xml.writeStartElement("jpackage-state"); xml.writeAttribute("version", creatorVersion); xml.writeAttribute("platform", creatorPlatform); @@ -171,7 +177,7 @@ static Path getPathInAppImage(ApplicationLayout appLayout) { */ static AppImageFile2 load(Path appImageDir) throws ConfigException, IOException { try { - Document doc = IOUtils.initDocumentBuilder().parse( + Document doc = XmlUtils.initDocumentBuilder().parse( Files.newInputStream(getPathInAppImage(appImageDir))); XPath xPath = XPathFactory.newInstance().newXPath(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java index b94675fd770a8..520715314333c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java @@ -24,14 +24,19 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.RuntimeBuilder; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; import java.util.stream.Stream; -import jdk.jpackage.internal.Functional.ThrowingFunction; +import jdk.jpackage.internal.util.function.ThrowingFunction; import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; @@ -46,10 +51,18 @@ import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; import static jdk.jpackage.internal.StandardBundlerParam.isRuntimeInstaller; -final class ApplicationFromParams { +record ApplicationFromParams( + Function, Launcher> launcherSupplier) { - static Application create(Map params, - Function, Launcher> launcherSupplier) throws ConfigException, IOException { + ApplicationFromParams { + Objects.requireNonNull(launcherSupplier); + } + + ApplicationFromParams() { + this(new LauncherFromParams()::create); + } + + Application create(Map params) throws ConfigException, IOException { var name = APP_NAME.fetchFrom(params); var description = DESCRIPTION.fetchFrom(params); var version = VERSION.fetchFrom(params); @@ -61,8 +74,10 @@ static Application create(Map params, var predefinedAppImage = getPredefinedAppImage(params); if (name == null && predefinedAppImage == null) { // Can happen when no name is given, and using a foreign app-image - throw new ConfigException(I18N.getString("error.no.name"), I18N.getString( - "error.no.name.advice")); + throw ConfigException.build() + .message("error.no.name") + .advice("error.no.name.advice") + .create(); } RuntimeBuilder runtimeBuilder; @@ -96,8 +111,10 @@ static Application create(Map params, return launcherSupplier.apply(mergeParams(params, launcherParams)); }).toList(); - var startupInfos = Stream.concat(Stream.of(mainLauncher), additionalLaunchers.stream()).map( - Launcher::startupInfo).toList(); + var startupInfos = Stream.concat( + Stream.of(mainLauncher), + additionalLaunchers.stream() + ).map(Launcher::startupInfo).toList(); runtimeBuilder = RuntimeBuilderFromParams.create(params, startupInfos); } @@ -128,7 +145,6 @@ static BundlerParamInfo createBundlerParam( return BundlerParamInfo.createBundlerParam("target.application", valueFunc); } - static final BundlerParamInfo APPLICATION = createBundlerParam(params -> { - return ApplicationFromParams.create(params, LauncherFromParams::create); - }); + static final BundlerParamInfo APPLICATION = createBundlerParam( + new ApplicationFromParams()::create); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java index 65c88da658963..8e21318061d0b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; import jdk.internal.util.OperatingSystem; import java.io.IOException; @@ -42,6 +44,7 @@ import java.util.ResourceBundle; import java.util.regex.Matcher; import java.util.regex.Pattern; +import jdk.jpackage.internal.util.function.ExceptionWrapper; /** * Arguments @@ -712,15 +715,25 @@ private void generateBundle(Map params) Map localParams = new HashMap<>(params); try { - bundler.validate(localParams); - Path result = bundler.execute(localParams, deployParams.outdir); - if (result == null) { - throw new PackagerException("MSG_BundlerFailed", - bundler.getID(), bundler.getName()); + try { + bundler.validate(localParams); + Path result = bundler.execute(localParams, deployParams.outdir); + if (result == null) { + throw new PackagerException("MSG_BundlerFailed", + bundler.getID(), bundler.getName()); + } + Log.verbose(MessageFormat.format( + I18N.getString("message.bundle-created"), + bundler.getName())); + } catch (ExceptionWrapper ex) { + if (ex.getCause() instanceof ConfigException cfgEx) { + throw cfgEx; + } else if (ex.getCause() instanceof PackagerException pkgEx) { + throw pkgEx; + } else { + throw ex; + } } - Log.verbose(MessageFormat.format( - I18N.getString("message.bundle-created"), - bundler.getName())); } catch (ConfigException e) { Log.verbose(e); if (e.getAdvice() != null) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java index d70c1126fa4b6..f5c5e85768780 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java @@ -24,9 +24,11 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.OverridableResource; import java.nio.file.Path; +import java.util.Optional; -interface BuildEnv { +public interface BuildEnv { Path buildRoot(); @@ -46,15 +48,9 @@ default Path configDir() { return buildRoot().resolve("config"); } - default OverridableResource createResource(String defaultName) { - return new OverridableResource(defaultName).setResourceDir(resourceDir()); - } - - record Impl(Path buildRoot, Path resourceDir) implements BuildEnv { - - } + OverridableResource createResource(String defaultName); - static BuildEnv withAppImageDir(BuildEnv env, Path appImageDir) { + public static BuildEnv withAppImageDir(BuildEnv env, Path appImageDir) { return new Proxy(env) { @Override public Path appImageDir() { @@ -63,6 +59,17 @@ public Path appImageDir() { }; } + public static record Impl(Path buildRoot, Path resourceDir, Class resourceLocator) implements BuildEnv { + @Override + public OverridableResource createResource(String defaultName) { + if (defaultName != null) { + return new OverridableResource(defaultName, resourceLocator); + } else { + return new OverridableResource(); + } + } + } + static class Proxy implements BuildEnv { Proxy(BuildEnv target) { @@ -79,6 +86,11 @@ public Path resourceDir() { return target.resourceDir(); } + @Override + public OverridableResource createResource(String defaultName) { + return target.createResource(defaultName); + } + private final BuildEnv target; } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java index 9f70d050a7c9e..e5ad9e9068ed5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java @@ -24,11 +24,13 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; import java.nio.file.Path; import java.util.Map; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import jdk.jpackage.internal.BuildEnv.Impl; import static jdk.jpackage.internal.BuildEnv.withAppImageDir; +import jdk.jpackage.internal.resources.ResourceLocator; final class BuildEnvFromParams { @@ -36,7 +38,7 @@ static BuildEnv create(Map params) throws ConfigExceptio var root = StandardBundlerParam.TEMP_ROOT.fetchFrom(params); var resourceDir = StandardBundlerParam.RESOURCE_DIR.fetchFrom(params); - var defaultEnv = new Impl(root, resourceDir); + var defaultEnv = new Impl(root, resourceDir, ResourceLocator.class); Path appImageDir; if (StandardBundlerParam.isRuntimeInstaller(params)) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java index 59916fc3ca194..a45f3de9077ce 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java @@ -25,6 +25,8 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; import java.nio.file.Path; import java.util.Map; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java index 73653cd9b2706..a9c11e75cfe37 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java @@ -27,7 +27,8 @@ import java.util.Map; import java.util.function.BiFunction; import java.util.function.Function; -import static jdk.jpackage.internal.Functional.ThrowingFunction.toFunction; +import jdk.jpackage.internal.util.function.ThrowingFunction; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; /** * BundlerParamInfo @@ -53,7 +54,7 @@ static BundlerParamInfo createStringBundlerParam(String id) { @SuppressWarnings({"unchecked", "rawtypes"}) static BundlerParamInfo createBundlerParam(String id, - Functional.ThrowingFunction, T2> valueFunc) { + ThrowingFunction, T2> valueFunc) { return new BundlerParamInfo(id, Object.class, toFunction(valueFunc), null); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java index 3093231eaaee8..3700af97c30a4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java @@ -24,6 +24,12 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.LauncherStartupInfo; +import jdk.jpackage.internal.model.LauncherJarStartupInfo; +import jdk.jpackage.internal.model.LauncherModularStartupInfo; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java index 3a96703e1b557..108eafdaa857f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.PackagerException; import java.io.File; import java.io.IOException; import java.nio.file.Files; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociation.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociation.java deleted file mode 100644 index 3eed999526500..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociation.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal; - -import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; -import static jdk.jpackage.internal.StandardBundlerParam.FA_EXTENSIONS; -import static jdk.jpackage.internal.StandardBundlerParam.FA_CONTENT_TYPE; -import static jdk.jpackage.internal.StandardBundlerParam.FA_ICON; -import static jdk.jpackage.internal.StandardBundlerParam.FA_DESCRIPTION; - -final class FileAssociation { - void verify() { - if (extensions.isEmpty()) { - Log.error(I18N.getString( - "message.creating-association-with-null-extension")); - } - } - - static void verify(List associations) throws ConfigException { - // only one mime type per association, at least one file extension - int assocIdx = 0; - for (var assoc : associations) { - ++assocIdx; - if (assoc.mimeTypes.isEmpty()) { - String msgKey = "error.no-content-types-for-file-association"; - throw new ConfigException( - MessageFormat.format(I18N.getString(msgKey), assocIdx), - MessageFormat.format(I18N.getString(msgKey + ".advice"), assocIdx)); - } - - if (assoc.mimeTypes.size() > 1) { - String msgKey = "error.too-many-content-types-for-file-association"; - throw new ConfigException( - MessageFormat.format(I18N.getString(msgKey), assocIdx), - MessageFormat.format(I18N.getString(msgKey + ".advice"), assocIdx)); - } - - assoc.verify(); - } - } - - static List fetchFrom(Map params) { - String launcherName = APP_NAME.fetchFrom(params); - - return FILE_ASSOCIATIONS.fetchFrom(params).stream().filter( - Objects::nonNull).map(fa -> { - FileAssociation assoc = new FileAssociation(); - - assoc.launcherPath = Path.of(launcherName); - assoc.description = Optional.ofNullable( - FA_DESCRIPTION.fetchFrom(fa)) - .orElse(launcherName + " association"); - assoc.extensions = Optional.ofNullable( - FA_EXTENSIONS.fetchFrom(fa)) - .orElse(Collections.emptyList()); - assoc.mimeTypes = Optional.ofNullable( - FA_CONTENT_TYPE.fetchFrom(fa)) - .orElse(Collections.emptyList()); - - Path icon = FA_ICON.fetchFrom(fa); - if (icon != null) { - assoc.iconPath = icon; - } - - return assoc; - }).toList(); - } - - Path launcherPath; - Path iconPath; - List mimeTypes; - List extensions; - String description; -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Functional.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Functional.java deleted file mode 100644 index d33d16ac7a989..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Functional.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal; - -import java.lang.reflect.InvocationTargetException; -import java.util.Collection; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.function.UnaryOperator; - -public class Functional { - - @FunctionalInterface - public interface ThrowingConsumer { - - void accept(T t) throws Throwable; - - public static Consumer toConsumer(ThrowingConsumer v) { - return o -> { - try { - v.accept(o); - } catch (Throwable ex) { - throw rethrowUnchecked(ex); - } - }; - } - } - - @FunctionalInterface - public interface ThrowingBiConsumer { - - void accept(T t, U u) throws Throwable; - - public static BiConsumer toBiConsumer(ThrowingBiConsumer v) { - return (t, u) -> { - try { - v.accept(t, u); - } catch (Throwable ex) { - throw rethrowUnchecked(ex); - } - }; - } - } - - @FunctionalInterface - public interface ThrowingSupplier { - - T get() throws Throwable; - - public static Supplier toSupplier(ThrowingSupplier v) { - return () -> { - try { - return v.get(); - } catch (Throwable ex) { - throw rethrowUnchecked(ex); - } - }; - } - } - - @FunctionalInterface - public interface ThrowingFunction { - - R apply(T t) throws Throwable; - - public static Function toFunction(ThrowingFunction v) { - return (t) -> { - try { - return v.apply(t); - } catch (Throwable ex) { - throw rethrowUnchecked(ex); - } - }; - } - } - - @FunctionalInterface - public interface ThrowingBiFunction { - - R apply(T t, U u) throws Throwable; - - public static BiFunction toBiFunction(ThrowingBiFunction v) { - return (t, u) -> { - try { - return v.apply(t, u); - } catch (Throwable ex) { - throw rethrowUnchecked(ex); - } - }; - } - } - - @FunctionalInterface - public interface ThrowingUnaryOperator { - - T apply(T t) throws Throwable; - - public static UnaryOperator toUnaryOperator(ThrowingUnaryOperator v) { - return (t) -> { - try { - return v.apply(t); - } catch (Throwable ex) { - throw rethrowUnchecked(ex); - } - }; - } - } - - @FunctionalInterface - public interface ThrowingRunnable { - - void run() throws Throwable; - - public static Runnable toRunnable(ThrowingRunnable v) { - return () -> { - try { - v.run(); - } catch (Throwable ex) { - throw rethrowUnchecked(ex); - } - }; - } - } - - public static Supplier identity(Supplier v) { - return v; - } - - public static Consumer identity(Consumer v) { - return v; - } - - public static BiConsumer identity(BiConsumer v) { - return v; - } - - public static Runnable identity(Runnable v) { - return v; - } - - public static BiFunction identityBiFunction(BiFunction v) { - return v; - } - - public static Function identityFunction(Function v) { - return v; - } - - public static UnaryOperator identityUnaryOperator(UnaryOperator v) { - return v; - } - - public static Predicate identityPredicate(Predicate v) { - return v; - } - - public static class ExceptionBox extends RuntimeException { - - private static final long serialVersionUID = 1L; - - public ExceptionBox(Throwable throwable) { - super(throwable); - } - } - - public static RuntimeException rethrowUnchecked(Throwable throwable) throws - ExceptionBox { - if (throwable instanceof RuntimeException runtimeThrowable) { - throw runtimeThrowable; - } - - if (throwable instanceof InvocationTargetException) { - throw new ExceptionBox(throwable.getCause()); - } - - throw new ExceptionBox(throwable); - } - - @SuppressWarnings("unchecked") - static > C toCollection(Collection v) { - Collection tmp = v; - return (C) tmp; - } -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Getter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Getter.java index 7d98721af0612..92c82d9fbf36f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Getter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Getter.java @@ -26,8 +26,8 @@ import java.util.function.Function; -final class Getter { - static T getValueOrDefault(C mainSrc, C defaultSrc, Function getter) { +public final class Getter { + public static T getValueOrDefault(C mainSrc, C defaultSrc, Function getter) { try { return getter.apply(mainSrc); } catch (UnsupportedOperationException ex) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java index e872b400f0334..b127e8c6c117d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java @@ -25,22 +25,18 @@ package jdk.jpackage.internal; import java.text.MessageFormat; -import java.util.ArrayList; import java.util.List; -import java.util.ListResourceBundle; import java.util.Map; -import jdk.internal.util.OperatingSystem; - import java.util.ResourceBundle; -import static java.util.stream.Collectors.toMap; -import java.util.stream.Stream; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.util.MultiResourceBundle; final class I18N { static String getString(String key) { return BUNDLE.getString(key); } - + static String format(String key, Object ... args) { var str = getString(key); if (args.length != 0) { @@ -50,48 +46,17 @@ static String format(String key, Object ... args) { } } - private static class MultiResourceBundle extends ListResourceBundle { - - MultiResourceBundle(ResourceBundle... bundles) { - contents = Stream.of(bundles).map(bundle -> { - return bundle.keySet().stream().map(key -> { - return Map.entry(key, bundle.getObject(key)); - }); - }).flatMap(x -> x).collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (o, n) -> { - // Override old value with the new one - return n; - })).entrySet().stream().map(e -> { - return new Object[]{e.getKey(), e.getValue()}; - }).toArray(Object[][]::new); - } - - @Override - protected Object[][] getContents() { - return contents; - } - - private final Object[][] contents; - } - - private static final MultiResourceBundle BUNDLE; + private static final ResourceBundle BUNDLE; static { - List bundleNames = new ArrayList<>(); - - bundleNames.add("jdk.jpackage.internal.resources.MainResources"); - - if (OperatingSystem.isLinux()) { - bundleNames.add("jdk.jpackage.internal.resources.LinuxResources"); - } else if (OperatingSystem.isWindows()) { - bundleNames.add("jdk.jpackage.internal.resources.WinResources"); - bundleNames.add("jdk.jpackage.internal.resources.WinResourcesNoL10N"); - } else if (OperatingSystem.isMacOS()) { - bundleNames.add("jdk.jpackage.internal.resources.MacResources"); - } else { - throw new IllegalStateException("Unknown platform"); - } - - BUNDLE = new MultiResourceBundle(bundleNames.stream().map(ResourceBundle::getBundle) - .toArray(ResourceBundle[]::new)); + var prefix = "jdk.jpackage.internal.resources."; + BUNDLE = MultiResourceBundle.create( + prefix + "MainResources", + Map.of( + OperatingSystem.LINUX, List.of(prefix + "LinuxResources"), + OperatingSystem.MACOS, List.of(prefix + "MacResources"), + OperatingSystem.WINDOWS, List.of(prefix + "WinResources", prefix + "WinResourcesNoL10N") + ) + ); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java index f4b0483bf98ea..090e50c2cf60f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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,41 +25,17 @@ package jdk.jpackage.internal; -import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.PackagerException; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.io.PrintStream; -import java.io.Writer; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.nio.file.FileVisitResult; import java.nio.file.Files; -import java.nio.file.CopyOption; import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.stream.XMLOutputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.stax.StAXResult; /** * IOUtils @@ -68,84 +44,6 @@ */ public class IOUtils { - public static void deleteRecursive(Path directory) throws IOException { - final AtomicReference exception = new AtomicReference<>(); - - if (!Files.exists(directory)) { - return; - } - - Files.walkFileTree(directory, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, - BasicFileAttributes attr) throws IOException { - if (OperatingSystem.isWindows()) { - Files.setAttribute(file, "dos:readonly", false); - } - try { - Files.delete(file); - } catch (IOException ex) { - exception.compareAndSet(null, ex); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, - BasicFileAttributes attr) throws IOException { - if (OperatingSystem.isWindows()) { - Files.setAttribute(dir, "dos:readonly", false); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException e) - throws IOException { - try { - Files.delete(dir); - } catch (IOException ex) { - exception.compareAndSet(null, ex); - } - return FileVisitResult.CONTINUE; - } - }); - if (exception.get() != null) { - throw exception.get(); - } - } - - public static void copyRecursive(Path src, Path dest, CopyOption... options) - throws IOException { - copyRecursive(src, dest, List.of(), options); - } - - public static void copyRecursive(Path src, Path dest, - final List excludes, CopyOption... options) - throws IOException { - Files.walkFileTree(src, new SimpleFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(final Path dir, - final BasicFileAttributes attrs) throws IOException { - if (excludes.contains(dir.toFile().getName())) { - return FileVisitResult.SKIP_SUBTREE; - } else { - Files.createDirectories(dest.resolve(src.relativize(dir))); - return FileVisitResult.CONTINUE; - } - } - - @Override - public FileVisitResult visitFile(final Path file, - final BasicFileAttributes attrs) throws IOException { - if (!excludes.contains(file.toFile().getName())) { - Files.copy(file, dest.resolve(src.relativize(file)), options); - } - return FileVisitResult.CONTINUE; - } - }); - } - public static void copyFile(Path sourceFile, Path destFile) throws IOException { Files.createDirectories(getParent(destFile)); @@ -291,90 +189,6 @@ static void writableOutputDir(Path outdir) throws PackagerException { } } - public static Path replaceSuffix(Path path, String suffix) { - Path parent = path.getParent(); - String filename = getFileName(path).toString().replaceAll("\\.[^.]*$", "") - + Optional.ofNullable(suffix).orElse(""); - return parent != null ? parent.resolve(filename) : Path.of(filename); - } - - public static Path addSuffix(Path path, String suffix) { - Path parent = path.getParent(); - String filename = getFileName(path).toString() + suffix; - return parent != null ? parent.resolve(filename) : Path.of(filename); - } - - public static String getSuffix(Path path) { - String filename = replaceSuffix(getFileName(path), null).toString(); - return getFileName(path).toString().substring(filename.length()); - } - - @FunctionalInterface - public static interface XmlConsumer { - void accept(XMLStreamWriter xml) throws IOException, XMLStreamException; - } - - public static void createXml(Path dstFile, XmlConsumer xmlConsumer) throws - IOException { - XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance(); - Files.createDirectories(getParent(dstFile)); - try (Writer w = Files.newBufferedWriter(dstFile)) { - // Wrap with pretty print proxy - XMLStreamWriter xml = (XMLStreamWriter) Proxy.newProxyInstance( - XMLStreamWriter.class.getClassLoader(), new Class[]{ - XMLStreamWriter.class}, new PrettyPrintHandler( - xmlFactory.createXMLStreamWriter(w))); - - xml.writeStartDocument(); - xmlConsumer.accept(xml); - xml.writeEndDocument(); - xml.flush(); - xml.close(); - } catch (XMLStreamException ex) { - throw new IOException(ex); - } catch (IOException ex) { - throw ex; - } - } - - public static void mergeXmls(XMLStreamWriter xml, Collection sources) - throws XMLStreamException, IOException { - xml = (XMLStreamWriter) Proxy.newProxyInstance( - XMLStreamWriter.class.getClassLoader(), new Class[]{ - XMLStreamWriter.class}, new SkipDocumentHandler(xml)); - - try { - TransformerFactory tf = TransformerFactory.newInstance(); - Result result = new StAXResult(xml); - for (var src : sources) { - tf.newTransformer().transform(src, result); - } - } catch (TransformerException ex) { - // Should never happen - throw new RuntimeException(ex); - } - } - - public static DocumentBuilderFactory initDocumentBuilderFactory() { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); - try { - dbf.setFeature( - "http://apache.org/xml/features/nonvalidating/load-external-dtd", - false); - } catch (ParserConfigurationException ex) { - throw new IllegalStateException(ex); - } - return dbf; - } - - public static DocumentBuilder initDocumentBuilder() { - try { - return initDocumentBuilderFactory().newDocumentBuilder(); - } catch (ParserConfigurationException ex) { - throw new IllegalStateException(ex); - } - } - public static Path getParent(Path p) { Path parent = p.getParent(); if (parent == null) { @@ -407,85 +221,4 @@ public static long getPID(Process p) { return -1; } } - - private static class PrettyPrintHandler implements InvocationHandler { - - PrettyPrintHandler(XMLStreamWriter target) { - this.target = target; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws - Throwable { - switch (method.getName()) { - case "writeStartElement": - // update state of parent node - if (depth > 0) { - hasChildElement.put(depth - 1, true); - } - // reset state of current node - hasChildElement.put(depth, false); - // indent for current depth - target.writeCharacters(EOL); - target.writeCharacters(repeat(depth, INDENT)); - depth++; - break; - case "writeEndElement": - depth--; - if (hasChildElement.get(depth) == true) { - target.writeCharacters(EOL); - target.writeCharacters(repeat(depth, INDENT)); - } - break; - case "writeProcessingInstruction": - case "writeEmptyElement": - // update state of parent node - if (depth > 0) { - hasChildElement.put(depth - 1, true); - } - // indent for current depth - target.writeCharacters(EOL); - target.writeCharacters(repeat(depth, INDENT)); - break; - default: - break; - } - method.invoke(target, args); - return null; - } - - private static String repeat(int d, String s) { - StringBuilder sb = new StringBuilder(); - while (d-- > 0) { - sb.append(s); - } - return sb.toString(); - } - - private final XMLStreamWriter target; - private int depth = 0; - private final Map hasChildElement = new HashMap<>(); - private static final String INDENT = " "; - private static final String EOL = "\n"; - } - - private static class SkipDocumentHandler implements InvocationHandler { - - SkipDocumentHandler(XMLStreamWriter target) { - this.target = target; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws - Throwable { - switch (method.getName()) { - case "writeStartDocument", "writeEndDocument" -> { - } - default -> method.invoke(target, args); - } - return null; - } - - private final XMLStreamWriter target; - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java index 5c07fee9e2773..2e54dc30d4297 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java @@ -24,6 +24,12 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.LauncherStartupInfo; +import jdk.jpackage.internal.model.LauncherModularStartupInfo; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.RuntimeBuilder; import java.io.File; import java.io.IOException; import java.io.PrintWriter; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java index 35460a77b2034..6ef11a95cb780 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java @@ -24,6 +24,9 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.OverridableResource; + class LauncherAsService { LauncherAsService(Launcher launcher, OverridableResource resource) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java index 01b3a9a9b6690..4391a5249f3b0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; import jdk.internal.util.OperatingSystem; import java.io.File; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java index 06d8abc2379a4..48020a4eb3614 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java @@ -24,16 +24,39 @@ */ package jdk.jpackage.internal; +import java.nio.file.Path; +import java.util.List; +import jdk.jpackage.internal.model.LauncherStartupInfo; +import jdk.jpackage.internal.model.Launcher; import java.util.Map; -import jdk.jpackage.internal.Launcher.Impl; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import jdk.jpackage.internal.model.Launcher.Impl; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; +import static jdk.jpackage.internal.StandardBundlerParam.FA_CONTENT_TYPE; +import static jdk.jpackage.internal.StandardBundlerParam.FA_DESCRIPTION; +import static jdk.jpackage.internal.StandardBundlerParam.FA_EXTENSIONS; +import static jdk.jpackage.internal.StandardBundlerParam.FA_ICON; +import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; +import static jdk.jpackage.internal.StandardBundlerParam.ICON; +import jdk.jpackage.internal.model.FileAssociation; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; -final class LauncherFromParams { +record LauncherFromParams(Function> faSupplier) { - static Launcher create(Map params) { + LauncherFromParams { + Objects.requireNonNull(faSupplier); + } + + LauncherFromParams() { + this(FileAssociation::create); + } + + Launcher create(Map params) { var name = APP_NAME.fetchFrom(params); LauncherStartupInfo startupInfo = null; @@ -42,10 +65,45 @@ static Launcher create(Map params) { } var isService = LAUNCHER_AS_SERVICE.fetchFrom(params); - var description = DESCRIPTION.fetchFrom(params); - var icon = StandardBundlerParam.ICON.fetchFrom(params); - var fa = FileAssociation.fetchFrom(params); + var desc = DESCRIPTION.fetchFrom(params); + var icon = ICON.fetchFrom(params); + + var faStream = Optional.ofNullable( + FILE_ASSOCIATIONS.fetchFrom(params)).orElseGet(List::of).stream().map(faParams -> { + var faDesc = FA_DESCRIPTION.fetchFrom(faParams); + var faIcon = FA_ICON.fetchFrom(faParams); + var faExtensions = FA_EXTENSIONS.fetchFrom(faParams); + var faMimeTypes = FA_CONTENT_TYPE.fetchFrom(faParams); + + return faExtensions.stream().map(faExtension -> { + return faMimeTypes.stream().map(faMimeType -> { + return faSupplier.apply(new FileAssociation() { + @Override + public String description() { + return faDesc; + } + + @Override + public Path icon() { + return faIcon; + } + + @Override + public String mimeType() { + return faMimeType; + } + + @Override + public String extension() { + return faExtension; + } + }); + }); + }).flatMap(x -> x); + }).flatMap(x -> x).filter(Optional::isPresent).map(Optional::get); + + var fa = toSupplier(() -> FileAssociation.create(faStream)).get().toList(); - return new Impl(name, startupInfo, fa, isService, description, icon); + return new Impl(name, startupInfo, fa, isService, desc, icon); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java index b13a6dff64907..edd946006207c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java @@ -24,6 +24,9 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.LauncherStartupInfo; +import jdk.jpackage.internal.model.LauncherJarStartupInfo; +import jdk.jpackage.internal.model.LauncherModularStartupInfo; import java.util.Map; import static jdk.jpackage.internal.StandardBundlerParam.ARGUMENTS; import static jdk.jpackage.internal.StandardBundlerParam.JAVA_OPTIONS; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java index 9d956c3fcc9de..e4a69c9a6344d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java index 71c0efa9c52be..d6b3e899aba73 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java @@ -24,15 +24,18 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.Application; import java.nio.file.Path; import java.util.Map; import java.util.Optional; -import jdk.jpackage.internal.Functional.ThrowingFunction; -import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; -import jdk.jpackage.internal.Package.Impl; -import jdk.jpackage.model.PackageType; -import jdk.jpackage.model.StandardPackageType; -import static jdk.jpackage.internal.Package.mapInstallDir; +import jdk.jpackage.internal.util.function.ThrowingFunction; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; +import jdk.jpackage.internal.model.Package.Impl; +import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.StandardPackageType; +import static jdk.jpackage.internal.model.Package.mapInstallDir; import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PlatformPackage.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PlatformPackage.java index c10f59464a32c..bba32a268524f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PlatformPackage.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PlatformPackage.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ApplicationLayout; import java.nio.file.Path; /** diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderFromParams.java index ac364d069fb29..0c0f6882ec4f5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderFromParams.java @@ -24,6 +24,9 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LauncherStartupInfo; +import jdk.jpackage.internal.model.RuntimeBuilder; import java.nio.file.Path; import java.util.List; import java.util.Map; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index 98a52b604f259..db0c698759bd6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -26,6 +26,8 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.OverridableResource; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -40,8 +42,9 @@ import java.util.Map; import java.util.Set; import java.util.stream.Stream; -import jdk.jpackage.internal.Functional.ThrowingFunction; -import static jdk.jpackage.internal.RuntimeBuilder.getDefaultModulePath; +import jdk.jpackage.internal.util.function.ThrowingFunction; +import jdk.jpackage.internal.resources.ResourceLocator; +import static jdk.jpackage.internal.model.RuntimeBuilder.getDefaultModulePath; /** * Standard bundler parameters. @@ -557,6 +560,12 @@ static Path getPredefinedAppImage(Map params) { } return applicationImage; } + + static OverridableResource createResource(String defaultName, + Map params) { + return new OverridableResource(defaultName, ResourceLocator.class).setResourceDir( + RESOURCE_DIR.fetchFrom(params)); + } private static String getDefaultAppVersion(Map params) { String appVersion = DEFAULT_VERSION; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java index 64876468afbab..8db0127152cc3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.DottedVersion; import jdk.internal.util.OperatingSystem; import java.io.IOException; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/AdditionalLauncher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/AdditionalLauncher.java similarity index 95% rename from src/jdk.jpackage/share/classes/jdk/jpackage/cli/AdditionalLauncher.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/AdditionalLauncher.java index a282b04dab011..01f964fc5241c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/AdditionalLauncher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/AdditionalLauncher.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.jpackage.cli; +package jdk.jpackage.internal.cli; import java.nio.file.Path; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/Option.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Option.java similarity index 95% rename from src/jdk.jpackage/share/classes/jdk/jpackage/cli/Option.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Option.java index 57b1b507e75d6..edc140cad0fb8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/Option.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Option.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.jpackage.cli; +package jdk.jpackage.internal.cli; public interface Option { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/OptionSpec.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java similarity index 93% rename from src/jdk.jpackage/share/classes/jdk/jpackage/cli/OptionSpec.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java index f065438ddfe86..ba69a71bed0c7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/OptionSpec.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java @@ -23,12 +23,12 @@ * questions. */ -package jdk.jpackage.cli; +package jdk.jpackage.internal.cli; import java.util.Objects; import java.util.Set; import java.util.function.Consumer; -import jdk.jpackage.model.PackageType; +import jdk.jpackage.internal.model.PackageType; public record OptionSpec(String name, ValueConverter valueConverter, String shortName, Set supportedPackageTypes, Consumer valueValidator) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/OptionSpecBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java similarity index 86% rename from src/jdk.jpackage/share/classes/jdk/jpackage/cli/OptionSpecBuilder.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java index 309951f8377e0..a71076755667a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/OptionSpecBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java @@ -22,15 +22,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.cli; +package jdk.jpackage.internal.cli; import java.util.Set; import java.util.function.Consumer; -import jdk.jpackage.model.PackageType; -import static jdk.jpackage.cli.StandardValueConverter.IDENTITY_CONV; -import static jdk.jpackage.cli.StandardValueConverter.PATH_ARRAY_CONV; -import static jdk.jpackage.cli.StandardValueConverter.PATH_CONV; -import static jdk.jpackage.cli.StandardValueConverter.STRING_ARRAY_CONV; +import jdk.jpackage.internal.model.PackageType; +import static jdk.jpackage.internal.cli.StandardValueConverter.IDENTITY_CONV; +import static jdk.jpackage.internal.cli.StandardValueConverter.PATH_ARRAY_CONV; +import static jdk.jpackage.internal.cli.StandardValueConverter.PATH_CONV; +import static jdk.jpackage.internal.cli.StandardValueConverter.STRING_ARRAY_CONV; final class OptionSpecBuilder { OptionSpec create() { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/PackageTypeGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/PackageTypeGroup.java similarity index 79% rename from src/jdk.jpackage/share/classes/jdk/jpackage/cli/PackageTypeGroup.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/PackageTypeGroup.java index 6d0e7b09e03e0..5a7422db3cb14 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/PackageTypeGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/PackageTypeGroup.java @@ -22,21 +22,21 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.cli; +package jdk.jpackage.internal.cli; import java.util.Set; import java.util.function.Function; import static java.util.stream.Collectors.toSet; import java.util.stream.Stream; -import jdk.jpackage.model.AppImagePackageType; -import jdk.jpackage.model.PackageType; -import jdk.jpackage.model.StandardPackageType; -import static jdk.jpackage.model.StandardPackageType.LINUX_DEB; -import static jdk.jpackage.model.StandardPackageType.LINUX_RPM; -import static jdk.jpackage.model.StandardPackageType.MAC_DMG; -import static jdk.jpackage.model.StandardPackageType.MAC_PKG; -import static jdk.jpackage.model.StandardPackageType.WIN_EXE; -import static jdk.jpackage.model.StandardPackageType.WIN_MSI; +import jdk.jpackage.internal.model.AppImagePackageType; +import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.StandardPackageType; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; +import static jdk.jpackage.internal.model.StandardPackageType.MAC_DMG; +import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG; +import static jdk.jpackage.internal.model.StandardPackageType.WIN_EXE; +import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; enum PackageTypeGroup { APP_IMAGE(name -> Set.of(AppImagePackageType.APP_IMAGE)), diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/ParsedOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ParsedOptions.java similarity index 95% rename from src/jdk.jpackage/share/classes/jdk/jpackage/cli/ParsedOptions.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ParsedOptions.java index cdb1eb5c95309..219abf17d60e8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/ParsedOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ParsedOptions.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.jpackage.cli; +package jdk.jpackage.internal.cli; import java.util.Optional; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java similarity index 87% rename from src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardOption.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index 63a20626193c4..dd80c9184810e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.cli; +package jdk.jpackage.internal.cli; import java.util.Collection; import java.util.List; @@ -30,18 +30,18 @@ import java.util.Optional; import java.util.function.UnaryOperator; import java.util.stream.Stream; -import jdk.jpackage.model.AppImagePackageType; -import jdk.jpackage.model.PackageType; -import jdk.jpackage.model.StandardPackageType; -import static jdk.jpackage.model.StandardPackageType.LINUX_DEB; -import static jdk.jpackage.model.StandardPackageType.LINUX_RPM; -import static jdk.jpackage.model.StandardPackageType.MAC_DMG; -import static jdk.jpackage.model.StandardPackageType.MAC_PKG; -import static jdk.jpackage.model.StandardPackageType.WIN_EXE; -import static jdk.jpackage.model.StandardPackageType.WIN_MSI; -import static jdk.jpackage.cli.PackageTypeGroup.ALL_PACKAGE_TYPES; -import static jdk.jpackage.cli.PackageTypeGroup.APP_IMAGE; -import static jdk.jpackage.cli.PackageTypeGroup.NATIVE_PACKAGE; +import jdk.jpackage.internal.model.AppImagePackageType; +import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.StandardPackageType; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; +import static jdk.jpackage.internal.model.StandardPackageType.MAC_DMG; +import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG; +import static jdk.jpackage.internal.model.StandardPackageType.WIN_EXE; +import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; +import static jdk.jpackage.internal.cli.PackageTypeGroup.ALL_PACKAGE_TYPES; +import static jdk.jpackage.internal.cli.PackageTypeGroup.APP_IMAGE; +import static jdk.jpackage.internal.cli.PackageTypeGroup.NATIVE_PACKAGE; public enum StandardOption implements Option { TYPE(build().name("type").shortName("t").valueConverter(new ValueConverter() { @@ -80,7 +80,7 @@ public Class valueType() { FILE_ASSOCIATIONS("file-associations", OptionSpecBuilder::ofPath), ADD_LAUNCHER(build().name("add-launcher").valueConverter(new ValueConverter() { @Override - public jdk.jpackage.cli.AdditionalLauncher convert(String value) { + public jdk.jpackage.internal.cli.AdditionalLauncher convert(String value) { var components = value.split("=", 2); if (components.length == 1) { return new AdditionalLauncher(null, @@ -92,7 +92,7 @@ public jdk.jpackage.cli.AdditionalLauncher convert(String value) { } @Override - public Class valueType() { + public Class valueType() { return AdditionalLauncher.class; } })), diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java similarity index 95% rename from src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardValueConverter.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java index fa371a117aee1..1d7421d1e1a73 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.jpackage.cli; +package jdk.jpackage.internal.cli; import java.io.File; import java.nio.file.Path; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardValueValidator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueValidator.java similarity index 95% rename from src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardValueValidator.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueValidator.java index 4b60baaead748..e36127c2d5890 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/StandardValueValidator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueValidator.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.cli; +package jdk.jpackage.internal.cli; import java.net.URI; import java.net.URISyntaxException; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/ValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java similarity index 95% rename from src/jdk.jpackage/share/classes/jdk/jpackage/cli/ValueConverter.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java index c2f03ba8b05bf..59dc8fc3a2b8e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/cli/ValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.cli; +package jdk.jpackage.internal.cli; public interface ValueConverter { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/model/AppImagePackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java similarity index 97% rename from src/jdk.jpackage/share/classes/jdk/jpackage/model/AppImagePackageType.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java index 8f2a46400d9a3..db20c4e41e439 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/model/AppImagePackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.jpackage.model; +package jdk.jpackage.internal.model; public final class AppImagePackageType implements PackageType { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java similarity index 90% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index 4a9fa283aa1ec..4010180e95785 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.nio.file.Path; import java.text.MessageFormat; @@ -32,9 +32,11 @@ import java.util.Optional; import java.util.function.Function; import jdk.internal.util.OperatingSystem; -import static jdk.jpackage.internal.Functional.ThrowingSupplier.toSupplier; +import jdk.jpackage.internal.IOUtils; +import jdk.jpackage.internal.util.PathUtils; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; -interface Application { +public interface Application { String name(); @@ -107,11 +109,11 @@ default Map extraAppImageFileData() { default OverridableResource createLauncherIconResource(Launcher launcher, Function resourceSupplier) { final String defaultIconName = launcher.defaultIconResourceName(); - final String resourcePublicName = launcher.executableName() + IOUtils.getSuffix(Path.of( + final String resourcePublicName = launcher.executableName() + PathUtils.getSuffix(Path.of( defaultIconName)); - var iconType = Internal.getLauncherIconType(launcher.icon()); - if (iconType == Internal.IconType.NoIcon) { + var iconType = IconType.getLauncherIconType(launcher.icon()); + if (iconType == IconType.NO_ICON) { return null; } @@ -120,7 +122,7 @@ default OverridableResource createLauncherIconResource(Launcher launcher, .setExternal(launcher.icon()) .setPublicName(resourcePublicName); - if (iconType == Internal.IconType.DefaultOrResourceDirIcon && mainLauncher() != launcher) { + if (iconType == IconType.DEFAULT_OR_RESOURCEDIR_ICON && mainLauncher() != launcher) { // No icon explicitly configured for this launcher. // Dry-run resource creation to figure out its source. final Path nullPath = null; @@ -257,22 +259,4 @@ public List launchers() { } } - static class Internal { - - private enum IconType { - DefaultOrResourceDirIcon, CustomIcon, NoIcon - }; - - private static IconType getLauncherIconType(Path iconPath) { - if (iconPath == null) { - return IconType.DefaultOrResourceDirIcon; - } - - if (iconPath.toFile().getName().isEmpty()) { - return IconType.NoIcon; - } - - return IconType.CustomIcon; - } - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java similarity index 95% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index e96b6b72de2c0..9c5176e7681a5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -22,8 +22,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; +import jdk.jpackage.internal.util.PathGroup; import jdk.internal.util.OperatingSystem; import java.nio.file.Path; @@ -34,7 +35,7 @@ * Application directory layout. */ public final class ApplicationLayout implements PathGroup.Facade { - enum PathRole { + public enum PathRole { /** * Java run-time directory. */ @@ -76,7 +77,7 @@ enum PathRole { CONTENT } - ApplicationLayout(Map paths) { + private ApplicationLayout(Map paths) { data = new PathGroup(paths); } @@ -143,7 +144,7 @@ public Path contentDirectory() { return pathGroup().getPath(PathRole.CONTENT); } - static ApplicationLayout linuxAppImage() { + public static ApplicationLayout linuxAppImage() { return new ApplicationLayout(Map.of( PathRole.LAUNCHERS, Path.of("bin"), PathRole.APP, Path.of("lib/app"), @@ -156,7 +157,7 @@ static ApplicationLayout linuxAppImage() { )); } - static ApplicationLayout windowsAppImage() { + public static ApplicationLayout windowsAppImage() { return new ApplicationLayout(Map.of( PathRole.LAUNCHERS, Path.of(""), PathRole.APP, Path.of("app"), @@ -168,7 +169,7 @@ static ApplicationLayout windowsAppImage() { )); } - static ApplicationLayout macAppImage() { + public static ApplicationLayout macAppImage() { return new ApplicationLayout(Map.of( PathRole.LAUNCHERS, Path.of("Contents/MacOS"), PathRole.APP, Path.of("Contents/app"), diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ConfigException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java similarity index 90% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/ConfigException.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java index 8fc105c69f716..c6406f914489c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ConfigException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; public class ConfigException extends Exception { private static final long serialVersionUID = 1L; @@ -52,9 +52,9 @@ public static Builder build() { return new Builder(); } - static final class Builder { + public static final class Builder { - ConfigException create() { + public ConfigException create() { return new ConfigException(msg, advice, cause); } @@ -72,6 +72,10 @@ public Builder cause(Exception v) { cause = v; return this; } + + public Builder causeAndMessage(Exception ex) { + return message(ex.getLocalizedMessage()).cause(ex); + } private String msg; private String advice; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DottedVersion.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DottedVersion.java similarity index 94% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/DottedVersion.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DottedVersion.java index 91c0a4915fd43..44c061b59be9c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DottedVersion.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DottedVersion.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.math.BigInteger; import java.text.MessageFormat; @@ -34,11 +34,7 @@ /** * Dotted numeric version string. E.g.: 1.0.37, 10, 0.5 */ -final class DottedVersion { - - DottedVersion(String version) { - this(version, true); - } +public final class DottedVersion { private DottedVersion(String version, boolean greedy) { this.value = version; @@ -140,15 +136,15 @@ public String getUnprocessedString() { private final String input; } - static DottedVersion greedy(String version) { - return new DottedVersion(version); + public static DottedVersion greedy(String version) { + return new DottedVersion(version, true); } - static DottedVersion lazy(String version) { + public static DottedVersion lazy(String version) { return new DottedVersion(version, false); } - static int compareComponents(DottedVersion a, DottedVersion b) { + public static int compareComponents(DottedVersion a, DottedVersion b) { int result = 0; BigInteger[] aComponents = a.getComponents(); BigInteger[] bComponents = b.getComponents(); @@ -208,11 +204,11 @@ public String getUnprocessedSuffix() { return suffix; } - String toComponentsString() { + public String toComponentsString() { return Stream.of(components).map(BigInteger::toString).collect(Collectors.joining(".")); } - BigInteger[] getComponents() { + public BigInteger[] getComponents() { return components; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java new file mode 100644 index 0000000000000..c8f0934e29b97 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.mapping; +import static java.util.stream.Collectors.toList; +import java.util.stream.Stream; + +public interface FileAssociation { + + String description(); + + Path icon(); + + String mimeType(); + + String extension(); + + record Impl(String description, Path icon, String mimeType, String extension) implements FileAssociation { + + public Impl { + Objects.requireNonNull(description); + } + } + + static class Proxy extends ProxyBase implements FileAssociation { + + protected Proxy(T target) { + super(target); + } + + @Override + public String description() { + return target.description(); + } + + @Override + public Path icon() { + return target.icon(); + } + + @Override + public String mimeType() { + return target.mimeType(); + } + + @Override + public String extension() { + return target.extension(); + } + } + + static Optional create(FileAssociation src) { + var mimeType = src.mimeType(); + if (mimeType == null) { + return Optional.empty(); + } + + var extension = src.extension(); + if (extension == null) { + return Optional.empty(); + } + + return Optional.of(new Impl(src.description(), src.icon(), mimeType, extension)); + } + + static Stream create(Stream sources) throws ConfigException { + var fas = sources.map(FileAssociation::create).filter(Optional::isPresent).map( + Optional::get).toList(); + + // Check extension to mime type relationship is 1:1 + var mimeTypeToExtension = fas.stream().collect(groupingBy( + FileAssociation::extension, mapping(FileAssociation::mimeType, + toList()))); + for (var entry : mimeTypeToExtension.entrySet()) { + if (entry.getValue().size() != 1) { + var extension = entry.getKey(); + throw ConfigException.build().message( + "error.fa-extension-with-multiple-mime-types", extension).create(); + } + } + + return fas.stream(); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java new file mode 100644 index 0000000000000..aceede7c02b36 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.text.MessageFormat; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.util.MultiResourceBundle; + +final class I18N { + + static String getString(String key) { + return BUNDLE.getString(key); + } + + static String format(String key, Object ... args) { + var str = getString(key); + if (args.length != 0) { + return MessageFormat.format(str, args); + } else { + return str; + } + } + + private static final ResourceBundle BUNDLE; + + static { + var prefix = "jdk.jpackage.internal.resources."; + BUNDLE = MultiResourceBundle.create( + prefix + "MainResources", + Map.of( + OperatingSystem.LINUX, List.of(prefix + "LinuxResources"), + OperatingSystem.MACOS, List.of(prefix + "MacResources"), + OperatingSystem.WINDOWS, List.of(prefix + "WinResources") + ) + ); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/IconType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/IconType.java new file mode 100644 index 0000000000000..96572eb7792ce --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/IconType.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.nio.file.Path; + +public enum IconType { + DEFAULT_OR_RESOURCEDIR_ICON, CUSTOM_ICON, NO_ICON; + + public static IconType getLauncherIconType(Path iconPath) { + if (iconPath == null) { + return DEFAULT_OR_RESOURCEDIR_ICON; + } + if (iconPath.toFile().getName().isEmpty()) { + return NO_ICON; + } + return CUSTOM_ICON; + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java similarity index 97% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java index c2e4857f36eb7..2b335f57f05f6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.io.InputStream; import java.nio.file.Path; @@ -32,10 +32,10 @@ import jdk.internal.util.OperatingSystem; import static jdk.internal.util.OperatingSystem.LINUX; import static jdk.internal.util.OperatingSystem.WINDOWS; -import static jdk.jpackage.internal.Functional.ThrowingConsumer.toConsumer; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; import jdk.jpackage.internal.resources.ResourceLocator; -interface Launcher { +public interface Launcher { String name(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java similarity index 90% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java index 1a54e9f19d7ff..2372450e1955d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherJarStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java @@ -22,11 +22,11 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.nio.file.Path; -interface LauncherJarStartupInfo extends LauncherStartupInfo { +public interface LauncherJarStartupInfo extends LauncherStartupInfo { /** * Returns path to the main jar relative to app's main source directory. * @@ -39,7 +39,7 @@ interface LauncherJarStartupInfo extends LauncherStartupInfo { final static class Impl extends LauncherStartupInfo.Proxy implements LauncherJarStartupInfo { - Impl(LauncherStartupInfo target, Path jarPath, boolean isClassNameFromMainJar) { + public Impl(LauncherStartupInfo target, Path jarPath, boolean isClassNameFromMainJar) { super(target); this.jarPath = jarPath; this.isClassNameFromMainJar = isClassNameFromMainJar; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherModularStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java similarity index 91% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherModularStartupInfo.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java index 332adb70945fc..d6fe71397ff1b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherModularStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java @@ -22,12 +22,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.nio.file.Path; import java.util.List; -interface LauncherModularStartupInfo extends LauncherStartupInfo { +public interface LauncherModularStartupInfo extends LauncherStartupInfo { String moduleName(); @@ -36,7 +36,7 @@ interface LauncherModularStartupInfo extends LauncherStartupInfo { final static class Impl extends LauncherStartupInfo.Proxy implements LauncherModularStartupInfo { - Impl(LauncherStartupInfo target, String moduleName, + public Impl(LauncherStartupInfo target, String moduleName, List modulePath) { super(target); this.moduleName = moduleName; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java similarity index 97% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java index 0c4afe54f7bbb..e4486960ddbd5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java @@ -22,12 +22,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.nio.file.Path; import java.util.List; -interface LauncherStartupInfo { +public interface LauncherStartupInfo { String qualifiedClassName(); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplication.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/MacApplication.java similarity index 94% rename from src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplication.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/MacApplication.java index 17a97dae080c6..3e546706992e3 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplication.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/MacApplication.java @@ -22,11 +22,11 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.util.Map; -interface MacApplication extends Application { +public interface MacApplication extends Application { boolean signed(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/OverridableResource.java similarity index 81% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/OverridableResource.java index ecd88bb7fb975..1b41fcd8f29da 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/OverridableResource.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.io.BufferedReader; import java.io.ByteArrayInputStream; @@ -35,17 +35,17 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.text.MessageFormat; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; -import jdk.jpackage.internal.resources.ResourceLocator; +import jdk.jpackage.internal.Log; /** @@ -69,30 +69,46 @@ * value was passed in #setExternal call that value will be used as a path to file * to copy in the destination file passed in #saveToFile function call. */ -final class OverridableResource { +public final class OverridableResource { - OverridableResource(String defaultName) { + public OverridableResource() { + defaultName = ""; + defaultResourceSupplier = null; + setSourceOrder(Source.External, Source.ResourceDir); + } + + public OverridableResource(String defaultName, + Supplier defaultResourceSupplier) { + Objects.requireNonNull(defaultName); + Objects.requireNonNull(defaultResourceSupplier); this.defaultName = defaultName; + this.defaultResourceSupplier = defaultResourceSupplier; setSourceOrder(Source.values()); } - Path getResourceDir() { + public OverridableResource(String defaultName, Class resourceLocator) { + this(defaultName, () -> { + return resourceLocator.getResourceAsStream(defaultName); + }); + } + + public Path getResourceDir() { return resourceDir; } - String getDefaultName() { + public String getDefaultName() { return defaultName; } - Path getPublicName() { + public Path getPublicName() { return publicName; } - Path getExternalPath() { + public Path getExternalPath() { return externalPath; } - OverridableResource setSubstitutionData(Map v) { + public OverridableResource setSubstitutionData(Map v) { if (v != null) { // Disconnect `v` substitutionData = new HashMap<>(v); @@ -102,30 +118,30 @@ OverridableResource setSubstitutionData(Map v) { return this; } - OverridableResource addSubstitutionDataEntry(String key, String value) { + public OverridableResource addSubstitutionDataEntry(String key, String value) { var entry = Map.of(key, value); Optional.ofNullable(substitutionData).ifPresentOrElse(v -> v.putAll( entry), () -> setSubstitutionData(entry)); return this; } - OverridableResource setCategory(String v) { + public OverridableResource setCategory(String v) { category = v; return this; } - OverridableResource setResourceDir(Path v) { + public OverridableResource setResourceDir(Path v) { resourceDir = v; return this; } - OverridableResource setResourceDir(File v) { + public OverridableResource setResourceDir(File v) { return setResourceDir(toPath(v)); } - enum Source { External, ResourceDir, DefaultResource }; + public enum Source { External, ResourceDir, DefaultResource }; - OverridableResource setSourceOrder(Source... v) { + public OverridableResource setSourceOrder(Source... v) { sources = Stream.of(v) .map(source -> Map.entry(source, getHandler(source))) .toList(); @@ -137,12 +153,12 @@ OverridableResource setSourceOrder(Source... v) { * * @return this */ - OverridableResource setPublicName(Path v) { + public OverridableResource setPublicName(Path v) { publicName = v; return this; } - OverridableResource setPublicName(String v) { + public OverridableResource setPublicName(String v) { return setPublicName(Path.of(v)); } @@ -151,25 +167,25 @@ OverridableResource setPublicName(String v) { * * @return this */ - OverridableResource setLogPublicName(Path v) { + public OverridableResource setLogPublicName(Path v) { logPublicName = v; return this; } - OverridableResource setLogPublicName(String v) { + public OverridableResource setLogPublicName(String v) { return setLogPublicName(Path.of(v)); } - OverridableResource setExternal(Path v) { + public OverridableResource setExternal(Path v) { externalPath = v; return this; } - OverridableResource setExternal(File v) { + public OverridableResource setExternal(File v) { return setExternal(toPath(v)); } - Source saveToStream(OutputStream dest) throws IOException { + public Source saveToStream(OutputStream dest) throws IOException { if (dest == null) { return sendToConsumer(null); } @@ -186,11 +202,11 @@ public void consume(InputStream in) throws IOException { }); } - Source saveInFolder(Path folderPath) throws IOException { + public Source saveInFolder(Path folderPath) throws IOException { return saveToFile(folderPath.resolve(getPublicName())); } - Source saveToFile(Path dest) throws IOException { + public Source saveToFile(Path dest) throws IOException { if (dest == null) { return sendToConsumer(null); } @@ -202,26 +218,16 @@ public Path publicName() { @Override public void consume(InputStream in) throws IOException { - Files.createDirectories(IOUtils.getParent(dest)); + Files.createDirectories(dest.getParent()); Files.copy(in, dest, StandardCopyOption.REPLACE_EXISTING); } }); } - Source saveToFile(File dest) throws IOException { + public Source saveToFile(File dest) throws IOException { return saveToFile(toPath(dest)); } - static InputStream readDefault(String resourceName) { - return ResourceLocator.class.getResourceAsStream(resourceName); - } - - static OverridableResource createResource(String defaultName, - Map params) { - return new OverridableResource(defaultName).setResourceDir( - RESOURCE_DIR.fetchFrom(params)); - } - private Source sendToConsumer(ResourceConsumer consumer) throws IOException { for (var source: sources) { if (source.getValue().apply(consumer)) { @@ -241,8 +247,7 @@ private String getPrintableCategory() { private boolean useExternal(ResourceConsumer dest) throws IOException { boolean used = externalPath != null && Files.exists(externalPath); if (used && dest != null) { - Log.verbose(MessageFormat.format(I18N.getString( - "message.using-custom-resource-from-file"), + Log.verbose(I18N.format("message.using-custom-resource-from-file", getPrintableCategory(), externalPath.toAbsolutePath().normalize())); @@ -270,9 +275,8 @@ private boolean useResourceDir(ResourceConsumer dest) throws IOException { final Path logResourceName = Optional.ofNullable(logPublicName).orElse( resourceName).normalize(); - Log.verbose(MessageFormat.format(I18N.getString( - "message.using-custom-resource"), getPrintableCategory(), - logResourceName)); + Log.verbose(I18N.format("message.using-custom-resource", + getPrintableCategory(), logResourceName)); try (InputStream in = Files.newInputStream(customResource)) { processResourceStream(in, dest); @@ -291,11 +295,10 @@ private boolean useDefault(ResourceConsumer dest) throws IOException { .orElse(Optional .ofNullable(publicName) .orElseGet(() -> dest.publicName())); - Log.verbose(MessageFormat.format( - I18N.getString("message.using-default-resource"), + Log.verbose(I18N.format("message.using-default-resource", defaultName, getPrintableCategory(), resourceName)); - try (InputStream in = readDefault(defaultName)) { + try (InputStream in = defaultResourceSupplier.get()) { processResourceStream(in, dest); } } @@ -386,6 +389,7 @@ private SourceHandler getHandler(Source sourceType) { private Path logPublicName; private Path externalPath; private final String defaultName; + private final Supplier defaultResourceSupplier; private List> sources; @FunctionalInterface diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java similarity index 98% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java index 11b0cc9e98329..f9f6107131f41 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java @@ -22,10 +22,8 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; -import jdk.jpackage.model.StandardPackageType; -import jdk.jpackage.model.PackageType; import java.nio.file.Path; import java.util.Optional; import static jdk.jpackage.internal.Getter.getValueOrDefault; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/model/PackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java similarity index 97% rename from src/jdk.jpackage/share/classes/jdk/jpackage/model/PackageType.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java index 1c36c075bf5a7..7dfbf505c6fa8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/model/PackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.jpackage.model; +package jdk.jpackage.internal.model; public interface PackageType {} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java similarity index 98% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerException.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java index 2483e9706ab21..733face432ce8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; public class PackagerException extends Exception { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ProxyBase.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ProxyBase.java similarity index 94% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/ProxyBase.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ProxyBase.java index 91b0974aefafb..66e1b783506d4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ProxyBase.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ProxyBase.java @@ -22,10 +22,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; abstract class ProxyBase { - ProxyBase(T target) { + protected ProxyBase(T target) { this.target = target; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java similarity index 72% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilder.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java index b93b8398cf8d4..6852dd533d384 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java @@ -22,27 +22,30 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.io.IOException; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; -import java.text.MessageFormat; import java.util.Arrays; import java.util.List; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.IOUtils; +import jdk.jpackage.internal.util.FileUtils; -interface RuntimeBuilder { +public interface RuntimeBuilder { - void createRuntime(ApplicationLayout appLayout) throws PackagerException, IOException; + public void createRuntime(ApplicationLayout appLayout) throws + PackagerException, IOException; - static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, Path... modulePath) throws ConfigException { + public static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, + Path... modulePath) throws ConfigException { if (!Files.exists(runtimeDir)) { - throw new ConfigException(MessageFormat.format(I18N.getString( - "message.runtime-image-dir-does-not-exist"), "--runtime-image", runtimeDir - .toString()), MessageFormat.format(I18N.getString( - "message.runtime-image-dir-does-not-exist.advice"), "--runtime-image")); + throw ConfigException.build() + .message("message.runtime-image-dir-does-not-exist", "--runtime-image", runtimeDir) + .advice("message.runtime-image-dir-does-not-exist.advice", "--runtime-image") + .create(); } return appLayout -> { @@ -50,7 +53,8 @@ static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, Path... modul // copy whole runtime, need to skip jmods and src.zip final List excludes = Arrays.asList("jmods", "src.zip"); - IOUtils.copyRecursive(runtimeHome, appLayout.runtimeHomeDirectory(), excludes, + FileUtils.copyRecursive(runtimeHome, appLayout.runtimeHomeDirectory(), + excludes, LinkOption.NOFOLLOW_LINKS); // if module-path given - copy modules to appDir/mods @@ -59,7 +63,7 @@ static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, Path... modul for (Path mp : modulePath) { if (!defaultModulePath.contains(mp.toAbsolutePath())) { - IOUtils.copyRecursive(mp, dest); + FileUtils.copyRecursive(mp, dest); } } }; @@ -78,7 +82,8 @@ private static Path getRuntimeHome(Path runtimeDir) { return runtimeDir; } - static List getDefaultModulePath() { - return List.of(Path.of(System.getProperty("java.home"), "jmods").toAbsolutePath()); + public static List getDefaultModulePath() { + return List.of( + Path.of(System.getProperty("java.home"), "jmods").toAbsolutePath()); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/model/StandardPackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java similarity index 97% rename from src/jdk.jpackage/share/classes/jdk/jpackage/model/StandardPackageType.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java index 5e062f33d903f..d51041b278de5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/model/StandardPackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.model; +package jdk.jpackage.internal.model; import java.util.stream.Stream; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java new file mode 100644 index 0000000000000..97595eda5bad3 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.util.Collection; + +public final class CollectionUtils { + + @SuppressWarnings("unchecked") + public static > C toCollection(Collection v) { + Collection tmp = v; + return (C) tmp; + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java new file mode 100644 index 0000000000000..d0d63ab0bc7ef --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.io.IOException; +import java.nio.file.CopyOption; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import jdk.internal.util.OperatingSystem; + +public final class FileUtils { + + public static void copyRecursive(Path src, Path dest, CopyOption... options) + throws IOException { + copyRecursive(src, dest, List.of(), options); + } + + public static void copyRecursive(Path src, Path dest, + final List excludes, CopyOption... options) throws + IOException { + Files.walkFileTree(src, new SimpleFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(final Path dir, + final BasicFileAttributes attrs) throws IOException { + if (excludes.contains(dir.toFile().getName())) { + return FileVisitResult.SKIP_SUBTREE; + } else { + Files.createDirectories(dest.resolve(src.relativize(dir))); + return FileVisitResult.CONTINUE; + } + } + + @Override + public FileVisitResult visitFile(final Path file, + final BasicFileAttributes attrs) throws IOException { + if (!excludes.contains(file.toFile().getName())) { + Files.copy(file, dest.resolve(src.relativize(file)), options); + } + return FileVisitResult.CONTINUE; + } + }); + } + + public static void deleteRecursive(Path directory) throws IOException { + final AtomicReference exception = new AtomicReference<>(); + if (!Files.exists(directory)) { + return; + } + Files.walkFileTree(directory, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attr) + throws IOException { + if (OperatingSystem.isWindows()) { + Files.setAttribute(file, "dos:readonly", false); + } + try { + Files.delete(file); + } catch (IOException ex) { + exception.compareAndSet(null, ex); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, + BasicFileAttributes attr) throws IOException { + if (OperatingSystem.isWindows()) { + Files.setAttribute(dir, "dos:readonly", false); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException e) + throws IOException { + try { + Files.delete(dir); + } catch (IOException ex) { + exception.compareAndSet(null, ex); + } + return FileVisitResult.CONTINUE; + } + }); + + if (exception.get() != null) { + throw exception.get(); + } + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java new file mode 100644 index 0000000000000..8e73170f90041 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListResourceBundle; +import java.util.Map; +import java.util.Optional; +import java.util.ResourceBundle; +import static java.util.stream.Collectors.toMap; +import java.util.stream.Stream; +import jdk.internal.util.OperatingSystem; + +public final class MultiResourceBundle extends ListResourceBundle { + + public static ResourceBundle create(String sharedResourceBundleName, + Map> platformResourceBundleNames) { + List bundleNames = new ArrayList<>(); + Optional.ofNullable(sharedResourceBundleName).ifPresent(bundleNames::add); + Optional.ofNullable(platformResourceBundleNames.get(OperatingSystem.current())).ifPresent(bundleNames::addAll); + if (bundleNames.isEmpty()) { + throw new IllegalArgumentException("Empty resource bundle names list"); + } else { + var resourceBundles = bundleNames.stream().map(ResourceBundle::getBundle).toArray(ResourceBundle[]::new); + if (resourceBundles.length == 1) { + return resourceBundles[0]; + } else { + return new MultiResourceBundle(resourceBundles); + } + } + } + + private MultiResourceBundle(ResourceBundle... bundles) { + contents = Stream.of(bundles).map(bundle -> { + return bundle.keySet().stream().map(key -> { + return Map.entry(key, bundle.getObject(key)); + }); + }).flatMap(x -> x).collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (o, n) -> { + // Override old value with the new one + return n; + })).entrySet().stream().map(e -> { + return new Object[]{e.getKey(), e.getValue()}; + }).toArray(Object[][]::new); + } + + @Override + protected Object[][] getContents() { + return contents; + } + + private final Object[][] contents; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java similarity index 88% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java index cec9e5c2eb2dc..845fb1ac8985e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.util; import java.io.IOException; import java.nio.file.Files; @@ -37,25 +37,26 @@ import java.util.function.BiFunction; import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.jpackage.internal.IOUtils; /** * Group of paths. * Each path in the group is assigned a unique id. */ -final class PathGroup { - PathGroup(Map paths) { +public final class PathGroup { + public PathGroup(Map paths) { entries = new HashMap<>(paths); } - Path getPath(Object id) { + public Path getPath(Object id) { if (id == null) { throw new NullPointerException(); } return entries.get(id); } - void setPath(Object id, Path path) { + public void setPath(Object id, Path path) { if (path != null) { entries.put(id, path); } else { @@ -63,7 +64,7 @@ void setPath(Object id, Path path) { } } - void ghostPath(Path path) { + public void ghostPath(Path path) { Objects.requireNonNull(path); setPath(new Object(), path); } @@ -71,21 +72,21 @@ void ghostPath(Path path) { /** * All configured IDs. */ - Set keys() { + public Set keys() { return entries.keySet(); } /** * All configured entries. */ - List paths() { + public List paths() { return entries.values().stream().toList(); } /** * Root entries. */ - List roots() { + public List roots() { // Sort by the number of path components in ascending order. List> sorted = normalizedPaths().stream().sorted( (a, b) -> a.getKey().getNameCount() - b.getKey().getNameCount()).toList(); @@ -101,7 +102,7 @@ List roots() { v -> v.getValue()).toList(); } - long sizeInBytes() throws IOException { + public long sizeInBytes() throws IOException { long reply = 0; for (Path dir : roots().stream().filter(f -> Files.isDirectory(f)).collect( Collectors.toList())) { @@ -113,25 +114,25 @@ long sizeInBytes() throws IOException { return reply; } - PathGroup resolveAt(Path root) { + public PathGroup resolveAt(Path root) { return new PathGroup(entries.entrySet().stream().collect( Collectors.toMap(e -> e.getKey(), e -> root.resolve(e.getValue())))); } - void copy(PathGroup dst) throws IOException { + public void copy(PathGroup dst) throws IOException { copy(this, dst, null, false); } - void move(PathGroup dst) throws IOException { + public void move(PathGroup dst) throws IOException { copy(this, dst, null, true); } - void transform(PathGroup dst, TransformHandler handler) throws IOException { + public void transform(PathGroup dst, TransformHandler handler) throws IOException { copy(this, dst, handler, false); } - static interface Facade { + public static interface Facade { PathGroup pathGroup(); default Collection paths() { @@ -162,12 +163,12 @@ default void transform(Facade dst, TransformHandler handler) throws } } - static interface TransformHandler { - default public void copyFile(Path src, Path dst) throws IOException { + public static interface TransformHandler { + default void copyFile(Path src, Path dst) throws IOException { } - default public void createDirectory(Path dir) throws IOException { + default void createDirectory(Path dir) throws IOException { } } @@ -197,7 +198,7 @@ private static void copy(boolean move, List> entries, handler = new TransformHandler() { @Override public void copyFile(Path src, Path dst) throws IOException { - Files.createDirectories(IOUtils.getParent(dst)); + Files.createDirectories(dst.getParent()); if (move) { Files.move(src, dst); } else { @@ -251,7 +252,7 @@ public void createDirectory(Path dir) throws IOException { for (var entry: entries) { Path srcFile = entry.getKey(); if (Files.isDirectory(srcFile)) { - IOUtils.deleteRecursive(srcFile); + FileUtils.deleteRecursive(srcFile); } } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java new file mode 100644 index 0000000000000..ff15e5dfbb51f --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java @@ -0,0 +1,31 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package jdk.jpackage.internal.util; + +import java.nio.file.Path; +import java.util.Optional; +import jdk.jpackage.internal.IOUtils; + +public final class PathUtils { + + public static String getSuffix(Path path) { + String filename = replaceSuffix(IOUtils.getFileName(path), null).toString(); + return IOUtils.getFileName(path).toString().substring(filename.length()); + } + + public static Path addSuffix(Path path, String suffix) { + Path parent = path.getParent(); + String filename = IOUtils.getFileName(path).toString() + suffix; + return parent != null ? parent.resolve(filename) : Path.of(filename); + } + + public static Path replaceSuffix(Path path, String suffix) { + Path parent = path.getParent(); + String filename = IOUtils.getFileName(path).toString().replaceAll("\\.[^.]*$", + "") + Optional.ofNullable(suffix).orElse(""); + return parent != null ? parent.resolve(filename) : Path.of(filename); + } + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java new file mode 100644 index 0000000000000..89b8f8dc7ec62 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.io.IOException; +import java.io.Writer; +import java.lang.reflect.Proxy; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collection; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stax.StAXResult; +import jdk.jpackage.internal.IOUtils; +import jdk.jpackage.internal.util.xml.PrettyPrintHandler; +import jdk.jpackage.internal.util.xml.SkipDocumentHandler; + +public final class XmlUtils { + + @FunctionalInterface + public interface XmlConsumer { + + void accept(XMLStreamWriter xml) throws IOException, XMLStreamException; + + } + + public static void createXml(Path dstFile, XmlConsumer xmlConsumer) throws + IOException { + XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance(); + Files.createDirectories(IOUtils.getParent(dstFile)); + try (Writer w = Files.newBufferedWriter(dstFile)) { + // Wrap with pretty print proxy + XMLStreamWriter xml = (XMLStreamWriter) Proxy.newProxyInstance(XMLStreamWriter.class.getClassLoader(), + new Class[]{XMLStreamWriter.class}, + new PrettyPrintHandler(xmlFactory.createXMLStreamWriter(w))); + xml.writeStartDocument(); + xmlConsumer.accept(xml); + xml.writeEndDocument(); + xml.flush(); + xml.close(); + } catch (XMLStreamException ex) { + throw new IOException(ex); + } catch (IOException ex) { + throw ex; + } + } + + public static void mergeXmls(XMLStreamWriter xml, Collection sources) + throws XMLStreamException, IOException { + xml = (XMLStreamWriter) Proxy.newProxyInstance(XMLStreamWriter.class.getClassLoader(), + new Class[]{XMLStreamWriter.class}, + new SkipDocumentHandler(xml)); + try { + TransformerFactory tf = TransformerFactory.newInstance(); + Result result = new StAXResult(xml); + for (Source src : sources) { + tf.newTransformer().transform(src, result); + } + } catch (TransformerException ex) { + // Should never happen + throw new RuntimeException(ex); + } + } + + public static DocumentBuilder initDocumentBuilder() { + try { + return initDocumentBuilderFactory().newDocumentBuilder(); + } catch (ParserConfigurationException ex) { + throw new IllegalStateException(ex); + } + } + + public static DocumentBuilderFactory initDocumentBuilderFactory() { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); + try { + dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", + false); + } catch (ParserConfigurationException ex) { + throw new IllegalStateException(ex); + } + return dbf; + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionWrapper.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionWrapper.java new file mode 100644 index 0000000000000..ebd5df5b24a16 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionWrapper.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +import java.lang.reflect.InvocationTargetException; + +public class ExceptionWrapper extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public static RuntimeException rethrowUnchecked(Throwable throwable) throws + ExceptionWrapper { + if (throwable instanceof RuntimeException runtimeThrowable) { + throw runtimeThrowable; + } + if (throwable instanceof InvocationTargetException) { + throw new ExceptionWrapper(throwable.getCause()); + } + throw new ExceptionWrapper(throwable); + } + + private ExceptionWrapper(Throwable throwable) { + super(throwable); + } + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiConsumer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiConsumer.java new file mode 100644 index 0000000000000..dd6e38faa2652 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiConsumer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +import java.util.function.BiConsumer; + +@FunctionalInterface +public interface ThrowingBiConsumer { + + void accept(T t, U u) throws Throwable; + + public static BiConsumer toBiConsumer( + ThrowingBiConsumer v) { + return (t, u) -> { + try { + v.accept(t, u); + } catch (Throwable ex) { + throw ExceptionWrapper.rethrowUnchecked(ex); + } + }; + } + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java new file mode 100644 index 0000000000000..7517981268860 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +import java.util.function.BiFunction; + +@FunctionalInterface +public interface ThrowingBiFunction { + + R apply(T t, U u) throws Throwable; + + public static BiFunction toBiFunction( + ThrowingBiFunction v) { + return (t, u) -> { + try { + return v.apply(t, u); + } catch (Throwable ex) { + throw ExceptionWrapper.rethrowUnchecked(ex); + } + }; + } + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java new file mode 100644 index 0000000000000..7efff50990159 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +import java.util.function.Consumer; + +@FunctionalInterface +public interface ThrowingConsumer { + + void accept(T t) throws Throwable; + + public static Consumer toConsumer(ThrowingConsumer v) { + return o -> { + try { + v.accept(o); + } catch (Throwable ex) { + throw ExceptionWrapper.rethrowUnchecked(ex); + } + }; + } + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java new file mode 100644 index 0000000000000..d78f5df079011 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +import java.util.function.Function; + +@FunctionalInterface +public interface ThrowingFunction { + + R apply(T t) throws Throwable; + + public static Function toFunction(ThrowingFunction v) { + return t -> { + try { + return v.apply(t); + } catch (Throwable ex) { + throw ExceptionWrapper.rethrowUnchecked(ex); + } + }; + } + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java new file mode 100644 index 0000000000000..b58b351305e6a --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +@FunctionalInterface +public interface ThrowingRunnable { + + void run() throws Throwable; + + public static Runnable toRunnable(ThrowingRunnable v) { + return () -> { + try { + v.run(); + } catch (Throwable ex) { + throw ExceptionWrapper.rethrowUnchecked(ex); + } + }; + } + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java new file mode 100644 index 0000000000000..f02fec3078a2a --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +import java.util.function.Supplier; + +@FunctionalInterface +public interface ThrowingSupplier { + + T get() throws Throwable; + + public static Supplier toSupplier(ThrowingSupplier v) { + return () -> { + try { + return v.get(); + } catch (Throwable ex) { + throw ExceptionWrapper.rethrowUnchecked(ex); + } + }; + } + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java new file mode 100644 index 0000000000000..7a08722816240 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +import java.util.function.UnaryOperator; + +@FunctionalInterface +public interface ThrowingUnaryOperator { + + T apply(T t) throws Throwable; + + public static UnaryOperator toUnaryOperator( + ThrowingUnaryOperator v) { + return t -> { + try { + return v.apply(t); + } catch (Throwable ex) { + throw ExceptionWrapper.rethrowUnchecked(ex); + } + }; + } + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/PrettyPrintHandler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/PrettyPrintHandler.java new file mode 100644 index 0000000000000..b3fd3c0643a89 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/PrettyPrintHandler.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.xml; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import javax.xml.stream.XMLStreamWriter; + +public class PrettyPrintHandler implements InvocationHandler { + + public PrettyPrintHandler(XMLStreamWriter target) { + this.target = target; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + switch (method.getName()) { + case "writeStartElement": + // update state of parent node + if (depth > 0) { + hasChildElement.put(depth - 1, true); + } + // reset state of current node + hasChildElement.put(depth, false); + // indent for current depth + target.writeCharacters(EOL); + target.writeCharacters(repeat(depth, INDENT)); + depth++; + break; + case "writeEndElement": + depth--; + if (hasChildElement.get(depth) == true) { + target.writeCharacters(EOL); + target.writeCharacters(repeat(depth, INDENT)); + } + break; + case "writeProcessingInstruction": + case "writeEmptyElement": + // update state of parent node + if (depth > 0) { + hasChildElement.put(depth - 1, true); + } + // indent for current depth + target.writeCharacters(EOL); + target.writeCharacters(repeat(depth, INDENT)); + break; + default: + break; + } + method.invoke(target, args); + return null; + } + + private static String repeat(int d, String s) { + StringBuilder sb = new StringBuilder(); + while (d-- > 0) { + sb.append(s); + } + return sb.toString(); + } + + private final XMLStreamWriter target; + private int depth = 0; + private final Map hasChildElement = new HashMap<>(); + private static final String INDENT = " "; + private static final String EOL = "\n"; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/SkipDocumentHandler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/SkipDocumentHandler.java new file mode 100644 index 0000000000000..79a927ff766b8 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/SkipDocumentHandler.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.xml; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import javax.xml.stream.XMLStreamWriter; + +public class SkipDocumentHandler implements InvocationHandler { + + public SkipDocumentHandler(XMLStreamWriter target) { + this.target = target; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + switch (method.getName()) { + case "writeStartDocument", "writeEndDocument" -> { + } + default -> method.invoke(target, args); + } + return null; + } + + private final XMLStreamWriter target; +} diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java index f2fa5443bf56d..2a5011f72a702 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.nio.file.Path; import java.util.EnumSet; @@ -32,6 +33,7 @@ import java.util.function.Supplier; import java.util.function.UnaryOperator; import java.util.stream.Collectors; +import jdk.jpackage.internal.resources.ResourceLocator; /** * Shell scripts of a package. @@ -83,7 +85,8 @@ static class ResourceConfig { } OverridableResource createResource() { - var resource = new OverridableResource(defaultName).setCategory(category); + var resource = new OverridableResource(defaultName, + ResourceLocator.class).setCategory(category); return getDefaultPublicName().map(resource::setPublicName).orElse( resource); } diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java index 64afc95516da8..9de39340fb6f1 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.OverridableResource; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -36,6 +37,7 @@ import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; +import jdk.jpackage.internal.resources.ResourceLocator; /** * Interface to add custom actions composed of shell commands to installers. @@ -105,7 +107,7 @@ protected static String stringifyShellCommands(List commands) { } protected static String stringifyTextFile(String resourceName) throws IOException { - try ( InputStream is = OverridableResource.readDefault(resourceName); + try ( InputStream is = ResourceLocator.class.getResourceAsStream(resourceName); InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8); BufferedReader reader = new BufferedReader(isr)) { return reader.lines().collect(Collectors.joining("\n")); diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java index fd3ee7e45921d..683773ffcbad8 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.Package; import java.io.IOException; interface ShellCustomActionFactory { diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellScriptResource.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellScriptResource.java index c6303636c66f4..7039911e96a47 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellScriptResource.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellScriptResource.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java index be75e02f36399..3470ae71f5e7d 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java @@ -24,6 +24,9 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.nio.file.Path; import java.util.Collections; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java index ee41a487f92fd..b8f41f0efbb97 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java @@ -24,6 +24,11 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.WinExePackage; +import jdk.jpackage.internal.model.WinLauncher; +import jdk.jpackage.internal.model.WinApplication; +import jdk.jpackage.internal.model.DottedVersion; +import jdk.jpackage.internal.model.OverridableResource; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java index 7512c44229a5a..8ae4ff31c59d1 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java @@ -24,6 +24,10 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.WinLauncher; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.WinApplication; import java.io.IOException; import java.nio.file.Path; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java index e5d6ba6fa4fc8..f968a0800a6a9 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java @@ -24,43 +24,44 @@ */ package jdk.jpackage.internal; -import java.io.IOException; +import jdk.jpackage.internal.model.WinLauncher; +import jdk.jpackage.internal.model.WinApplication; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import static jdk.jpackage.internal.ApplicationFromParams.createBundlerParam; import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; -import static jdk.jpackage.internal.WinLauncher.WinShortcut.WinShortcutDesktop; -import static jdk.jpackage.internal.WinLauncher.WinShortcut.WinShortcutStartMenu; +import jdk.jpackage.internal.model.WinApplication.Impl; +import static jdk.jpackage.internal.model.WinLauncher.WinShortcut.WIN_SHORTCUT_DESKTOP; +import static jdk.jpackage.internal.model.WinLauncher.WinShortcut.WIN_SHORTCUT_START_MENU; final class WinApplicationFromParams { - private static WinApplication create(Map params) throws ConfigException, IOException { - var app = ApplicationFromParams.create(params, launcherParams -> { - var launcher = LauncherFromParams.create(launcherParams); - boolean isConsole = CONSOLE_HINT.fetchFrom(launcherParams); + private static WinLauncher createLauncher(Map params) { + var launcher = new LauncherFromParams().create(params); - var shortcuts = Map.of(WinShortcutDesktop, List.of(SHORTCUT_HINT, - WIN_SHORTCUT_HINT), WinShortcutStartMenu, - List.of(MENU_HINT, WIN_MENU_HINT)).entrySet().stream().filter( - e -> { - var shortcutParams = e.getValue(); - if (launcherParams.containsKey(shortcutParams.get(0).getID())) { - // This is an explicit shortcut configuration for an addition launcher - return shortcutParams.get(0).fetchFrom(launcherParams); - } else { - return shortcutParams.get(1).fetchFrom(launcherParams); - } - }).map(Map.Entry::getKey).collect(Collectors.toSet()); + boolean isConsole = CONSOLE_HINT.fetchFrom(params); - return new WinLauncher.Impl(launcher, isConsole, shortcuts); - }); - return new WinApplication.Impl(app); + var shortcuts = Map.of(WIN_SHORTCUT_DESKTOP, List.of(SHORTCUT_HINT, + WIN_SHORTCUT_HINT), WIN_SHORTCUT_START_MENU, List.of(MENU_HINT, + WIN_MENU_HINT)).entrySet().stream().filter(e -> { + var shortcutParams = e.getValue(); + if (params.containsKey(shortcutParams.get(0).getID())) { + // This is an explicit shortcut configuration for an addition launcher + return shortcutParams.get(0).fetchFrom(params); + } else { + return shortcutParams.get(1).fetchFrom(params); + } + }).map(Map.Entry::getKey).collect(Collectors.toSet()); + + return new WinLauncher.Impl(launcher, isConsole, shortcuts); } - static final BundlerParamInfo APPLICATION = createBundlerParam( - WinApplicationFromParams::create); + static final BundlerParamInfo APPLICATION = createBundlerParam(params -> { + var app = new ApplicationFromParams(WinApplicationFromParams::createLauncher).create(params); + return new Impl(app); + }); private static final BundlerParamInfo WIN_MENU_HINT = new BundlerParamInfo<>( Arguments.CLIOptions.WIN_MENU_HINT.getId(), @@ -77,7 +78,7 @@ private static WinApplication create(Map params) throws // valueOf(null) is false, // and we actually do want null in some cases (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); - + public static final BundlerParamInfo CONSOLE_HINT = new BundlerParamInfo<>( Arguments.CLIOptions.WIN_CONSOLE_HINT.getId(), Boolean.class, diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java index 943e0b46bfd2e..e5f6ee9c7d1a0 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java @@ -24,14 +24,19 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.WinExePackage; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.Map; -import static jdk.jpackage.internal.Functional.ThrowingRunnable.toRunnable; +import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; import static jdk.jpackage.internal.StandardBundlerParam.ICON; +import jdk.jpackage.internal.resources.ResourceLocator; @SuppressWarnings("restricted") public class WinExeBundler extends AbstractBundler { @@ -110,7 +115,7 @@ private Path buildEXE(BuildEnv env, WinExePackage pkg, Path msi, // Copy template msi wrapper next to msi file final Path exePath = msi.getParent().resolve(pkg.packageFileNameWithSuffix()); - try (InputStream is = OverridableResource.readDefault("msiwrapper.exe")) { + try (InputStream is = ResourceLocator.class.getResourceAsStream("msiwrapper.exe")) { Files.copy(is, exePath); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 5267a086f330e..305259e3e9bf2 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -25,6 +25,11 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.WinMsiPackage; +import jdk.jpackage.internal.model.OverridableResource; +import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.io.InputStream; import java.io.Writer; @@ -189,8 +194,6 @@ public boolean validate(Map params) wixFragments.stream().map(WixFragmentBuilder::getLoggableWixFeatures).flatMap( List::stream).distinct().toList().forEach(Log::verbose); - FileAssociation.verify(FileAssociation.fetchFrom(params)); - return true; } catch (RuntimeException re) { if (re.getCause() instanceof ConfigException) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java index 0011776000b56..7f0641066bf5c 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.WinMsiPackage; import java.nio.file.Path; import java.util.Map; import java.util.Optional; @@ -31,8 +33,8 @@ import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; -import jdk.jpackage.internal.WinMsiPackage.Impl; -import static jdk.jpackage.model.StandardPackageType.WIN_MSI; +import jdk.jpackage.internal.model.WinMsiPackage.Impl; +import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; final class WinMsiPackageFromParams { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index d46957bf3d6d3..d146f4adae824 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -25,10 +25,15 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.WinLauncher; +import jdk.jpackage.internal.model.WinMsiPackage; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.DottedVersion; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.util.PathGroup; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Path; -import java.nio.file.Files; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; @@ -45,6 +50,7 @@ import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; +import static java.util.stream.Collectors.toMap; import java.util.stream.Stream; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; @@ -54,10 +60,13 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import static jdk.jpackage.internal.Functional.toCollection; -import jdk.jpackage.internal.IOUtils.XmlConsumer; -import jdk.jpackage.internal.WinLauncher.WinShortcut; +import static jdk.jpackage.internal.util.CollectionUtils.toCollection; +import jdk.jpackage.internal.model.WinLauncher.WinShortcut; import jdk.jpackage.internal.WixToolset.WixToolsetType; +import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.util.PathUtils; +import jdk.jpackage.internal.util.XmlUtils; +import jdk.jpackage.internal.util.XmlUtils.XmlConsumer; import org.w3c.dom.NodeList; /** @@ -171,45 +180,20 @@ protected Collection getFragmentWriters() { ); } - private void normalizeFileAssociation(FileAssociation fa) { - fa.launcherPath = addExeSuffixToPath( - installedAppImage.launchersDirectory().resolve(fa.launcherPath)); - - if (fa.iconPath != null && !Files.exists(fa.iconPath)) { - fa.iconPath = null; - } - - if (fa.iconPath != null) { - fa.iconPath = fa.iconPath.toAbsolutePath(); - } - - // Filter out empty extensions. - fa.extensions = fa.extensions.stream().filter(Predicate.not( - String::isEmpty)).toList(); - } - - private static Path addExeSuffixToPath(Path path) { - return IOUtils.addSuffix(path, ".exe"); - } - private Path getInstalledFaIcoPath(FileAssociation fa) { - String fname = String.format("fa_%s.ico", String.join("_", fa.extensions)); + String fname = String.format("fa_%s.ico", fa.extension()); return installedAppImage.destktopIntegrationDirectory().resolve(fname); } private void initFileAssociations() { - var allFileAssociations = launchers.stream().map(Launcher::fileAssociations).flatMap( - List::stream).toList(); - associations = allFileAssociations.stream() - .peek(this::normalizeFileAssociation) - // Filter out file associations without extensions. - .filter(fa -> !fa.extensions.isEmpty()) - .toList(); - - associations.stream().filter(fa -> fa.iconPath != null).forEach(fa -> { + associations = launchers.stream().collect(toMap( + Launcher::executableNameWithSuffix, + WinLauncher::fileAssociations)); + + associations.values().stream().flatMap(List::stream).filter(fa -> fa.icon() != null).forEach(fa -> { // Need to add fa icon in the image. Object key = new Object(); - appImage.pathGroup().setPath(key, fa.iconPath); + appImage.pathGroup().setPath(key, fa.icon()); installedAppImage.pathGroup().setPath(key, getInstalledFaIcoPath(fa)); }); } @@ -454,8 +438,11 @@ private void addFaComponentGroup(XMLStreamWriter xml) throws XMLStreamException, IOException { List componentIds = new ArrayList<>(); - for (var fa : associations) { - componentIds.addAll(addFaComponents(xml, fa)); + for (var entry : associations.entrySet()) { + var launcherExe = entry.getKey(); + for (var fa : entry.getValue()) { + componentIds.add(addFaComponent(xml, launcherExe, fa)); + } } addComponentGroup(xml, "FileAssociations", componentIds); } @@ -507,7 +494,7 @@ private String addShortcutComponent(XMLStreamWriter xml, Path launcherPath, throw throwInvalidPathException(launcherPath); } - String launcherBasename = IOUtils.replaceSuffix( + String launcherBasename = PathUtils.replaceSuffix( IOUtils.getFileName(launcherPath), "").toString(); Path shortcutPath = folder.getPath(this).resolve(launcherBasename); @@ -520,50 +507,44 @@ private String addShortcutComponent(XMLStreamWriter xml, Path launcherPath, }); } - private List addFaComponents(XMLStreamWriter xml, - FileAssociation fa) throws XMLStreamException, IOException { - List components = new ArrayList<>(); - for (var extension: fa.extensions) { - Path path = INSTALLDIR.resolve(String.format("%s_%s", extension, - fa.launcherPath.getFileName())); - components.add(addComponent(xml, path, Component.ProgId, unused -> { - xml.writeAttribute("Description", fa.description); - - if (fa.iconPath != null) { - xml.writeAttribute("Icon", Id.File.of(getInstalledFaIcoPath(fa))); - xml.writeAttribute("IconIndex", "0"); - } + private String addFaComponent(XMLStreamWriter xml, + String launcherExe, FileAssociation fa) throws + XMLStreamException, IOException { - xml.writeStartElement("Extension"); - xml.writeAttribute("Id", extension); - xml.writeAttribute("Advertise", "no"); + Path path = INSTALLDIR.resolve(String.format("%s_%s", fa.extension(), launcherExe)); + return addComponent(xml, path, Component.ProgId, unused -> { + xml.writeAttribute("Description", fa.description()); - var mimeIt = fa.mimeTypes.iterator(); - if (mimeIt.hasNext()) { - String mime = mimeIt.next(); - xml.writeAttribute("ContentType", mime); + if (fa.icon() != null) { + xml.writeAttribute("Icon", Id.File.of(getInstalledFaIcoPath(fa))); + xml.writeAttribute("IconIndex", "0"); + } - if (!defaultedMimes.contains(mime)) { - xml.writeStartElement("MIME"); - xml.writeAttribute("ContentType", mime); - xml.writeAttribute("Default", "yes"); - xml.writeEndElement(); - defaultedMimes.add(mime); - } - } + xml.writeStartElement("Extension"); + xml.writeAttribute("Id", fa.extension()); + xml.writeAttribute("Advertise", "no"); - xml.writeStartElement("Verb"); - xml.writeAttribute("Id", "open"); - xml.writeAttribute("Command", "!(loc.ContextMenuCommandLabel)"); - xml.writeAttribute("Argument", "\"%1\" %*"); - xml.writeAttribute("TargetFile", Id.File.of(fa.launcherPath)); - xml.writeEndElement(); // + var mime = fa.mimeType(); + xml.writeAttribute("ContentType", mime); - xml.writeEndElement(); // - })); - } + if (!defaultedMimes.contains(mime)) { + xml.writeStartElement("MIME"); + xml.writeAttribute("ContentType", mime); + xml.writeAttribute("Default", "yes"); + xml.writeEndElement(); + defaultedMimes.add(mime); + } + + xml.writeStartElement("Verb"); + xml.writeAttribute("Id", "open"); + xml.writeAttribute("Command", "!(loc.ContextMenuCommandLabel)"); + xml.writeAttribute("Argument", "\"%1\" %*"); + xml.writeAttribute("TargetFile", Id.File.of( + installedAppImage.launchersDirectory().resolve(launcherExe))); + xml.writeEndElement(); // - return components; + xml.writeEndElement(); // + }); } private List addRootBranch(XMLStreamWriter xml, Path path) @@ -759,7 +740,7 @@ private List addServiceConfigs(XMLStreamWriter xml) throws } try { - var buffer = new DOMResult(IOUtils.initDocumentBuilder().newDocument()); + var buffer = new DOMResult(XmlUtils.initDocumentBuilder().newDocument()); var bufferWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( buffer); @@ -909,9 +890,9 @@ private static IllegalArgumentException throwInvalidPathException(Path v) { } enum ShortcutsFolder { - ProgramMenu(PROGRAM_MENU_PATH, WinShortcut.WinShortcutDesktop, + ProgramMenu(PROGRAM_MENU_PATH, WinShortcut.WIN_SHORTCUT_DESKTOP, "JP_INSTALL_STARTMENU_SHORTCUT", "JpStartMenuShortcutPrompt"), - Desktop(DESKTOP_PATH, WinShortcut.WinShortcutStartMenu, + Desktop(DESKTOP_PATH, WinShortcut.WIN_SHORTCUT_START_MENU, "JP_INSTALL_DESKTOP_SHORTCUT", "JpDesktopShortcutPrompt"); private ShortcutsFolder(Path root, WinShortcut shortcutId, @@ -961,7 +942,7 @@ static Set getForPackage(WinMsiPackage pkg) { private String programMenuFolderName; - private List associations; + private Map> associations; private Set shortcutFolders; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java index 500724db13982..4a86a02db15e4 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java @@ -24,6 +24,9 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.WinMsiPackage; +import jdk.jpackage.internal.model.DottedVersion; +import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; @@ -37,11 +40,12 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.stream.XMLStreamWriter; -import jdk.jpackage.internal.IOUtils.XmlConsumer; -import jdk.jpackage.internal.OverridableResource.Source; +import jdk.jpackage.internal.model.OverridableResource.Source; import jdk.internal.util.Architecture; import jdk.jpackage.internal.WixSourceConverter.ResourceGroup; import jdk.jpackage.internal.WixToolset.WixToolsetType; +import jdk.jpackage.internal.util.XmlUtils; +import jdk.jpackage.internal.util.XmlUtils.XmlConsumer; /** * Creates WiX fragment. @@ -156,7 +160,7 @@ final protected void addResource(OverridableResource resource, String saveAsName } private void createWixSource(Path file, XmlConsumer xmlConsumer) throws IOException { - IOUtils.createXml(file, xml -> { + XmlUtils.createXml(file, xml -> { xml.writeStartElement("Wix"); for (var ns : getWixNamespaces().entrySet()) { switch (ns.getKey()) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java index 54e6f3311fe82..01f02b375130d 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.WinLauncher; +import jdk.jpackage.internal.model.OverridableResource; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -38,6 +40,7 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; +import jdk.jpackage.internal.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -94,7 +97,7 @@ private void writeResource(OverridableResource resource, XMLStreamWriter xml) resource.saveToStream(buffer); try { - Document doc = IOUtils.initDocumentBuilder().parse( + Document doc = XmlUtils.initDocumentBuilder().parse( new ByteArrayInputStream(buffer.toByteArray())); XPath xPath = XPathFactory.newInstance().newXPath(); @@ -108,7 +111,7 @@ private void writeResource(OverridableResource resource, XMLStreamWriter xml) sources.add(new DOMSource(n)); } - IOUtils.mergeXmls(xml, sources); + XmlUtils.mergeXmls(xml, sources); } catch (SAXException ex) { throw new IOException(ex); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixPipeline.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixPipeline.java index 835247ed1debb..5b626c8a565f5 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixPipeline.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixPipeline.java @@ -36,6 +36,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.jpackage.internal.util.PathUtils; /** * WiX pipeline. Compiles and links WiX sources. @@ -180,7 +181,7 @@ private void buildMsiWix3(Path msi) throws IOException { } private Path compileWix3(WixSource wixSource) throws IOException { - Path wixObj = wixObjDir.toAbsolutePath().resolve(IOUtils.replaceSuffix( + Path wixObj = wixObjDir.toAbsolutePath().resolve(PathUtils.replaceSuffix( IOUtils.getFileName(wixSource.source), ".wixobj")); List cmdline = new ArrayList<>(List.of( diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java index 7786d64a78693..ec0cb23dd4f9e 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.OverridableResource; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -52,6 +53,8 @@ import javax.xml.transform.stax.StAXResult; import javax.xml.transform.stream.StreamSource; import jdk.jpackage.internal.WixToolset.WixToolsetType; +import jdk.jpackage.internal.resources.ResourceLocator; +import jdk.jpackage.internal.util.XmlUtils; import org.w3c.dom.Document; import org.xml.sax.SAXException; @@ -69,7 +72,7 @@ enum Status { WixSourceConverter(Path resourceDir) throws IOException { var buf = new ByteArrayOutputStream(); - new OverridableResource("wix3-to-wix4-conv.xsl") + new OverridableResource("wix3-to-wix4-conv.xsl", ResourceLocator.class) .setPublicName("wix-conv.xsl") .setResourceDir(resourceDir) .setCategory(I18N.getString("resource.wix-src-conv")) @@ -98,7 +101,7 @@ Status appyTo(OverridableResource resource, Path resourceSaveAsFile) throws IOEx Document inputXmlDom; try { - inputXmlDom = IOUtils.initDocumentBuilder().parse(new ByteArrayInputStream(buf)); + inputXmlDom = XmlUtils.initDocumentBuilder().parse(new ByteArrayInputStream(buf)); } catch (SAXException ex) { // Malformed XML, don't run converter, save as is. resource.saveToFile(resourceSaveAsFile); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java index f16b28edf2448..e5ad02940e2de 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.DottedVersion; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Files; @@ -41,6 +43,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.jpackage.internal.WixToolset.WixToolsetType; +import jdk.jpackage.internal.util.PathUtils; /** * WiX tool. @@ -51,7 +54,7 @@ public enum WixTool { Wix4("wix", DottedVersion.lazy("4.0.4")); WixTool(String commandName, DottedVersion minimalVersion) { - this.toolFileName = IOUtils.addSuffix(Path.of(commandName), ".exe"); + this.toolFileName = PathUtils.addSuffix(Path.of(commandName), ".exe"); this.minimalVersion = minimalVersion; } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java index ab433616f44a6..4df225b14b8a4 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.DottedVersion; import java.nio.file.Path; import java.util.Map; import java.util.Set; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java index bb85aa9f58e49..4db3e3580dbb4 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.WinMsiPackage; +import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; @@ -38,9 +40,10 @@ import java.util.function.Supplier; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import jdk.jpackage.internal.IOUtils.XmlConsumer; import jdk.jpackage.internal.WixAppImageFragmentBuilder.ShortcutsFolder; import jdk.jpackage.internal.WixToolset.WixToolsetType; +import jdk.jpackage.internal.resources.ResourceLocator; +import jdk.jpackage.internal.util.XmlUtils.XmlConsumer; /** * Creates UI WiX fragment. @@ -120,7 +123,7 @@ void addFilesToConfigRoot() throws IOException { if (withCustomActionsDll) { String fname = "wixhelper.dll"; // CA dll - try (InputStream is = OverridableResource.readDefault(fname)) { + try (InputStream is = ResourceLocator.class.getResourceAsStream(fname)) { Files.copy(is, getConfigRoot().resolve(fname)); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/MsiVersion.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java similarity index 90% rename from src/jdk.jpackage/windows/classes/jdk/jpackage/internal/MsiVersion.java rename to src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java index c1ced66916923..3141f71ff78fc 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/MsiVersion.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java @@ -22,10 +22,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.math.BigInteger; -import java.text.MessageFormat; final class MsiVersion { @@ -40,14 +39,12 @@ final class MsiVersion { * @throws IllegalArgumentException */ static DottedVersion of(String value) { - DottedVersion ver = new DottedVersion(value); + DottedVersion ver = DottedVersion.greedy(value); BigInteger[] components = ver.getComponents(); if (components.length < 2 || components.length > 4) { - throw new IllegalArgumentException(MessageFormat.format( - I18N.getString("error.msi-product-version-components"), - value)); + throw new IllegalArgumentException(I18N.format("error.msi-product-version-components", value)); } if (BigInteger.valueOf(255).compareTo(components[0]) < 0) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java similarity index 85% rename from src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java rename to src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java index da9c4d1ddaafa..6a431403bd9bd 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplication.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java @@ -22,16 +22,16 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; -interface WinApplication extends Application { +public interface WinApplication extends Application { default DottedVersion winVersion() { return DottedVersion.lazy(version()); } - static class Impl extends Application.Proxy implements WinApplication { - Impl(Application app) { + public static class Impl extends Application.Proxy implements WinApplication { + public Impl(Application app) { super(app); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java similarity index 84% rename from src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java rename to src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java index eeb3e0b69c915..25237d3294210 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java @@ -22,21 +22,19 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; -import jdk.jpackage.model.StandardPackageType; -import jdk.jpackage.model.PackageType; import java.nio.file.Path; -interface WinExePackage extends Package { +public interface WinExePackage extends Package { WinMsiPackage msiPackage(); Path icon(); - static class Impl extends Package.Proxy implements WinExePackage { + public static class Impl extends Package.Proxy implements WinExePackage { - Impl(WinMsiPackage msiPackage, Path icon) throws ConfigException { + public Impl(WinMsiPackage msiPackage, Path icon) throws ConfigException { super(msiPackage); this.icon = icon; if (icon != null) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java similarity index 86% rename from src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java rename to src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java index cacdc4db322d1..ab0526d38ae5e 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinLauncher.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java @@ -22,13 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.io.InputStream; import java.util.Set; import jdk.jpackage.internal.resources.ResourceLocator; -interface WinLauncher extends Launcher { +public interface WinLauncher extends Launcher { @Override default String executableSuffix() { @@ -43,19 +43,20 @@ default InputStream executableResource() { isConsole() ? "jpackageapplauncher.exe" : "jpackageapplauncherw.exe"); } + @Override default String defaultIconResourceName() { return "JavaApp.ico"; } enum WinShortcut { - WinShortcutDesktop, - WinShortcutStartMenu + WIN_SHORTCUT_DESKTOP, + WIN_SHORTCUT_START_MENU } Set shortcuts(); - static class Impl extends Launcher.Proxy implements WinLauncher { - Impl(Launcher launcher, boolean isConsole, Set shortcuts) { + public static class Impl extends Launcher.Proxy implements WinLauncher { + public Impl(Launcher launcher, boolean isConsole, Set shortcuts) { super(launcher); this.isConsole = isConsole; this.shortcuts = shortcuts; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java similarity index 83% rename from src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java rename to src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java index 7ef73a6eb049f..8a0bd35ea4f09 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -30,7 +30,7 @@ import java.util.Optional; import java.util.UUID; -interface WinMsiPackage extends Package { +public interface WinMsiPackage extends Package { default DottedVersion msiVersion() { return MsiVersion.of(version()); @@ -58,23 +58,28 @@ default UUID productCode() { Path serviceInstaller(); - static class Impl extends Package.Proxy implements WinMsiPackage { + public static class Impl extends Package.Proxy implements WinMsiPackage { - Impl(Package pkg, boolean withInstallDirChooser, boolean withShortcutPrompt, String helpURL, - String updateURL, String startMenuGroupName, boolean isSystemWideInstall, + public Impl(Package pkg, boolean withInstallDirChooser, + boolean withShortcutPrompt, String helpURL, String updateURL, + String startMenuGroupName, boolean isSystemWideInstall, UUID upgradeCode, Path serviceInstaller) throws ConfigException { super(pkg); try { MsiVersion.of(pkg.version()); } catch (IllegalArgumentException ex) { - throw new ConfigException(ex.getMessage(), I18N.getString( - "error.version-string-wrong-format.advice"), ex); + throw ConfigException.build() + .causeAndMessage(ex) + .advice("error.version-string-wrong-format.advice") + .create(); } if (pkg.app().isService() && (serviceInstaller == null || !Files.exists(serviceInstaller))) { - throw new ConfigException(I18N.getString("error.missing-service-installer"), I18N - .getString("error.missing-service-installer.advice")); + throw ConfigException.build() + .message("error.missing-service-installer") + .advice("error.missing-service-installer.advice") + .create(); } this.withInstallDirChooser = withInstallDirChooser; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java index 518d6a9584b21..7d2e915ef1570 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java @@ -29,8 +29,7 @@ import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.ApplicationLayout; -import jdk.jpackage.internal.IOUtils; +import jdk.jpackage.internal.util.XmlUtils; import org.w3c.dom.Document; import org.xml.sax.SAXException; @@ -49,7 +48,7 @@ public AppImageFile(String mainLauncherName, String mainLauncherClassName) { } public void save(Path appImageDir) throws IOException { - IOUtils.createXml(getPathInAppImage(appImageDir), xml -> { + XmlUtils.createXml(getPathInAppImage(appImageDir), xml -> { xml.writeStartElement("jpackage-state"); xml.writeAttribute("version", getVersion()); xml.writeAttribute("platform", getPlatform()); @@ -78,7 +77,7 @@ public void save(Path appImageDir) throws IOException { public static AppImageFile load(Path appImageDir) { try { - Document doc = IOUtils.initDocumentBuilder().parse( + Document doc = XmlUtils.initDocumentBuilder().parse( Files.newInputStream(getPathInAppImage(appImageDir))); XPath xPath = XPathFactory.newInstance().newXPath(); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java new file mode 100644 index 0000000000000..3f1005b2496da --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import java.nio.file.Path; +import java.util.Optional; + +public record ApplicationLayout(Path launchersDirectory, Path appDirectory, + Path runtimeDirectory, Path runtimeHomeDirectory, Path appModsDirectory, + Path destktopIntegrationDirectory, Path contentDirectory) { + + public ApplicationLayout resolveAt(Path root) { + return new ApplicationLayout( + resolve(root, launchersDirectory), + resolve(root, appDirectory), + resolve(root, runtimeDirectory), + resolve(root, runtimeHomeDirectory), + resolve(root, appModsDirectory), + resolve(root, destktopIntegrationDirectory), + resolve(root, contentDirectory)); + } + + public static ApplicationLayout linuxAppImage() { + return new ApplicationLayout( + Path.of("bin"), + Path.of("lib/app"), + Path.of("lib/runtime"), + Path.of("lib/runtime"), + Path.of("lib"), + Path.of("lib/app/mods"), + Path.of("lib") + ); + } + + public static ApplicationLayout windowsAppImage() { + return new ApplicationLayout( + Path.of(""), + Path.of("app"), + Path.of("runtime"), + Path.of("runtime"), + Path.of(""), + Path.of("app/mods"), + Path.of("") + ); + } + + public static ApplicationLayout macAppImage() { + return new ApplicationLayout( + Path.of("Contents/MacOS"), + Path.of("Contents/app"), + Path.of("Contents/runtime"), + Path.of("Contents/runtime/Contents/Home"), + Path.of("Contents/Resources"), + Path.of("Contents/app/mods"), + Path.of("Contents") + ); + } + + public static ApplicationLayout platformAppImage() { + if (TKit.isWindows()) { + return windowsAppImage(); + } + + if (TKit.isLinux()) { + return linuxAppImage(); + } + + if (TKit.isOSX()) { + return macAppImage(); + } + + throw new IllegalArgumentException("Unknown platform"); + } + + public static ApplicationLayout javaRuntime() { + return new ApplicationLayout( + null, + null, + Path.of(""), + null, + null, + null, + null + ); + } + + public static ApplicationLayout linuxUsrTreePackageImage(Path prefix, + String packageName) { + final Path lib = prefix.resolve(Path.of("lib", packageName)); + return new ApplicationLayout( + prefix.resolve("bin"), + lib.resolve("app"), + lib.resolve("runtime"), + lib.resolve("runtime"), + lib, + lib.resolve("app/mods"), + lib + ); + } + + private static Path resolve(Path base, Path path) { + return Optional.ofNullable(path).map(base::resolve).orElse(null); + } +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java index 4908519782896..a3f5853f9e9d0 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java @@ -32,7 +32,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; -import jdk.jpackage.internal.IOUtils; +import jdk.jpackage.internal.util.PathUtils; final public class FileAssociations { @@ -79,7 +79,7 @@ Path getLinuxIconFileName() { if (icon == null) { return null; } - return Path.of(getMime().replace('/', '-') + IOUtils.getSuffix(icon)); + return Path.of(getMime().replace('/', '-') + PathUtils.getSuffix(icon)); } Path getPropertiesFile() { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index e86d1e4d5a233..7680bd2c3ee59 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -45,8 +45,6 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.ApplicationLayout; -import jdk.jpackage.internal.PackageFile; import static jdk.jpackage.test.AdditionalLauncher.forEachAdditionalLauncher; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.Functional.ThrowingFunction; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java index b7ebc4939ba38..69cf363aeef44 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java @@ -35,7 +35,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.IOUtils; +import jdk.jpackage.internal.util.PathUtils; import static jdk.jpackage.test.Functional.ThrowingConsumer.toConsumer; import static jdk.jpackage.test.PackageType.LINUX; import static jdk.jpackage.test.PackageType.MAC_PKG; @@ -335,7 +335,7 @@ private static void verifyMacDaemonPlistFile(JPackageCommand cmd, TKit.assertEquals(installedLauncherPath.toString(), args.get(0), "Check path to launcher in 'ProgramArguments' property in the property file"); - var expectedLabel = IOUtils.replaceSuffix(servicePlistFile.getFileName(), "").toString(); + var expectedLabel = PathUtils.replaceSuffix(servicePlistFile.getFileName(), "").toString(); TKit.assertEquals(expectedLabel, servicePlist.queryValue("Label"), "Check value of 'Label' property in the property file"); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index 402b409788248..5fa26c8f022c6 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -40,8 +40,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.ApplicationLayout; -import jdk.jpackage.internal.IOUtils; +import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.PackageTest.PackageHandlers; @@ -578,7 +577,7 @@ private static String queryMimeTypeDefaultHandler(String mimeType) { private static void verifyIconInScriptlet(Scriptlet scriptletType, List scriptletBody, Path iconPathInPackage) { - final String dashMime = IOUtils.replaceSuffix( + final String dashMime = PathUtils.replaceSuffix( iconPathInPackage.getFileName(), null).toString(); final String xdgCmdName = "xdg-icon-resource"; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index ded548aface4d..af7b01ace5f38 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -42,11 +42,11 @@ import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.IOUtils; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.Functional.ThrowingSupplier; import jdk.jpackage.test.PackageTest.PackageHandlers; import jdk.jpackage.internal.RetryExecutor; +import jdk.jpackage.internal.util.PathUtils; import org.xml.sax.SAXException; import org.w3c.dom.NodeList; @@ -211,7 +211,7 @@ static PackageHandlers createPkgPackageHandlers() { // Unpack all ".pkg" files from $dataDir folder in $unpackDir folder try (var dataListing = Files.list(dataDir)) { dataListing.filter(file -> { - return ".pkg".equals(IOUtils.getSuffix(file.getFileName())); + return ".pkg".equals(PathUtils.getSuffix(file.getFileName())); }).forEach(ThrowingConsumer.toConsumer(pkgDir -> { // Installation root of the package is stored in // /pkg-info@install-location attribute in $pkgDir/PackageInfo xml file diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageFile.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageFile.java new file mode 100644 index 0000000000000..a0285201174f4 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageFile.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import java.nio.file.Path; + +public class PackageFile { + + public static Path getPathInAppImage(Path appImageDir) { + return ApplicationLayout.platformAppImage() + .resolveAt(appImageDir) + .appDirectory() + .resolve(FILENAME); + } + + private static final String FILENAME = ".package"; +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index d597c62d83f17..3f3766b686e28 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -22,7 +22,6 @@ */ package jdk.jpackage.test; -import java.awt.Desktop; import java.awt.GraphicsEnvironment; import java.io.File; import java.io.IOException; @@ -47,7 +46,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; -import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.test.Functional.ThrowingBiConsumer; import static jdk.jpackage.test.Functional.ThrowingBiConsumer.toBiConsumer; import jdk.jpackage.test.Functional.ThrowingConsumer; diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java index 53fe04509b03c..6b5a45c356446 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java @@ -22,6 +22,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.PackagerException; import java.nio.file.Path; import java.io.IOException; import org.hamcrest.BaseMatcher; diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java index b17a98a178330..00d2deccf4b86 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java @@ -22,6 +22,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.DottedVersion; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java index eaddbb9eaa94b..a9329de98bed5 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java @@ -23,6 +23,8 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.DottedVersion; import java.nio.file.Path; import jdk.internal.util.OperatingSystem; import static org.hamcrest.CoreMatchers.is; @@ -54,11 +56,11 @@ public void testVersionParserUsage() { // Minimal version is 1, actual is 10. Should be OK. assertNull(new ToolValidator(TOOL_JAVA).setMinimalVersion( - new DottedVersion("1")).setVersionParser(unused -> "10").validate()); + DottedVersion.greedy("1")).setVersionParser(unused -> "10").validate()); // Minimal version is 5, actual is 4.99.37. Error expected. assertValidationFailure(new ToolValidator(TOOL_JAVA).setMinimalVersion( - new DottedVersion("5")).setVersionParser(unused -> "4.99.37").validate(), + DottedVersion.greedy("5")).setVersionParser(unused -> "4.99.37").validate(), false); // Minimal version is 8, actual is 10, lexicographical comparison is used. Error expected. @@ -67,14 +69,14 @@ public void testVersionParserUsage() { // Minimal version is 8, actual is 10, Use DottedVersion class for comparison. Should be OK. assertNull(new ToolValidator(TOOL_JAVA).setMinimalVersion( - new DottedVersion("8")).setVersionParser(unused -> "10").validate()); + DottedVersion.greedy("8")).setVersionParser(unused -> "10").validate()); } private static void assertValidationFailure(ConfigException v, boolean withCause) { assertNotNull(v); assertThat("", is(not(v.getMessage().strip()))); - assertThat("", is(not(v.advice.strip()))); + assertThat("", is(not(v.getAdvice().strip()))); if (withCause) { assertNotNull(v.getCause()); } else { diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ApplicationLayoutTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java similarity index 97% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ApplicationLayoutTest.java rename to test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java index b047a6d64d710..63447ffd5f7c9 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ApplicationLayoutTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java @@ -21,8 +21,9 @@ * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; +import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/CompareDottedVersionTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/CompareDottedVersionTest.java similarity index 99% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/CompareDottedVersionTest.java rename to test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/CompareDottedVersionTest.java index d77b4e85eb718..68efc557949a4 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/CompareDottedVersionTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/CompareDottedVersionTest.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.util.ArrayList; import java.util.List; diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/DottedVersionTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java similarity index 98% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/DottedVersionTest.java rename to test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java index 0443fdf64e7ea..d3a87d2749b51 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/DottedVersionTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java @@ -20,8 +20,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; +import jdk.jpackage.internal.model.DottedVersion; import java.util.Collections; import java.util.List; import java.util.function.Function; diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/InvalidDottedVersionTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/InvalidDottedVersionTest.java similarity index 94% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/InvalidDottedVersionTest.java rename to test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/InvalidDottedVersionTest.java index b0b866e41fbbe..31e5f074a6099 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/InvalidDottedVersionTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/InvalidDottedVersionTest.java @@ -20,8 +20,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; +import jdk.jpackage.internal.model.DottedVersion; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -65,7 +66,7 @@ public static List data() { @Test public void testIt() { exceptionRule.expect(IllegalArgumentException.class); - new DottedVersion(version); + DottedVersion.greedy(version); } private final String version; diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/OverridableResourceTest.java similarity index 94% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java rename to test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/OverridableResourceTest.java index 02bb56c7d7fb6..b470fa95a2796 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/OverridableResourceTest.java @@ -21,8 +21,9 @@ * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; +import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; @@ -53,7 +54,7 @@ public class OverridableResourceTest { @Test public void testDefault() throws IOException { - byte[] actualBytes = saveToFile(new OverridableResource(DEFAULT_NAME)); + byte[] actualBytes = saveToFile(new OverridableResource(DEFAULT_NAME, ResourceLocator.class)); try (InputStream is = ResourceLocator.class.getResourceAsStream( DEFAULT_NAME)) { @@ -63,7 +64,7 @@ public void testDefault() throws IOException { @Test public void testDefaultWithSubstitution() throws IOException { - OverridableResource resource = new OverridableResource(DEFAULT_NAME); + OverridableResource resource = new OverridableResource(DEFAULT_NAME, ResourceLocator.class); List linesBeforeSubstitution = convertToStringList(saveToFile( resource)); @@ -119,7 +120,7 @@ private void testCustom(String defaultName) throws IOException { Path customFile = createCustomFile("foo", expectedResourceData); List actualResourceData = convertToStringList(saveToFile( - new OverridableResource(defaultName) + new OverridableResource(defaultName, ResourceLocator.class) .setPublicName(customFile.getFileName()) .setResourceDir(customFile.getParent()))); @@ -150,7 +151,7 @@ private void testCustomtWithSubstitution(String defaultName) throws IOException "Bar", "Bar", "Goodbye", "JJ"); final List actualResourceData = convertToStringList(saveToFile( - new OverridableResource(defaultName) + new OverridableResource(defaultName, ResourceLocator.class) .setPublicName(customFile.getFileName()) .setSubstitutionData(substitutionData) .setResourceDir(customFile.getParent()))); @@ -159,7 +160,7 @@ private void testCustomtWithSubstitution(String defaultName) throws IOException // Don't call setPublicName() final Path dstFile = tempFolder.newFolder().toPath().resolve(customFile.getFileName()); - new OverridableResource(defaultName) + new OverridableResource(defaultName, ResourceLocator.class) .setSubstitutionData(substitutionData) .setResourceDir(customFile.getParent()) .saveToFile(dstFile); @@ -169,7 +170,7 @@ private void testCustomtWithSubstitution(String defaultName) throws IOException // Verify setSubstitutionData() stores a copy of passed in data Map substitutionData2 = new HashMap(substitutionData); - var resource = new OverridableResource(defaultName) + var resource = new OverridableResource(defaultName, ResourceLocator.class) .setResourceDir(customFile.getParent()); resource.setSubstitutionData(substitutionData2); @@ -186,7 +187,7 @@ public void testNoDefault() throws IOException { Path dstFolder = tempFolder.newFolder().toPath(); Path dstFile = dstFolder.resolve(Path.of("foo", "bar")); - new OverridableResource(null).saveToFile(dstFile); + new OverridableResource().saveToFile(dstFile); assertFalse(dstFile.toFile().exists()); } diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PathGroupTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java similarity index 99% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PathGroupTest.java rename to test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java index c14bdf3cb60e1..c4d039d52e164 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PathGroupTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java @@ -21,7 +21,7 @@ * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.util; import java.io.IOException; import java.nio.file.Files; diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java index 48f5dca898640..8b6ce291e1746 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java @@ -22,7 +22,6 @@ */ import java.nio.file.Path; -import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.TKit; import jdk.jpackage.test.PackageTest; @@ -30,6 +29,7 @@ import jdk.jpackage.test.MacHelper; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.ApplicationLayout; /** * Tests generation of dmg and pkg from signed predefined app image which was diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java index c555b0386cde3..cbd76158ae0cc 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java @@ -22,13 +22,13 @@ */ import java.nio.file.Path; -import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; import jdk.jpackage.test.MacHelper; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.ApplicationLayout; /** * Tests generation of dmg and pkg with --mac-sign and related arguments. diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java index a34f7921b9126..22c2339dd4d40 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java @@ -22,7 +22,6 @@ */ import java.nio.file.Path; -import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.TKit; import jdk.jpackage.test.PackageTest; @@ -30,6 +29,7 @@ import jdk.jpackage.test.MacHelper; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.ApplicationLayout; /** * Note: Testing unsgined app image is done to verify support for per-user diff --git a/test/jdk/tools/jpackage/macosx/base/SigningCheck.java b/test/jdk/tools/jpackage/macosx/base/SigningCheck.java index 4ba2763804f06..270c563fd9a1e 100644 --- a/test/jdk/tools/jpackage/macosx/base/SigningCheck.java +++ b/test/jdk/tools/jpackage/macosx/base/SigningCheck.java @@ -22,10 +22,6 @@ */ import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.io.IOException; import jdk.jpackage.test.TKit; import jdk.jpackage.test.Executor; diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java index a343e20d8a748..38c67e814aaa0 100644 --- a/test/jdk/tools/jpackage/share/AppContentTest.java +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -22,19 +22,16 @@ */ import java.nio.file.Path; -import java.nio.file.Files; -import jdk.jpackage.internal.ApplicationLayout; -import jdk.jpackage.test.PackageTest; -import jdk.jpackage.test.PackageType; -import jdk.jpackage.test.TKit; -import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Annotations.Parameter; -import jdk.jpackage.test.Annotations.Parameters; import java.util.Arrays; import java.util.Collection; import java.util.List; - import jdk.internal.util.OSVersion; +import jdk.jpackage.test.Annotations.Parameters; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.ApplicationLayout; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.TKit; + /** * Tests generation of packages with input folder containing empty folders. diff --git a/test/jdk/tools/jpackage/share/EmptyFolderPackageTest.java b/test/jdk/tools/jpackage/share/EmptyFolderPackageTest.java index c7af050c6850f..0132f0dc54c21 100644 --- a/test/jdk/tools/jpackage/share/EmptyFolderPackageTest.java +++ b/test/jdk/tools/jpackage/share/EmptyFolderPackageTest.java @@ -22,10 +22,10 @@ */ import java.nio.file.Path; -import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.ApplicationLayout; /** * Tests generation of packages with input folder containing empty folders. diff --git a/test/jdk/tools/jpackage/share/EmptyFolderTest.java b/test/jdk/tools/jpackage/share/EmptyFolderTest.java index a41c4a66702d1..28e5750bcf578 100644 --- a/test/jdk/tools/jpackage/share/EmptyFolderTest.java +++ b/test/jdk/tools/jpackage/share/EmptyFolderTest.java @@ -24,7 +24,7 @@ import java.nio.file.Path; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.internal.ApplicationLayout; +import jdk.jpackage.test.ApplicationLayout; /** * Tests generation of app image with input folder containing empty folders. diff --git a/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java b/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java index 1726fe3eac69e..6575a5e8e1a1c 100644 --- a/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java +++ b/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java @@ -21,20 +21,11 @@ * questions. */ -import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.test.TKit; -import jdk.jpackage.test.PackageTest; -import jdk.jpackage.test.PackageType; -import jdk.jpackage.test.Functional; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.ApplicationLayout; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JavaTool; import jdk.jpackage.test.Executor; diff --git a/test/jdk/tools/jpackage/windows/WinLongVersionTest.java b/test/jdk/tools/jpackage/windows/WinLongVersionTest.java index 5181a89e6b637..36cfd9b110cf0 100644 --- a/test/jdk/tools/jpackage/windows/WinLongVersionTest.java +++ b/test/jdk/tools/jpackage/windows/WinLongVersionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Set; import java.util.UUID; import java.util.function.Supplier; import javax.xml.transform.Result; @@ -36,7 +35,7 @@ import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.IOUtils; +import jdk.jpackage.internal.util.XmlUtils; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Executor; import jdk.jpackage.test.PackageTest; @@ -150,7 +149,7 @@ public static void test() throws IOException { Path scriptPath = resourceDir.resolve(String.format( "%s-post-msi.wsf", cmd.name())); - IOUtils.createXml(scriptPath, xml -> { + XmlUtils.createXml(scriptPath, xml -> { xml.writeStartElement("job"); xml.writeAttribute("id", "main"); xml.writeStartElement("script"); @@ -196,7 +195,7 @@ public static void testNoUpgradeTable() throws IOException { cmd.setFakeRuntime(); // Create package without Upgrade table - Document doc = IOUtils.initDocumentBuilder().parse( + Document doc = XmlUtils.initDocumentBuilder().parse( Files.newInputStream(TKit.SRC_ROOT.resolve( "windows/classes/jdk/jpackage/internal/resources/main.wxs"))); XPath xPath = XPathFactory.newInstance().newXPath(); diff --git a/test/jdk/tools/jpackage/windows/WinScriptTest.java b/test/jdk/tools/jpackage/windows/WinScriptTest.java index 775102cd0141c..9c31d3908c9c3 100644 --- a/test/jdk/tools/jpackage/windows/WinScriptTest.java +++ b/test/jdk/tools/jpackage/windows/WinScriptTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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,8 +24,7 @@ import java.io.IOException; import java.nio.file.Path; import java.util.List; -import java.util.ArrayList; -import jdk.jpackage.internal.IOUtils; +import jdk.jpackage.internal.util.XmlUtils; import jdk.jpackage.test.TKit; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; @@ -148,7 +147,7 @@ void assertJPackageOutput(List output) { } void createScript(JPackageCommand cmd) throws IOException { - IOUtils.createXml(Path.of(cmd.getArgumentValue("--resource-dir"), + XmlUtils.createXml(Path.of(cmd.getArgumentValue("--resource-dir"), String.format("%s-%s.wsf", cmd.name(), scriptSuffixName)), xml -> { xml.writeStartElement("job"); xml.writeAttribute("id", "main"); From 7f9586ea2a7172f37eda90a7abf4968f578fcb0e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 30 Oct 2024 17:00:55 -0400 Subject: [PATCH 0082/1101] Remove duplicated import --- test/jdk/tools/jpackage/share/EmptyFolderTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/test/jdk/tools/jpackage/share/EmptyFolderTest.java b/test/jdk/tools/jpackage/share/EmptyFolderTest.java index c9e82e2e9af5b..9eb5ffea47f57 100644 --- a/test/jdk/tools/jpackage/share/EmptyFolderTest.java +++ b/test/jdk/tools/jpackage/share/EmptyFolderTest.java @@ -29,7 +29,6 @@ import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.ApplicationLayout; -import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; /** From 2faab33946a9c5f915af5490d0066014ff61bce0 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 30 Oct 2024 17:10:53 -0400 Subject: [PATCH 0083/1101] Bad merge fix --- test/jdk/tools/jpackage/share/AppContentTest.java | 9 ++++++--- test/jdk/tools/jpackage/share/EmptyFolderTest.java | 3 +-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java index 4fb9c05a6f144..d00cc3701cc3b 100644 --- a/test/jdk/tools/jpackage/share/AppContentTest.java +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -27,10 +27,13 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -import jdk.internal.util.OSVersion; +import static java.util.stream.Collectors.joining; +import java.util.stream.Stream; +import static jdk.jpackage.internal.util.FileUtils.copyRecursive; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.ApplicationLayout; +import jdk.jpackage.test.Functional.ThrowingFunction; +import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.TKit; @@ -148,7 +151,7 @@ private static Path copyAppContentPath(Path appContentPath) throws IOException { var srcPath = TKit.TEST_SRC_ROOT.resolve(appContentPath); var dstPath = appContentArg.resolve(srcPath.getFileName()); Files.createDirectories(dstPath.getParent()); - IOUtils.copyRecursive(srcPath, dstPath); + copyRecursive(srcPath, dstPath); return appContentArg; } diff --git a/test/jdk/tools/jpackage/share/EmptyFolderTest.java b/test/jdk/tools/jpackage/share/EmptyFolderTest.java index 9eb5ffea47f57..1b8d47d5a4193 100644 --- a/test/jdk/tools/jpackage/share/EmptyFolderTest.java +++ b/test/jdk/tools/jpackage/share/EmptyFolderTest.java @@ -25,10 +25,9 @@ import java.nio.file.Files; import java.nio.file.Path; import jdk.jpackage.test.PackageTest; -import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.ApplicationLayout; +import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; /** From b67175fee627f74eeae0b235e042007faaa8bf4d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 1 Nov 2024 17:56:52 -0400 Subject: [PATCH 0084/1101] Clean model interfaces from implementation details. Added a number of builder class to create launcher, application, package, etc. model types. --- .../jpackage/internal/LinuxAppBundler.java | 2 +- .../internal/LinuxApplicationFromParams.java | 59 ----- .../jpackage/internal/LinuxDebBundler.java | 2 +- ...arams.java => LinuxDebPackageBuilder.java} | 37 +-- .../jpackage/internal/LinuxFromParams.java | 130 +++++++++++ .../internal/LinuxPackageBuilder.java | 136 +++++++++++ .../internal/LinuxPackageFromParams.java | 72 ------ .../jpackage/internal/LinuxRpmBundler.java | 2 +- ...arams.java => LinuxRpmPackageBuilder.java} | 39 ++-- .../internal/model/LinuxApplication.java | 4 +- .../internal/model/LinuxDebPackage.java | 10 +- .../internal/model/LinuxLauncher.java | 2 +- .../jpackage/internal/model/LinuxPackage.java | 80 +------ .../internal/model/LinuxRpmPackage.java | 13 +- .../internal/MacLaunchersAsServices.java | 2 +- .../internal/model/MacApplication.java | 0 .../internal/AbstractAppImageBuilder.java | 3 +- .../jdk/jpackage/internal/AppImageFile2.java | 13 +- .../jpackage/internal/ApplicationBuilder.java | 148 ++++++++++++ .../internal/ApplicationFromParams.java | 150 ------------ .../jpackage/internal/BuildEnvFromParams.java | 9 +- .../jdk/jpackage/internal/FromParams.java | 177 +++++++++++++++ .../jpackage/internal/LauncherBuilder.java | 151 +++++++++++++ .../jpackage/internal/LauncherFromParams.java | 46 ++-- .../internal/LauncherStartupInfoBuilder.java | 89 ++++++++ .../LauncherStartupInfoFromParams.java | 55 ----- .../jdk/jpackage/internal/PackageBuilder.java | 213 ++++++++++++++++++ .../jpackage/internal/PackageFromParams.java | 79 ------- .../internal/RuntimeBuilderBuilder.java | 177 +++++++++++++++ .../internal/RuntimeBuilderFromParams.java | 64 ------ .../jpackage/internal/model/Application.java | 52 +---- .../internal/model/ApplicationLaunchers.java | 62 +++++ .../internal/model/FileAssociation.java | 38 ---- .../jdk/jpackage/internal/model/Launcher.java | 39 +--- .../model/LauncherJarStartupInfo.java | 2 +- .../model/LauncherModularStartupInfo.java | 2 +- .../internal/model/LauncherStartupInfo.java | 6 +- .../jdk/jpackage/internal/model/Package.java | 134 +---------- .../internal/model/RuntimeBuilder.java | 49 ---- .../jdk/jpackage/internal/WinAppBundler.java | 2 +- .../internal/WinApplicationFromParams.java | 90 -------- .../jdk/jpackage/internal/WinExeBundler.java | 4 +- .../internal/WinExePackageBuilder.java} | 56 ++--- .../jdk/jpackage/internal/WinFromParams.java | 185 +++++++++++++++ .../jdk/jpackage/internal/WinMsiBundler.java | 4 +- .../internal/WinMsiPackageBuilder.java | 140 ++++++++++++ .../internal/WinMsiPackageFromParams.java | 116 ---------- .../jpackage/internal/model/MsiVersion.java | 4 +- .../internal/model/WinApplication.java | 2 +- .../internal/model/WinExePackage.java | 5 +- .../jpackage/internal/model/WinLauncher.java | 26 ++- .../internal/model/WinMsiPackage.java | 44 ++-- 52 files changed, 1813 insertions(+), 1213 deletions(-) delete mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java rename src/jdk.jpackage/linux/classes/jdk/jpackage/internal/{LinuxRpmPackageFromParams.java => LinuxDebPackageBuilder.java} (60%) create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java delete mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java rename src/jdk.jpackage/linux/classes/jdk/jpackage/internal/{LinuxDebPackageFromParams.java => LinuxRpmPackageBuilder.java} (58%) rename src/jdk.jpackage/{share => macosx}/classes/jdk/jpackage/internal/model/MacApplication.java (100%) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderFromParams.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java delete mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java rename src/jdk.jpackage/{share/classes/jdk/jpackage/internal/PlatformPackage.java => windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java} (61%) create mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java create mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java delete mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java index affdc1bca88df..d6d17f747f261 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java @@ -29,7 +29,7 @@ public class LinuxAppBundler extends AppImageBundler { public LinuxAppBundler() { setAppImageSupplier((params, output) -> { // Order is important! - var app = LinuxApplicationFromParams.APPLICATION.fetchFrom(params); + var app = LinuxFromParams.APPLICATION.fetchFrom(params); var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); LinuxAppImageBuilder.build().create(app).execute(BuildEnv.withAppImageDir(env, output)); }); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java deleted file mode 100644 index 2c0ce4628cee5..0000000000000 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationFromParams.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal; - -import jdk.jpackage.internal.model.LinuxApplication; -import jdk.jpackage.internal.model.LinuxLauncher; -import java.util.Map; -import java.util.stream.Stream; -import static jdk.jpackage.internal.ApplicationFromParams.createBundlerParam; -import jdk.jpackage.internal.model.LinuxApplication.Impl; -import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; - -final class LinuxApplicationFromParams { - - private static LinuxLauncher createLauncher(Map params) { - var launcher = new LauncherFromParams().create(params); - var shortcut = Stream.of(SHORTCUT_HINT, LINUX_SHORTCUT_HINT).filter(param -> { - return params.containsKey(param.getID()); - }).map(param -> { - return param.fetchFrom(params); - }).findFirst(); - return new LinuxLauncher.Impl(launcher, shortcut); - } - - static final BundlerParamInfo APPLICATION = createBundlerParam(params -> { - var app = new ApplicationFromParams(LinuxApplicationFromParams::createLauncher).create(params); - return new Impl(app); - }); - - private static final BundlerParamInfo LINUX_SHORTCUT_HINT = new BundlerParamInfo<>( - Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(), - Boolean.class, - params -> false, - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) - ? false : Boolean.valueOf(s) - ); -} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index cf0b8d0556fd5..159aed254c2fe 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -62,7 +62,7 @@ public class LinuxDebBundler extends LinuxPackageBundler { private static final String TOOL_FAKEROOT = "fakeroot"; public LinuxDebBundler() { - super(LinuxDebPackageFromParams.PACKAGE); + super(LinuxFromParams.DEB_PACKAGE); } @Override diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java similarity index 60% rename from src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java rename to src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java index c69a68194e9b1..4a57ba2406a43 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java @@ -24,27 +24,36 @@ */ package jdk.jpackage.internal; +import java.util.Objects; +import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxRpmPackage; -import java.util.Map; -import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; -import jdk.jpackage.internal.model.LinuxRpmPackage.Impl; -import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; -final class LinuxRpmPackageFromParams { +final class LinuxDebPackageBuilder { - private static LinuxRpmPackage create(Map params) throws ConfigException { - var pkg = LinuxPackageFromParams.create(params, LINUX_RPM); + LinuxDebPackageBuilder(LinuxPackageBuilder pkgBuilder) { + Objects.requireNonNull(pkgBuilder); + this.pkgBuilder = pkgBuilder; + } - var licenseType = LICENSE_TYPE.fetchFrom(params); + LinuxRpmPackage create() throws ConfigException { + var pkg = pkgBuilder.create(); + return new LinuxRpmPackage.Impl( + pkg, + Optional.ofNullable(maintainerEmail).orElseGet(DEFAULTS::maintainerEmail)); + } - return new Impl(pkg, licenseType); + LinuxDebPackageBuilder maintainerEmail(String v) { + maintainerEmail = v; + return this; } - static final BundlerParamInfo PACKAGE = createBundlerParam( - LinuxRpmPackageFromParams::create); + private record Defaults(String maintainerEmail) { + } + + private String maintainerEmail; + + private final LinuxPackageBuilder pkgBuilder; - private static final BundlerParamInfo LICENSE_TYPE = createStringBundlerParam( - Arguments.CLIOptions.LINUX_RPM_LICENSE_TYPE.getId()); + private static final Defaults DEFAULTS = new Defaults("Unknown"); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java new file mode 100644 index 0000000000000..91ce997a8cf0c --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.io.IOException; +import jdk.jpackage.internal.model.ConfigException; +import java.util.Map; +import java.util.stream.Stream; +import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; +import static jdk.jpackage.internal.FromParams.createApplicationBuilder; +import static jdk.jpackage.internal.FromParams.createApplicationBundlerParam; +import static jdk.jpackage.internal.FromParams.createPackageBuilder; +import static jdk.jpackage.internal.FromParams.createPackageBundlerParam; +import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; +import jdk.jpackage.internal.model.LinuxApplication; +import jdk.jpackage.internal.model.LinuxLauncher; +import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.StandardPackageType; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; + +final class LinuxFromParams { + + private static LinuxApplication createLinuxApplication( + Map params) throws ConfigException, IOException { + var launcherFromParams = new LauncherFromParams(); + var app = createApplicationBuilder(params, toFunction(launcherParams -> { + var launcher = launcherFromParams.create(params); + var shortcut = Stream.of(SHORTCUT_HINT, LINUX_SHORTCUT_HINT).filter(param -> { + return params.containsKey(param.getID()); + }).map(param -> { + return param.fetchFrom(params); + }).findFirst(); + return new LinuxLauncher.Impl(launcher, shortcut); + })).create(); + return new LinuxApplication.Impl(app); + } + + private static LinuxPackageBuilder createLinuxPackageBuilder( + Map params, StandardPackageType type) throws ConfigException, IOException { + + var app = createLinuxApplication(params); + + var pkgBuilder = createPackageBuilder(params, app, type) + .name(LINUX_PACKAGE_NAME.fetchFrom(params)); + + return new LinuxPackageBuilder(pkgBuilder) + .additionalDependencies(LINUX_PACKAGE_DEPENDENCIES.fetchFrom(params)) + .category(LINUX_CATEGORY.fetchFrom(params)) + .menuGroupName(LINUX_MENU_GROUP.fetchFrom(params)) + .release(RELEASE.fetchFrom(params)); + } + + private static LinuxPackage createLinuxRpmPackage( + Map params) throws ConfigException, IOException { + var pkgBuilder = createLinuxPackageBuilder(params, LINUX_RPM); + return new LinuxRpmPackageBuilder(pkgBuilder) + .licenseType(LICENSE_TYPE.fetchFrom(params)) + .create(); + } + + private static LinuxPackage createLinuxDebPackage( + Map params) throws ConfigException, IOException { + var pkgBuilder = createLinuxPackageBuilder(params, LINUX_DEB); + return new LinuxDebPackageBuilder(pkgBuilder) + .maintainerEmail(MAINTAINER_EMAIL.fetchFrom(params)) + .create(); + } + + static final BundlerParamInfo APPLICATION = createApplicationBundlerParam( + LinuxFromParams::createLinuxApplication); + + static final BundlerParamInfo RPM_PACKAGE = createPackageBundlerParam( + LinuxFromParams::createLinuxRpmPackage); + + static final BundlerParamInfo DEB_PACKAGE = createPackageBundlerParam( + LinuxFromParams::createLinuxDebPackage); + + private static final BundlerParamInfo LINUX_SHORTCUT_HINT = new BundlerParamInfo<>( + Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(), + Boolean.class, + params -> false, + (s, p) -> (s == null || "null".equalsIgnoreCase(s)) + ? false : Boolean.valueOf(s) + ); + + private static final BundlerParamInfo LINUX_CATEGORY = createStringBundlerParam( + Arguments.CLIOptions.LINUX_CATEGORY.getId()); + + private static final BundlerParamInfo LINUX_PACKAGE_DEPENDENCIES = createStringBundlerParam( + Arguments.CLIOptions.LINUX_PACKAGE_DEPENDENCIES.getId()); + + private static final BundlerParamInfo LINUX_MENU_GROUP = createStringBundlerParam( + Arguments.CLIOptions.LINUX_MENU_GROUP.getId()); + + private static final BundlerParamInfo RELEASE = createStringBundlerParam( + Arguments.CLIOptions.RELEASE.getId()); + + private static final BundlerParamInfo LINUX_PACKAGE_NAME = createStringBundlerParam( + Arguments.CLIOptions.LINUX_BUNDLE_NAME.getId()); + + private static final BundlerParamInfo LICENSE_TYPE = createStringBundlerParam( + Arguments.CLIOptions.LINUX_RPM_LICENSE_TYPE.getId()); + + private static final BundlerParamInfo MAINTAINER_EMAIL = createStringBundlerParam( + Arguments.CLIOptions.LINUX_DEB_MAINTAINER.getId()); +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java new file mode 100644 index 0000000000000..9a8d26666360a --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Pattern; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.StandardPackageType; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; + +final class LinuxPackageBuilder { + + LinuxPackageBuilder(PackageBuilder pkgBuilder) { + Objects.requireNonNull(pkgBuilder); + this.pkgBuilder = pkgBuilder; + } + + LinuxPackage create() throws ConfigException { + if (pkgBuilder.isNameDefault()) { + // Lower case and turn spaces/underscores into dashes + pkgBuilder.name(pkgBuilder.create().packageName().toLowerCase().replaceAll("[ _]", "-")); + } + + var pkg = pkgBuilder.create(); + + validatePackageName(pkg.packageName(), pkg.asStandardPackageType()); + + return new LinuxPackage.Impl(pkg, + Optional.ofNullable(menuGroupName).orElseGet(DEFAULTS::menuGroupName), + Optional.ofNullable(category).orElseGet(DEFAULTS::category), + additionalDependencies, + Optional.ofNullable(release).orElseGet(DEFAULTS::release), + LinuxPackageArch.getValue(pkg.asStandardPackageType())); + } + + LinuxPackageBuilder menuGroupName(String v) { + menuGroupName = v; + return this; + } + + LinuxPackageBuilder category(String v) { + category = v; + return this; + } + + LinuxPackageBuilder additionalDependencies(String v) { + additionalDependencies = v; + return this; + } + + LinuxPackageBuilder release(String v) { + release = v; + return this; + } + + private static void validatePackageName(String packageName, + StandardPackageType pkgType) throws ConfigException { + switch (pkgType) { + case LINUX_DEB -> { + // + // Debian rules for package naming are used here + // https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Source + // + // Package names must consist only of lower case letters (a-z), + // digits (0-9), plus (+) and minus (-) signs, and periods (.). + // They must be at least two characters long and + // must start with an alphanumeric character. + // + var regexp = Pattern.compile("^[a-z][a-z\\d\\+\\-\\.]+"); + if (!regexp.matcher(packageName).matches()) { + throw ConfigException.build() + .message(I18N.format("error.deb-invalid-value-for-package-name", packageName)) + .advice(I18N.getString("error.deb-invalid-value-for-package-name.advice")) + .create(); + } + } + case LINUX_RPM -> { + // + // Fedora rules for package naming are used here + // https://fedoraproject.org/wiki/Packaging:NamingGuidelines?rd=Packaging/NamingGuidelines + // + // all Fedora packages must be named using only the following ASCII + // characters. These characters are displayed here: + // + // abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._+ + // + var regexp = Pattern.compile("[a-z\\d\\+\\-\\.\\_]+", Pattern.CASE_INSENSITIVE); + if (!regexp.matcher(packageName).matches()) { + throw ConfigException.build() + .message(I18N.format("error.rpm-invalid-value-for-package-name", packageName)) + .advice(I18N.getString("error.rpm-invalid-value-for-package-name.advice")) + .create(); + } + } + } + } + + private record Defaults(String release, String menuGroupName, String category) { + } + + private String menuGroupName; + private String category; + private String additionalDependencies; + private String release; + + private final PackageBuilder pkgBuilder; + + private static final Defaults DEFAULTS = new Defaults("1", I18N.getString( + "param.menu-group.default"), "misc"); + +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java deleted file mode 100644 index de23f9ee60832..0000000000000 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageFromParams.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal; - -import jdk.jpackage.internal.model.LinuxPackage; -import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.ConfigException; -import java.util.Map; -import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; -import jdk.jpackage.internal.model.LinuxPackage.Impl; -import jdk.jpackage.internal.model.StandardPackageType; - -final class LinuxPackageFromParams { - - static LinuxPackage create(Map params, StandardPackageType pkgType) throws ConfigException { - var pkg = PackageFromParams.create(params, LinuxApplicationFromParams.APPLICATION, pkgType); - var menuGroupName = LINUX_MENU_GROUP.fetchFrom(params); - var category = LINUX_CATEGORY.fetchFrom(params); - var additionalDependencies = LINUX_PACKAGE_DEPENDENCIES.fetchFrom(params); - var release = RELEASE.fetchFrom(params); - - var packageName = LINUX_PACKAGE_NAME.fetchFrom(params); - if (packageName != null) { - pkg = Package.override(pkg, new Package.Unsupported() { - @Override - public String packageName() { - return packageName; - } - }); - } - - return new Impl(pkg, menuGroupName, category, additionalDependencies, - release, LinuxPackageArch.getValue(pkg.asStandardPackageType())); - } - - private static final BundlerParamInfo LINUX_CATEGORY = createStringBundlerParam( - Arguments.CLIOptions.LINUX_CATEGORY.getId()); - - private static final BundlerParamInfo LINUX_PACKAGE_DEPENDENCIES = createStringBundlerParam( - Arguments.CLIOptions.LINUX_PACKAGE_DEPENDENCIES.getId()); - - private static final BundlerParamInfo LINUX_MENU_GROUP = createStringBundlerParam( - Arguments.CLIOptions.LINUX_MENU_GROUP.getId()); - - private static final BundlerParamInfo RELEASE = createStringBundlerParam( - Arguments.CLIOptions.RELEASE.getId()); - - private static final BundlerParamInfo LINUX_PACKAGE_NAME = createStringBundlerParam( - Arguments.CLIOptions.LINUX_BUNDLE_NAME.getId()); -} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index 8d2672a1e86ac..ae3ac0b5219ba 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -66,7 +66,7 @@ public class LinuxRpmBundler extends LinuxPackageBundler { "4.10"); public LinuxRpmBundler() { - super(LinuxRpmPackageFromParams.PACKAGE); + super(LinuxFromParams.RPM_PACKAGE); } @Override diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java similarity index 58% rename from src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java rename to src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java index 345079db38254..4115de7b15314 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java @@ -24,26 +24,37 @@ */ package jdk.jpackage.internal; +import java.util.Objects; +import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.LinuxDebPackage; -import java.util.Map; -import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; -import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; +import jdk.jpackage.internal.model.LinuxRpmPackage; -final class LinuxDebPackageFromParams { +final class LinuxRpmPackageBuilder { - private static LinuxDebPackage create(Map params) throws ConfigException { - var pkg = LinuxPackageFromParams.create(params, LINUX_DEB); + LinuxRpmPackageBuilder(LinuxPackageBuilder pkgBuilder) { + Objects.requireNonNull(pkgBuilder); + this.pkgBuilder = pkgBuilder; + } - var maintainerEmail = MAINTAINER_EMAIL.fetchFrom(params); + LinuxRpmPackage create() throws ConfigException { + var pkg = pkgBuilder.create(); + return new LinuxRpmPackage.Impl( + pkg, + Optional.ofNullable(licenseType).orElseGet(DEFAULTS::licenseType)); + } - return new LinuxDebPackage.Impl(pkg, maintainerEmail); + LinuxRpmPackageBuilder licenseType(String v) { + licenseType = v; + return this; } - static final BundlerParamInfo PACKAGE = createBundlerParam( - LinuxDebPackageFromParams::create); + private record Defaults(String licenseType) { + } + + private String licenseType; + + private final LinuxPackageBuilder pkgBuilder; - private static final BundlerParamInfo MAINTAINER_EMAIL = createStringBundlerParam( - Arguments.CLIOptions.LINUX_DEB_MAINTAINER.getId()); + private static final Defaults DEFAULTS = new Defaults(I18N.getString( + "param.license-type.default")); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java index 041913d65a5fe..28bb9a0c09951 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java @@ -26,9 +26,9 @@ package jdk.jpackage.internal.model; public interface LinuxApplication extends Application { - public static class Impl extends Application.Proxy implements LinuxApplication { + class Impl extends Application.Proxy implements LinuxApplication { public Impl(Application app) { super(app); } } -} \ No newline at end of file +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java index 2f5ca2f0f5ebd..640034f2114a3 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; -import java.util.Optional; public interface LinuxDebPackage extends LinuxPackage { @@ -50,12 +49,11 @@ default Path relativeCopyrightFilePath() { } } - static class Impl extends LinuxPackage.Proxy implements LinuxDebPackage { + class Impl extends LinuxPackage.Proxy implements LinuxDebPackage { public Impl(LinuxPackage target, String maintainerEmail) { super(target); - this.maintainerEmail = Optional.ofNullable(maintainerEmail).orElseGet( - LinuxDebPackage.Defaults.INSTANCE::maintainerEmail); + this.maintainerEmail = maintainerEmail; } @Override @@ -65,8 +63,4 @@ public String maintainerEmail() { private final String maintainerEmail; } - - static record Defaults(String maintainerEmail) { - static final Defaults INSTANCE = new Defaults("Unknown"); - } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java index 2140d7b8789a9..01e284d7f3555 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java @@ -43,7 +43,7 @@ default String defaultIconResourceName() { return "JavaApp.png"; } - public static class Impl extends Launcher.Proxy implements LinuxLauncher { + class Impl extends Launcher.Proxy implements LinuxLauncher { public Impl(Launcher launcher, Optional shortcut) { super(launcher); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java index 41e94fcee0f13..0b39b423d0598 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java @@ -25,9 +25,6 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.Optional; -import java.util.regex.Pattern; public interface LinuxPackage extends Package { @@ -72,34 +69,14 @@ default boolean isInstallDirInUsrTree() { return !relativeInstallDir().getFileName().equals(Path.of(packageName())); } - public static class Impl extends Package.Proxy implements LinuxPackage { + class Impl extends Package.Proxy implements LinuxPackage { public Impl(Package target, String menuGroupName, String category, String additionalDependencies, String release, String arch) throws ConfigException { - super(Package.override(target, new Package.Unsupported() { - @Override - public String packageName() { - var packageName = target.packageName(); - if (target.type() instanceof StandardPackageType type) { - switch (type) { - case LINUX_DEB, LINUX_RPM -> { - // make sure to lower case and spaces/underscores become dashes - packageName = packageName.toLowerCase().replaceAll("[ _]", "-"); - } - } - } - return packageName; - } - })); - - if (type() instanceof StandardPackageType type) { - validatePackageName(packageName(), type); - } - - this.menuGroupName = Optional.ofNullable(menuGroupName).orElseGet(Defaults.INSTANCE::menuGroupName); - this.category = Optional.ofNullable(category).orElseGet(Defaults.INSTANCE::category); - this.release = Optional.ofNullable(release).orElseGet(Defaults.INSTANCE::release); - + super(target); + this.menuGroupName = menuGroupName; + this.category = category; + this.release = release; this.additionalDependencies = additionalDependencies; this.arch = arch; } @@ -136,7 +113,7 @@ public String arch() { private final String arch; } - static class Proxy extends Package.Proxy implements LinuxPackage { + class Proxy extends Package.Proxy implements LinuxPackage { public Proxy(T target) { super(target); @@ -167,49 +144,4 @@ public String arch() { return target.arch(); } } - - static record Defaults(String release, String menuGroupName, String category) { - private static final Defaults INSTANCE = new Defaults("1", - I18N.getString("param.menu-group.default"), "misc"); - } - - private static void validatePackageName(String packageName, - StandardPackageType pkgType) throws ConfigException { - switch (pkgType) { - case LINUX_DEB -> { - // - // Debian rules for package naming are used here - // https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Source - // - // Package names must consist only of lower case letters (a-z), - // digits (0-9), plus (+) and minus (-) signs, and periods (.). - // They must be at least two characters long and - // must start with an alphanumeric character. - // - var regexp = Pattern.compile("^[a-z][a-z\\d\\+\\-\\.]+"); - if (!regexp.matcher(packageName).matches()) { - throw new ConfigException(MessageFormat.format(I18N.getString( - "error.deb-invalid-value-for-package-name"), packageName), I18N - .getString("error.deb-invalid-value-for-package-name.advice")); - } - } - case LINUX_RPM -> { - // - // Fedora rules for package naming are used here - // https://fedoraproject.org/wiki/Packaging:NamingGuidelines?rd=Packaging/NamingGuidelines - // - // all Fedora packages must be named using only the following ASCII - // characters. These characters are displayed here: - // - // abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._+ - // - var regexp = Pattern.compile("[a-z\\d\\+\\-\\.\\_]+", Pattern.CASE_INSENSITIVE); - if (!regexp.matcher(packageName).matches()) { - throw new ConfigException(MessageFormat.format(I18N.getString( - "error.rpm-invalid-value-for-package-name"), packageName), I18N - .getString("error.rpm-invalid-value-for-package-name.advice")); - } - } - } - } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java index 9bf3235a0dd6e..d5e542f2fc58e 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java @@ -24,18 +24,15 @@ */ package jdk.jpackage.internal.model; -import java.util.Optional; - public interface LinuxRpmPackage extends LinuxPackage { String licenseType(); - public static class Impl extends LinuxPackage.Proxy implements LinuxRpmPackage { + class Impl extends LinuxPackage.Proxy implements LinuxRpmPackage { public Impl(LinuxPackage target, String licenseType) { super(target); - this.licenseType = Optional.ofNullable(licenseType).orElseGet( - LinuxRpmPackage.Defaults.INSTANCE::licenseType); + this.licenseType = licenseType; } @Override @@ -45,10 +42,4 @@ public String licenseType() { private final String licenseType; } - - static record Defaults(String licenseType) { - - private final static Defaults INSTANCE = new Defaults(I18N.getString( - "param.license-type.default")); - } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index ceb40945684f5..748605930f399 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -49,7 +49,7 @@ static ShellCustomAction create(Map params, Path outputDir) throws IOException { // Order is important! - var pkg = PackageFromParams.PACKAGE.fetchFrom(params); + var pkg = FromParams.PACKAGE.fetchFrom(params); var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); if (pkg.isRuntimeInstaller()) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/MacApplication.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java similarity index 100% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/MacApplication.java rename to src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java index 08b96802d982d..deba781566899 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java @@ -40,6 +40,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import jdk.jpackage.internal.resources.ResourceLocator; import jdk.jpackage.internal.util.FileUtils; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; /* * AbstractAppImageBuilder @@ -74,7 +75,7 @@ public String version() { }, new Launcher.Unsupported() { @Override public LauncherStartupInfo startupInfo() { - return LauncherStartupInfoFromParams.create(params); + return toSupplier(() -> new LauncherFromParams().create(params).startupInfo()).get(); } @Override diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index 26da22c785248..c831c55258af8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -93,6 +93,13 @@ String getAppVersion() { return appVersion; } + /** + * Returns application name. Never returns null or empty value. + */ + String getAppName() { + return launcherName; + } + /** * Returns main application launcher name. Never returns null or empty value. */ @@ -331,12 +338,16 @@ Map getExtra() { private final Set stdKeys; } - static record LauncherInfo(String name, boolean service, Map extra) { + record LauncherInfo(String name, boolean service, Map extra) { LauncherInfo { if (name == null || name.isBlank()) { throw new InavlidAppImageFileException(); } } + + Launcher asLauncher() { + return new Launcher.Impl(name, null, null, service, null, null); + } } private static class InavlidAppImageFileException extends RuntimeException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java new file mode 100644 index 0000000000000..03137b0b026ec --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import jdk.jpackage.internal.AppImageFile2.LauncherInfo; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLaunchers; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.RuntimeBuilder; + +final class ApplicationBuilder { + + Application create() throws ConfigException { + final var launchersAsList = Optional.ofNullable(launchers).map( + ApplicationLaunchers::asList).orElseGet(List::of); + final String effectiveName; + if (name != null) { + effectiveName = name; + } else if (!launchersAsList.isEmpty()) { + effectiveName = launchers.mainLauncher().name(); + } else { + throw ConfigException.build() + .message("error.no.name") + .advice("error.no.name.advice") + .create(); + } + + return new Application.Impl( + effectiveName, + Optional.ofNullable(description).orElseGet(DEFAULTS::description), + Optional.ofNullable(version).orElseGet(DEFAULTS::version), + Optional.ofNullable(vendor).orElseGet(DEFAULTS::vendor), + Optional.ofNullable(copyright).orElseGet(DEFAULTS::copyright), + srcDir, contentDirs, runtimeBuilder, launchersAsList); + } + + ApplicationBuilder runtimeBuilder(RuntimeBuilder v) { + runtimeBuilder = v; + return this; + } + + ApplicationBuilder initFromAppImage(AppImageFile2 appImageFile, + Function mapper) { + if (version == null) { + version = appImageFile.getAppVersion(); + } + if (name == null) { + name = appImageFile.getAppName(); + } + runtimeBuilder = null; + + var mainLauncherInfo = new LauncherInfo(appImageFile.getLauncherName(), false, Map.of()); + + launchers = new ApplicationLaunchers( + mapper.apply(mainLauncherInfo), + appImageFile.getAddLaunchers().stream().map(mapper).toList()); + + return this; + } + + ApplicationBuilder launchers(ApplicationLaunchers v) { + launchers = v; + return this; + } + + ApplicationBuilder name(String v) { + name = v; + return this; + } + + ApplicationBuilder description(String v) { + description = v; + return this; + } + + ApplicationBuilder version(String v) { + version = v; + return this; + } + + ApplicationBuilder vendor(String v) { + vendor = v; + return this; + } + + ApplicationBuilder copyright(String v) { + copyright = v; + return this; + } + + ApplicationBuilder srcDir(Path v) { + srcDir = v; + return this; + } + + ApplicationBuilder contentDirs(List v) { + contentDirs = v; + return this; + } + + private record Defaults(String description, String version, String vendor, String copyright) { + } + + private String name; + private String description; + private String version; + private String vendor; + private String copyright; + private Path srcDir; + private List contentDirs; + private RuntimeBuilder runtimeBuilder; + private ApplicationLaunchers launchers; + + private static final Defaults DEFAULTS = new Defaults( + I18N.getString("param.description.default"), + "1.0", + I18N.getString("param.vendor.default"), + I18N.format("param.copyright.default", new Date())); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java deleted file mode 100644 index 520715314333c..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationFromParams.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal; - -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.RuntimeBuilder; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Stream; -import jdk.jpackage.internal.util.function.ThrowingFunction; -import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; -import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.COPYRIGHT; -import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; -import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; -import static jdk.jpackage.internal.StandardBundlerParam.ICON; -import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; -import static jdk.jpackage.internal.StandardBundlerParam.SOURCE_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; -import static jdk.jpackage.internal.StandardBundlerParam.isRuntimeInstaller; - -record ApplicationFromParams( - Function, Launcher> launcherSupplier) { - - ApplicationFromParams { - Objects.requireNonNull(launcherSupplier); - } - - ApplicationFromParams() { - this(new LauncherFromParams()::create); - } - - Application create(Map params) throws ConfigException, IOException { - var name = APP_NAME.fetchFrom(params); - var description = DESCRIPTION.fetchFrom(params); - var version = VERSION.fetchFrom(params); - var vendor = VENDOR.fetchFrom(params); - var copyright = COPYRIGHT.fetchFrom(params); - var srcDir = SOURCE_DIR.fetchFrom(params); - var contentDirs = APP_CONTENT.fetchFrom(params); - - var predefinedAppImage = getPredefinedAppImage(params); - if (name == null && predefinedAppImage == null) { - // Can happen when no name is given, and using a foreign app-image - throw ConfigException.build() - .message("error.no.name") - .advice("error.no.name.advice") - .create(); - } - - RuntimeBuilder runtimeBuilder; - - Launcher mainLauncher; - List additionalLaunchers; - if (isRuntimeInstaller(params)) { - runtimeBuilder = null; - mainLauncher = null; - additionalLaunchers = List.of(); - } else if (predefinedAppImage != null) { - runtimeBuilder = null; - - var appImage = AppImageFile2.load(predefinedAppImage); - - version = appImage.getAppVersion(); - - mainLauncher = launcherSupplier.apply(mergeParams(params, Map.of(APP_NAME.getID(), - appImage.getLauncherName(), DESCRIPTION.getID(), description))); - additionalLaunchers = appImage.getAddLaunchers().stream().map(li -> { - Map launcherParams = new HashMap<>(); - launcherParams.put(APP_NAME.getID(), li.name()); - launcherParams.put(LAUNCHER_AS_SERVICE.getID(), Boolean.toString(li.service())); - launcherParams.putAll(li.extra()); - return launcherSupplier.apply(mergeParams(params, launcherParams)); - }).toList(); - } else { - var launchers = Optional.ofNullable(ADD_LAUNCHERS.fetchFrom(params)).orElseGet(List::of); - mainLauncher = launcherSupplier.apply(params); - additionalLaunchers = launchers.stream().map(launcherParams -> { - return launcherSupplier.apply(mergeParams(params, launcherParams)); - }).toList(); - - var startupInfos = Stream.concat( - Stream.of(mainLauncher), - additionalLaunchers.stream() - ).map(Launcher::startupInfo).toList(); - - runtimeBuilder = RuntimeBuilderFromParams.create(params, startupInfos); - } - - List launchers = Optional.ofNullable(mainLauncher).map(v -> { - return Stream.concat(Stream.of(v), additionalLaunchers.stream()).toList(); - }).orElse(null); - - return new Application.Impl(name, description, version, vendor, - copyright, srcDir, contentDirs, runtimeBuilder, launchers); - } - - private static Map mergeParams(Map mainParams, - Map launcherParams) { - if (!launcherParams.containsKey(DESCRIPTION.getID())) { - launcherParams = new HashMap<>(launcherParams); -// FIXME: this is a good improvement but it fails existing tests -// launcherParams.put(DESCRIPTION.getID(), String.format("%s (%s)", DESCRIPTION.fetchFrom( -// mainParams), APP_NAME.fetchFrom(launcherParams))); - launcherParams.put(DESCRIPTION.getID(), DESCRIPTION.fetchFrom(mainParams)); - } - return AddLauncherArguments.merge(mainParams, launcherParams, ICON.getID(), ADD_LAUNCHERS - .getID(), FILE_ASSOCIATIONS.getID()); - } - - static BundlerParamInfo createBundlerParam( - ThrowingFunction, T> valueFunc) { - return BundlerParamInfo.createBundlerParam("target.application", valueFunc); - } - - static final BundlerParamInfo APPLICATION = createBundlerParam( - new ApplicationFromParams()::create); -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java index e5ad9e9068ed5..89f6787ab82fd 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java @@ -27,7 +27,6 @@ import jdk.jpackage.internal.model.ConfigException; import java.nio.file.Path; import java.util.Map; -import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import jdk.jpackage.internal.BuildEnv.Impl; import static jdk.jpackage.internal.BuildEnv.withAppImageDir; import jdk.jpackage.internal.resources.ResourceLocator; @@ -46,15 +45,13 @@ static BuildEnv create(Map params) throws ConfigExceptio } else if (StandardBundlerParam.hasPredefinedAppImage(params)) { appImageDir = StandardBundlerParam.getPredefinedAppImage(params); } else { - Path dir = ApplicationFromParams.APPLICATION.fetchFrom(params).appImageDirName(); + Path dir = FromParams.APPLICATION.fetchFrom(params).appImageDirName(); appImageDir = defaultEnv.buildRoot().resolve("image").resolve(dir); } return withAppImageDir(defaultEnv, appImageDir); } - static final BundlerParamInfo BUILD_ENV = BundlerParamInfo.createBundlerParam("env", BuildEnvFromParams::create); - - static final BundlerParamInfo PACKAGE_TYPE = createStringBundlerParam( - Arguments.CLIOptions.PACKAGE_TYPE.getId()); + static final BundlerParamInfo BUILD_ENV = BundlerParamInfo.createBundlerParam( + "env", BuildEnvFromParams::create); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java new file mode 100644 index 0000000000000..cd1f52c57d31e --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.Launcher; +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import jdk.jpackage.internal.AppImageFile2.LauncherInfo; +import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; +import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; +import static jdk.jpackage.internal.StandardBundlerParam.ADD_MODULES; +import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; +import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.COPYRIGHT; +import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; +import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; +import static jdk.jpackage.internal.StandardBundlerParam.ICON; +import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; +import static jdk.jpackage.internal.StandardBundlerParam.JLINK_OPTIONS; +import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; +import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; +import static jdk.jpackage.internal.StandardBundlerParam.LIMIT_MODULES; +import static jdk.jpackage.internal.StandardBundlerParam.MODULE_PATH; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; +import static jdk.jpackage.internal.StandardBundlerParam.SOURCE_DIR; +import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; +import static jdk.jpackage.internal.StandardBundlerParam.VERSION; +import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLaunchers; +import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.util.function.ThrowingFunction; + +final class FromParams { + + static ApplicationBuilder createApplicationBuilder(Map params, + Function, Launcher> launcherMapper) + throws ConfigException, IOException { + + var appBuilder = new ApplicationBuilder() + .name(APP_NAME.fetchFrom(params)) + .description(DESCRIPTION.fetchFrom(params)) + .version(VERSION.fetchFrom(params)) + .vendor(VENDOR.fetchFrom(params)) + .copyright(COPYRIGHT.fetchFrom(params)) + .srcDir(SOURCE_DIR.fetchFrom(params)) + .contentDirs(APP_CONTENT.fetchFrom(params)); + + var predefinedAppImage = getPredefinedAppImage(params); + + if (predefinedAppImage != null) { + var appIMafeFile = AppImageFile2.load(predefinedAppImage); + appBuilder.initFromAppImage(appIMafeFile, launcherInfo -> { + var launcherParams = mapLauncherInfo(launcherInfo); + return launcherMapper.apply(mergeParams(params, launcherParams)); + }); + } else { + var launchers = createLaunchers(params, launcherMapper); + + var runtimeBuilderBuilder = new RuntimeBuilderBuilder() + .modulePath(MODULE_PATH.fetchFrom(params)); + + Path predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); + if (predefinedRuntimeImage != null) { + runtimeBuilderBuilder.forRuntime(predefinedRuntimeImage); + } else { + var startupInfos = launchers.asList().stream().map(Launcher::startupInfo).toList(); + runtimeBuilderBuilder.forNewRuntime(startupInfos) + .addModules(ADD_MODULES.fetchFrom(params)) + .limitModules(LIMIT_MODULES.fetchFrom(params)) + .options(JLINK_OPTIONS.fetchFrom(params)) + .appy(); + } + + appBuilder.launchers(launchers).runtimeBuilder(runtimeBuilderBuilder.create()); + } + + return appBuilder; + } + + static PackageBuilder createPackageBuilder( + Map params, Application app, + PackageType type) throws ConfigException { + return new PackageBuilder(app, type) + .name(INSTALLER_NAME.fetchFrom(params)) + .description(DESCRIPTION.fetchFrom(params)) + .version(VERSION.fetchFrom(params)) + .aboutURL(ABOUT_URL.fetchFrom(params)) + .licenseFile(Optional.ofNullable(LICENSE_FILE.fetchFrom(params)).map(Path::of).orElse(null)) + .predefinedAppImage(getPredefinedAppImage(params)) + .installDir(Optional.ofNullable(INSTALL_DIR.fetchFrom(params)).map(Path::of).orElse(null)); + } + + static BundlerParamInfo createApplicationBundlerParam( + ThrowingFunction, T> valueFunc) { + return BundlerParamInfo.createBundlerParam("target.application", params -> { + var app = valueFunc.apply(params); + params.put(APPLICATION.getID(), app); + return app; + }); + } + + static BundlerParamInfo createPackageBundlerParam( + ThrowingFunction, T> valueFunc) { + return BundlerParamInfo.createBundlerParam("target.package", params -> { + var pkg = valueFunc.apply(params); + params.put(PACKAGE.getID(), pkg); + return pkg; + }); + } + + private static ApplicationLaunchers createLaunchers( + Map params, + Function, Launcher> launcherMapper) { + var launchers = Optional.ofNullable(ADD_LAUNCHERS.fetchFrom(params)).orElseGet(List::of); + + var mainLauncher = launcherMapper.apply(params); + var additionalLaunchers = launchers.stream().map(launcherParams -> { + return launcherMapper.apply(mergeParams(params, launcherParams)); + }).toList(); + + return new ApplicationLaunchers(mainLauncher, additionalLaunchers); + } + + private static Map mapLauncherInfo(LauncherInfo launcherInfo) { + Map launcherParams = new HashMap<>(); + launcherParams.put(APP_NAME.getID(), launcherInfo.name()); + launcherParams.put(LAUNCHER_AS_SERVICE.getID(), Boolean.toString(launcherInfo.service())); + launcherParams.putAll(launcherInfo.extra()); + return launcherParams; + } + + private static Map mergeParams(Map mainParams, + Map launcherParams) { + if (!launcherParams.containsKey(DESCRIPTION.getID())) { + launcherParams = new HashMap<>(launcherParams); +// FIXME: this is a good improvement but it fails existing tests +// launcherParams.put(DESCRIPTION.getID(), String.format("%s (%s)", DESCRIPTION.fetchFrom( +// mainParams), APP_NAME.fetchFrom(launcherParams))); + launcherParams.put(DESCRIPTION.getID(), DESCRIPTION.fetchFrom(mainParams)); + } + return AddLauncherArguments.merge(mainParams, launcherParams, ICON.getID(), ADD_LAUNCHERS + .getID(), FILE_ASSOCIATIONS.getID()); + } + + static final BundlerParamInfo APPLICATION = createApplicationBundlerParam(null); + static final BundlerParamInfo PACKAGE = createPackageBundlerParam(null); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java new file mode 100644 index 0000000000000..a8c9a12847c98 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.mapping; +import static java.util.stream.Collectors.toList; +import java.util.stream.Stream; +import jdk.internal.util.OperatingSystem; +import static jdk.internal.util.OperatingSystem.LINUX; +import static jdk.internal.util.OperatingSystem.MACOS; +import static jdk.internal.util.OperatingSystem.WINDOWS; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.Launcher.Impl; +import jdk.jpackage.internal.model.LauncherStartupInfo; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; + +final class LauncherBuilder { + + Launcher create() throws ConfigException { + if (icon != null) { + validateIcon(icon); + } + var fa = toFunction(this::createFileAssociations).apply(faSources.stream()).toList(); + return new Impl(name, startupInfo, fa, isService, description, icon); + } + + LauncherBuilder name(String v) { + name = v; + return this; + } + + LauncherBuilder startupInfo(LauncherStartupInfo v) { + startupInfo = v; + return this; + } + + LauncherBuilder faSources(List v) { + faSources = v; + return this; + } + + LauncherBuilder faMapper(Function> v) { + faMapper = v; + return this; + } + + LauncherBuilder isService(boolean v) { + isService = v; + return this; + } + + LauncherBuilder description(String v) { + description = v; + return this; + } + + LauncherBuilder icon(Path v) { + icon = v; + return this; + } + + static Optional mapFileAssociation(FileAssociation src) { + var mimeType = src.mimeType(); + if (mimeType == null) { + return Optional.empty(); + } + + var extension = src.extension(); + if (extension == null) { + return Optional.empty(); + } + + return Optional.of(new FileAssociation.Impl(src.description(), src.icon(), mimeType, extension)); + } + + static void validateIcon(Path icon) throws ConfigException { + switch (OperatingSystem.current()) { + case WINDOWS -> { + if (!icon.getFileName().toString().toLowerCase().endsWith(".ico")) { + throw ConfigException.build().message("message.icon-not-ico", icon).create(); + } + } + case LINUX -> { + if (!icon.getFileName().toString().endsWith(".png")) { + throw ConfigException.build().message("message.icon-not-png", icon).create(); + } + } + case MACOS -> { + if (!icon.getFileName().toString().endsWith(".icns")) { + throw ConfigException.build().message("message.icon-not-icns", icon).create(); + } + } + } + } + + private Stream createFileAssociations( + Stream sources) throws ConfigException { + var fas = sources.map(faMapper).filter(Optional::isPresent).map(Optional::get).toList(); + + // Check extension to mime type relationship is 1:1 + var mimeTypeToExtension = fas.stream().collect(groupingBy( + FileAssociation::extension, mapping(FileAssociation::mimeType, + toList()))); + for (var entry : mimeTypeToExtension.entrySet()) { + if (entry.getValue().size() != 1) { + var extension = entry.getKey(); + throw ConfigException.build().message( + "error.fa-extension-with-multiple-mime-types", extension).create(); + } + } + + return fas.stream(); + } + + private String name; + private LauncherStartupInfo startupInfo; + private List faSources; + private Function> faMapper = LauncherBuilder::mapFileAssociation; + private boolean isService; + private String description; + private Path icon; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java index 48020a4eb3614..271e70c9151e7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java @@ -26,14 +26,13 @@ import java.nio.file.Path; import java.util.List; -import jdk.jpackage.internal.model.LauncherStartupInfo; import jdk.jpackage.internal.model.Launcher; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.function.Function; -import jdk.jpackage.internal.model.Launcher.Impl; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.ARGUMENTS; import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; import static jdk.jpackage.internal.StandardBundlerParam.FA_CONTENT_TYPE; import static jdk.jpackage.internal.StandardBundlerParam.FA_DESCRIPTION; @@ -43,32 +42,37 @@ import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.ICON; +import static jdk.jpackage.internal.StandardBundlerParam.JAVA_OPTIONS; +import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.FileAssociation; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; -record LauncherFromParams(Function> faSupplier) { +record LauncherFromParams(Function> faMapper) { LauncherFromParams { - Objects.requireNonNull(faSupplier); + Objects.requireNonNull(faMapper); } - + LauncherFromParams() { - this(FileAssociation::create); + this(LauncherBuilder::mapFileAssociation); } - Launcher create(Map params) { - var name = APP_NAME.fetchFrom(params); + Launcher create(Map params) throws ConfigException { + var builder = new LauncherBuilder() + .description(DESCRIPTION.fetchFrom(params)) + .icon(ICON.fetchFrom(params)) + .isService(LAUNCHER_AS_SERVICE.fetchFrom(params)) + .name(APP_NAME.fetchFrom(params)) + .faMapper(faMapper); - LauncherStartupInfo startupInfo = null; if (PREDEFINED_APP_IMAGE.fetchFrom(params) == null) { - startupInfo = LauncherStartupInfoFromParams.create(params); + builder.startupInfo(new LauncherStartupInfoBuilder() + .launcherData(StandardBundlerParam.LAUNCHER_DATA.fetchFrom(params)) + .defaultParameters(ARGUMENTS.fetchFrom(params)) + .javaOptions(JAVA_OPTIONS.fetchFrom(params)) + .create()); } - var isService = LAUNCHER_AS_SERVICE.fetchFrom(params); - var desc = DESCRIPTION.fetchFrom(params); - var icon = ICON.fetchFrom(params); - - var faStream = Optional.ofNullable( + var faSources = Optional.ofNullable( FILE_ASSOCIATIONS.fetchFrom(params)).orElseGet(List::of).stream().map(faParams -> { var faDesc = FA_DESCRIPTION.fetchFrom(faParams); var faIcon = FA_ICON.fetchFrom(faParams); @@ -77,7 +81,7 @@ Launcher create(Map params) { return faExtensions.stream().map(faExtension -> { return faMimeTypes.stream().map(faMimeType -> { - return faSupplier.apply(new FileAssociation() { + return (FileAssociation)new FileAssociation() { @Override public String description() { return faDesc; @@ -97,13 +101,11 @@ public String mimeType() { public String extension() { return faExtension; } - }); + }; }); }).flatMap(x -> x); - }).flatMap(x -> x).filter(Optional::isPresent).map(Optional::get); - - var fa = toSupplier(() -> FileAssociation.create(faStream)).get().toList(); + }).flatMap(x -> x).toList(); - return new Impl(name, startupInfo, fa, isService, desc, icon); + return builder.faSources(faSources).create(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java new file mode 100644 index 0000000000000..e2d2412f235d0 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.List; +import java.util.function.UnaryOperator; +import jdk.jpackage.internal.model.LauncherJarStartupInfo; +import jdk.jpackage.internal.model.LauncherModularStartupInfo; +import jdk.jpackage.internal.model.LauncherStartupInfo.Impl; +import jdk.jpackage.internal.model.LauncherStartupInfo; + +final class LauncherStartupInfoBuilder { + + LauncherStartupInfo create() { + return decorator.apply(new Impl(qualifiedClassName, javaOptions, + defaultParameters, classPath)); + } + + LauncherStartupInfoBuilder launcherData(LauncherData launcherData) { + if (launcherData.isModular()) { + decorator = new ModuleStartupInfo(launcherData.moduleName(), + launcherData.modulePath()); + } else { + decorator = new JarStartupInfo(launcherData.mainJarName(), + launcherData.isClassNameFromMainJar()); + } + classPath = launcherData.classPath(); + qualifiedClassName = launcherData.qualifiedClassName(); + return this; + } + + LauncherStartupInfoBuilder javaOptions(List v) { + javaOptions = v; + return this; + } + + LauncherStartupInfoBuilder defaultParameters(List v) { + defaultParameters = v; + return this; + } + + private static record ModuleStartupInfo(String moduleName, + List modulePath) implements UnaryOperator { + + @Override + public LauncherStartupInfo apply(LauncherStartupInfo base) { + return new LauncherModularStartupInfo.Impl(base, moduleName, modulePath); + } + } + + private static record JarStartupInfo(Path jarPath, + boolean isClassNameFromMainJar) implements + UnaryOperator { + + @Override + public LauncherStartupInfo apply(LauncherStartupInfo base) { + return new LauncherJarStartupInfo.Impl(base, jarPath, isClassNameFromMainJar); + } + } + + private String qualifiedClassName; + private List javaOptions; + private List defaultParameters; + private List classPath; + private UnaryOperator decorator; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java deleted file mode 100644 index edd946006207c..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoFromParams.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal; - -import jdk.jpackage.internal.model.LauncherStartupInfo; -import jdk.jpackage.internal.model.LauncherJarStartupInfo; -import jdk.jpackage.internal.model.LauncherModularStartupInfo; -import java.util.Map; -import static jdk.jpackage.internal.StandardBundlerParam.ARGUMENTS; -import static jdk.jpackage.internal.StandardBundlerParam.JAVA_OPTIONS; - -final class LauncherStartupInfoFromParams { - - static LauncherStartupInfo create(Map params) { - var inputDir = StandardBundlerParam.SOURCE_DIR.fetchFrom(params); - var launcherData = StandardBundlerParam.LAUNCHER_DATA.fetchFrom(params); - var javaOptions = JAVA_OPTIONS.fetchFrom(params); - var arguments = ARGUMENTS.fetchFrom(params); - - var startupInfo = new LauncherStartupInfo.Impl( - launcherData.qualifiedClassName(), javaOptions, arguments, - launcherData.classPath()); - - if (launcherData.isModular()) { - return new LauncherModularStartupInfo.Impl(startupInfo, - launcherData.moduleName(), launcherData.modulePath()); - } else { - return new LauncherJarStartupInfo.Impl(startupInfo, - launcherData.mainJarName(), - launcherData.isClassNameFromMainJar()); - } - } -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java new file mode 100644 index 0000000000000..ee911d28ed60f --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.Application; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.Package.Impl; +import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.StandardPackageType; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; +import static jdk.jpackage.internal.model.StandardPackageType.MAC_DMG; +import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG; +import static jdk.jpackage.internal.model.StandardPackageType.WIN_EXE; +import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; + +final class PackageBuilder { + + PackageBuilder(Application app, PackageType type) { + Objects.requireNonNull(app); + Objects.requireNonNull(type); + this.app = app; + this.type = type; + } + + Package create() throws ConfigException { + final var effectiveName = Optional.ofNullable(name).orElseGet(app::name); + + final Path relativeInstallDir; + if (installDir != null) { + var normalizedInstallDir = mapInstallDir(installDir, type); + if (type instanceof StandardPackageType stdType) { + do { + switch (stdType) { + case LINUX_DEB, LINUX_RPM -> { + switch (normalizedInstallDir.toString()) { + case "/usr", "/usr/local" -> { + break; + } + } + } + case WIN_EXE, WIN_MSI -> { + break; + } + case MAC_DMG,MAC_PKG -> { + } + } + normalizedInstallDir = normalizedInstallDir.resolve(effectiveName); + } while(false); + } + relativeInstallDir = normalizedInstallDir; + } else if (type instanceof StandardPackageType stdType) { + relativeInstallDir = defaultRelativeInstallDir(stdType, effectiveName, app); + } else { + throw new UnsupportedOperationException(); + } + + return new Impl( + app, + type, + effectiveName, + Optional.ofNullable(description).orElseGet(app::description), + version = Optional.ofNullable(version).orElseGet(app::version), + aboutURL, + licenseFile, + predefinedAppImage, + relativeInstallDir); + } + + PackageBuilder name(String v) { + name = v; + return this; + } + + boolean isNameDefault() { + return name == null; + } + + PackageBuilder fileName(Path v) { + fileName = v; + return this; + } + + PackageBuilder description(String v) { + description = v; + return this; + } + + PackageBuilder version(String v) { + version = v; + return this; + } + + PackageBuilder aboutURL(String v) { + aboutURL = v; + return this; + } + + PackageBuilder licenseFile(Path v) { + licenseFile = v; + return this; + } + + PackageBuilder predefinedAppImage(Path v) { + predefinedAppImage = v; + return this; + } + + PackageBuilder installDir(Path v) { + installDir = v; + return this; + } + + private static Path mapInstallDir(Path installDir, PackageType pkgType) + throws ConfigException { + var ex = ConfigException.build().message("error.invalid-install-dir", + installDir).create(); + + if (installDir.getNameCount() == 0) { + throw ex; + } + + if (installDir.getFileName().equals(Path.of(""))) { + // Trailing '/' or '\\'. Strip them away. + installDir = installDir.getParent(); + } + + if (installDir.toString().isEmpty()) { + throw ex; + } + + switch (pkgType) { + case StandardPackageType.WIN_EXE, StandardPackageType.WIN_MSI -> { + if (installDir.isAbsolute()) { + throw ex; + } + } + default -> { + if (!installDir.isAbsolute()) { + throw ex; + } + } + } + + if (!installDir.normalize().toString().equals(installDir.toString())) { + // Don't allow '..' or '.' in path components + throw ex; + } + + return installDir; + } + + private static Path defaultRelativeInstallDir(StandardPackageType pkgType, String pkgName, Application app) { + switch (pkgType) { + case WIN_EXE, WIN_MSI -> { + return Path.of(app.name()); + } + case LINUX_DEB, LINUX_RPM -> { + return Path.of("opt").resolve(pkgName); + } + case MAC_DMG, MAC_PKG -> { + Path base; + if (app.isRuntime()) { + base = Path.of("Library/Java/JavaVirtualMachines"); + } else { + base = Path.of("Applications"); + } + return base.resolve(pkgName); + } + default -> { + throw new UnsupportedOperationException(); + } + } + } + + private String name; + private Path fileName; + private String description; + private String version; + private String aboutURL; + private Path licenseFile; + private Path predefinedAppImage; + private Path installDir; + + final private PackageType type; + final private Application app; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java deleted file mode 100644 index d6b3e899aba73..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFromParams.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal; - -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.Application; -import java.nio.file.Path; -import java.util.Map; -import java.util.Optional; -import jdk.jpackage.internal.util.function.ThrowingFunction; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; -import jdk.jpackage.internal.model.Package.Impl; -import jdk.jpackage.internal.model.PackageType; -import jdk.jpackage.internal.model.StandardPackageType; -import static jdk.jpackage.internal.model.Package.mapInstallDir; -import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; -import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; -import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; - -final class PackageFromParams { - - static Package create(Map params, - BundlerParamInfo appParam, PackageType pkgType) throws ConfigException { - var app = appParam.fetchFrom(params); - var packageName = Optional.ofNullable(INSTALLER_NAME.fetchFrom(params)).orElseGet(app::name); - var description = Optional.ofNullable(DESCRIPTION.fetchFrom(params)).orElseGet(app::name); - var version = Optional.ofNullable(VERSION.fetchFrom(params)).orElseGet(app::version); - var aboutURL = ABOUT_URL.fetchFrom(params); - var licenseFile = Optional.ofNullable(LICENSE_FILE.fetchFrom(params)).map(Path::of).orElse(null); - var predefinedAppImage = getPredefinedAppImage(params); - - Path installBaseDir = Optional.ofNullable(INSTALL_DIR.fetchFrom(params)).map(v -> { - return toSupplier(() -> { - return mapInstallDir(Path.of(v), pkgType); - }).get(); - }).orElse(null); - - return new Impl(app, pkgType, packageName, description, version, - aboutURL, licenseFile, predefinedAppImage, installBaseDir); - } - - static BundlerParamInfo createBundlerParam( - ThrowingFunction, T> valueFunc) { - return BundlerParamInfo.createBundlerParam("target.package", valueFunc); - } - - static final BundlerParamInfo PACKAGE = createBundlerParam(params -> { - return PackageFromParams.create(params, ApplicationFromParams.APPLICATION, - StandardPackageType.fromCmdLineType(BuildEnvFromParams.PACKAGE_TYPE - .fetchFrom(params))); - }); -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java new file mode 100644 index 0000000000000..98cc84f128616 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Files; +import java.nio.file.LinkOption; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LauncherStartupInfo; +import jdk.jpackage.internal.model.RuntimeBuilder; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; +import jdk.internal.util.OperatingSystem; +import static jdk.jpackage.internal.model.RuntimeBuilder.getDefaultModulePath; +import jdk.jpackage.internal.util.FileUtils; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + +final class RuntimeBuilderBuilder { + + RuntimeBuilder create() { + return impl.get(); + } + + RuntimeBuilderBuilder modulePath(List v) { + modulePath = v; + return this; + } + + RuntimeBuilderBuilder forRuntime(Path predefinedRuntimeImage) { + impl = new CopyingRuntime(this, predefinedRuntimeImage); + return this; + } + + RuntimeBuilderConfigBuilder forNewRuntime(List startupInfos) { + return new RuntimeBuilderConfigBuilder(startupInfos); + } + + final class RuntimeBuilderConfigBuilder { + + RuntimeBuilderConfigBuilder(List startupInfos) { + Objects.requireNonNull(startupInfos); + if (startupInfos.isEmpty()) { + throw new IllegalArgumentException(); + } + this.startupInfos = startupInfos; + } + + RuntimeBuilderBuilder appy() { + impl = new BuildingRuntime(RuntimeBuilderBuilder.this, addModules, + limitModules, options, startupInfos); + return RuntimeBuilderBuilder.this; + } + + public RuntimeBuilderConfigBuilder addModules(Set v) { + addModules = v; + return this; + } + + public RuntimeBuilderConfigBuilder limitModules(Set v) { + limitModules = v; + return this; + } + + public RuntimeBuilderConfigBuilder options(List v) { + options = v; + return this; + } + + private Set addModules; + private Set limitModules; + private List options; + private final List startupInfos; + } + + private static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, + Path... modulePath) throws ConfigException { + if (!Files.exists(runtimeDir)) { + throw ConfigException.build() + .message("message.runtime-image-dir-does-not-exist", + "--runtime-image", runtimeDir) + .advice("message.runtime-image-dir-does-not-exist.advice", + "--runtime-image") + .create(); + } + + return appLayout -> { + final Path runtimeHome = getRuntimeHome(runtimeDir); + + // copy whole runtime, need to skip jmods and src.zip + final List excludes = Arrays.asList("jmods", "src.zip"); + FileUtils.copyRecursive(runtimeHome, + appLayout.runtimeHomeDirectory(), + excludes, + LinkOption.NOFOLLOW_LINKS); + + // if module-path given - copy modules to appDir/mods + List defaultModulePath = getDefaultModulePath(); + Path dest = appLayout.appModsDirectory(); + + for (Path mp : modulePath) { + if (!defaultModulePath.contains(mp.toAbsolutePath())) { + FileUtils.copyRecursive(mp, dest); + } + } + }; + } + + private static Path getRuntimeHome(Path runtimeDir) { + if (OperatingSystem.isMacOS()) { + // On Mac topImage can be runtime root or runtime home. + Path runtimeHome = runtimeDir.resolve("Contents/Home"); + if (Files.isDirectory(runtimeHome)) { + // topImage references runtime root, adjust it to pick data from + // runtime home + return runtimeHome; + } + } + return runtimeDir; + } + + private record CopyingRuntime(RuntimeBuilderBuilder thiz, Path predefinedRuntimeImage) + implements Supplier { + + @Override + public RuntimeBuilder get() { + return toSupplier(() -> createCopyingRuntimeBuilder( + predefinedRuntimeImage, + Optional.ofNullable(thiz.modulePath).orElseGet(List::of).toArray(Path[]::new)) + ).get(); + } + } + + private record BuildingRuntime(RuntimeBuilderBuilder thiz, Set addModules, + Set limitModules, List options, + List startupInfos) implements Supplier { + + @Override + public RuntimeBuilder get() { + return toSupplier(() -> JLinkRuntimeBuilder.createJLinkRuntimeBuilder( + Optional.ofNullable(thiz.modulePath).orElseGet(List::of), + Optional.ofNullable(addModules).orElseGet(Set::of), + Optional.ofNullable(limitModules).orElseGet(Set::of), + Optional.ofNullable(options).orElseGet(List::of), + startupInfos) + ).get(); + } + } + + private List modulePath; + private Supplier impl; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderFromParams.java deleted file mode 100644 index 0c0f6882ec4f5..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderFromParams.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal; - -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.LauncherStartupInfo; -import jdk.jpackage.internal.model.RuntimeBuilder; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import static jdk.jpackage.internal.StandardBundlerParam.ADD_MODULES; -import static jdk.jpackage.internal.StandardBundlerParam.JLINK_OPTIONS; -import static jdk.jpackage.internal.StandardBundlerParam.LIMIT_MODULES; -import static jdk.jpackage.internal.StandardBundlerParam.MODULE_PATH; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; - -final class RuntimeBuilderFromParams { - - static RuntimeBuilder create(Map params, - List startupInfos) throws ConfigException { - List modulePath = Optional.ofNullable(MODULE_PATH.fetchFrom(params)).orElseGet( - List::of); - - Path predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); - if (predefinedRuntimeImage != null) { - return RuntimeBuilder.createCopyingRuntimeBuilder(predefinedRuntimeImage, modulePath - .toArray(Path[]::new)); - } else { - Set addModules = Optional.ofNullable(ADD_MODULES.fetchFrom(params)).orElseGet( - Set::of); - Set limitModules = Optional.ofNullable(LIMIT_MODULES.fetchFrom(params)) - .orElseGet(Set::of); - List options = Optional.ofNullable(JLINK_OPTIONS.fetchFrom(params)).orElseGet( - List::of); - return JLinkRuntimeBuilder.createJLinkRuntimeBuilder(modulePath, addModules, - limitModules, options, startupInfos); - - } - } -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index 4010180e95785..be4dca5864287 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -25,14 +25,10 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.Date; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Function; -import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.IOUtils; import jdk.jpackage.internal.util.PathUtils; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; @@ -55,34 +51,17 @@ public interface Application { RuntimeBuilder runtimeBuilder(); default Path appImageDirName() { - switch (OperatingSystem.current()) { - case MACOS -> { - return Path.of(name() + ".app"); - } - default -> { - return Path.of(name()); - } - } + return Path.of(name()); } List launchers(); default Launcher mainLauncher() { - return Optional.ofNullable(launchers()).map(launchers -> { - Launcher launcher; - if (launchers.isEmpty()) { - launcher = null; - } else { - launcher = launchers.getFirst(); - } - return launcher; - }).orElse(null); + return ApplicationLaunchers.fromList(launchers()).mainLauncher(); } default List additionalLaunchers() { - return Optional.ofNullable(launchers()).map(launchers -> { - return launchers.subList(1, launchers.size()); - }).orElseGet(List::of); + return ApplicationLaunchers.fromList(launchers()).additionalLaunchers(); } default boolean isRuntime() { @@ -137,29 +116,12 @@ default OverridableResource createLauncherIconResource(Launcher launcher, return resource; } - static record Impl(String name, String description, String version, + record Impl(String name, String description, String version, String vendor, String copyright, Path srcDir, List contentDirs, - RuntimeBuilder runtimeBuilder, List launchers) implements Application { - public Impl { - name = Optional.ofNullable(name).orElseGet(() -> { - return mainLauncher().name(); - }); - description = Optional.ofNullable(description).orElseGet(Defaults.INSTANCE::description); - version = Optional.ofNullable(version).orElseGet(Defaults.INSTANCE::version); - vendor = Optional.ofNullable(vendor).orElseGet(Defaults.INSTANCE::vendor); - copyright = Optional.ofNullable(copyright).orElseGet(Defaults.INSTANCE::copyright); - } - } - - static record Defaults(String description, String version, String vendor, String copyright) { - private static final Defaults INSTANCE = new Defaults( - I18N.getString("param.description.default"), - "1.0", - I18N.getString("param.vendor.default"), - MessageFormat.format(I18N.getString("param.copyright.default"), new Date())); + RuntimeBuilder runtimeBuilder, List launchers) implements Application { } - static class Proxy extends ProxyBase implements Application { + class Proxy extends ProxyBase implements Application { Proxy(T target) { super(target); @@ -211,7 +173,7 @@ public List launchers() { } } - static class Unsupported implements Application { + class Unsupported implements Application { @Override public String name() { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java new file mode 100644 index 0000000000000..6cbd087aff165 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +public record ApplicationLaunchers(Launcher mainLauncher, + List additionalLaunchers) { + + public ApplicationLaunchers { + if (mainLauncher == null && additionalLaunchers != null) { + throw new IllegalArgumentException(); + } + } + + public ApplicationLaunchers() { + this(null, null); + } + + public ApplicationLaunchers(Launcher mainLauncher) { + this(mainLauncher, List.of()); + } + + public List asList() { + return Optional.ofNullable(mainLauncher).map(v -> { + return Stream.concat(Stream.of(v), additionalLaunchers.stream()).toList(); + }).orElseGet(List::of); + } + + public static ApplicationLaunchers fromList(List launchers) { + if (launchers == null || launchers.isEmpty()) { + return new ApplicationLaunchers(); + } else { + return new ApplicationLaunchers(launchers.getFirst(), + launchers.subList(1, launchers.size() - 1)); + } + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java index c8f0934e29b97..be519df63b49a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java @@ -26,11 +26,6 @@ import java.nio.file.Path; import java.util.Objects; -import java.util.Optional; -import static java.util.stream.Collectors.groupingBy; -import static java.util.stream.Collectors.mapping; -import static java.util.stream.Collectors.toList; -import java.util.stream.Stream; public interface FileAssociation { @@ -75,37 +70,4 @@ public String extension() { return target.extension(); } } - - static Optional create(FileAssociation src) { - var mimeType = src.mimeType(); - if (mimeType == null) { - return Optional.empty(); - } - - var extension = src.extension(); - if (extension == null) { - return Optional.empty(); - } - - return Optional.of(new Impl(src.description(), src.icon(), mimeType, extension)); - } - - static Stream create(Stream sources) throws ConfigException { - var fas = sources.map(FileAssociation::create).filter(Optional::isPresent).map( - Optional::get).toList(); - - // Check extension to mime type relationship is 1:1 - var mimeTypeToExtension = fas.stream().collect(groupingBy( - FileAssociation::extension, mapping(FileAssociation::mimeType, - toList()))); - for (var entry : mimeTypeToExtension.entrySet()) { - if (entry.getValue().size() != 1) { - var extension = entry.getKey(); - throw ConfigException.build().message( - "error.fa-extension-with-multiple-mime-types", extension).create(); - } - } - - return fas.stream(); - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java index 2b335f57f05f6..429226edc54ec 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java @@ -29,10 +29,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import jdk.internal.util.OperatingSystem; -import static jdk.internal.util.OperatingSystem.LINUX; -import static jdk.internal.util.OperatingSystem.WINDOWS; -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; import jdk.jpackage.internal.resources.ResourceLocator; public interface Launcher { @@ -79,39 +75,14 @@ default String defaultIconResourceName() { return null; } - static record Impl(String name, LauncherStartupInfo startupInfo, + record Impl(String name, LauncherStartupInfo startupInfo, List fileAssociations, boolean isService, - String description, Path icon) implements Launcher { - public Impl { - if (icon != null && !icon.toString().isEmpty()) { - toConsumer(Launcher::validateIcon).accept(icon); - } - } + String description, Path icon) implements Launcher { } - static void validateIcon(Path icon) throws ConfigException { - switch (OperatingSystem.current()) { - case WINDOWS -> { - if (!icon.getFileName().toString().toLowerCase().endsWith(".ico")) { - throw ConfigException.build().message("message.icon-not-ico", icon).create(); - } - } - case LINUX -> { - if (!icon.getFileName().toString().endsWith(".png")) { - throw ConfigException.build().message("message.icon-not-png", icon).create(); - } - } - case MACOS -> { - if (!icon.getFileName().toString().endsWith(".icns")) { - throw ConfigException.build().message("message.icon-not-icns", icon).create(); - } - } - } - } - - static class Proxy extends ProxyBase implements Launcher { + class Proxy extends ProxyBase implements Launcher { - Proxy(T target) { + public Proxy(T target) { super(target); } @@ -146,7 +117,7 @@ public Path icon() { } } - static class Unsupported implements Launcher { + class Unsupported implements Launcher { @Override public String name() { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java index 2372450e1955d..86d63bf7ca50b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java @@ -36,7 +36,7 @@ public interface LauncherJarStartupInfo extends LauncherStartupInfo { boolean isClassNameFromMainJar(); - final static class Impl extends LauncherStartupInfo.Proxy + final class Impl extends LauncherStartupInfo.Proxy implements LauncherJarStartupInfo { public Impl(LauncherStartupInfo target, Path jarPath, boolean isClassNameFromMainJar) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java index d6fe71397ff1b..42e6b5493b6ac 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java @@ -33,7 +33,7 @@ public interface LauncherModularStartupInfo extends LauncherStartupInfo { List modulePath(); - final static class Impl extends LauncherStartupInfo.Proxy + final class Impl extends LauncherStartupInfo.Proxy implements LauncherModularStartupInfo { public Impl(LauncherStartupInfo target, String moduleName, diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java index e4486960ddbd5..0f645ec141eda 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java @@ -58,10 +58,10 @@ record Impl(String qualifiedClassName, List javaOptions, } - static class Proxy extends ProxyBase + class Proxy extends ProxyBase implements LauncherStartupInfo { - Proxy(T target) { + public Proxy(T target) { super(target); } @@ -86,7 +86,7 @@ public List classPath() { } } - static class Unsupported implements LauncherStartupInfo { + class Unsupported implements LauncherStartupInfo { @Override public String qualifiedClassName() { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java index f9f6107131f41..8b035e06c228b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java @@ -26,11 +26,9 @@ import java.nio.file.Path; import java.util.Optional; -import static jdk.jpackage.internal.Getter.getValueOrDefault; public interface Package { - Application app(); PackageType type(); @@ -102,14 +100,7 @@ default ApplicationLayout installedPackageLayout() { * Returns package file name. */ default String packageFileName() { - if (type() instanceof StandardPackageType type) { - switch (type) { - case WIN_MSI, WIN_EXE -> { - return String.format("%s-%s", packageName(), version()); - } - } - } - throw new UnsupportedOperationException(); + return String.format("%s-%s", packageName(), version()); } default String packageFileSuffix() { @@ -134,47 +125,14 @@ default boolean isRuntimeInstaller() { * On Windows it should be relative to %ProgramFiles% and relative * to the system root ('/') on other platforms. */ - default Path relativeInstallDir() { - var path = Optional.ofNullable(configuredInstallBaseDir()).map(v -> { - switch (asStandardPackageType()) { - case LINUX_DEB, LINUX_RPM -> { - switch (v.toString()) { - case "/usr", "/usr/local" -> { - return v; - } - } - } - case WIN_EXE, WIN_MSI -> { - return v; - } - } - return v.resolve(packageName()); - }).orElseGet(() -> defaultInstallDir(this)); - - switch (asStandardPackageType()) { - case WIN_EXE, WIN_MSI -> { - return path; - } - default -> { - return Path.of("/").relativize(path); - } - } - } + Path relativeInstallDir(); - Path configuredInstallBaseDir(); - - static record Impl(Application app, PackageType type, String packageName, + record Impl(Application app, PackageType type, String packageName, String description, String version, String aboutURL, Path licenseFile, - Path predefinedAppImage, Path configuredInstallBaseDir) implements Package { - - public Impl { - description = Optional.ofNullable(description).orElseGet(app::description); - version = Optional.ofNullable(version).orElseGet(app::version); - packageName = Optional.ofNullable(packageName).orElseGet(app::name); - } + Path predefinedAppImage, Path relativeInstallDir) implements Package { } - static class Unsupported implements Package { + class Unsupported implements Package { @Override public Application app() { @@ -217,13 +175,13 @@ public Path predefinedAppImage() { } @Override - public Path configuredInstallBaseDir() { + public Path relativeInstallDir() { throw new UnsupportedOperationException(); } } - static class Proxy extends ProxyBase implements Package { + class Proxy extends ProxyBase implements Package { Proxy(T target) { super(target); @@ -270,82 +228,8 @@ public Path predefinedAppImage() { } @Override - public Path configuredInstallBaseDir() { - return target.configuredInstallBaseDir(); - } - } - - static Package override(Package base, Package overrides) { - return new Impl( - getValueOrDefault(overrides, base, Package::app), - getValueOrDefault(overrides, base, Package::type), - getValueOrDefault(overrides, base, Package::packageName), - getValueOrDefault(overrides, base, Package::description), - getValueOrDefault(overrides, base, Package::version), - getValueOrDefault(overrides, base, Package::aboutURL), - getValueOrDefault(overrides, base, Package::licenseFile), - getValueOrDefault(overrides, base, Package::predefinedAppImage), - getValueOrDefault(overrides, base, Package::configuredInstallBaseDir)); - } - - static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigException { - var ex = ConfigException.build().message("error.invalid-install-dir", - installDir).create(); - - if (installDir.getNameCount() == 0) { - throw ex; - } - - if (installDir.getFileName().equals(Path.of(""))) { - // Trailing '/' or '\\'. Strip them away. - installDir = installDir.getParent(); - } - - if (installDir.toString().isEmpty()) { - throw ex; - } - - switch (pkgType) { - case StandardPackageType.WIN_EXE, StandardPackageType.WIN_MSI -> { - if (installDir.isAbsolute()) { - throw ex; - } - } - default -> { - if (!installDir.isAbsolute()) { - throw ex; - } - } - } - - if (!installDir.normalize().toString().equals(installDir.toString())) { - // Don't allow '..' or '.' in path components - throw ex; - } - - return installDir; - } - - private static Path defaultInstallDir(Package pkg) { - switch (pkg.asStandardPackageType()) { - case WIN_EXE, WIN_MSI -> { - return Path.of(pkg.app().name()); - } - case LINUX_DEB, LINUX_RPM -> { - return Path.of("/opt").resolve(pkg.packageName()); - } - case MAC_DMG, MAC_PKG -> { - Path base; - if (pkg.isRuntimeInstaller()) { - base = Path.of("/Library/Java/JavaVirtualMachines"); - } else { - base = Path.of("/Applications"); - } - return base.resolve(pkg.packageName()); - } - default -> { - throw new UnsupportedOperationException(); - } + public Path relativeInstallDir() { + return target.relativeInstallDir(); } } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java index 6852dd533d384..e9588f8dae331 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java @@ -25,63 +25,14 @@ package jdk.jpackage.internal.model; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.LinkOption; import java.nio.file.Path; -import java.util.Arrays; import java.util.List; -import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.IOUtils; -import jdk.jpackage.internal.util.FileUtils; public interface RuntimeBuilder { public void createRuntime(ApplicationLayout appLayout) throws PackagerException, IOException; - public static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, - Path... modulePath) throws ConfigException { - if (!Files.exists(runtimeDir)) { - throw ConfigException.build() - .message("message.runtime-image-dir-does-not-exist", "--runtime-image", runtimeDir) - .advice("message.runtime-image-dir-does-not-exist.advice", "--runtime-image") - .create(); - } - - return appLayout -> { - final Path runtimeHome = getRuntimeHome(runtimeDir); - - // copy whole runtime, need to skip jmods and src.zip - final List excludes = Arrays.asList("jmods", "src.zip"); - FileUtils.copyRecursive(runtimeHome, appLayout.runtimeHomeDirectory(), - excludes, - LinkOption.NOFOLLOW_LINKS); - - // if module-path given - copy modules to appDir/mods - List defaultModulePath = getDefaultModulePath(); - Path dest = appLayout.appModsDirectory(); - - for (Path mp : modulePath) { - if (!defaultModulePath.contains(mp.toAbsolutePath())) { - FileUtils.copyRecursive(mp, dest); - } - } - }; - } - - private static Path getRuntimeHome(Path runtimeDir) { - if (OperatingSystem.isMacOS()) { - // On Mac topImage can be runtime root or runtime home. - Path runtimeHome = runtimeDir.resolve("Contents/Home"); - if (Files.isDirectory(runtimeHome)) { - // topImage references runtime root, adjust it to pick data from - // runtime home - return runtimeHome; - } - } - return runtimeDir; - } - public static List getDefaultModulePath() { return List.of( Path.of(System.getProperty("java.home"), "jmods").toAbsolutePath()); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java index 12518f65eca6c..126f89cbdb2e3 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java @@ -29,7 +29,7 @@ public class WinAppBundler extends AppImageBundler { public WinAppBundler() { setAppImageSupplier((params, output) -> { // Order is important! - var app = WinApplicationFromParams.APPLICATION.fetchFrom(params); + var app = WinFromParams.APPLICATION.fetchFrom(params); var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); WinAppImageBuilder.build().create(app).execute( BuildEnv.withAppImageDir(env, output)); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java deleted file mode 100644 index f968a0800a6a9..0000000000000 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinApplicationFromParams.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal; - -import jdk.jpackage.internal.model.WinLauncher; -import jdk.jpackage.internal.model.WinApplication; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import static jdk.jpackage.internal.ApplicationFromParams.createBundlerParam; -import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; -import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; -import jdk.jpackage.internal.model.WinApplication.Impl; -import static jdk.jpackage.internal.model.WinLauncher.WinShortcut.WIN_SHORTCUT_DESKTOP; -import static jdk.jpackage.internal.model.WinLauncher.WinShortcut.WIN_SHORTCUT_START_MENU; - -final class WinApplicationFromParams { - - private static WinLauncher createLauncher(Map params) { - var launcher = new LauncherFromParams().create(params); - - boolean isConsole = CONSOLE_HINT.fetchFrom(params); - - var shortcuts = Map.of(WIN_SHORTCUT_DESKTOP, List.of(SHORTCUT_HINT, - WIN_SHORTCUT_HINT), WIN_SHORTCUT_START_MENU, List.of(MENU_HINT, - WIN_MENU_HINT)).entrySet().stream().filter(e -> { - var shortcutParams = e.getValue(); - if (params.containsKey(shortcutParams.get(0).getID())) { - // This is an explicit shortcut configuration for an addition launcher - return shortcutParams.get(0).fetchFrom(params); - } else { - return shortcutParams.get(1).fetchFrom(params); - } - }).map(Map.Entry::getKey).collect(Collectors.toSet()); - - return new WinLauncher.Impl(launcher, isConsole, shortcuts); - } - - static final BundlerParamInfo APPLICATION = createBundlerParam(params -> { - var app = new ApplicationFromParams(WinApplicationFromParams::createLauncher).create(params); - return new Impl(app); - }); - - private static final BundlerParamInfo WIN_MENU_HINT = new BundlerParamInfo<>( - Arguments.CLIOptions.WIN_MENU_HINT.getId(), - Boolean.class, - p -> false, - // valueOf(null) is false, - // and we actually do want null in some cases - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); - - private static final BundlerParamInfo WIN_SHORTCUT_HINT = new BundlerParamInfo<>( - Arguments.CLIOptions.WIN_SHORTCUT_HINT.getId(), - Boolean.class, - p -> false, - // valueOf(null) is false, - // and we actually do want null in some cases - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); - - public static final BundlerParamInfo CONSOLE_HINT = new BundlerParamInfo<>( - Arguments.CLIOptions.WIN_CONSOLE_HINT.getId(), - Boolean.class, - params -> false, - // valueOf(null) is false, - // and we actually do want null in some cases - (s, p) -> (s == null - || "null".equalsIgnoreCase(s)) ? true : Boolean.valueOf(s)); -} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java index e5f6ee9c7d1a0..d329a5a827aac 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java @@ -81,7 +81,7 @@ public Path execute(Map params, Path outdir) throws PackagerException { // Order is important! - var pkg = WinMsiPackageFromParams.PACKAGE.fetchFrom(params); + var pkg = WinFromParams.MSI_PACKAGE.fetchFrom(params); var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); IOUtils.writableOutputDir(outdir); @@ -100,7 +100,7 @@ public Path execute(Map params, Path outdir) .setEnvironmentVariable("JpMsiFile", msi.toAbsolutePath().toString()) .run(env, pkg.packageName()); - var exePkg = new WinExePackage.Impl(pkg, ICON.fetchFrom(params)); + var exePkg = new WinExePackageBuilder(pkg).icon(ICON.fetchFrom(params)).create(); return buildEXE(env, exePkg, msi, outdir); } catch (IOException|ConfigException ex) { Log.verbose(ex); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PlatformPackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java similarity index 61% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/PlatformPackage.java rename to src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java index bba32a268524f..70f0497e7a5c1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PlatformPackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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,33 +24,33 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ApplicationLayout; import java.nio.file.Path; +import java.util.Objects; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.WinExePackage; +import jdk.jpackage.internal.model.WinMsiPackage; -/** - * - * Platform package of an application. - */ -interface PlatformPackage { - - /** - * Platform-specific package name. - */ - String name(); - - /** - * Root directory where sources for packaging tool should be stored. On Unix - * systems contents of this directory will be installed in "/" directory. - */ - Path sourceRoot(); - - /** - * Source application layout from which to build the package. - */ - ApplicationLayout sourceApplicationLayout(); - - /** - * Application layout of the installed package. - */ - ApplicationLayout installedApplicationLayout(); +final class WinExePackageBuilder { + + WinExePackageBuilder(WinMsiPackage pkg) { + Objects.requireNonNull(pkg); + this.pkg = pkg; + } + + WinExePackage create() throws ConfigException { + if (icon != null) { + LauncherBuilder.validateIcon(icon); + } + + return new WinExePackage.Impl(pkg, icon); + } + + WinExePackageBuilder icon(Path v) { + icon = v; + return this; + } + + private Path icon; + + private final WinMsiPackage pkg; } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java new file mode 100644 index 0000000000000..c19dd0cef3218 --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.io.IOException; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.WinMsiPackage; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import static java.util.stream.Collectors.toSet; +import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; +import static jdk.jpackage.internal.FromParams.createApplicationBuilder; +import static jdk.jpackage.internal.FromParams.createApplicationBundlerParam; +import static jdk.jpackage.internal.FromParams.createPackageBuilder; +import static jdk.jpackage.internal.FromParams.createPackageBundlerParam; +import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; +import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; +import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; +import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; +import jdk.jpackage.internal.model.WinApplication; +import jdk.jpackage.internal.model.WinLauncher; +import static jdk.jpackage.internal.model.WinLauncher.WinShortcut.WIN_SHORTCUT_DESKTOP; +import static jdk.jpackage.internal.model.WinLauncher.WinShortcut.WIN_SHORTCUT_START_MENU; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; + +final class WinFromParams { + + private static WinApplication createWinApplication( + Map params) throws ConfigException, IOException { + var launcherFromParams = new LauncherFromParams(); + var app = createApplicationBuilder(params, toFunction(launcherParams -> { + var launcher = launcherFromParams.create(params); + + boolean isConsole = CONSOLE_HINT.fetchFrom(params); + + var shortcuts = Map.of(WIN_SHORTCUT_DESKTOP, List.of(SHORTCUT_HINT, + WIN_SHORTCUT_HINT), WIN_SHORTCUT_START_MENU, List.of(MENU_HINT, + WIN_MENU_HINT)).entrySet().stream().filter(e -> { + var shortcutParams = e.getValue(); + if (params.containsKey(shortcutParams.get(0).getID())) { + // This is an explicit shortcut configuration for an addition launcher + return shortcutParams.get(0).fetchFrom(params); + } else { + return shortcutParams.get(1).fetchFrom(params); + } + }).map(Map.Entry::getKey).collect(toSet()); + + return new WinLauncher.Impl(launcher, isConsole, shortcuts); + })).create(); + return new WinApplication.Impl(app); + } + + private static WinMsiPackage createWinMsiPackage(Map params) throws ConfigException, IOException { + + var app = createWinApplication(params); + + var pkgBuilder = createPackageBuilder(params, app, WIN_MSI); + + final Path serviceInstaller; + if (!app.isService()) { + serviceInstaller = null; + } else { + serviceInstaller = Optional.ofNullable(RESOURCE_DIR.fetchFrom(params)).map( + resourceDir -> { + return resourceDir.resolve("service-installer.exe"); + }).orElse(null); + } + + return new WinMsiPackageBuilder(pkgBuilder) + .helpURL(HELP_URL.fetchFrom(params)) + .isSystemWideInstall(MSI_SYSTEM_WIDE.fetchFrom(params)) + .serviceInstaller(serviceInstaller) + .startMenuGroupName(MENU_GROUP.fetchFrom(params)) + .updateURL(UPDATE_URL.fetchFrom(params)) + .upgradeCode(getUpgradeCode(params)) + .withInstallDirChooser(INSTALLDIR_CHOOSER.fetchFrom(params)) + .withShortcutPrompt(SHORTCUT_PROMPT.fetchFrom(params)) + .create(); + } + + private static UUID getUpgradeCode(Map params) throws ConfigException { + try { + return Optional.ofNullable(UPGRADE_UUID.fetchFrom(params)).map(UUID::fromString).orElse( + null); + } catch (IllegalArgumentException ex) { + throw new ConfigException(ex); + } + } + + static final BundlerParamInfo APPLICATION = createApplicationBundlerParam( + WinFromParams::createWinApplication); + + static final BundlerParamInfo MSI_PACKAGE = createPackageBundlerParam( + WinFromParams::createWinMsiPackage); + + private static final BundlerParamInfo WIN_MENU_HINT = new BundlerParamInfo<>( + Arguments.CLIOptions.WIN_MENU_HINT.getId(), + Boolean.class, + p -> false, + // valueOf(null) is false, + // and we actually do want null in some cases + (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); + + private static final BundlerParamInfo WIN_SHORTCUT_HINT = new BundlerParamInfo<>( + Arguments.CLIOptions.WIN_SHORTCUT_HINT.getId(), + Boolean.class, + p -> false, + // valueOf(null) is false, + // and we actually do want null in some cases + (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); + + public static final BundlerParamInfo CONSOLE_HINT = new BundlerParamInfo<>( + Arguments.CLIOptions.WIN_CONSOLE_HINT.getId(), + Boolean.class, + params -> false, + // valueOf(null) is false, + // and we actually do want null in some cases + (s, p) -> (s == null + || "null".equalsIgnoreCase(s)) ? true : Boolean.valueOf(s)); + + private static final BundlerParamInfo INSTALLDIR_CHOOSER = new BundlerParamInfo<>( + Arguments.CLIOptions.WIN_DIR_CHOOSER.getId(), + Boolean.class, + params -> false, + (s, p) -> Boolean.valueOf(s) + ); + + private static final BundlerParamInfo SHORTCUT_PROMPT = new BundlerParamInfo<>( + Arguments.CLIOptions.WIN_SHORTCUT_PROMPT.getId(), + Boolean.class, + params -> false, + (s, p) -> Boolean.valueOf(s) + ); + + private static final BundlerParamInfo MENU_GROUP = new BundlerParamInfo<>( + Arguments.CLIOptions.WIN_MENU_GROUP.getId(), + String.class, + params -> I18N.getString("param.menu-group.default"), + (s, p) -> s + ); + + private static final BundlerParamInfo MSI_SYSTEM_WIDE = new BundlerParamInfo<>( + Arguments.CLIOptions.WIN_PER_USER_INSTALLATION.getId(), + Boolean.class, + params -> true, // MSIs default to system wide + // valueOf(null) is false, + // and we actually do want null + (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? null + : Boolean.valueOf(s) + ); + + private static final BundlerParamInfo HELP_URL = createStringBundlerParam( + Arguments.CLIOptions.WIN_HELP_URL.getId()); + + private static final BundlerParamInfo UPDATE_URL = createStringBundlerParam( + Arguments.CLIOptions.WIN_UPDATE_URL.getId()); + + private static final BundlerParamInfo UPGRADE_UUID = createStringBundlerParam( + Arguments.CLIOptions.WIN_UPGRADE_UUID.getId()); +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 305259e3e9bf2..3a7a230401908 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -175,7 +175,7 @@ public boolean validate(Map params) throws ConfigException { try { // Order is important! - WinApplicationFromParams.APPLICATION.fetchFrom(params); + WinFromParams.APPLICATION.fetchFrom(params); BuildEnvFromParams.BUILD_ENV.fetchFrom(params); if (wixToolset == null) { @@ -262,7 +262,7 @@ public Path execute(Map params, IOUtils.writableOutputDir(outputParentDir); // Order is important! - var pkg = WinMsiPackageFromParams.PACKAGE.fetchFrom(params); + var pkg = WinFromParams.MSI_PACKAGE.fetchFrom(params); var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); Path imageDir = env.appImageDir(); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java new file mode 100644 index 0000000000000..e1043c707cd37 --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.MsiVersion; +import jdk.jpackage.internal.model.WinMsiPackage; + +final class WinMsiPackageBuilder { + + WinMsiPackageBuilder(PackageBuilder pkgBuilder) { + Objects.requireNonNull(pkgBuilder); + this.pkgBuilder = pkgBuilder; + } + + WinMsiPackage create() throws ConfigException { + var pkg = pkgBuilder.create(); + + try { + MsiVersion.of(pkg.version()); + } catch (IllegalArgumentException ex) { + throw ConfigException.build() + .causeAndMessage(ex) + .advice("error.version-string-wrong-format.advice") + .create(); + } + + if (pkg.app().isService() && (serviceInstaller == null || !Files.exists(serviceInstaller))) { + throw ConfigException.build() + .message("error.missing-service-installer") + .advice("error.missing-service-installer.advice") + .create(); + } + + return new WinMsiPackage.Impl( + pkg, + withInstallDirChooser, + withShortcutPrompt, + helpURL, + updateURL, + startMenuGroupName, + isSystemWideInstall, + Optional.ofNullable(upgradeCode).orElseGet(() -> upgradeCode(pkg.app())), + productCode(pkg.app(), pkg.version()), + serviceInstaller); + } + + private static UUID upgradeCode(Application app) { + return createNameUUID("UpgradeCode", app.vendor(), app.name()); + } + + private static UUID productCode(Application app, String pkgVersion) { + return createNameUUID("ProductCode", app.vendor(), app.name(), pkgVersion); + } + + WinMsiPackageBuilder withInstallDirChooser(boolean v) { + withInstallDirChooser = v; + return this; + } + + WinMsiPackageBuilder withShortcutPrompt(boolean v) { + withShortcutPrompt = v; + return this; + } + + WinMsiPackageBuilder helpURL(String v) { + helpURL = v; + return this; + } + + WinMsiPackageBuilder updateURL(String v) { + updateURL = v; + return this; + } + + WinMsiPackageBuilder startMenuGroupName(String v) { + startMenuGroupName = v; + return this; + } + + WinMsiPackageBuilder isSystemWideInstall(boolean v) { + isSystemWideInstall = v; + return this; + } + + WinMsiPackageBuilder serviceInstaller(Path v) { + serviceInstaller = v; + return this; + } + + WinMsiPackageBuilder upgradeCode(UUID v) { + upgradeCode = v; + return this; + } + + private static UUID createNameUUID(String... components) { + String key = String.join("/", components); + return UUID.nameUUIDFromBytes(key.getBytes(StandardCharsets.UTF_8)); + } + + private boolean withInstallDirChooser; + private boolean withShortcutPrompt; + private String helpURL; + private String updateURL; + private String startMenuGroupName; + private boolean isSystemWideInstall; + private Path serviceInstaller; + private UUID upgradeCode; + + private final PackageBuilder pkgBuilder; +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java deleted file mode 100644 index 7f0641066bf5c..0000000000000 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageFromParams.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal; - -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.WinMsiPackage; -import java.nio.file.Path; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; -import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; -import static jdk.jpackage.internal.PackageFromParams.createBundlerParam; -import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; -import jdk.jpackage.internal.model.WinMsiPackage.Impl; -import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; - -final class WinMsiPackageFromParams { - - private static WinMsiPackage create(Map params) throws ConfigException { - var pkg = PackageFromParams.create(params, WinApplicationFromParams.APPLICATION, WIN_MSI); - var withInstallDirChooser = INSTALLDIR_CHOOSER.fetchFrom(params); - var withShortcutPrompt = SHORTCUT_PROMPT.fetchFrom(params); - var helpURL = HELP_URL.fetchFrom(params); - var updateURL = UPDATE_URL.fetchFrom(params); - var startMenuGroupName = MENU_GROUP.fetchFrom(params); - var isSystemWideInstall = MSI_SYSTEM_WIDE.fetchFrom(params); - var upgradeCode = getUpgradeCode(params); - - final Path serviceInstaller; - if (!pkg.app().isService()) { - serviceInstaller = null; - } else { - serviceInstaller = Optional.ofNullable(RESOURCE_DIR.fetchFrom(params)).map( - resourceDir -> { - return resourceDir.resolve("service-installer.exe"); - }).orElse(null); - } - - return new Impl(pkg, withInstallDirChooser, withShortcutPrompt, helpURL, updateURL, - startMenuGroupName, isSystemWideInstall, upgradeCode, serviceInstaller); - } - - private static UUID getUpgradeCode(Map params) throws ConfigException { - try { - return Optional.ofNullable(UPGRADE_UUID.fetchFrom(params)).map(UUID::fromString).orElse( - null); - } catch (IllegalArgumentException ex) { - throw new ConfigException(ex); - } - } - - static final BundlerParamInfo PACKAGE = createBundlerParam( - WinMsiPackageFromParams::create); - - private static final BundlerParamInfo INSTALLDIR_CHOOSER = new BundlerParamInfo<>( - Arguments.CLIOptions.WIN_DIR_CHOOSER.getId(), - Boolean.class, - params -> false, - (s, p) -> Boolean.valueOf(s) - ); - - private static final BundlerParamInfo SHORTCUT_PROMPT = new BundlerParamInfo<>( - Arguments.CLIOptions.WIN_SHORTCUT_PROMPT.getId(), - Boolean.class, - params -> false, - (s, p) -> Boolean.valueOf(s) - ); - - private static final BundlerParamInfo MENU_GROUP = new BundlerParamInfo<>( - Arguments.CLIOptions.WIN_MENU_GROUP.getId(), - String.class, - params -> I18N.getString("param.menu-group.default"), - (s, p) -> s - ); - - private static final BundlerParamInfo MSI_SYSTEM_WIDE = new BundlerParamInfo<>( - Arguments.CLIOptions.WIN_PER_USER_INSTALLATION.getId(), - Boolean.class, - params -> true, // MSIs default to system wide - // valueOf(null) is false, - // and we actually do want null - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? null - : Boolean.valueOf(s) - ); - - private static final BundlerParamInfo HELP_URL = createStringBundlerParam( - Arguments.CLIOptions.WIN_HELP_URL.getId()); - - private static final BundlerParamInfo UPDATE_URL = createStringBundlerParam( - Arguments.CLIOptions.WIN_UPDATE_URL.getId()); - - private static final BundlerParamInfo UPGRADE_UUID = createStringBundlerParam( - Arguments.CLIOptions.WIN_UPGRADE_UUID.getId()); -} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java index 3141f71ff78fc..9ae4f2d751861 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java @@ -27,7 +27,7 @@ import java.math.BigInteger; -final class MsiVersion { +public final class MsiVersion { /** * Parse the given string as Windows MSI Product version. * https://msdn.microsoft.com/en-us/library/aa370859%28v=VS.85%29.aspx The @@ -38,7 +38,7 @@ final class MsiVersion { * 65,535. * @throws IllegalArgumentException */ - static DottedVersion of(String value) { + public static DottedVersion of(String value) { DottedVersion ver = DottedVersion.greedy(value); BigInteger[] components = ver.getComponents(); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java index 6a431403bd9bd..beb09740d517f 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java @@ -30,7 +30,7 @@ default DottedVersion winVersion() { return DottedVersion.lazy(version()); } - public static class Impl extends Application.Proxy implements WinApplication { + class Impl extends Application.Proxy implements WinApplication { public Impl(Application app) { super(app); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java index 25237d3294210..4e241071052c0 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java @@ -32,14 +32,11 @@ public interface WinExePackage extends Package { Path icon(); - public static class Impl extends Package.Proxy implements WinExePackage { + class Impl extends Package.Proxy implements WinExePackage { public Impl(WinMsiPackage msiPackage, Path icon) throws ConfigException { super(msiPackage); this.icon = icon; - if (icon != null) { - Launcher.validateIcon(icon); - } } @Override diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java index ab0526d38ae5e..eed66091b72d1 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java @@ -25,7 +25,10 @@ package jdk.jpackage.internal.model; import java.io.InputStream; +import java.util.Map; +import java.util.Optional; import java.util.Set; +import static java.util.stream.Collectors.toMap; import jdk.jpackage.internal.resources.ResourceLocator; public interface WinLauncher extends Launcher { @@ -43,19 +46,36 @@ default InputStream executableResource() { isConsole() ? "jpackageapplauncher.exe" : "jpackageapplauncherw.exe"); } + @Override + default Map extraAppImageFileData() { + return Optional.ofNullable(shortcuts()).orElseGet(Set::of).stream().collect( + toMap(WinShortcut::name, v -> Boolean.toString(true))); + } + @Override default String defaultIconResourceName() { return "JavaApp.ico"; } enum WinShortcut { - WIN_SHORTCUT_DESKTOP, - WIN_SHORTCUT_START_MENU + WIN_SHORTCUT_DESKTOP("shortcut"), + WIN_SHORTCUT_START_MENU("menu"), + ; + + WinShortcut(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + private final String name; } Set shortcuts(); - public static class Impl extends Launcher.Proxy implements WinLauncher { + class Impl extends Launcher.Proxy implements WinLauncher { public Impl(Launcher launcher, boolean isConsole, Set shortcuts) { super(launcher); this.isConsole = isConsole; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java index 8a0bd35ea4f09..090f1b94034dd 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal.model; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Optional; import java.util.UUID; @@ -48,40 +47,21 @@ default DottedVersion msiVersion() { boolean isSystemWideInstall(); - default UUID upgradeCode() { - return createNameUUID("UpgradeCode", app().vendor(), app().name()); - } + UUID upgradeCode(); - default UUID productCode() { - return createNameUUID("ProductCode", app().vendor(), app().name(), version()); - } + UUID productCode(); Path serviceInstaller(); - public static class Impl extends Package.Proxy implements WinMsiPackage { + class Impl extends Package.Proxy implements WinMsiPackage { public Impl(Package pkg, boolean withInstallDirChooser, boolean withShortcutPrompt, String helpURL, String updateURL, String startMenuGroupName, boolean isSystemWideInstall, - UUID upgradeCode, Path serviceInstaller) throws ConfigException { + UUID upgradeCode, UUID productCode, Path serviceInstaller) + throws ConfigException { super(pkg); - try { - MsiVersion.of(pkg.version()); - } catch (IllegalArgumentException ex) { - throw ConfigException.build() - .causeAndMessage(ex) - .advice("error.version-string-wrong-format.advice") - .create(); - } - - if (pkg.app().isService() && (serviceInstaller == null || !Files.exists(serviceInstaller))) { - throw ConfigException.build() - .message("error.missing-service-installer") - .advice("error.missing-service-installer.advice") - .create(); - } - this.withInstallDirChooser = withInstallDirChooser; this.withShortcutPrompt = withShortcutPrompt; this.helpURL = helpURL; @@ -89,6 +69,7 @@ public Impl(Package pkg, boolean withInstallDirChooser, this.startMenuGroupName = startMenuGroupName; this.isSystemWideInstall = isSystemWideInstall; this.upgradeCode = upgradeCode; + this.productCode = productCode; this.serviceInstaller = serviceInstaller; } @@ -124,7 +105,12 @@ public boolean isSystemWideInstall() { @Override public UUID upgradeCode() { - return Optional.ofNullable(upgradeCode).orElseGet(WinMsiPackage.super::upgradeCode); + return upgradeCode; + } + + @Override + public UUID productCode() { + return productCode; } @Override @@ -139,11 +125,7 @@ public Path serviceInstaller() { private final String startMenuGroupName; private final boolean isSystemWideInstall; private final UUID upgradeCode; + private final UUID productCode; private final Path serviceInstaller; } - - private static UUID createNameUUID(String... components) { - String key = String.join("/", components); - return UUID.nameUUIDFromBytes(key.getBytes(StandardCharsets.UTF_8)); - } } From 4ae566baf4d7f919650cf938258c96f0d2c5a6ee Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 00:32:32 -0400 Subject: [PATCH 0085/1101] Split ApplicationLayout into AppImageLayout, ApplicationLayout, and RuntimeLayout. --- .../jpackage/internal/DesktopIntegration.java | 6 +- .../internal/LinuxAppImageBuilder.java | 14 +- .../internal/LinuxApplicationLayout.java | 52 +++ .../jpackage/internal/LinuxDebBundler.java | 5 +- .../jpackage/internal/LinuxFromParams.java | 3 +- .../internal/LinuxLaunchersAsServices.java | 7 +- .../internal/LinuxPackageBuilder.java | 30 +- .../internal/LinuxPackageBundler.java | 18 +- .../jpackage/internal/model/LinuxPackage.java | 26 +- .../jpackage/internal/AppImageBuilder.java | 6 +- .../jdk/jpackage/internal/AppImageFile2.java | 39 +- .../jpackage/internal/ApplicationBuilder.java | 14 +- .../jdk/jpackage/internal/CfgFile.java | 14 +- .../jdk/jpackage/internal/FromParams.java | 8 +- .../internal/JLinkRuntimeBuilder.java | 6 +- .../jdk/jpackage/internal/PackageFile.java | 17 +- .../internal/RuntimeBuilderBuilder.java | 31 +- .../internal/model/AppImageLayout.java | 86 +++++ .../jpackage/internal/model/Application.java | 35 +- .../internal/model/ApplicationLayout.java | 344 ++++++++++-------- .../jdk/jpackage/internal/model/Package.java | 36 +- .../internal/model/RuntimeBuilder.java | 3 +- .../{Getter.java => model/RuntimeLayout.java} | 27 +- .../resources/MainResources.properties | 4 +- .../jdk/jpackage/internal/util/PathGroup.java | 32 -- .../jdk/jpackage/internal/util/PathUtils.java | 3 + .../jpackage/internal/WinAppImageBuilder.java | 8 + .../jdk/jpackage/internal/WinFromParams.java | 3 +- .../jdk/jpackage/internal/WinMsiBundler.java | 20 +- .../internal/WixAppImageFragmentBuilder.java | 63 ++-- .../internal/model/ApplicationLayoutTest.java | 11 +- 31 files changed, 606 insertions(+), 365 deletions(-) create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{Getter.java => model/RuntimeLayout.java} (67%) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index ca9ba8d7c4276..b3ec69592ee2e 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -236,7 +236,7 @@ private Map createDataForDesktopFile() { f -> f.installPath().toString()).orElse(null)); data.put("DEPLOY_BUNDLE_CATEGORY", pkg.category()); data.put("APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo( - pkg.installedPackageLayout().launchersDirectory().resolve( + pkg.asInstalledPackageApplicationLayout().launchersDirectory().resolve( launcher.executableNameWithSuffix()).toString())); return data; @@ -337,9 +337,9 @@ void applyTo(Map data) { * - installPath(): path where it should be installed by package manager; */ private InstallableFile createDesktopFile(String fileName) { - var srcPath = pkg.packageLayout().resolveAt(env.appImageDir()).destktopIntegrationDirectory().resolve( + var srcPath = pkg.asPackageApplicationLayout().resolveAt(env.appImageDir()).destktopIntegrationDirectory().resolve( fileName); - var installPath = pkg.installedPackageLayout().destktopIntegrationDirectory().resolve( + var installPath = pkg.asInstalledPackageApplicationLayout().destktopIntegrationDirectory().resolve( fileName); return new InstallableFile(srcPath, installPath); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index 2ed79857aa5d3..c24b1232ee13e 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -45,8 +45,7 @@ private final static class LauncherCallbackImpl implements AppImageBuilder.Launc public void onLauncher(Application app, AppImageBuilder.LauncherContext ctx) throws IOException, PackagerException { if (ctx.launcher() == app.mainLauncher()) { - var launcherLib = ctx.resolvedAppLayout().pathGroup().getPath( - ApplicationLayout.PathRole.LINUX_APPLAUNCHER_LIB); + var launcherLib = ((LinuxApplicationLayout)ctx.resolvedAppLayout()).libAppLauncher(); try (var in = ResourceLocator.class.getResourceAsStream("libjpackageapplauncheraux.so")) { Files.createDirectories(launcherLib.getParent()); Files.copy(in, launcherLib); @@ -64,4 +63,15 @@ public void onLauncher(Application app, launcherIcon.saveToFile(iconTarget); } } + + final static LinuxApplicationLayout APPLICATION_LAYOUT = new LinuxApplicationLayout( + ApplicationLayout.build() + .launchersDirectory("bin") + .appDirectory("lib/app") + .runtimeDirectory("lib/runtime") + .destktopIntegrationDirectory("lib") + .appModsDirectory("lib/app/mods") + .contentDirectory("lib") + .create(), + Path.of("lib/libapplauncher.so")); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java new file mode 100644 index 0000000000000..8c6910fca445d --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import jdk.jpackage.internal.model.*; +import java.nio.file.Path; +import static jdk.jpackage.internal.util.PathUtils.resolveNullable; + +final class LinuxApplicationLayout extends ApplicationLayout.Proxy { + + LinuxApplicationLayout(ApplicationLayout layout, Path libAppLauncher) { + super(layout); + this.libAppLauncher = libAppLauncher; + } + + @Override + public LinuxApplicationLayout resolveAt(Path root) { + return new LinuxApplicationLayout(target.resolveAt(root), + resolveNullable(root, libAppLauncher)); + } + + /** + * Path to "libapplauncher.so". + */ + Path libAppLauncher() { + return libAppLauncher; + } + + private final Path libAppLauncher; +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index 159aed254c2fe..9c34562161688 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -52,6 +52,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.AppImageLayout; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; @@ -347,7 +348,9 @@ protected Map createReplacementData(BuildEnv env, LinuxPackage p data.put("APPLICATION_COPYRIGHT", pkg.app().copyright()); data.put("APPLICATION_LICENSE_TEXT", licenseText); data.put("APPLICATION_ARCH", pkg.arch()); - data.put("APPLICATION_INSTALLED_SIZE", Long.toString(pkg.packageLayout().resolveAt(env.appImageDir()).sizeInBytes() >> 10)); + data.put("APPLICATION_INSTALLED_SIZE", Long.toString( + AppImageLayout.toPathGroup(pkg.packageLayout().resolveAt( + env.appImageDir())).sizeInBytes() >> 10)); data.put("APPLICATION_HOMEPAGE", Optional.ofNullable(pkg.aboutURL()).map( value -> "Homepage: " + value).orElse("")); data.put("APPLICATION_VERSION_WITH_RELEASE", ((LinuxDebPackage) pkg).versionWithRelease()); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java index 91ce997a8cf0c..31aa4f15ca885 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java @@ -33,6 +33,7 @@ import static jdk.jpackage.internal.FromParams.createApplicationBundlerParam; import static jdk.jpackage.internal.FromParams.createPackageBuilder; import static jdk.jpackage.internal.FromParams.createPackageBundlerParam; +import static jdk.jpackage.internal.LinuxAppImageBuilder.APPLICATION_LAYOUT; import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; import jdk.jpackage.internal.model.LinuxApplication; import jdk.jpackage.internal.model.LinuxLauncher; @@ -55,7 +56,7 @@ private static LinuxApplication createLinuxApplication( return param.fetchFrom(params); }).findFirst(); return new LinuxLauncher.Impl(launcher, shortcut); - })).create(); + }), APPLICATION_LAYOUT).create(); return new LinuxApplication.Impl(app); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java index a90b23ffdff6e..c3bbef5a5dc4a 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java @@ -79,8 +79,11 @@ private static class LauncherImpl extends UnixLauncherAsService { unitFilename = getServiceUnitFileName(pkg.packageName(), launcher.executableName()); - getResource().setPublicName(unitFilename).addSubstitutionDataEntry("APPLICATION_LAUNCHER", - Enquoter.forPropertyValues().applyTo(pkg.installedPackageLayout().resolveAt(env.appImageDir()).launchersDirectory().resolve( + getResource().setPublicName(unitFilename).addSubstitutionDataEntry( + "APPLICATION_LAUNCHER", + Enquoter.forPropertyValues().applyTo( + pkg.asInstalledPackageApplicationLayout().resolveAt( + env.appImageDir()).launchersDirectory().resolve( getName()).toString())); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index 9a8d26666360a..096021d1bf1ab 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -24,9 +24,12 @@ */ package jdk.jpackage.internal; +import java.nio.file.Path; import java.util.Objects; import java.util.Optional; import java.util.regex.Pattern; +import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxPackage; import jdk.jpackage.internal.model.StandardPackageType; @@ -50,7 +53,18 @@ LinuxPackage create() throws ConfigException { validatePackageName(pkg.packageName(), pkg.asStandardPackageType()); + var reply = create(pkg, pkg.packageLayout()); + if (reply.isInstallDirInUsrTree()) { + reply = create(pkg, usrTreePackageLayout(pkg.relativeInstallDir(), pkg.packageName())); + } + + return reply; + } + + private LinuxPackage create(jdk.jpackage.internal.model.Package pkg, + AppImageLayout pkgLayout) throws ConfigException { return new LinuxPackage.Impl(pkg, + pkgLayout, Optional.ofNullable(menuGroupName).orElseGet(DEFAULTS::menuGroupName), Optional.ofNullable(category).orElseGet(DEFAULTS::category), additionalDependencies, @@ -78,6 +92,20 @@ LinuxPackageBuilder release(String v) { return this; } + private static LinuxApplicationLayout usrTreePackageLayout(Path prefix, String packageName) { + final var lib = prefix.resolve(Path.of("lib", packageName)); + return new LinuxApplicationLayout( + ApplicationLayout.build() + .launchersDirectory(prefix.resolve("bin")) + .appDirectory(lib.resolve("app")) + .runtimeDirectory(lib.resolve("runtime")) + .destktopIntegrationDirectory(lib) + .appModsDirectory(lib.resolve("app/mods")) + .contentDirectory(lib) + .create(), + lib.resolve("lib/libapplauncher.so")); + } + private static void validatePackageName(String packageName, StandardPackageType pkgType) throws ConfigException { switch (pkgType) { @@ -132,5 +160,5 @@ private record Defaults(String release, String menuGroupName, String category) { private static final Defaults DEFAULTS = new Defaults("1", I18N.getString( "param.menu-group.default"), "misc"); - + } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index d478bf1b177fa..4199ab9374c91 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -39,6 +39,8 @@ import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Stream; +import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.ApplicationLayout; abstract class LinuxPackageBundler extends AbstractBundler { @@ -125,12 +127,16 @@ public final Path execute(Map params, } } - // Copy app layout omitting application image info file. - var srcLayout = pkg.appLayout().resolveAt(srcAppImageDir); - Optional.ofNullable(AppImageFile2.getPathInAppImage(srcLayout)).ifPresent( - appImageFile -> srcLayout.pathGroup().ghostPath( - appImageFile)); - srcLayout.copy(pkg.packageLayout().resolveAt(pkgEnv.appImageDir())); + var srcLayout = pkg.appImageLayout().resolveAt(srcAppImageDir); + var srcLayoutPathGroup = AppImageLayout.toPathGroup(srcLayout); + + if (srcLayout instanceof ApplicationLayout appLayout) { + // Copy app layout omitting application image info file. + srcLayoutPathGroup.ghostPath(AppImageFile2.getPathInAppImage(appLayout)); + } + + srcLayoutPathGroup.copy(AppImageLayout.toPathGroup( + pkg.packageLayout().resolveAt(pkgEnv.appImageDir()))); } for (var ca : customActions) { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java index 0b39b423d0598..8c76201f015d3 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java @@ -39,13 +39,7 @@ public interface LinuxPackage extends Package { String arch(); @Override - default ApplicationLayout packageLayout() { - if (isInstallDirInUsrTree()) { - return ApplicationLayout.linuxUsrTreePackageImage(relativeInstallDir(), packageName()); - } else { - return Package.super.packageLayout(); - } - } + AppImageLayout packageLayout(); @Override default String packageFileName() { @@ -71,9 +65,12 @@ default boolean isInstallDirInUsrTree() { class Impl extends Package.Proxy implements LinuxPackage { - public Impl(Package target, String menuGroupName, String category, - String additionalDependencies, String release, String arch) throws ConfigException { + public Impl(Package target, AppImageLayout packageLayout, + String menuGroupName, String category, + String additionalDependencies, String release, String arch) + throws ConfigException { super(target); + this.packageLayout = packageLayout; this.menuGroupName = menuGroupName; this.category = category; this.release = release; @@ -81,6 +78,11 @@ public Impl(Package target, String menuGroupName, String category, this.arch = arch; } + @Override + public AppImageLayout packageLayout() { + return packageLayout; + } + @Override public String menuGroupName() { return menuGroupName; @@ -106,6 +108,7 @@ public String arch() { return arch; } + private final AppImageLayout packageLayout; private final String menuGroupName; private final String category; private final String additionalDependencies; @@ -119,6 +122,11 @@ public Proxy(T target) { super(target); } + @Override + public AppImageLayout packageLayout() { + return target.packageLayout(); + } + @Override public String menuGroupName() { return target.menuGroupName(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java index 03e292c0d34fa..7d0b987713ac0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -50,7 +50,7 @@ Builder launcherCallback(LauncherCallback v) { } AppImageBuilder create(Application app) { - return new AppImageBuilder(app, app.appLayout(), launcherCallback); + return new AppImageBuilder(app, app.asApplicationLayout(), launcherCallback); } AppImageBuilder create(Package pkg) { @@ -72,7 +72,7 @@ private AppImageBuilder(Application app, ApplicationLayout appLayout, LauncherCa } private AppImageBuilder(Package pkg, LauncherCallback launcherCallback) { - this(pkg.app(), pkg.packageLayout(), launcherCallback); + this(pkg.app(), pkg.asPackageApplicationLayout(), launcherCallback); } private static void copyRecursive(Path srcDir, Path dstDir, BuildEnv env) throws IOException { @@ -111,7 +111,7 @@ void execute(BuildEnv env) throws IOException, PackagerException { } if (withAppImageFile) { - new AppImageFile2(app).save(env.appImageDir()); + new AppImageFile2(app).save(resolvedAppLayout); } for (var launcher : app.launchers()) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index c831c55258af8..12b0f301a069f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -33,7 +33,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.NoSuchFileException; -import java.text.MessageFormat; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -117,11 +116,9 @@ String getMainClass() { /** * Saves file with application image info in application image using values * from this instance. - * @param appImageDir - path to application image - * @throws IOException */ - void save(Path appImageDir) throws IOException { - XmlUtils.createXml(getPathInAppImage(appImageDir), xml -> { + void save(ApplicationLayout appLayout) throws IOException { + XmlUtils.createXml(getPathInAppImage(appLayout), xml -> { xml.writeStartElement("jpackage-state"); xml.writeAttribute("version", creatorVersion); xml.writeAttribute("platform", creatorPlatform); @@ -158,34 +155,22 @@ void save(Path appImageDir) throws IOException { }); } - /** - * Returns path to application image info file. - * @param appImageDir - path to application image - */ - static Path getPathInAppImage(Path appImageDir) { - return getPathInAppImage(ApplicationLayout.platformAppImage().resolveAt( - appImageDir)); - } - /** * Returns path to application image info file. * @param appLayout - application layout */ static Path getPathInAppImage(ApplicationLayout appLayout) { - return Optional.ofNullable(appLayout.appDirectory()).map( - path -> path.resolve(FILENAME)).orElse(null); + return appLayout.appDirectory().resolve(FILENAME); } /** * Loads application image info from application image. - * @param appImageDir - path to application image - * @return valid info about application image or null - * @throws IOException + * @param appLayout - application layout */ - static AppImageFile2 load(Path appImageDir) throws ConfigException, IOException { + static AppImageFile2 load(ApplicationLayout appLayout) throws ConfigException, IOException { + var srcFilePath = getPathInAppImage(appLayout); try { - Document doc = XmlUtils.initDocumentBuilder().parse( - Files.newInputStream(getPathInAppImage(appImageDir))); + Document doc = XmlUtils.initDocumentBuilder().parse(Files.newInputStream(srcFilePath)); XPath xPath = XPathFactory.newInstance().newXPath(); @@ -263,12 +248,14 @@ public Map extraAppImageFileData() { // Exception reading input XML (probably malformed XML) throw new IOException(ex); } catch (NoSuchFileException ex) { - throw new ConfigException(MessageFormat.format(I18N.getString( - "error.foreign-app-image"), appImageDir), null); + throw ConfigException.build() + .message(I18N.format("error.foreign-app-image", FILENAME)) + .create(); } catch (InavlidAppImageFileException ex) { // Invalid input XML - throw new ConfigException(MessageFormat.format(I18N.getString( - "error.invalid-app-image"), appImageDir), null); + throw ConfigException.build() + .message(I18N.format("error.invalid-app-image-file", FILENAME)) + .create(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 03137b0b026ec..24839535fba80 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -28,9 +28,11 @@ import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; import jdk.jpackage.internal.AppImageFile2.LauncherInfo; +import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLaunchers; import jdk.jpackage.internal.model.ConfigException; @@ -40,6 +42,8 @@ final class ApplicationBuilder { Application create() throws ConfigException { + Objects.requireNonNull(appImageLayout); + final var launchersAsList = Optional.ofNullable(launchers).map( ApplicationLaunchers::asList).orElseGet(List::of); final String effectiveName; @@ -60,7 +64,7 @@ Application create() throws ConfigException { Optional.ofNullable(version).orElseGet(DEFAULTS::version), Optional.ofNullable(vendor).orElseGet(DEFAULTS::vendor), Optional.ofNullable(copyright).orElseGet(DEFAULTS::copyright), - srcDir, contentDirs, runtimeBuilder, launchersAsList); + srcDir, contentDirs, appImageLayout, runtimeBuilder, launchersAsList); } ApplicationBuilder runtimeBuilder(RuntimeBuilder v) { @@ -92,6 +96,11 @@ ApplicationBuilder launchers(ApplicationLaunchers v) { return this; } + ApplicationBuilder appImageLayout(AppImageLayout v) { + appImageLayout = v; + return this; + } + ApplicationBuilder name(String v) { name = v; return this; @@ -137,9 +146,10 @@ private record Defaults(String description, String version, String vendor, Strin private String copyright; private Path srcDir; private List contentDirs; + private AppImageLayout appImageLayout; private RuntimeBuilder runtimeBuilder; private ApplicationLaunchers launchers; - + private static final Defaults DEFAULTS = new Defaults( I18N.getString("param.description.default"), "1.0", diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java index 3700af97c30a4..21a04e531446a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java @@ -124,12 +124,14 @@ void create(ApplicationLayout unresolvedAppLayout, ApplicationLayout appLayout) } private ApplicationLayout createAppCfgLayout(ApplicationLayout appLayout) { - ApplicationLayout appCfgLayout = appLayout.resolveAt(Path.of("$ROOTDIR")); - appCfgLayout.pathGroup().setPath(ApplicationLayout.PathRole.APP, - Path.of("$APPDIR")); - appCfgLayout.pathGroup().setPath(ApplicationLayout.PathRole.MODULES, - appCfgLayout.appDirectory().resolve(appCfgLayout.appModsDirectory().getFileName())); - return appCfgLayout; + return ApplicationLayout + .buildFrom(appLayout.resolveAt(Path.of("$ROOTDIR"))) + .appDirectory("$APPDIR") + .appModsDirectory( + Path.of("$APPDIR").resolve( + appLayout.appModsDirectory().relativize( + appLayout.appDirectory()))) + .create(); } private final LauncherStartupInfo startupInfo; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java index cd1f52c57d31e..1e8a917d2e9be 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -55,15 +55,17 @@ import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; +import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLaunchers; +import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.util.function.ThrowingFunction; final class FromParams { static ApplicationBuilder createApplicationBuilder(Map params, - Function, Launcher> launcherMapper) + Function, Launcher> launcherMapper, AppImageLayout appLayout) throws ConfigException, IOException { var appBuilder = new ApplicationBuilder() @@ -73,12 +75,14 @@ static ApplicationBuilder createApplicationBuilder(Map p .vendor(VENDOR.fetchFrom(params)) .copyright(COPYRIGHT.fetchFrom(params)) .srcDir(SOURCE_DIR.fetchFrom(params)) + .appImageLayout(appLayout) .contentDirs(APP_CONTENT.fetchFrom(params)); var predefinedAppImage = getPredefinedAppImage(params); if (predefinedAppImage != null) { - var appIMafeFile = AppImageFile2.load(predefinedAppImage); + var appIMafeFile = AppImageFile2.load( + (ApplicationLayout) appLayout.resolveAt(predefinedAppImage)); appBuilder.initFromAppImage(appIMafeFile, launcherInfo -> { var launcherParams = mapLauncherInfo(launcherInfo); return launcherMapper.apply(mergeParams(params, launcherParams)); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java index 2e54dc30d4297..febe0b9126d80 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java @@ -28,7 +28,6 @@ import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.LauncherStartupInfo; import jdk.jpackage.internal.model.LauncherModularStartupInfo; -import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.RuntimeBuilder; import java.io.File; import java.io.IOException; @@ -54,6 +53,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.module.ModulePath; +import jdk.jpackage.internal.model.AppImageLayout; final class JLinkRuntimeBuilder implements RuntimeBuilder { @@ -62,10 +62,10 @@ private JLinkRuntimeBuilder(List jlinkCmdLine) { } @Override - public void createRuntime(ApplicationLayout appLayout) throws PackagerException, IOException { + public void createRuntime(AppImageLayout appImageLayout) throws PackagerException, IOException { var args = new ArrayList(); args.add("--output"); - args.add(appLayout.runtimeHomeDirectory().toString()); + args.add(appImageLayout.runtimeDirectory().toString()); args.addAll(jlinkCmdLine); StringWriter writer = new StringWriter(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java index e4a69c9a6344d..e225305c6caee 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java @@ -30,26 +30,15 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; -import java.util.Optional; -public final class PackageFile { - - /** - * Returns path to package file. - * @param appImageDir - path to application image - */ - public static Path getPathInAppImage(Path appImageDir) { - return getPathInAppImage(ApplicationLayout.platformAppImage().resolveAt( - appImageDir)); - } +final class PackageFile { /** * Returns path to package file. * @param appLayout - application layout */ - public static Path getPathInAppImage(ApplicationLayout appLayout) { - return Optional.ofNullable(appLayout.appDirectory()).map( - path -> path.resolve(FILENAME)).orElse(null); + static Path getPathInAppImage(ApplicationLayout appLayout) { + return appLayout.appDirectory().resolve(FILENAME); } PackageFile(String packageName) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java index 98cc84f128616..a88987ef6c58c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java @@ -26,9 +26,6 @@ import java.nio.file.Files; import java.nio.file.LinkOption; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.LauncherStartupInfo; -import jdk.jpackage.internal.model.RuntimeBuilder; import java.nio.file.Path; import java.util.Arrays; import java.util.List; @@ -36,7 +33,10 @@ import java.util.Optional; import java.util.Set; import java.util.function.Supplier; -import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LauncherStartupInfo; +import jdk.jpackage.internal.model.RuntimeBuilder; import static jdk.jpackage.internal.model.RuntimeBuilder.getDefaultModulePath; import jdk.jpackage.internal.util.FileUtils; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; @@ -109,19 +109,17 @@ private static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, .create(); } - return appLayout -> { - final Path runtimeHome = getRuntimeHome(runtimeDir); - + return appImageLayout -> { // copy whole runtime, need to skip jmods and src.zip final List excludes = Arrays.asList("jmods", "src.zip"); - FileUtils.copyRecursive(runtimeHome, - appLayout.runtimeHomeDirectory(), + FileUtils.copyRecursive(runtimeDir, + appImageLayout.runtimeDirectory(), excludes, LinkOption.NOFOLLOW_LINKS); // if module-path given - copy modules to appDir/mods List defaultModulePath = getDefaultModulePath(); - Path dest = appLayout.appModsDirectory(); + Path dest = ((ApplicationLayout)appImageLayout).appModsDirectory(); for (Path mp : modulePath) { if (!defaultModulePath.contains(mp.toAbsolutePath())) { @@ -131,19 +129,6 @@ private static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, }; } - private static Path getRuntimeHome(Path runtimeDir) { - if (OperatingSystem.isMacOS()) { - // On Mac topImage can be runtime root or runtime home. - Path runtimeHome = runtimeDir.resolve("Contents/Home"); - if (Files.isDirectory(runtimeHome)) { - // topImage references runtime root, adjust it to pick data from - // runtime home - return runtimeHome; - } - } - return runtimeDir; - } - private record CopyingRuntime(RuntimeBuilderBuilder thiz, Path predefinedRuntimeImage) implements Supplier { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java new file mode 100644 index 0000000000000..e73800d467627 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + + +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; +import jdk.jpackage.internal.util.PathGroup; +import static jdk.jpackage.internal.util.PathUtils.resolveNullable; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; + + +/** + * App image directory layout. + */ +public interface AppImageLayout { + + /** + * Path to Java run-time directory. + */ + Path runtimeDirectory(); + + AppImageLayout resolveAt(Path root); + + record Impl(Path runtimeDirectory) implements AppImageLayout { + + @Override + public AppImageLayout resolveAt(Path base) { + return new Impl(resolveNullable(base, runtimeDirectory)); + } + } + + class Proxy extends ProxyBase implements AppImageLayout { + + public Proxy(T target) { + super(target); + } + + @Override + public Path runtimeDirectory() { + return target.runtimeDirectory(); + } + + @Override + public AppImageLayout resolveAt(Path root) { + return target.resolveAt(root); + } + } + + public static PathGroup toPathGroup(AppImageLayout appImageLayout) { + return new PathGroup(Stream.of(appImageLayout.getClass().getMethods()).filter(m -> { + return m.getReturnType().isAssignableFrom(Path.class) && m.getParameterCount() == 0; + }).>mapMulti((m, consumer) -> { + Optional.ofNullable(toFunction(m::invoke).apply(appImageLayout)).ifPresent(path -> { + consumer.accept(Map.entry(m.getName(), (Path)path)); + }); + }).collect(HashMap::new, (ctnr, e) -> { + ctnr.put(e.getKey(), e.getValue()); + }, Map::putAll)); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index be4dca5864287..49d74d756b3ce 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -48,6 +48,16 @@ public interface Application { List contentDirs(); + AppImageLayout imageLayout(); + + default ApplicationLayout asApplicationLayout() { + if (imageLayout() instanceof ApplicationLayout layout) { + return layout; + } else { + throw new UnsupportedOperationException(); + } + } + RuntimeBuilder runtimeBuilder(); default Path appImageDirName() { @@ -73,14 +83,6 @@ default boolean isService() { Launcher::isService).findAny().isPresent(); } - default ApplicationLayout appLayout() { - if (isRuntime()) { - return ApplicationLayout.javaRuntime(); - } else { - return ApplicationLayout.platformAppImage(); - } - } - default Map extraAppImageFileData() { return Map.of(); } @@ -116,9 +118,10 @@ default OverridableResource createLauncherIconResource(Launcher launcher, return resource; } - record Impl(String name, String description, String version, - String vendor, String copyright, Path srcDir, List contentDirs, - RuntimeBuilder runtimeBuilder, List launchers) implements Application { + record Impl(String name, String description, String version, String vendor, + String copyright, Path srcDir, List contentDirs, + AppImageLayout imageLayout, RuntimeBuilder runtimeBuilder, + List launchers) implements Application { } class Proxy extends ProxyBase implements Application { @@ -162,6 +165,11 @@ public List contentDirs() { return target.contentDirs(); } + @Override + public AppImageLayout imageLayout() { + return target.imageLayout(); + } + @Override public RuntimeBuilder runtimeBuilder() { return target.runtimeBuilder(); @@ -210,6 +218,11 @@ public List contentDirs() { throw new UnsupportedOperationException(); } + @Override + public AppImageLayout imageLayout() { + throw new UnsupportedOperationException(); + } + @Override public RuntimeBuilder runtimeBuilder() { throw new UnsupportedOperationException(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index 9c5176e7681a5..b91a61cb2dd90 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -24,198 +24,238 @@ */ package jdk.jpackage.internal.model; -import jdk.jpackage.internal.util.PathGroup; -import jdk.internal.util.OperatingSystem; - import java.nio.file.Path; -import java.util.Map; - +import static jdk.jpackage.internal.util.PathUtils.resolveNullable; /** * Application directory layout. */ -public final class ApplicationLayout implements PathGroup.Facade { - public enum PathRole { - /** - * Java run-time directory. - */ - RUNTIME, - - /** - * Java run-time home directory. - */ - RUNTIME_HOME, - - /** - * Application data directory. - */ - APP, - - /** - * Directory with application launchers. - */ - LAUNCHERS, - - /** - * Directory for files for desktop integration. - */ - DESKTOP, - - /** - * Directory with application Java modules. - */ - MODULES, - - /** - * Linux app launcher shared library. - */ - LINUX_APPLAUNCHER_LIB, - - /** - * Location of additional application content - */ - CONTENT - } - - private ApplicationLayout(Map paths) { - data = new PathGroup(paths); - } - - private ApplicationLayout(PathGroup data) { - this.data = data; - } - - @Override - public PathGroup pathGroup() { - return data; - } - - @Override - public ApplicationLayout resolveAt(Path root) { - return new ApplicationLayout(pathGroup().resolveAt(root)); - } +public interface ApplicationLayout extends AppImageLayout { /** * Path to launchers directory. */ - public Path launchersDirectory() { - return pathGroup().getPath(PathRole.LAUNCHERS); - } + Path launchersDirectory(); /** * Path to application data directory. */ - public Path appDirectory() { - return pathGroup().getPath(PathRole.APP); - } - - /** - * Path to Java run-time directory. - */ - public Path runtimeDirectory() { - return pathGroup().getPath(PathRole.RUNTIME); - } - - /** - * Path to Java run-time home directory. - */ - public Path runtimeHomeDirectory() { - return pathGroup().getPath(PathRole.RUNTIME_HOME); - } + Path appDirectory(); /** * Path to application mods directory. */ - public Path appModsDirectory() { - return pathGroup().getPath(PathRole.MODULES); - } + Path appModsDirectory(); /** * Path to directory with application's desktop integration files. */ - public Path destktopIntegrationDirectory() { - return pathGroup().getPath(PathRole.DESKTOP); - } + Path destktopIntegrationDirectory(); /** * Path to directory with additional application content. */ - public Path contentDirectory() { - return pathGroup().getPath(PathRole.CONTENT); - } + Path contentDirectory(); - public static ApplicationLayout linuxAppImage() { - return new ApplicationLayout(Map.of( - PathRole.LAUNCHERS, Path.of("bin"), - PathRole.APP, Path.of("lib/app"), - PathRole.RUNTIME, Path.of("lib/runtime"), - PathRole.RUNTIME_HOME, Path.of("lib/runtime"), - PathRole.DESKTOP, Path.of("lib"), - PathRole.MODULES, Path.of("lib/app/mods"), - PathRole.LINUX_APPLAUNCHER_LIB, Path.of("lib/libapplauncher.so"), - PathRole.CONTENT, Path.of("lib") - )); + @Override + ApplicationLayout resolveAt(Path root); + + final class Impl extends AppImageLayout.Proxy implements ApplicationLayout { + + public Impl(AppImageLayout target, Path launchersDirectory, + Path appDirectory, Path appModsDirectory, + Path destktopIntegrationDirectory, Path contentDirectory) { + super(target); + this.launchersDirectory = launchersDirectory; + this.appDirectory = appDirectory; + this.appModsDirectory = appModsDirectory; + this.destktopIntegrationDirectory = destktopIntegrationDirectory; + this.contentDirectory = contentDirectory; + } + + @Override + public Path launchersDirectory() { + return launchersDirectory; + } + + @Override + public Path appDirectory() { + return appDirectory; + } + + @Override + public Path appModsDirectory() { + return appModsDirectory; + } + + @Override + public Path destktopIntegrationDirectory() { + return destktopIntegrationDirectory; + } + + @Override + public Path contentDirectory() { + return contentDirectory; + } + + @Override + public ApplicationLayout resolveAt(Path base) { + return new ApplicationLayout.Impl(target, + resolveNullable(base, launchersDirectory), + resolveNullable(base, appDirectory), + resolveNullable(base, appModsDirectory), + resolveNullable(base, destktopIntegrationDirectory), + resolveNullable(base, contentDirectory)); + } + + private final Path launchersDirectory; + private final Path appDirectory; + private final Path appModsDirectory; + private final Path destktopIntegrationDirectory; + private final Path contentDirectory; } - public static ApplicationLayout windowsAppImage() { - return new ApplicationLayout(Map.of( - PathRole.LAUNCHERS, Path.of(""), - PathRole.APP, Path.of("app"), - PathRole.RUNTIME, Path.of("runtime"), - PathRole.RUNTIME_HOME, Path.of("runtime"), - PathRole.DESKTOP, Path.of(""), - PathRole.MODULES, Path.of("app/mods"), - PathRole.CONTENT, Path.of("") - )); + public static Builder build() { + return new Builder(); } - public static ApplicationLayout macAppImage() { - return new ApplicationLayout(Map.of( - PathRole.LAUNCHERS, Path.of("Contents/MacOS"), - PathRole.APP, Path.of("Contents/app"), - PathRole.RUNTIME, Path.of("Contents/runtime"), - PathRole.RUNTIME_HOME, Path.of("Contents/runtime/Contents/Home"), - PathRole.DESKTOP, Path.of("Contents/Resources"), - PathRole.MODULES, Path.of("Contents/app/mods"), - PathRole.CONTENT, Path.of("Contents") - )); + public static Builder buildFrom(ApplicationLayout appLayout) { + return new Builder(appLayout); } - public static ApplicationLayout platformAppImage() { - if (OperatingSystem.isWindows()) { - return windowsAppImage(); + class Proxy extends AppImageLayout.Proxy implements ApplicationLayout { + + public Proxy(T target) { + super(target); } - if (OperatingSystem.isLinux()) { - return linuxAppImage(); + @Override + public Path launchersDirectory() { + return target.launchersDirectory(); } - if (OperatingSystem.isMacOS()) { - return macAppImage(); + @Override + public Path appDirectory() { + return target.appDirectory(); } - throw new IllegalArgumentException("Unknown platform: " + OperatingSystem.current()); - } + @Override + public Path appModsDirectory() { + return target.appModsDirectory(); + } - public static ApplicationLayout javaRuntime() { - return new ApplicationLayout(Map.of(PathRole.RUNTIME, Path.of(""))); - } + @Override + public Path destktopIntegrationDirectory() { + return target.destktopIntegrationDirectory(); + } + + @Override + public Path contentDirectory() { + return target.contentDirectory(); + } - public static ApplicationLayout linuxUsrTreePackageImage(Path prefix, - String packageName) { - final Path lib = prefix.resolve(Path.of("lib", packageName)); - return new ApplicationLayout(Map.of( - PathRole.LAUNCHERS, prefix.resolve("bin"), - PathRole.APP, lib.resolve("app"), - PathRole.RUNTIME, lib.resolve("runtime"), - PathRole.RUNTIME_HOME, lib.resolve("runtime"), - PathRole.DESKTOP, lib, - PathRole.MODULES, lib.resolve("app/mods"), - PathRole.LINUX_APPLAUNCHER_LIB, lib.resolve( - "lib/libapplauncher.so"), - PathRole.CONTENT, lib - )); + @Override + public ApplicationLayout resolveAt(Path root) { + return target.resolveAt(root); + } } - private final PathGroup data; + final class Builder { + private Builder() { + } + + private Builder(ApplicationLayout appLayout) { + launchersDirectory = appLayout.launchersDirectory(); + appDirectory = appLayout.appDirectory(); + runtimeDirectory = appLayout.runtimeDirectory(); + appModsDirectory = appLayout.appModsDirectory(); + destktopIntegrationDirectory = appLayout.destktopIntegrationDirectory(); + contentDirectory = appLayout.contentDirectory(); + } + + public ApplicationLayout create() { + return new ApplicationLayout.Impl( + new AppImageLayout.Impl(runtimeDirectory), + launchersDirectory, + appDirectory, + appModsDirectory, + destktopIntegrationDirectory, + contentDirectory); + } + + public Builder setAll(String path) { + return setAll(Path.of(path)); + } + + public Builder setAll(Path path) { + launchersDirectory(path); + appDirectory(path); + runtimeDirectory(path); + appModsDirectory(path); + destktopIntegrationDirectory(path); + contentDirectory(path); + return this; + } + + public Builder launchersDirectory(String v) { + return launchersDirectory(Path.of(v)); + } + + public Builder launchersDirectory(Path v) { + launchersDirectory = v; + return this; + } + + public Builder appDirectory(String v) { + return appDirectory(Path.of(v)); + } + + public Builder appDirectory(Path v) { + appDirectory = v; + return this; + } + + public Builder runtimeDirectory(String v) { + return runtimeDirectory(Path.of(v)); + } + + public Builder runtimeDirectory(Path v) { + runtimeDirectory = v; + return this; + } + + public Builder appModsDirectory(String v) { + return appModsDirectory(Path.of(v)); + } + + public Builder appModsDirectory(Path v) { + appModsDirectory = v; + return this; + } + + public Builder destktopIntegrationDirectory(String v) { + return destktopIntegrationDirectory(Path.of(v)); + } + + public Builder destktopIntegrationDirectory(Path v) { + destktopIntegrationDirectory = v; + return this; + } + + public Builder contentDirectory(String v) { + return contentDirectory(Path.of(v)); + } + + public Builder contentDirectory(Path v) { + contentDirectory = v; + return this; + } + + private Path launchersDirectory; + private Path appDirectory; + private Path runtimeDirectory; + private Path appModsDirectory; + private Path destktopIntegrationDirectory; + private Path contentDirectory; + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java index 8b035e06c228b..ea9250de1e83d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java @@ -62,29 +62,33 @@ default StandardPackageType asStandardPackageType() { /** * Returns source app image layout. */ - default ApplicationLayout appLayout() { - return app().appLayout(); + default AppImageLayout appImageLayout() { + return app().imageLayout(); + } + + default ApplicationLayout asApplicationLayout() { + return app().asApplicationLayout(); } /** * Returns app image layout inside of the package. */ - default ApplicationLayout packageLayout() { - var layout = appLayout(); - var pathGroup = layout.pathGroup(); - var baseDir = relativeInstallDir(); + default AppImageLayout packageLayout() { + return appImageLayout().resolveAt(relativeInstallDir()); + } - for (var key : pathGroup.keys()) { - pathGroup.setPath(key, baseDir.resolve(pathGroup.getPath(key))); + default ApplicationLayout asPackageApplicationLayout() { + if (packageLayout() instanceof ApplicationLayout layout) { + return layout; + } else { + throw new UnsupportedOperationException(); } - - return layout; } /** * Returns app image layout of the installed package. */ - default ApplicationLayout installedPackageLayout() { + default AppImageLayout installedPackageLayout() { Path root = relativeInstallDir(); if (type() instanceof StandardPackageType type) { switch (type) { @@ -93,7 +97,15 @@ default ApplicationLayout installedPackageLayout() { } } } - return appLayout().resolveAt(root); + return appImageLayout().resolveAt(root); + } + + default ApplicationLayout asInstalledPackageApplicationLayout() { + if (installedPackageLayout() instanceof ApplicationLayout layout) { + return layout; + } else { + throw new UnsupportedOperationException(); + } } /** diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java index e9588f8dae331..f4cf57b515716 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java @@ -30,8 +30,7 @@ public interface RuntimeBuilder { - public void createRuntime(ApplicationLayout appLayout) throws - PackagerException, IOException; + public void createRuntime(AppImageLayout appImageLayout) throws PackagerException, IOException; public static List getDefaultModulePath() { return List.of( diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Getter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java similarity index 67% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/Getter.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java index 92c82d9fbf36f..ca9989a5f9741 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Getter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, 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,16 +22,25 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; -import java.util.function.Function; +import java.nio.file.Path; -public final class Getter { - public static T getValueOrDefault(C mainSrc, C defaultSrc, Function getter) { - try { - return getter.apply(mainSrc); - } catch (UnsupportedOperationException ex) { - return getter.apply(defaultSrc); + +/** + * App image directory layout. + */ +public interface RuntimeLayout extends AppImageLayout { + + final class Impl extends AppImageLayout.Proxy implements RuntimeLayout { + + public Impl(AppImageLayout target) { + super(target); + } + + @Override + public RuntimeLayout resolveAt(Path root) { + return new RuntimeLayout.Impl(target.resolveAt(root)); } } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index 68d84b973bd43..85e80f0d69431 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -79,8 +79,8 @@ error.no.name.advice=Specify name with --name warning.no.jdk.modules.found=Warning: No JDK Modules found -error.foreign-app-image=Error: Missing .jpackage.xml file in app-image dir "{0}" -error.invalid-app-image=Error: app-image dir "{0}" generated by another jpackage version or malformed "{1}" +error.foreign-app-image=Missing {0} file in app-image dir +error.invalid-app-image-file=app-image dir generated by another jpackage version or malformed {0} file error.invalid-install-dir=Invalid installation directory "{0}" diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java index 845fb1ac8985e..c1aa34507972e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java @@ -37,7 +37,6 @@ import java.util.function.BiFunction; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.IOUtils; /** @@ -132,37 +131,6 @@ public void transform(PathGroup dst, TransformHandler handler) throws IOExceptio copy(this, dst, handler, false); } - public static interface Facade { - PathGroup pathGroup(); - - default Collection paths() { - return pathGroup().paths(); - } - - default List roots() { - return pathGroup().roots(); - } - - default long sizeInBytes() throws IOException { - return pathGroup().sizeInBytes(); - } - - T resolveAt(Path root); - - default void copy(Facade dst) throws IOException { - pathGroup().copy(dst.pathGroup()); - } - - default void move(Facade dst) throws IOException { - pathGroup().move(dst.pathGroup()); - } - - default void transform(Facade dst, TransformHandler handler) throws - IOException { - pathGroup().transform(dst.pathGroup(), handler); - } - } - public static interface TransformHandler { default void copyFile(Path src, Path dst) throws IOException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java index ff15e5dfbb51f..3c76416330eb4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java @@ -28,4 +28,7 @@ public static Path replaceSuffix(Path path, String suffix) { return parent != null ? parent.resolve(filename) : Path.of(filename); } + public static Path resolveNullable(Path base, Path path) { + return Optional.ofNullable(path).map(base::resolve).orElse(null); + } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java index 8ae4ff31c59d1..3c322335a459d 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java @@ -30,6 +30,7 @@ import jdk.jpackage.internal.model.WinApplication; import java.io.IOException; import java.nio.file.Path; +import jdk.jpackage.internal.model.ApplicationLayout; final class WinAppImageBuilder { @@ -61,4 +62,11 @@ public void onLauncher(Application app, ctx.env(), ctx.launcherExecutable(), iconTarget); } } + + final static ApplicationLayout APPLICATION_LAYOUT = ApplicationLayout.build() + .setAll("") + .appDirectory("app") + .runtimeDirectory("runtime") + .appModsDirectory(Path.of("app", "mods")) + .create(); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java index c19dd0cef3218..9c1408e907515 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java @@ -41,6 +41,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; +import static jdk.jpackage.internal.WinAppImageBuilder.APPLICATION_LAYOUT; import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; import jdk.jpackage.internal.model.WinApplication; import jdk.jpackage.internal.model.WinLauncher; @@ -71,7 +72,7 @@ private static WinApplication createWinApplication( }).map(Map.Entry::getKey).collect(toSet()); return new WinLauncher.Impl(launcher, isConsole, shortcuts); - })).create(); + }), APPLICATION_LAYOUT).create(); return new WinApplication.Impl(app); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 3a7a230401908..c8dc6066c1ef9 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -29,7 +29,6 @@ import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.WinMsiPackage; import jdk.jpackage.internal.model.OverridableResource; -import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.io.InputStream; import java.io.Writer; @@ -55,6 +54,9 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; +import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.RuntimeLayout; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; @@ -207,13 +209,13 @@ public boolean validate(Map params) private void prepareProto(WinMsiPackage pkg, BuildEnv env) throws PackagerException, IOException { - ApplicationLayout appLayout; + AppImageLayout appImageLayout; // We either have an application image or need to build one. if (pkg.app().runtimeBuilder() != null) { // Runtime builder is present, build app image. WinAppImageBuilder.build().create(pkg.app()).execute(env); - appLayout = pkg.appLayout().resolveAt(env.appImageDir()); + appImageLayout = pkg.appImageLayout().resolveAt(env.appImageDir()); } else { Path srcAppImageDir = pkg.predefinedAppImage(); if (srcAppImageDir == null) { @@ -227,17 +229,17 @@ private void prepareProto(WinMsiPackage pkg, BuildEnv env) throws } } - appLayout = pkg.appLayout().resolveAt(srcAppImageDir); + appImageLayout = pkg.appImageLayout().resolveAt(srcAppImageDir); } // Configure installer icon - if (pkg.isRuntimeInstaller()) { + if (appImageLayout instanceof RuntimeLayout runtimeLayout) { // Use icon from java launcher. // Assume java.exe exists in Java Runtime being packed. // Ignore custom icon if any as we don't want to copy anything in // Java Runtime image. - installerIcon = appLayout.runtimeDirectory().resolve(Path.of("bin", "java.exe")); - } else { + installerIcon = runtimeLayout.runtimeDirectory().resolve(Path.of("bin", "java.exe")); + } else if (appImageLayout instanceof ApplicationLayout appLayout) { installerIcon = appLayout.launchersDirectory().resolve( pkg.app().mainLauncher().executableNameWithSuffix()); } @@ -323,8 +325,8 @@ private Map prepareMainProjectFile(BuildEnv env, WinMsiPackage p data.put("JpAboutURL", value); }); - data.put("JpAppSizeKb", Long.toString(pkg.packageLayout().resolveAt( - env.appImageDir()).sizeInBytes() >> 10)); + data.put("JpAppSizeKb", Long.toString(AppImageLayout.toPathGroup( + pkg.packageLayout().resolveAt(env.appImageDir())).sizeInBytes() >> 10)); data.put("JpConfigDir", env.configDir().toAbsolutePath().toString()); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index d146f4adae824..b99224a7aee8b 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -63,6 +63,7 @@ import static jdk.jpackage.internal.util.CollectionUtils.toCollection; import jdk.jpackage.internal.model.WinLauncher.WinShortcut; import jdk.jpackage.internal.WixToolset.WixToolsetType; +import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.XmlUtils; @@ -90,19 +91,10 @@ void initFromParams(BuildEnv env, WinMsiPackage pkg) { installDir = (systemWide ? PROGRAM_FILES : LOCAL_PROGRAM_FILES).resolve( pkg.relativeInstallDir()); - do { - ApplicationLayout layout = pkg.appLayout(); - // Don't want app image info file in installed application. - Optional.ofNullable(AppImageFile2.getPathInAppImage(layout)).ifPresent( - appImageFile -> layout.pathGroup().ghostPath(appImageFile)); - - // Want absolute paths to source files in generated WiX sources. - // This is to handle scenario if sources would be processed from - // different current directory. - appImage = layout.resolveAt(appImageRoot.toAbsolutePath().normalize()); - } while (false); - - installedAppImage = pkg.appLayout().resolveAt(INSTALLDIR); + // Want absolute paths to source files in generated WiX sources. + // This is to handle scenario if sources would be processed from + // different current directory. + initAppImageLayouts(pkg.appImageLayout(), appImageRoot.toAbsolutePath().normalize()); launchers = toCollection(Optional.ofNullable(pkg.app().launchers()).orElseGet(List::of)); @@ -143,8 +135,7 @@ void addFilesToConfigRoot() throws IOException { removeFolderItems = new HashMap<>(); defaultedMimes = new HashSet<>(); if (packageFile != null) { - packageFile.save(ApplicationLayout.windowsAppImage().resolveAt( - getConfigRoot())); + packageFile.save(ApplicationLayout.build().setAll(getConfigRoot()).create()); } super.addFilesToConfigRoot(); } @@ -193,11 +184,30 @@ private void initFileAssociations() { associations.values().stream().flatMap(List::stream).filter(fa -> fa.icon() != null).forEach(fa -> { // Need to add fa icon in the image. Object key = new Object(); - appImage.pathGroup().setPath(key, fa.icon()); - installedAppImage.pathGroup().setPath(key, getInstalledFaIcoPath(fa)); + appImagePathGroup.setPath(key, fa.icon()); + installedAppImagePathGroup.setPath(key, getInstalledFaIcoPath(fa)); }); } + private void initAppImageLayouts(AppImageLayout appImageLayout, Path appImageRoot) { + var srcAppImageLayout = appImageLayout.resolveAt(appImageRoot); + + var installedAppImageLayout = appImageLayout.resolveAt(INSTALLDIR); + + appImagePathGroup = AppImageLayout.toPathGroup(srcAppImageLayout); + installedAppImagePathGroup = AppImageLayout.toPathGroup(installedAppImageLayout); + + if (appImageLayout instanceof ApplicationLayout appLayout) { + // Don't want app image info file in installed application. + var appImageFile = AppImageFile2.getPathInAppImage(appLayout); + appImagePathGroup.ghostPath(appImageFile); + + installedAppImage = (ApplicationLayout)installedAppImageLayout; + } else { + installedAppImage = null; + } + } + private static UUID createNameUUID(String str) { return UUID.nameUUIDFromBytes(str.getBytes(StandardCharsets.UTF_8)); } @@ -631,7 +641,7 @@ private List addDirectoryHierarchy(XMLStreamWriter xml) Set allDirs = new HashSet<>(); Set emptyDirs = new HashSet<>(); - appImage.transform(installedAppImage, new PathGroup.TransformHandler() { + appImagePathGroup.transform(installedAppImagePathGroup, new PathGroup.TransformHandler() { @Override public void copyFile(Path src, Path dst) throws IOException { Path dir = dst.getParent(); @@ -692,7 +702,7 @@ private void addFilesComponentGroup(XMLStreamWriter xml) throws XMLStreamException, IOException { List> files = new ArrayList<>(); - appImage.transform(installedAppImage, new PathGroup.TransformHandler() { + appImagePathGroup.transform(installedAppImagePathGroup, new PathGroup.TransformHandler() { @Override public void copyFile(Path src, Path dst) throws IOException { files.add(Map.entry(src, dst)); @@ -705,8 +715,10 @@ public void copyFile(Path src, Path dst) throws IOException { } if (packageFile != null) { - files.add(Map.entry(PackageFile.getPathInAppImage( - getConfigRoot().toAbsolutePath().normalize()), + files.add(Map.entry( + PackageFile.getPathInAppImage( + ApplicationLayout.build().setAll( + getConfigRoot().toAbsolutePath().normalize()).create()), PackageFile.getPathInAppImage(installedAppImage))); } @@ -777,12 +789,9 @@ private List addServiceConfigs(XMLStreamWriter xml) throws private void addIcons(XMLStreamWriter xml) throws XMLStreamException, IOException { - PathGroup srcPathGroup = appImage.pathGroup(); - PathGroup dstPathGroup = installedAppImage.pathGroup(); - // Build list of copy operations for all .ico files in application image List> icoFiles = new ArrayList<>(); - srcPathGroup.transform(dstPathGroup, new PathGroup.TransformHandler() { + appImagePathGroup.transform(installedAppImagePathGroup, new PathGroup.TransformHandler() { @Override public void copyFile(Path src, Path dst) throws IOException { if (IOUtils.getFileName(src).toString().endsWith(".ico")) { @@ -952,9 +961,11 @@ static Set getForPackage(WinMsiPackage pkg) { private InstallableFile serviceInstaller; - private ApplicationLayout appImage; private ApplicationLayout installedAppImage; + private PathGroup appImagePathGroup; + private PathGroup installedAppImagePathGroup; + private Map removeFolderItems; private Set defaultedMimes; diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java index 63447ffd5f7c9..88fa008b62be7 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java @@ -23,7 +23,6 @@ package jdk.jpackage.internal.model; -import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -38,10 +37,12 @@ public class ApplicationLayoutTest { @Rule public final TemporaryFolder tempFolder = new TemporaryFolder(); - private void fillLinuxAppImage() throws IOException { + private ApplicationLayout fillAppImage() throws IOException { appImage = tempFolder.newFolder("Foo").toPath(); Path base = appImage.getFileName(); + + var layout = ApplicationLayout.build().app; tempFolder.newFolder(base.toString(), "bin"); tempFolder.newFolder(base.toString(), "lib", "app", "mods"); @@ -55,9 +56,9 @@ private void fillLinuxAppImage() throws IOException { } @Test - public void testLinux() throws IOException { - fillLinuxAppImage(); - testApplicationLayout(ApplicationLayout.linuxAppImage()); + public void test() throws IOException { + fillAppImage(); + testApplicationLayout(ApplicationLayout.build().launchersDirectory( appImage)); } private void testApplicationLayout(ApplicationLayout layout) throws IOException { From b69f7a25cc79c453a7d7dc031a993a6f0a93e099 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 09:35:09 -0400 Subject: [PATCH 0086/1101] Fix compilation error --- .../classes/jdk/jpackage/internal/MacLaunchersAsServices.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index 748605930f399..fd642ac3203c4 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -81,7 +81,7 @@ private static class MacLauncherAsService extends UnixLauncherAsService { .setPublicName(plistFilename) .addSubstitutionDataEntry("LABEL", label) .addSubstitutionDataEntry("APPLICATION_LAUNCHER", - pkg.installedPackageLayout().launchersDirectory().resolve( + pkg.asInstalledPackageApplicationLayout().launchersDirectory().resolve( getName()).toString()); } From 94bc6fb559796898f6f3c20a040104254bf760b3 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 09:43:19 -0400 Subject: [PATCH 0087/1101] Added transitional ApplicationLayoutUtils class --- .../internal/ApplicationLayoutUtils.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java new file mode 100644 index 0000000000000..a8be8acadfb12 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.ApplicationLayout; + + +final class ApplicationLayoutUtils { + + public final static ApplicationLayout PLATFORM_APPLICATION_LAYOUT; + + private final static ApplicationLayout WIN_APPLICATION_LAYOUT = ApplicationLayout.build() + .setAll("") + .appDirectory("app") + .runtimeDirectory("runtime") + .appModsDirectory(Path.of("app", "mods")) + .create(); + + private final static ApplicationLayout MAC_APPLICATION_LAYOUT = ApplicationLayout.build() + .launchersDirectory("Contents/MacOS") + .appDirectory("Contents/app") + .runtimeDirectory("Contents/runtime") + .destktopIntegrationDirectory("Contents/Resources") + .appModsDirectory("Contents/app/mods") + .contentDirectory("Contents") + .create(); + + private final static ApplicationLayout LINUX_APPLICATION_LAYOUT = ApplicationLayout.build() + .launchersDirectory("bin") + .appDirectory("lib/app") + .runtimeDirectory("lib/runtime") + .destktopIntegrationDirectory("lib") + .appModsDirectory("lib/app/mods") + .contentDirectory("lib") + .create(); + + static { + switch (OperatingSystem.current()) { + case WINDOWS -> PLATFORM_APPLICATION_LAYOUT = WIN_APPLICATION_LAYOUT; + case MACOS -> PLATFORM_APPLICATION_LAYOUT = MAC_APPLICATION_LAYOUT; + case LINUX -> PLATFORM_APPLICATION_LAYOUT = LINUX_APPLICATION_LAYOUT; + default -> { + throw new UnsupportedOperationException(); + } + } + } +} From 022d68090df0edab827fcb90adc0613324dc0cdb Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 09:45:45 -0400 Subject: [PATCH 0088/1101] Rename PathUtils.resolveNullable() -> PathUtils.resolveNullablePath() --- .../jdk/jpackage/internal/model/AppImageLayout.java | 4 ++-- .../jpackage/internal/model/ApplicationLayout.java | 12 ++++++------ .../jdk/jpackage/internal/util/PathUtils.java | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java index e73800d467627..b172af1731011 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java @@ -31,8 +31,8 @@ import java.util.Optional; import java.util.stream.Stream; import jdk.jpackage.internal.util.PathGroup; -import static jdk.jpackage.internal.util.PathUtils.resolveNullable; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; +import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; /** @@ -51,7 +51,7 @@ record Impl(Path runtimeDirectory) implements AppImageLayout { @Override public AppImageLayout resolveAt(Path base) { - return new Impl(resolveNullable(base, runtimeDirectory)); + return new Impl(resolveNullablePath(base, runtimeDirectory)); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index b91a61cb2dd90..d5fb53eed18f2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -25,7 +25,7 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; -import static jdk.jpackage.internal.util.PathUtils.resolveNullable; +import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; /** * Application directory layout. @@ -101,11 +101,11 @@ public Path contentDirectory() { @Override public ApplicationLayout resolveAt(Path base) { return new ApplicationLayout.Impl(target, - resolveNullable(base, launchersDirectory), - resolveNullable(base, appDirectory), - resolveNullable(base, appModsDirectory), - resolveNullable(base, destktopIntegrationDirectory), - resolveNullable(base, contentDirectory)); + resolveNullablePath(base, launchersDirectory), + resolveNullablePath(base, appDirectory), + resolveNullablePath(base, appModsDirectory), + resolveNullablePath(base, destktopIntegrationDirectory), + resolveNullablePath(base, contentDirectory)); } private final Path launchersDirectory; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java index 3c76416330eb4..3024ed1378640 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java @@ -28,7 +28,7 @@ public static Path replaceSuffix(Path path, String suffix) { return parent != null ? parent.resolve(filename) : Path.of(filename); } - public static Path resolveNullable(Path base, Path path) { + public static Path resolveNullablePath(Path base, Path path) { return Optional.ofNullable(path).map(base::resolve).orElse(null); } } From 4b197fc4b60e51601b8fd457cb3641d6edcdc9ba Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 09:46:09 -0400 Subject: [PATCH 0089/1101] Fix compilation errors --- .../jdk/jpackage/internal/LinuxAppImageBuilder.java | 11 +---------- .../jdk/jpackage/internal/LinuxApplicationLayout.java | 4 ++-- .../jdk/jpackage/internal/MacAppImageBuilder.java | 4 ++-- .../jpackage/internal/MacBaseInstallerBundler.java | 7 ++++--- .../jpackage/internal/AbstractAppImageBuilder.java | 4 ++-- .../classes/jdk/jpackage/internal/AppImageFile.java | 2 +- .../jdk/jpackage/internal/StandardBundlerParam.java | 10 ++++++---- .../jdk/jpackage/internal/WinAppImageBuilder.java | 7 +------ 8 files changed, 19 insertions(+), 30 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index c24b1232ee13e..b89ffbd00efb7 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -27,7 +27,6 @@ import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.OverridableResource; -import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -65,13 +64,5 @@ public void onLauncher(Application app, } final static LinuxApplicationLayout APPLICATION_LAYOUT = new LinuxApplicationLayout( - ApplicationLayout.build() - .launchersDirectory("bin") - .appDirectory("lib/app") - .runtimeDirectory("lib/runtime") - .destktopIntegrationDirectory("lib") - .appModsDirectory("lib/app/mods") - .contentDirectory("lib") - .create(), - Path.of("lib/libapplauncher.so")); + ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT, Path.of("lib/libapplauncher.so")); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java index 8c6910fca445d..13dc7496c69e0 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java @@ -26,7 +26,7 @@ import jdk.jpackage.internal.model.*; import java.nio.file.Path; -import static jdk.jpackage.internal.util.PathUtils.resolveNullable; +import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; final class LinuxApplicationLayout extends ApplicationLayout.Proxy { @@ -38,7 +38,7 @@ final class LinuxApplicationLayout extends ApplicationLayout.Proxy params) if (withPackageFile) { new PackageFile(APP_NAME.fetchFrom(params)).save( - ApplicationLayout.macAppImage().resolveAt(root)); + ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT.resolveAt(root)); } /*********** Take care of "config" files *******/ diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index 0f1996f217ddf..388715ac1e42e 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -157,11 +157,12 @@ protected void validateAppImageAndBundeler( "message.app-image-requires-app-name.advice")); } if (AppImageFile.load(applicationImage).isSigned()) { + var appLayout = ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT.resolveAt(applicationImage); if (!Files.exists( - PackageFile.getPathInAppImage(applicationImage))) { + PackageFile.getPathInAppImage(appLayout))) { Log.info(MessageFormat.format(I18N.getString( "warning.per.user.app.image.signed"), - PackageFile.getPathInAppImage(applicationImage))); + PackageFile.getPathInAppImage(appLayout))); } } else { if (Optional.ofNullable( @@ -192,7 +193,7 @@ protected Path prepareAppBundle(Map params) if (!StandardBundlerParam.isRuntimeInstaller(params) && !AppImageFile.load(predefinedImage).isSigned()) { new PackageFile(APP_NAME.fetchFrom(params)).save( - ApplicationLayout.macAppImage().resolveAt(appDir)); + ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT.resolveAt(appDir)); // We need to re-sign app image after adding ".package" to it. // We only do this if app image was not signed which means it is // signed with ad-hoc signature. App bundles with ad-hoc diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java index deba781566899..d144cfdf30c6c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java @@ -55,7 +55,7 @@ public abstract class AbstractAppImageBuilder { public AbstractAppImageBuilder(Path root) { this.root = root; - appLayout = ApplicationLayout.platformAppImage().resolveAt(root); + appLayout = ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT.resolveAt(root); } public InputStream getResourceAsStream(String name) { @@ -82,7 +82,7 @@ public LauncherStartupInfo startupInfo() { public String name() { return APP_NAME.fetchFrom(params); } - }).create(ApplicationLayout.platformAppImage(), appLayout); + }).create(ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT, appLayout); } protected void copyApplication(Map params) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index 04959928e23f9..e05cf854b30f1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -182,7 +182,7 @@ boolean isAppStore() { * @param appImageDir - path to application image */ static Path getPathInAppImage(Path appImageDir) { - return ApplicationLayout.platformAppImage() + return ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT .resolveAt(appImageDir) .appDirectory() .resolve(FILENAME); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index db0c698759bd6..c73a7083ee398 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -42,6 +42,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Stream; +import static jdk.jpackage.internal.ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT; import jdk.jpackage.internal.util.function.ThrowingFunction; import jdk.jpackage.internal.resources.ResourceLocator; import static jdk.jpackage.internal.model.RuntimeBuilder.getDefaultModulePath; @@ -106,9 +107,9 @@ final class StandardBundlerParam { if (isRuntimeInstaller(params)) { return null; } else if (hasPredefinedAppImage(params)) { - return ThrowingFunction.toFunction( - AppImageFile2::load).apply( - getPredefinedAppImage(params)).getMainClass(); + var appImage = getPredefinedAppImage(params); + var appLayout = PLATFORM_APPLICATION_LAYOUT.resolveAt(appImage); + return ThrowingFunction.toFunction(AppImageFile2::load).apply(appLayout).getMainClass(); } return LAUNCHER_DATA.fetchFrom(params).qualifiedClassName(); }, @@ -149,8 +150,9 @@ final class StandardBundlerParam { Path appImage = PREDEFINED_APP_IMAGE.fetchFrom(params); String appName = NAME.fetchFrom(params); if (appImage != null) { + var appLayout = PLATFORM_APPLICATION_LAYOUT.resolveAt(appImage); String name = ThrowingFunction.toFunction( - AppImageFile2::load).apply(appImage).getLauncherName(); + AppImageFile2::load).apply(appLayout).getLauncherName(); appName = (name != null) ? name : appName; } else if (appName == null) { String s = MAIN_CLASS.fetchFrom(params); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java index 3c322335a459d..bcaac2f77a955 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java @@ -63,10 +63,5 @@ public void onLauncher(Application app, } } - final static ApplicationLayout APPLICATION_LAYOUT = ApplicationLayout.build() - .setAll("") - .appDirectory("app") - .runtimeDirectory("runtime") - .appModsDirectory(Path.of("app", "mods")) - .create(); + final static ApplicationLayout APPLICATION_LAYOUT = ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT; } From a101cec678d4ffc7a7116e7a9bc129a621b0e308 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 10:52:08 -0400 Subject: [PATCH 0090/1101] Merge bugfix --- .../jdk/jpackage/internal/AbstractAppImageBuilder.java | 5 +---- .../share/classes/jdk/jpackage/internal/IOUtils.java | 6 ++++++ .../classes/jdk/jpackage/internal/StandardBundlerParam.java | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java index f2d659162f07c..8461f606d8cb0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java @@ -36,15 +36,12 @@ import java.util.ArrayList; import java.util.Map; import java.util.List; -import java.util.Objects; -import java.util.stream.Stream; -import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.SOURCE_DIR; import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; import static jdk.jpackage.internal.StandardBundlerParam.OUTPUT_DIR; import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; +import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import jdk.jpackage.internal.resources.ResourceLocator; import jdk.jpackage.internal.util.FileUtils; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java index da6adf32a8ace..72d360791ea3b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java @@ -31,11 +31,17 @@ import java.io.InputStreamReader; import java.io.IOException; import java.io.PrintStream; +import java.nio.file.CopyOption; +import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import jdk.internal.util.OperatingSystem; /** * IOUtils diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index af8c20b1bbd52..aeba30137c474 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -91,8 +91,8 @@ final class StandardBundlerParam { (s, p) -> Path.of(s) ); - static final StandardBundlerParam OUTPUT_DIR = - new StandardBundlerParam<>( + static final BundlerParamInfo OUTPUT_DIR = + new BundlerParamInfo<>( Arguments.CLIOptions.OUTPUT.getId(), Path.class, p -> Path.of("").toAbsolutePath(), From 4c7e33ab4431a9de400ecd425d439b72b1b4cfd7 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 10:53:22 -0400 Subject: [PATCH 0091/1101] Make check for main jar in the app image optional --- .../jpackage/helpers/jdk/jpackage/test/JPackageCommand.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 1d41795d07f6f..e9bbdeefb247e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -819,6 +819,11 @@ public static enum AppLayoutAssert { TKit.assertFileExists(cmd.appLauncherCfgPath(null)); } }), + MAIN_JAR_FILE(cmd -> { + Optional.ofNullable(cmd.getArgumentValue("--main-jar", () -> null)).ifPresent(mainJar -> { + TKit.assertFileExists(cmd.appLayout().appDirectory().resolve(mainJar)); + }); + }), RUNTIME_DIRECTORY(cmd -> { TKit.assertDirectoryExists(cmd.appRuntimeDirectory()); if (TKit.isOSX()) { From 6ab39357947b6efc27948a2d3a27ac870ca50f28 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 13:28:27 -0400 Subject: [PATCH 0092/1101] Bugfix --- .../classes/jdk/jpackage/internal/model/ApplicationLayout.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index d5fb53eed18f2..e9731e11642c6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -100,7 +100,7 @@ public Path contentDirectory() { @Override public ApplicationLayout resolveAt(Path base) { - return new ApplicationLayout.Impl(target, + return new ApplicationLayout.Impl(target.resolveAt(base), resolveNullablePath(base, launchersDirectory), resolveNullablePath(base, appDirectory), resolveNullablePath(base, appModsDirectory), From 46d880a5e67412263e022786e962ff35bff8dd27 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 13:28:44 -0400 Subject: [PATCH 0093/1101] Fix app layout unit test --- .../internal/model/ApplicationLayoutTest.java | 110 +++++++++++------- 1 file changed, 65 insertions(+), 45 deletions(-) diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java index 88fa008b62be7..4642a3df8a233 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java @@ -25,11 +25,13 @@ import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Path; -import org.junit.Test; +import java.util.List; +import java.util.stream.Stream; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import org.junit.Rule; +import org.junit.Test; import org.junit.rules.TemporaryFolder; -import static org.junit.Assert.assertTrue; public class ApplicationLayoutTest { @@ -37,54 +39,72 @@ public class ApplicationLayoutTest { @Rule public final TemporaryFolder tempFolder = new TemporaryFolder(); - private ApplicationLayout fillAppImage() throws IOException { - appImage = tempFolder.newFolder("Foo").toPath(); - - Path base = appImage.getFileName(); - - var layout = ApplicationLayout.build().app; - - tempFolder.newFolder(base.toString(), "bin"); - tempFolder.newFolder(base.toString(), "lib", "app", "mods"); - tempFolder.newFolder(base.toString(), "lib", "runtime", "bin"); - tempFolder.newFile(base.resolve("bin/Foo").toString()); - tempFolder.newFile(base.resolve("lib/app/Foo.cfg").toString()); - tempFolder.newFile(base.resolve("lib/app/hello.jar").toString()); - tempFolder.newFile(base.resolve("lib/Foo.png").toString()); - tempFolder.newFile(base.resolve("lib/libapplauncher.so").toString()); - tempFolder.newFile(base.resolve("lib/runtime/bin/java").toString()); - } + public void test(boolean move) throws IOException { + final var srcAppImageRoot = tempFolder.newFolder("src").toPath(); - @Test - public void test() throws IOException { - fillAppImage(); - testApplicationLayout(ApplicationLayout.build().launchersDirectory( appImage)); - } + final var appImageCopyFiles = List.of("bin/Foo", "lib/app/Foo.cfg", "lib/app/hello.jar", "runtime/bin/java"); + final var appImageCopyDirs = List.of("lib/app/hello"); + + final var appImageNoCopyFiles = List.of("lib/Foo.cfg", "Foo"); + final var appImageNoCopyDirs = List.of("lib/hello", "a/b/c"); - private void testApplicationLayout(ApplicationLayout layout) throws IOException { - ApplicationLayout srcLayout = layout.resolveAt(appImage); - assertApplicationLayout(srcLayout); + for (var path : Stream.concat(appImageCopyFiles.stream(), appImageNoCopyFiles.stream()).map(srcAppImageRoot::resolve).toList()) { + Files.createDirectories(path.getParent()); + Files.createFile(path); + } - ApplicationLayout dstLayout = layout.resolveAt( - appImage.getParent().resolve( - "Copy" + appImage.getFileName().toString())); - srcLayout.move(dstLayout); - Files.deleteIfExists(appImage); - assertApplicationLayout(dstLayout); + for (var path : Stream.concat(appImageCopyDirs.stream(), appImageNoCopyDirs.stream()).map(srcAppImageRoot::resolve).toList()) { + Files.createDirectories(path); + } - dstLayout.copy(srcLayout); - assertApplicationLayout(srcLayout); - assertApplicationLayout(dstLayout); + final var layout = ApplicationLayout.build() + .launchersDirectory("bin") + .appDirectory("lib/app") + .runtimeDirectory("runtime") + .create(); + + final var dstAppImageRoot = tempFolder.newFolder("dst").toPath(); + + final var srcPathGroup = AppImageLayout.toPathGroup(layout.resolveAt(srcAppImageRoot)); + final var dstPathGroup = AppImageLayout.toPathGroup(layout.resolveAt(dstAppImageRoot)); + if (move) { + srcPathGroup.move(dstPathGroup); + } else { + srcPathGroup.copy(dstPathGroup); + } + + for (var path : Stream.concat(appImageNoCopyDirs.stream(), appImageNoCopyFiles.stream()).map(srcAppImageRoot::resolve).toList()) { + assertTrue(Files.exists(path)); + } + + for (var path : appImageCopyDirs) { + var srcPath = srcAppImageRoot.resolve(path); + if (move) { + assertFalse(Files.exists(srcPath)); + } else { + assertTrue(Files.isDirectory(srcPath)); + } + assertTrue(Files.isDirectory(dstAppImageRoot.resolve(path))); + } + + for (var path : appImageCopyFiles) { + var srcPath = srcAppImageRoot.resolve(path); + if (move) { + assertFalse(Files.exists(srcPath)); + } else { + assertTrue(Files.isRegularFile(srcPath)); + } + assertTrue(Files.isRegularFile(dstAppImageRoot.resolve(path))); + } } - private void assertApplicationLayout(ApplicationLayout layout) throws IOException { - assertTrue(Files.isRegularFile(layout.appDirectory().resolve("Foo.cfg"))); - assertTrue(Files.isRegularFile(layout.appDirectory().resolve("hello.jar"))); - assertTrue(Files.isDirectory(layout.appModsDirectory())); - assertTrue(Files.isRegularFile(layout.launchersDirectory().resolve("Foo"))); - assertTrue(Files.isRegularFile(layout.destktopIntegrationDirectory().resolve("Foo.png"))); - assertTrue(Files.isRegularFile(layout.runtimeDirectory().resolve("bin/java"))); + @Test + public void testMove() throws IOException { + test(true); } - private Path appImage; + @Test + public void testCopy() throws IOException { + test(false); + } } From 95cf55d452203802a8bb6e612e557775d94fe12b Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 13:37:01 -0400 Subject: [PATCH 0094/1101] OverridableResourceTest unit test failure fixed --- .../internal/model/OverridableResourceTest.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/OverridableResourceTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/OverridableResourceTest.java index b470fa95a2796..db902dd5f72ee 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/OverridableResourceTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/OverridableResourceTest.java @@ -23,7 +23,6 @@ package jdk.jpackage.internal.model; -import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; @@ -33,6 +32,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.resources.ResourceLocator; @@ -120,7 +120,7 @@ private void testCustom(String defaultName) throws IOException { Path customFile = createCustomFile("foo", expectedResourceData); List actualResourceData = convertToStringList(saveToFile( - new OverridableResource(defaultName, ResourceLocator.class) + createOverridableResource(defaultName) .setPublicName(customFile.getFileName()) .setResourceDir(customFile.getParent()))); @@ -151,7 +151,7 @@ private void testCustomtWithSubstitution(String defaultName) throws IOException "Bar", "Bar", "Goodbye", "JJ"); final List actualResourceData = convertToStringList(saveToFile( - new OverridableResource(defaultName, ResourceLocator.class) + createOverridableResource(defaultName) .setPublicName(customFile.getFileName()) .setSubstitutionData(substitutionData) .setResourceDir(customFile.getParent()))); @@ -160,7 +160,7 @@ private void testCustomtWithSubstitution(String defaultName) throws IOException // Don't call setPublicName() final Path dstFile = tempFolder.newFolder().toPath().resolve(customFile.getFileName()); - new OverridableResource(defaultName, ResourceLocator.class) + createOverridableResource(defaultName) .setSubstitutionData(substitutionData) .setResourceDir(customFile.getParent()) .saveToFile(dstFile); @@ -170,7 +170,7 @@ private void testCustomtWithSubstitution(String defaultName) throws IOException // Verify setSubstitutionData() stores a copy of passed in data Map substitutionData2 = new HashMap(substitutionData); - var resource = new OverridableResource(defaultName, ResourceLocator.class) + var resource = createOverridableResource(defaultName) .setResourceDir(customFile.getParent()); resource.setSubstitutionData(substitutionData2); @@ -226,6 +226,12 @@ private Path createCustomFile(String publicName, List data) throws return customFile; } + + private static OverridableResource createOverridableResource(String defaultName) { + return Optional.ofNullable(defaultName).map(name -> { + return new OverridableResource(defaultName, ResourceLocator.class); + }).orElseGet(OverridableResource::new); + } private static List convertToStringList(byte[] data) { return List.of(new String(data, StandardCharsets.UTF_8).split("\\R")); From 8d9d960f73f0524dd59ccce65d88ef967994e5d8 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 14:31:42 -0400 Subject: [PATCH 0095/1101] - rename `Impl` classes in `Stub` - seal Proxy methods - seal `Stub` classes that are not records --- .../jpackage/internal/DesktopIntegration.java | 24 +++--- .../internal/LinuxDebPackageBuilder.java | 2 +- .../jpackage/internal/LinuxFromParams.java | 4 +- .../internal/LinuxPackageBuilder.java | 2 +- .../internal/LinuxRpmPackageBuilder.java | 2 +- .../internal/model/LinuxApplication.java | 4 +- .../internal/model/LinuxDebPackage.java | 4 +- .../internal/model/LinuxLauncher.java | 4 +- .../jpackage/internal/model/LinuxPackage.java | 16 ++-- .../internal/model/LinuxRpmPackage.java | 4 +- .../jdk/jpackage/internal/AppImageFile2.java | 2 +- .../jpackage/internal/ApplicationBuilder.java | 2 +- .../jpackage/internal/LauncherBuilder.java | 6 +- .../internal/LauncherStartupInfoBuilder.java | 8 +- .../jdk/jpackage/internal/PackageBuilder.java | 4 +- .../internal/model/AppImageLayout.java | 6 +- .../jpackage/internal/model/Application.java | 22 +++--- .../internal/model/ApplicationLayout.java | 20 ++--- .../internal/model/FileAssociation.java | 14 ++-- .../jdk/jpackage/internal/model/Launcher.java | 14 ++-- .../model/LauncherJarStartupInfo.java | 6 +- .../model/LauncherModularStartupInfo.java | 4 +- .../internal/model/LauncherStartupInfo.java | 10 +-- .../jdk/jpackage/internal/model/Package.java | 73 +++++++++---------- .../internal/model/RuntimeLayout.java | 6 +- .../internal/WinExePackageBuilder.java | 2 +- .../jdk/jpackage/internal/WinFromParams.java | 4 +- .../internal/WinMsiPackageBuilder.java | 2 +- .../internal/model/WinApplication.java | 4 +- .../internal/model/WinExePackage.java | 29 +++++--- .../jpackage/internal/model/WinLauncher.java | 4 +- .../internal/model/WinMsiPackage.java | 6 +- 32 files changed, 161 insertions(+), 153 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index b3ec69592ee2e..4f165e960f02d 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -457,21 +457,21 @@ private static int normalizeIconSize(int iconSize) { private static class LinuxFileAssociation extends FileAssociation.Proxy { LinuxFileAssociation(FileAssociation fa) { - super(fa); - var icon = fa.icon(); - if (icon != null && Files.isReadable(icon)) { - iconSize = getSquareSizeOfImage(icon.toFile()); - } else { - iconSize = -1; - } + this(fa, getIconSize(fa)); } - @Override - public Path icon() { - if (iconSize < 0) { - return null; + private LinuxFileAssociation(FileAssociation fa, int iconSize) { + super(iconSize > 0 ? fa : new FileAssociation.Stub(fa.description(), + fa.icon(), fa.mimeType(), fa.extension())); + this.iconSize = iconSize; + } + + private static int getIconSize(FileAssociation fa) { + var icon = fa.icon(); + if (icon != null && Files.isReadable(icon)) { + return getSquareSizeOfImage(icon.toFile()); } else { - return super.icon(); + return -1; } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java index 4a57ba2406a43..fcd730b31bea0 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java @@ -38,7 +38,7 @@ final class LinuxDebPackageBuilder { LinuxRpmPackage create() throws ConfigException { var pkg = pkgBuilder.create(); - return new LinuxRpmPackage.Impl( + return new LinuxRpmPackage.Stub( pkg, Optional.ofNullable(maintainerEmail).orElseGet(DEFAULTS::maintainerEmail)); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java index 31aa4f15ca885..69c749f9b79ec 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java @@ -55,9 +55,9 @@ private static LinuxApplication createLinuxApplication( }).map(param -> { return param.fetchFrom(params); }).findFirst(); - return new LinuxLauncher.Impl(launcher, shortcut); + return new LinuxLauncher.Stub(launcher, shortcut); }), APPLICATION_LAYOUT).create(); - return new LinuxApplication.Impl(app); + return new LinuxApplication.Stub(app); } private static LinuxPackageBuilder createLinuxPackageBuilder( diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index 096021d1bf1ab..a8028325b3bd9 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -63,7 +63,7 @@ LinuxPackage create() throws ConfigException { private LinuxPackage create(jdk.jpackage.internal.model.Package pkg, AppImageLayout pkgLayout) throws ConfigException { - return new LinuxPackage.Impl(pkg, + return new LinuxPackage.Stub(pkg, pkgLayout, Optional.ofNullable(menuGroupName).orElseGet(DEFAULTS::menuGroupName), Optional.ofNullable(category).orElseGet(DEFAULTS::category), diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java index 4115de7b15314..aeaa7d1d41b5c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java @@ -38,7 +38,7 @@ final class LinuxRpmPackageBuilder { LinuxRpmPackage create() throws ConfigException { var pkg = pkgBuilder.create(); - return new LinuxRpmPackage.Impl( + return new LinuxRpmPackage.Stub( pkg, Optional.ofNullable(licenseType).orElseGet(DEFAULTS::licenseType)); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java index 28bb9a0c09951..e4024ea165d0e 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java @@ -26,8 +26,8 @@ package jdk.jpackage.internal.model; public interface LinuxApplication extends Application { - class Impl extends Application.Proxy implements LinuxApplication { - public Impl(Application app) { + final class Stub extends Application.Proxy implements LinuxApplication { + public Stub(Application app) { super(app); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java index 640034f2114a3..e7496ad6a4159 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java @@ -49,9 +49,9 @@ default Path relativeCopyrightFilePath() { } } - class Impl extends LinuxPackage.Proxy implements LinuxDebPackage { + final class Stub extends LinuxPackage.Proxy implements LinuxDebPackage { - public Impl(LinuxPackage target, String maintainerEmail) { + public Stub(LinuxPackage target, String maintainerEmail) { super(target); this.maintainerEmail = maintainerEmail; } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java index 01e284d7f3555..9988fbc9a5b6e 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java @@ -43,9 +43,9 @@ default String defaultIconResourceName() { return "JavaApp.png"; } - class Impl extends Launcher.Proxy implements LinuxLauncher { + final class Stub extends Launcher.Proxy implements LinuxLauncher { - public Impl(Launcher launcher, Optional shortcut) { + public Stub(Launcher launcher, Optional shortcut) { super(launcher); this.shortcut = shortcut; } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java index 8c76201f015d3..5ef5d74c9de05 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java @@ -63,9 +63,9 @@ default boolean isInstallDirInUsrTree() { return !relativeInstallDir().getFileName().equals(Path.of(packageName())); } - class Impl extends Package.Proxy implements LinuxPackage { + final class Stub extends Package.Proxy implements LinuxPackage { - public Impl(Package target, AppImageLayout packageLayout, + public Stub(Package target, AppImageLayout packageLayout, String menuGroupName, String category, String additionalDependencies, String release, String arch) throws ConfigException { @@ -123,32 +123,32 @@ public Proxy(T target) { } @Override - public AppImageLayout packageLayout() { + final public AppImageLayout packageLayout() { return target.packageLayout(); } @Override - public String menuGroupName() { + final public String menuGroupName() { return target.menuGroupName(); } @Override - public String category() { + final public String category() { return target.category(); } @Override - public String additionalDependencies() { + final public String additionalDependencies() { return target.additionalDependencies(); } @Override - public String release() { + final public String release() { return target.release(); } @Override - public String arch() { + final public String arch() { return target.arch(); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java index d5e542f2fc58e..af3fd9e1b6cb6 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java @@ -28,9 +28,9 @@ public interface LinuxRpmPackage extends LinuxPackage { String licenseType(); - class Impl extends LinuxPackage.Proxy implements LinuxRpmPackage { + final class Stub extends LinuxPackage.Proxy implements LinuxRpmPackage { - public Impl(LinuxPackage target, String licenseType) { + public Stub(LinuxPackage target, String licenseType) { super(target); this.licenseType = licenseType; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index 12b0f301a069f..a33ae180c38e1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -333,7 +333,7 @@ record LauncherInfo(String name, boolean service, Map extra) { } Launcher asLauncher() { - return new Launcher.Impl(name, null, null, service, null, null); + return new Launcher.Stub(name, null, null, service, null, null); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 24839535fba80..250d9ac72f449 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -58,7 +58,7 @@ Application create() throws ConfigException { .create(); } - return new Application.Impl( + return new Application.Stub( effectiveName, Optional.ofNullable(description).orElseGet(DEFAULTS::description), Optional.ofNullable(version).orElseGet(DEFAULTS::version), diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java index a8c9a12847c98..1e97ce7eacd17 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java @@ -39,7 +39,7 @@ import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.Launcher.Impl; +import jdk.jpackage.internal.model.Launcher.Stub; import jdk.jpackage.internal.model.LauncherStartupInfo; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; @@ -50,7 +50,7 @@ Launcher create() throws ConfigException { validateIcon(icon); } var fa = toFunction(this::createFileAssociations).apply(faSources.stream()).toList(); - return new Impl(name, startupInfo, fa, isService, description, icon); + return new Stub(name, startupInfo, fa, isService, description, icon); } LauncherBuilder name(String v) { @@ -99,7 +99,7 @@ static Optional mapFileAssociation(FileAssociation src) { return Optional.empty(); } - return Optional.of(new FileAssociation.Impl(src.description(), src.icon(), mimeType, extension)); + return Optional.of(new FileAssociation.Stub(src.description(), src.icon(), mimeType, extension)); } static void validateIcon(Path icon) throws ConfigException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java index e2d2412f235d0..73446b0540ba6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java @@ -29,13 +29,13 @@ import java.util.function.UnaryOperator; import jdk.jpackage.internal.model.LauncherJarStartupInfo; import jdk.jpackage.internal.model.LauncherModularStartupInfo; -import jdk.jpackage.internal.model.LauncherStartupInfo.Impl; +import jdk.jpackage.internal.model.LauncherStartupInfo.Stub; import jdk.jpackage.internal.model.LauncherStartupInfo; final class LauncherStartupInfoBuilder { LauncherStartupInfo create() { - return decorator.apply(new Impl(qualifiedClassName, javaOptions, + return decorator.apply(new Stub(qualifiedClassName, javaOptions, defaultParameters, classPath)); } @@ -67,7 +67,7 @@ private static record ModuleStartupInfo(String moduleName, @Override public LauncherStartupInfo apply(LauncherStartupInfo base) { - return new LauncherModularStartupInfo.Impl(base, moduleName, modulePath); + return new LauncherModularStartupInfo.Stub(base, moduleName, modulePath); } } @@ -77,7 +77,7 @@ private static record JarStartupInfo(Path jarPath, @Override public LauncherStartupInfo apply(LauncherStartupInfo base) { - return new LauncherJarStartupInfo.Impl(base, jarPath, isClassNameFromMainJar); + return new LauncherJarStartupInfo.Stub(base, jarPath, isClassNameFromMainJar); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index ee911d28ed60f..54a972654a086 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -30,7 +30,7 @@ import java.util.Objects; import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.Package.Impl; +import jdk.jpackage.internal.model.Package.Stub; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.StandardPackageType; import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; @@ -81,7 +81,7 @@ Package create() throws ConfigException { throw new UnsupportedOperationException(); } - return new Impl( + return new Stub( app, type, effectiveName, diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java index b172af1731011..ec3f2aeb55b01 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java @@ -47,11 +47,11 @@ public interface AppImageLayout { AppImageLayout resolveAt(Path root); - record Impl(Path runtimeDirectory) implements AppImageLayout { + record Stub(Path runtimeDirectory) implements AppImageLayout { @Override public AppImageLayout resolveAt(Path base) { - return new Impl(resolveNullablePath(base, runtimeDirectory)); + return new Stub(resolveNullablePath(base, runtimeDirectory)); } } @@ -62,7 +62,7 @@ public Proxy(T target) { } @Override - public Path runtimeDirectory() { + final public Path runtimeDirectory() { return target.runtimeDirectory(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index 49d74d756b3ce..4e41a8f52b134 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -118,7 +118,7 @@ default OverridableResource createLauncherIconResource(Launcher launcher, return resource; } - record Impl(String name, String description, String version, String vendor, + record Stub(String name, String description, String version, String vendor, String copyright, Path srcDir, List contentDirs, AppImageLayout imageLayout, RuntimeBuilder runtimeBuilder, List launchers) implements Application { @@ -131,52 +131,52 @@ class Proxy extends ProxyBase implements Application { } @Override - public String name() { + final public String name() { return target.name(); } @Override - public String description() { + final public String description() { return target.description(); } @Override - public String version() { + final public String version() { return target.version(); } @Override - public String vendor() { + final public String vendor() { return target.vendor(); } @Override - public String copyright() { + final public String copyright() { return target.copyright(); } @Override - public Path srcDir() { + final public Path srcDir() { return target.srcDir(); } @Override - public List contentDirs() { + final public List contentDirs() { return target.contentDirs(); } @Override - public AppImageLayout imageLayout() { + final public AppImageLayout imageLayout() { return target.imageLayout(); } @Override - public RuntimeBuilder runtimeBuilder() { + final public RuntimeBuilder runtimeBuilder() { return target.runtimeBuilder(); } @Override - public List launchers() { + final public List launchers() { return target.launchers(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index e9731e11642c6..b37ee37b5965f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -60,9 +60,9 @@ public interface ApplicationLayout extends AppImageLayout { @Override ApplicationLayout resolveAt(Path root); - final class Impl extends AppImageLayout.Proxy implements ApplicationLayout { + final class Stub extends AppImageLayout.Proxy implements ApplicationLayout { - public Impl(AppImageLayout target, Path launchersDirectory, + public Stub(AppImageLayout target, Path launchersDirectory, Path appDirectory, Path appModsDirectory, Path destktopIntegrationDirectory, Path contentDirectory) { super(target); @@ -100,7 +100,7 @@ public Path contentDirectory() { @Override public ApplicationLayout resolveAt(Path base) { - return new ApplicationLayout.Impl(target.resolveAt(base), + return new ApplicationLayout.Stub(target.resolveAt(base), resolveNullablePath(base, launchersDirectory), resolveNullablePath(base, appDirectory), resolveNullablePath(base, appModsDirectory), @@ -130,27 +130,27 @@ public Proxy(T target) { } @Override - public Path launchersDirectory() { + final public Path launchersDirectory() { return target.launchersDirectory(); } @Override - public Path appDirectory() { + final public Path appDirectory() { return target.appDirectory(); } @Override - public Path appModsDirectory() { + final public Path appModsDirectory() { return target.appModsDirectory(); } @Override - public Path destktopIntegrationDirectory() { + final public Path destktopIntegrationDirectory() { return target.destktopIntegrationDirectory(); } @Override - public Path contentDirectory() { + final public Path contentDirectory() { return target.contentDirectory(); } @@ -174,8 +174,8 @@ private Builder(ApplicationLayout appLayout) { } public ApplicationLayout create() { - return new ApplicationLayout.Impl( - new AppImageLayout.Impl(runtimeDirectory), + return new ApplicationLayout.Stub( + new AppImageLayout.Stub(runtimeDirectory), launchersDirectory, appDirectory, appModsDirectory, diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java index be519df63b49a..4f2932ac298ef 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java @@ -37,36 +37,36 @@ public interface FileAssociation { String extension(); - record Impl(String description, Path icon, String mimeType, String extension) implements FileAssociation { + record Stub(String description, Path icon, String mimeType, String extension) implements FileAssociation { - public Impl { + public Stub { Objects.requireNonNull(description); } } - static class Proxy extends ProxyBase implements FileAssociation { + class Proxy extends ProxyBase implements FileAssociation { protected Proxy(T target) { super(target); } @Override - public String description() { + final public String description() { return target.description(); } @Override - public Path icon() { + final public Path icon() { return target.icon(); } @Override - public String mimeType() { + final public String mimeType() { return target.mimeType(); } @Override - public String extension() { + final public String extension() { return target.extension(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java index 429226edc54ec..04ae424f392f0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java @@ -75,7 +75,7 @@ default String defaultIconResourceName() { return null; } - record Impl(String name, LauncherStartupInfo startupInfo, + record Stub(String name, LauncherStartupInfo startupInfo, List fileAssociations, boolean isService, String description, Path icon) implements Launcher { } @@ -87,32 +87,32 @@ public Proxy(T target) { } @Override - public String name() { + final public String name() { return target.name(); } @Override - public LauncherStartupInfo startupInfo() { + final public LauncherStartupInfo startupInfo() { return target.startupInfo(); } @Override - public List fileAssociations() { + final public List fileAssociations() { return target.fileAssociations(); } @Override - public boolean isService() { + final public boolean isService() { return target.isService(); } @Override - public String description() { + final public String description() { return target.description(); } @Override - public Path icon() { + final public Path icon() { return target.icon(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java index 86d63bf7ca50b..e10ba7470a303 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java @@ -30,16 +30,16 @@ public interface LauncherJarStartupInfo extends LauncherStartupInfo { /** * Returns path to the main jar relative to app's main source directory. * - * @see jdk.jpackage.internal.Application#mainSrcDir() + * @see jdk.jpackage.internal.model.Application#srcDir() */ Path jarPath(); boolean isClassNameFromMainJar(); - final class Impl extends LauncherStartupInfo.Proxy + final class Stub extends LauncherStartupInfo.Proxy implements LauncherJarStartupInfo { - public Impl(LauncherStartupInfo target, Path jarPath, boolean isClassNameFromMainJar) { + public Stub(LauncherStartupInfo target, Path jarPath, boolean isClassNameFromMainJar) { super(target); this.jarPath = jarPath; this.isClassNameFromMainJar = isClassNameFromMainJar; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java index 42e6b5493b6ac..85fcaf396a5fc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java @@ -33,10 +33,10 @@ public interface LauncherModularStartupInfo extends LauncherStartupInfo { List modulePath(); - final class Impl extends LauncherStartupInfo.Proxy + final class Stub extends LauncherStartupInfo.Proxy implements LauncherModularStartupInfo { - public Impl(LauncherStartupInfo target, String moduleName, + public Stub(LauncherStartupInfo target, String moduleName, List modulePath) { super(target); this.moduleName = moduleName; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java index 0f645ec141eda..7a7f5a8015897 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java @@ -52,7 +52,7 @@ default String packageName() { */ List classPath(); - record Impl(String qualifiedClassName, List javaOptions, + record Stub(String qualifiedClassName, List javaOptions, List defaultParameters, List classPath) implements LauncherStartupInfo { @@ -66,22 +66,22 @@ public Proxy(T target) { } @Override - public String qualifiedClassName() { + final public String qualifiedClassName() { return target.qualifiedClassName(); } @Override - public List javaOptions() { + final public List javaOptions() { return target.javaOptions(); } @Override - public List defaultParameters() { + final public List defaultParameters() { return target.defaultParameters(); } @Override - public List classPath() { + final public List classPath() { return target.classPath(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java index ea9250de1e83d..392e45b87dfd6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java @@ -139,109 +139,108 @@ default boolean isRuntimeInstaller() { */ Path relativeInstallDir(); - record Impl(Application app, PackageType type, String packageName, + record Stub(Application app, PackageType type, String packageName, String description, String version, String aboutURL, Path licenseFile, Path predefinedAppImage, Path relativeInstallDir) implements Package { } + + class Proxy extends ProxyBase implements Package { - class Unsupported implements Package { + Proxy(T target) { + super(target); + } @Override - public Application app() { - throw new UnsupportedOperationException(); + final public Application app() { + return target.app(); } @Override - public PackageType type() { - throw new UnsupportedOperationException(); + final public PackageType type() { + return target.type(); } @Override - public String packageName() { - throw new UnsupportedOperationException(); + final public String packageName() { + return target.packageName(); } @Override - public String description() { - throw new UnsupportedOperationException(); + final public String description() { + return target.description(); } @Override - public String version() { - throw new UnsupportedOperationException(); + final public String version() { + return target.version(); } @Override - public String aboutURL() { - throw new UnsupportedOperationException(); + final public String aboutURL() { + return target.aboutURL(); } @Override - public Path licenseFile() { - throw new UnsupportedOperationException(); + final public Path licenseFile() { + return target.licenseFile(); } @Override - public Path predefinedAppImage() { - throw new UnsupportedOperationException(); + final public Path predefinedAppImage() { + return target.predefinedAppImage(); } @Override - public Path relativeInstallDir() { - throw new UnsupportedOperationException(); + final public Path relativeInstallDir() { + return target.relativeInstallDir(); } - } - - class Proxy extends ProxyBase implements Package { - - Proxy(T target) { - super(target); - } + + class Unsupported implements Package { @Override public Application app() { - return target.app(); + throw new UnsupportedOperationException(); } @Override public PackageType type() { - return target.type(); + throw new UnsupportedOperationException(); } @Override public String packageName() { - return target.packageName(); + throw new UnsupportedOperationException(); } @Override public String description() { - return target.description(); + throw new UnsupportedOperationException(); } @Override public String version() { - return target.version(); + throw new UnsupportedOperationException(); } @Override public String aboutURL() { - return target.aboutURL(); + throw new UnsupportedOperationException(); } @Override public Path licenseFile() { - return target.licenseFile(); + throw new UnsupportedOperationException(); } @Override public Path predefinedAppImage() { - return target.predefinedAppImage(); + throw new UnsupportedOperationException(); } @Override public Path relativeInstallDir() { - return target.relativeInstallDir(); + throw new UnsupportedOperationException(); } - } + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java index ca9989a5f9741..a963e9684b729 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java @@ -32,15 +32,15 @@ */ public interface RuntimeLayout extends AppImageLayout { - final class Impl extends AppImageLayout.Proxy implements RuntimeLayout { + final class Stub extends AppImageLayout.Proxy implements RuntimeLayout { - public Impl(AppImageLayout target) { + public Stub(AppImageLayout target) { super(target); } @Override public RuntimeLayout resolveAt(Path root) { - return new RuntimeLayout.Impl(target.resolveAt(root)); + return new RuntimeLayout.Stub(target.resolveAt(root)); } } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java index 70f0497e7a5c1..1a57333f452e1 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java @@ -42,7 +42,7 @@ WinExePackage create() throws ConfigException { LauncherBuilder.validateIcon(icon); } - return new WinExePackage.Impl(pkg, icon); + return new WinExePackage.Stub(pkg, icon); } WinExePackageBuilder icon(Path v) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java index 9c1408e907515..39b02586e1979 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java @@ -71,9 +71,9 @@ private static WinApplication createWinApplication( } }).map(Map.Entry::getKey).collect(toSet()); - return new WinLauncher.Impl(launcher, isConsole, shortcuts); + return new WinLauncher.Stub(launcher, isConsole, shortcuts); }), APPLICATION_LAYOUT).create(); - return new WinApplication.Impl(app); + return new WinApplication.Stub(app); } private static WinMsiPackage createWinMsiPackage(Map params) throws ConfigException, IOException { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java index e1043c707cd37..88cd76bcd2c77 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java @@ -61,7 +61,7 @@ WinMsiPackage create() throws ConfigException { .create(); } - return new WinMsiPackage.Impl( + return new WinMsiPackage.Stub( pkg, withInstallDirChooser, withShortcutPrompt, diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java index beb09740d517f..d056c35fda0c8 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java @@ -30,8 +30,8 @@ default DottedVersion winVersion() { return DottedVersion.lazy(version()); } - class Impl extends Application.Proxy implements WinApplication { - public Impl(Application app) { + final class Stub extends Application.Proxy implements WinApplication { + public Stub(Application app) { super(app); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java index 4e241071052c0..684615d237f03 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import static jdk.jpackage.internal.model.StandardPackageType.WIN_EXE; public interface WinExePackage extends Package { @@ -32,21 +33,17 @@ public interface WinExePackage extends Package { Path icon(); - class Impl extends Package.Proxy implements WinExePackage { + final class Stub extends Package.Proxy implements WinExePackage { - public Impl(WinMsiPackage msiPackage, Path icon) throws ConfigException { - super(msiPackage); + public Stub(WinMsiPackage msiPackage, Path icon) throws ConfigException { + super(createExePackage(msiPackage)); + this.msiPackage = msiPackage; this.icon = icon; } - @Override - public PackageType type() { - return StandardPackageType.WIN_EXE; - } - @Override public WinMsiPackage msiPackage() { - return target; + return msiPackage; } @Override @@ -54,6 +51,20 @@ public Path icon() { return icon; } + private static Package createExePackage(Package pkg) { + return new Package.Stub( + pkg.app(), + WIN_EXE, + pkg.packageName(), + pkg.description(), + pkg.version(), + pkg.aboutURL(), + pkg.licenseFile(), + pkg.predefinedAppImage(), + pkg.relativeInstallDir()); + } + + private final WinMsiPackage msiPackage; private final Path icon; } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java index eed66091b72d1..b67a7e3d557fa 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java @@ -75,8 +75,8 @@ public String getName() { Set shortcuts(); - class Impl extends Launcher.Proxy implements WinLauncher { - public Impl(Launcher launcher, boolean isConsole, Set shortcuts) { + final class Stub extends Launcher.Proxy implements WinLauncher { + public Stub(Launcher launcher, boolean isConsole, Set shortcuts) { super(launcher); this.isConsole = isConsole; this.shortcuts = shortcuts; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java index 090f1b94034dd..7c7b069221e48 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java @@ -24,9 +24,7 @@ */ package jdk.jpackage.internal.model; -import java.nio.charset.StandardCharsets; import java.nio.file.Path; -import java.util.Optional; import java.util.UUID; public interface WinMsiPackage extends Package { @@ -53,9 +51,9 @@ default DottedVersion msiVersion() { Path serviceInstaller(); - class Impl extends Package.Proxy implements WinMsiPackage { + final class Stub extends Package.Proxy implements WinMsiPackage { - public Impl(Package pkg, boolean withInstallDirChooser, + public Stub(Package pkg, boolean withInstallDirChooser, boolean withShortcutPrompt, String helpURL, String updateURL, String startMenuGroupName, boolean isSystemWideInstall, UUID upgradeCode, UUID productCode, Path serviceInstaller) From e3bc73676b6f98a502c5cddfd763867a6ae74b67 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 14:48:39 -0400 Subject: [PATCH 0096/1101] Bugfix. SimplePackageTest is a pass on Windows --- .../jdk/jpackage/internal/model/ApplicationLaunchers.java | 2 +- .../jdk/jpackage/internal/WixAppImageFragmentBuilder.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java index 6cbd087aff165..253e0282e7d28 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java @@ -56,7 +56,7 @@ public static ApplicationLaunchers fromList(List launchers) { return new ApplicationLaunchers(); } else { return new ApplicationLaunchers(launchers.getFirst(), - launchers.subList(1, launchers.size() - 1)); + launchers.subList(1, launchers.size())); } } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index b99224a7aee8b..e482d761e2815 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -197,7 +197,7 @@ private void initAppImageLayouts(AppImageLayout appImageLayout, Path appImageRoo appImagePathGroup = AppImageLayout.toPathGroup(srcAppImageLayout); installedAppImagePathGroup = AppImageLayout.toPathGroup(installedAppImageLayout); - if (appImageLayout instanceof ApplicationLayout appLayout) { + if (srcAppImageLayout instanceof ApplicationLayout appLayout) { // Don't want app image info file in installed application. var appImageFile = AppImageFile2.getPathInAppImage(appLayout); appImagePathGroup.ghostPath(appImageFile); From 247480fe276257d8ef00793b66519428877a36a0 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 19:35:08 -0400 Subject: [PATCH 0097/1101] Bugfix. AddLauncherTest.test() is a pass. --- .../classes/jdk/jpackage/internal/LinuxFromParams.java | 6 +++--- .../classes/jdk/jpackage/internal/WinFromParams.java | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java index 69c749f9b79ec..e207094830686 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java @@ -49,11 +49,11 @@ private static LinuxApplication createLinuxApplication( Map params) throws ConfigException, IOException { var launcherFromParams = new LauncherFromParams(); var app = createApplicationBuilder(params, toFunction(launcherParams -> { - var launcher = launcherFromParams.create(params); + var launcher = launcherFromParams.create(launcherParams); var shortcut = Stream.of(SHORTCUT_HINT, LINUX_SHORTCUT_HINT).filter(param -> { - return params.containsKey(param.getID()); + return launcherParams.containsKey(param.getID()); }).map(param -> { - return param.fetchFrom(params); + return param.fetchFrom(launcherParams); }).findFirst(); return new LinuxLauncher.Stub(launcher, shortcut); }), APPLICATION_LAYOUT).create(); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java index 39b02586e1979..a75342fc7beaf 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java @@ -55,19 +55,19 @@ private static WinApplication createWinApplication( Map params) throws ConfigException, IOException { var launcherFromParams = new LauncherFromParams(); var app = createApplicationBuilder(params, toFunction(launcherParams -> { - var launcher = launcherFromParams.create(params); + var launcher = launcherFromParams.create(launcherParams); - boolean isConsole = CONSOLE_HINT.fetchFrom(params); + boolean isConsole = CONSOLE_HINT.fetchFrom(launcherParams); var shortcuts = Map.of(WIN_SHORTCUT_DESKTOP, List.of(SHORTCUT_HINT, WIN_SHORTCUT_HINT), WIN_SHORTCUT_START_MENU, List.of(MENU_HINT, WIN_MENU_HINT)).entrySet().stream().filter(e -> { var shortcutParams = e.getValue(); - if (params.containsKey(shortcutParams.get(0).getID())) { + if (launcherParams.containsKey(shortcutParams.get(0).getID())) { // This is an explicit shortcut configuration for an addition launcher - return shortcutParams.get(0).fetchFrom(params); + return shortcutParams.get(0).fetchFrom(launcherParams); } else { - return shortcutParams.get(1).fetchFrom(params); + return shortcutParams.get(1).fetchFrom(launcherParams); } }).map(Map.Entry::getKey).collect(toSet()); From 78afeee2b1ec793a84890ebf64abee1616b10b0f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 19:38:36 -0400 Subject: [PATCH 0098/1101] - move OverridableResource back to jdk.jpackage.internal package where it belong - move Application.createLauncherIconResource() to AppImageBuilder.createLauncherIconResource() - add test if launchers have unique names to ApplicationBuilder.create() --- .../jpackage/internal/DesktopIntegration.java | 7 ++- .../internal/LinuxAppImageBuilder.java | 1 - .../jpackage/internal/LinuxDebBundler.java | 1 - .../internal/MacPkgInstallerScripts.java | 1 - .../jpackage/internal/AppImageBuilder.java | 52 ++++++++++++++++++- .../jpackage/internal/ApplicationBuilder.java | 7 +++ .../jdk/jpackage/internal/BuildEnv.java | 1 - .../jpackage/internal/LauncherAsService.java | 1 - .../{model => }/OverridableResource.java | 5 +- .../internal/StandardBundlerParam.java | 1 - .../jpackage/internal/model/Application.java | 31 ----------- .../jdk/jpackage/internal/model/IconType.java | 41 --------------- .../jdk/jpackage/internal/PackageScripts.java | 1 - .../jpackage/internal/ShellCustomAction.java | 1 - .../internal/ShellScriptResource.java | 1 - .../internal/UnixLaunchersAsServices.java | 1 - .../internal/ExecutableRebrander.java | 1 - .../jpackage/internal/WinAppImageBuilder.java | 3 +- .../jdk/jpackage/internal/WinExeBundler.java | 1 - .../jdk/jpackage/internal/WinMsiBundler.java | 1 - .../jpackage/internal/WixFragmentBuilder.java | 3 +- .../internal/WixLauncherAsService.java | 1 - .../jpackage/internal/WixSourceConverter.java | 1 - .../internal/WixUiFragmentBuilder.java | 1 - .../{model => }/OverridableResourceTest.java | 2 +- 25 files changed, 66 insertions(+), 101 deletions(-) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{model => }/OverridableResource.java (99%) delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/IconType.java rename test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/{model => }/OverridableResourceTest.java (99%) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 4f165e960f02d..68c9fc774af64 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -28,7 +28,6 @@ import jdk.jpackage.internal.model.LinuxLauncher; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.OverridableResource; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; @@ -43,11 +42,11 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; import java.util.stream.Stream; import javax.imageio.ImageIO; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; +import static jdk.jpackage.internal.AppImageBuilder.createLauncherIconResource; import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.XmlUtils; @@ -80,7 +79,7 @@ private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launche // - user explicitly requested to create a shortcut boolean withDesktopFile = !associations.isEmpty() || launcher.shortcut().orElse(false); - var curIconResource = pkg.app().createLauncherIconResource(launcher, + var curIconResource = createLauncherIconResource(pkg.app(), launcher, env::createResource); if (curIconResource == null) { // This is additional launcher with explicit `no icon` configuration. @@ -116,7 +115,7 @@ private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launche if (curIconResource == null) { // Create default icon. - curIconResource = pkg.app().createLauncherIconResource(pkg.app().mainLauncher(), env::createResource); + curIconResource = createLauncherIconResource(pkg.app(), pkg.app().mainLauncher(), env::createResource); } } else { desktopFile = null; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index b89ffbd00efb7..3e3dd02be76b7 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -26,7 +26,6 @@ import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index 9c34562161688..77f45a8ed4075 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -29,7 +29,6 @@ import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxDebPackage; -import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.nio.file.FileVisitResult; import java.nio.file.Files; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java index cd0457b0ec170..a1e153dd7fe89 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java @@ -24,7 +24,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.OverridableResource; import java.util.function.Supplier; import jdk.jpackage.internal.PackageScripts.ResourceConfig; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java index 7d0b987713ac0..ba18f8f1bbb29 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -29,7 +29,6 @@ import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.OverridableResource; import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.nio.file.Files; @@ -37,7 +36,10 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.function.Function; import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.PathUtils; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; final class AppImageBuilder { @@ -135,9 +137,41 @@ void execute(BuildEnv env) throws IOException, PackagerException { } } + static OverridableResource createLauncherIconResource(Application app, + Launcher launcher, + Function resourceSupplier) { + final String defaultIconName = launcher.defaultIconResourceName(); + final String resourcePublicName = launcher.executableName() + PathUtils.getSuffix(Path.of( + defaultIconName)); + + var iconType = IconType.getLauncherIconType(launcher.icon()); + if (iconType == IconType.NO_ICON) { + return null; + } + + OverridableResource resource = resourceSupplier.apply(defaultIconName) + .setCategory("icon") + .setExternal(launcher.icon()) + .setPublicName(resourcePublicName); + + if (iconType == IconType.DEFAULT_OR_RESOURCEDIR_ICON && app.mainLauncher() != launcher) { + // No icon explicitly configured for this launcher. + // Dry-run resource creation to figure out its source. + final Path nullPath = null; + if (toSupplier(() -> resource.saveToFile(nullPath)).get() != OverridableResource.Source.ResourceDir) { + // No icon in resource dir for this launcher, inherit icon + // configured for the main launcher. + return createLauncherIconResource(app, app.mainLauncher(), + resourceSupplier).setLogPublicName(resourcePublicName); + } + } + + return resource; + } + static interface LauncherCallback { default public void onLauncher(Application app, LauncherContext ctx) throws IOException, PackagerException { - var iconResource = app.createLauncherIconResource(ctx.launcher, + var iconResource = createLauncherIconResource(app, ctx.launcher, ctx.env::createResource); if (iconResource != null) { onLauncher(app, ctx, iconResource); @@ -153,6 +187,20 @@ static record LauncherContext(Launcher launcher, BuildEnv env, ApplicationLayout resolvedAppLayout, Path launcherExecutable) { } + private enum IconType { + DEFAULT_OR_RESOURCEDIR_ICON, CUSTOM_ICON, NO_ICON; + + public static IconType getLauncherIconType(Path iconPath) { + if (iconPath == null) { + return DEFAULT_OR_RESOURCEDIR_ICON; + } + if (iconPath.toFile().getName().isEmpty()) { + return NO_ICON; + } + return CUSTOM_ICON; + } + } + private final boolean withAppImageFile; private final Application app; private final ApplicationLayout appLayout; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 250d9ac72f449..b235daf99daf4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -46,6 +46,13 @@ Application create() throws ConfigException { final var launchersAsList = Optional.ofNullable(launchers).map( ApplicationLaunchers::asList).orElseGet(List::of); + + final var launcherCount = launchersAsList.size(); + + if (launcherCount != launchers.asList().stream().map(Launcher::name).distinct().count()) { + throw ConfigException.build().message("ERR_NoUniqueName").create(); + } + final String effectiveName; if (name != null) { effectiveName = name; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java index f5c5e85768780..d4b58fa2c8f93 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java @@ -24,7 +24,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.OverridableResource; import java.nio.file.Path; import java.util.Optional; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java index 6ef11a95cb780..b97cacbac7dbf 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal; import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.OverridableResource; class LauncherAsService { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/OverridableResource.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java similarity index 99% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/OverridableResource.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java index 1b41fcd8f29da..7740c0eecf547 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/OverridableResource.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal.model; +package jdk.jpackage.internal; import java.io.BufferedReader; import java.io.ByteArrayInputStream; @@ -45,7 +45,6 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.Log; /** @@ -69,7 +68,7 @@ * value was passed in #setExternal call that value will be used as a path to file * to copy in the destination file passed in #saveToFile function call. */ -public final class OverridableResource { +final class OverridableResource { public OverridableResource() { defaultName = ""; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index aeba30137c474..204a99825464a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -27,7 +27,6 @@ import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.OverridableResource; import java.io.File; import java.io.IOException; import java.nio.file.Files; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index 4e41a8f52b134..c38b0773fcfc1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -87,37 +87,6 @@ default Map extraAppImageFileData() { return Map.of(); } - default OverridableResource createLauncherIconResource(Launcher launcher, - Function resourceSupplier) { - final String defaultIconName = launcher.defaultIconResourceName(); - final String resourcePublicName = launcher.executableName() + PathUtils.getSuffix(Path.of( - defaultIconName)); - - var iconType = IconType.getLauncherIconType(launcher.icon()); - if (iconType == IconType.NO_ICON) { - return null; - } - - OverridableResource resource = resourceSupplier.apply(defaultIconName) - .setCategory("icon") - .setExternal(launcher.icon()) - .setPublicName(resourcePublicName); - - if (iconType == IconType.DEFAULT_OR_RESOURCEDIR_ICON && mainLauncher() != launcher) { - // No icon explicitly configured for this launcher. - // Dry-run resource creation to figure out its source. - final Path nullPath = null; - if (toSupplier(() -> resource.saveToFile(nullPath)).get() != OverridableResource.Source.ResourceDir) { - // No icon in resource dir for this launcher, inherit icon - // configured for the main launcher. - return createLauncherIconResource(mainLauncher(), - resourceSupplier).setLogPublicName(resourcePublicName); - } - } - - return resource; - } - record Stub(String name, String description, String version, String vendor, String copyright, Path srcDir, List contentDirs, AppImageLayout imageLayout, RuntimeBuilder runtimeBuilder, diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/IconType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/IconType.java deleted file mode 100644 index 96572eb7792ce..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/IconType.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal.model; - -import java.nio.file.Path; - -public enum IconType { - DEFAULT_OR_RESOURCEDIR_ICON, CUSTOM_ICON, NO_ICON; - - public static IconType getLauncherIconType(Path iconPath) { - if (iconPath == null) { - return DEFAULT_OR_RESOURCEDIR_ICON; - } - if (iconPath.toFile().getName().isEmpty()) { - return NO_ICON; - } - return CUSTOM_ICON; - } -} diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java index 2a5011f72a702..b5dd828227326 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java @@ -24,7 +24,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.nio.file.Path; import java.util.EnumSet; diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java index 9de39340fb6f1..418007b163182 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java @@ -24,7 +24,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.OverridableResource; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellScriptResource.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellScriptResource.java index 7039911e96a47..c6303636c66f4 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellScriptResource.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellScriptResource.java @@ -24,7 +24,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java index 3470ae71f5e7d..798124a34ca14 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java @@ -26,7 +26,6 @@ import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.nio.file.Path; import java.util.Collections; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java index b8f41f0efbb97..68b82a90ab7fb 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java @@ -28,7 +28,6 @@ import jdk.jpackage.internal.model.WinLauncher; import jdk.jpackage.internal.model.WinApplication; import jdk.jpackage.internal.model.DottedVersion; -import jdk.jpackage.internal.model.OverridableResource; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java index bcaac2f77a955..814820b61ed59 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java @@ -30,6 +30,7 @@ import jdk.jpackage.internal.model.WinApplication; import java.io.IOException; import java.nio.file.Path; +import static jdk.jpackage.internal.AppImageBuilder.createLauncherIconResource; import jdk.jpackage.internal.model.ApplicationLayout; final class WinAppImageBuilder { @@ -45,7 +46,7 @@ private final static class LauncherCallbackImpl implements public void onLauncher(Application app, AppImageBuilder.LauncherContext ctx) throws IOException, PackagerException { Path iconTarget = null; - var iconResource = app.createLauncherIconResource(ctx.launcher(), + var iconResource = createLauncherIconResource(app, ctx.launcher(), name -> ctx.env().createResource(name)); if (iconResource != null) { var iconDir = ctx.env().buildRoot().resolve("icons"); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java index d329a5a827aac..08ccd46e00363 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java @@ -27,7 +27,6 @@ import jdk.jpackage.internal.model.WinExePackage; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index c8dc6066c1ef9..26a426b03fbf2 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -28,7 +28,6 @@ import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.WinMsiPackage; -import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.io.InputStream; import java.io.Writer; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java index 4a86a02db15e4..0b086cf5503eb 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java @@ -26,7 +26,6 @@ import jdk.jpackage.internal.model.WinMsiPackage; import jdk.jpackage.internal.model.DottedVersion; -import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; @@ -40,7 +39,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.stream.XMLStreamWriter; -import jdk.jpackage.internal.model.OverridableResource.Source; +import jdk.jpackage.internal.OverridableResource.Source; import jdk.internal.util.Architecture; import jdk.jpackage.internal.WixSourceConverter.ResourceGroup; import jdk.jpackage.internal.WixToolset.WixToolsetType; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java index 01f02b375130d..1cc37bf983d05 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal; import jdk.jpackage.internal.model.WinLauncher; -import jdk.jpackage.internal.model.OverridableResource; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java index ec0cb23dd4f9e..58f777bd71b48 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java @@ -24,7 +24,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.OverridableResource; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java index 4db3e3580dbb4..8a67df62e690e 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal; import jdk.jpackage.internal.model.WinMsiPackage; -import jdk.jpackage.internal.model.OverridableResource; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/OverridableResourceTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java similarity index 99% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/OverridableResourceTest.java rename to test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java index db902dd5f72ee..c149f3e293be9 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/OverridableResourceTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java @@ -21,7 +21,7 @@ * questions. */ -package jdk.jpackage.internal.model; +package jdk.jpackage.internal; import java.io.IOException; import java.io.InputStream; From 216c7ae2a60847397a16df59080e1fac8d367981 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 22:56:31 -0400 Subject: [PATCH 0099/1101] Move check for null and empty string inside of validateIcon() method --- .../classes/jdk/jpackage/internal/LauncherBuilder.java | 8 +++++--- .../jdk/jpackage/internal/WinExePackageBuilder.java | 5 +---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java index 1e97ce7eacd17..2935ad8829503 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java @@ -46,9 +46,7 @@ final class LauncherBuilder { Launcher create() throws ConfigException { - if (icon != null) { - validateIcon(icon); - } + validateIcon(icon); var fa = toFunction(this::createFileAssociations).apply(faSources.stream()).toList(); return new Stub(name, startupInfo, fa, isService, description, icon); } @@ -103,6 +101,10 @@ static Optional mapFileAssociation(FileAssociation src) { } static void validateIcon(Path icon) throws ConfigException { + if (icon == null || icon.toString().isEmpty()) { + return; + } + switch (OperatingSystem.current()) { case WINDOWS -> { if (!icon.getFileName().toString().toLowerCase().endsWith(".ico")) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java index 1a57333f452e1..eb248f2a06a40 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java @@ -38,10 +38,7 @@ final class WinExePackageBuilder { } WinExePackage create() throws ConfigException { - if (icon != null) { - LauncherBuilder.validateIcon(icon); - } - + LauncherBuilder.validateIcon(icon); return new WinExePackage.Stub(pkg, icon); } From 101e3d28c9b147b7f8812971bd3b536097915e90 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 22:56:48 -0400 Subject: [PATCH 0100/1101] bugfix --- .../share/classes/jdk/jpackage/internal/CfgFile.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java index 21a04e531446a..41166e0cd5a27 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java @@ -129,8 +129,8 @@ private ApplicationLayout createAppCfgLayout(ApplicationLayout appLayout) { .appDirectory("$APPDIR") .appModsDirectory( Path.of("$APPDIR").resolve( - appLayout.appModsDirectory().relativize( - appLayout.appDirectory()))) + appLayout.appDirectory().relativize( + appLayout.appModsDirectory()))) .create(); } From 8a77750c6dae8cc0e8c4e97919aaee9cac7f3874 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 23:35:19 -0400 Subject: [PATCH 0101/1101] Better Application.isRuntime() implementation --- .../classes/jdk/jpackage/internal/model/Application.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index c38b0773fcfc1..a47ee5c1d91ea 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -28,9 +28,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.function.Function; -import jdk.jpackage.internal.util.PathUtils; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; public interface Application { @@ -75,7 +72,7 @@ default List additionalLaunchers() { } default boolean isRuntime() { - return mainLauncher() == null; + return imageLayout() instanceof RuntimeLayout; } default boolean isService() { From 8d0067f2e1fdc85be00444c2be8425a2b7dfc106 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 2 Nov 2024 23:35:53 -0400 Subject: [PATCH 0102/1101] Bugfix to make AppImagePackageTest test pass --- .../jdk/jpackage/internal/LinuxPackageBuilder.java | 8 ++++---- .../classes/jdk/jpackage/internal/AppImageFile2.java | 4 ++-- .../jpackage/internal/resources/MainResources.properties | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index a8028325b3bd9..30bf1030f98d2 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -122,8 +122,8 @@ private static void validatePackageName(String packageName, var regexp = Pattern.compile("^[a-z][a-z\\d\\+\\-\\.]+"); if (!regexp.matcher(packageName).matches()) { throw ConfigException.build() - .message(I18N.format("error.deb-invalid-value-for-package-name", packageName)) - .advice(I18N.getString("error.deb-invalid-value-for-package-name.advice")) + .message("error.deb-invalid-value-for-package-name", packageName) + .advice("error.deb-invalid-value-for-package-name.advice") .create(); } } @@ -140,8 +140,8 @@ private static void validatePackageName(String packageName, var regexp = Pattern.compile("[a-z\\d\\+\\-\\.\\_]+", Pattern.CASE_INSENSITIVE); if (!regexp.matcher(packageName).matches()) { throw ConfigException.build() - .message(I18N.format("error.rpm-invalid-value-for-package-name", packageName)) - .advice(I18N.getString("error.rpm-invalid-value-for-package-name.advice")) + .message("error.rpm-invalid-value-for-package-name", packageName) + .advice("error.rpm-invalid-value-for-package-name.advice") .create(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index a33ae180c38e1..7725452aac176 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -249,12 +249,12 @@ public Map extraAppImageFileData() { throw new IOException(ex); } catch (NoSuchFileException ex) { throw ConfigException.build() - .message(I18N.format("error.foreign-app-image", FILENAME)) + .message("error.foreign-app-image", FILENAME) .create(); } catch (InavlidAppImageFileException ex) { // Invalid input XML throw ConfigException.build() - .message(I18N.format("error.invalid-app-image-file", FILENAME)) + .message("error.invalid-app-image-file", FILENAME) .create(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index 85e80f0d69431..f32fd4850a380 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -79,7 +79,7 @@ error.no.name.advice=Specify name with --name warning.no.jdk.modules.found=Warning: No JDK Modules found -error.foreign-app-image=Missing {0} file in app-image dir +error.foreign-app-image=Error: Missing {0} file in app-image dir error.invalid-app-image-file=app-image dir generated by another jpackage version or malformed {0} file error.invalid-install-dir=Invalid installation directory "{0}" From 85dc99a8f53dca27ec1e976108bb8c5a1a04c5bf Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 00:17:58 -0400 Subject: [PATCH 0103/1101] Fix runtime packaging --- .../jpackage/internal/ApplicationBuilder.java | 2 +- .../jdk/jpackage/internal/FromParams.java | 20 +++++++--- .../internal/model/RuntimeLayout.java | 12 +----- .../internal/model/RuntimeLayoutStub.java | 39 +++++++++++++++++++ 4 files changed, 55 insertions(+), 18 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayoutStub.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index b235daf99daf4..ff81a187abd51 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -49,7 +49,7 @@ Application create() throws ConfigException { final var launcherCount = launchersAsList.size(); - if (launcherCount != launchers.asList().stream().map(Launcher::name).distinct().count()) { + if (launcherCount != launchersAsList.stream().map(Launcher::name).distinct().count()) { throw ConfigException.build().message("ERR_NoUniqueName").create(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java index 1e8a917d2e9be..326d178c63359 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -55,17 +55,18 @@ import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; -import jdk.jpackage.internal.model.AppImageLayout; +import static jdk.jpackage.internal.StandardBundlerParam.isRuntimeInstaller; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLaunchers; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.RuntimeLayout; import jdk.jpackage.internal.util.function.ThrowingFunction; final class FromParams { static ApplicationBuilder createApplicationBuilder(Map params, - Function, Launcher> launcherMapper, AppImageLayout appLayout) + Function, Launcher> launcherMapper, ApplicationLayout appLayout) throws ConfigException, IOException { var appBuilder = new ApplicationBuilder() @@ -75,14 +76,21 @@ static ApplicationBuilder createApplicationBuilder(Map p .vendor(VENDOR.fetchFrom(params)) .copyright(COPYRIGHT.fetchFrom(params)) .srcDir(SOURCE_DIR.fetchFrom(params)) - .appImageLayout(appLayout) .contentDirs(APP_CONTENT.fetchFrom(params)); + var isRuntimeInstaller = isRuntimeInstaller(params); + + if (isRuntimeInstaller) { + appBuilder.appImageLayout(RuntimeLayout.INSTANCE); + } else { + appBuilder.appImageLayout(appLayout); + } + var predefinedAppImage = getPredefinedAppImage(params); - if (predefinedAppImage != null) { - var appIMafeFile = AppImageFile2.load( - (ApplicationLayout) appLayout.resolveAt(predefinedAppImage)); + if (isRuntimeInstaller) { + } else if (predefinedAppImage != null) { + var appIMafeFile = AppImageFile2.load(appLayout.resolveAt(predefinedAppImage)); appBuilder.initFromAppImage(appIMafeFile, launcherInfo -> { var launcherParams = mapLauncherInfo(launcherInfo); return launcherMapper.apply(mergeParams(params, launcherParams)); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java index a963e9684b729..9c98a4329bba7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java @@ -32,15 +32,5 @@ */ public interface RuntimeLayout extends AppImageLayout { - final class Stub extends AppImageLayout.Proxy implements RuntimeLayout { - - public Stub(AppImageLayout target) { - super(target); - } - - @Override - public RuntimeLayout resolveAt(Path root) { - return new RuntimeLayout.Stub(target.resolveAt(root)); - } - } + static final RuntimeLayout INSTANCE = new RuntimeLayoutStub(new AppImageLayout.Stub(Path.of(""))); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayoutStub.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayoutStub.java new file mode 100644 index 0000000000000..69d12a21f43c3 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayoutStub.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.nio.file.Path; + +final class RuntimeLayoutStub extends AppImageLayout.Proxy implements RuntimeLayout { + + RuntimeLayoutStub(AppImageLayout target) { + super(target); + } + + @Override + public RuntimeLayout resolveAt(Path root) { + return new RuntimeLayoutStub(target.resolveAt(root)); + } +} From 3f92f758da662cb21815788e03f93435dc611870 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 00:25:01 -0400 Subject: [PATCH 0104/1101] Bugfix to make InstallDirTest.testCommon() pass on windows --- .../jdk/jpackage/internal/PackageBuilder.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index 54a972654a086..5380948ab1bd6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -56,23 +56,24 @@ Package create() throws ConfigException { if (installDir != null) { var normalizedInstallDir = mapInstallDir(installDir, type); if (type instanceof StandardPackageType stdType) { - do { - switch (stdType) { - case LINUX_DEB, LINUX_RPM -> { - switch (normalizedInstallDir.toString()) { - case "/usr", "/usr/local" -> { - break; - } + boolean addPackageName = true; + switch (stdType) { + case LINUX_DEB, LINUX_RPM -> { + switch (normalizedInstallDir.toString()) { + case "/usr", "/usr/local" -> { + addPackageName = false; } } - case WIN_EXE, WIN_MSI -> { - break; - } - case MAC_DMG,MAC_PKG -> { - } } + case WIN_EXE, WIN_MSI -> { + addPackageName = false; + } + case MAC_DMG,MAC_PKG -> { + } + } + if (addPackageName) { normalizedInstallDir = normalizedInstallDir.resolve(effectiveName); - } while(false); + } } relativeInstallDir = normalizedInstallDir; } else if (type instanceof StandardPackageType stdType) { @@ -207,7 +208,7 @@ private static Path defaultRelativeInstallDir(StandardPackageType pkgType, Strin private Path licenseFile; private Path predefinedAppImage; private Path installDir; - + final private PackageType type; final private Application app; } From 7505a52ceb0173fc008b703368eda56d36fff41c Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 09:09:16 -0500 Subject: [PATCH 0105/1101] Wrong import-s removed --- test/jdk/tools/jpackage/share/InOutPathTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java index 699d88e318947..9f4c8d7043d2b 100644 --- a/test/jdk/tools/jpackage/share/InOutPathTest.java +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -31,14 +31,14 @@ import java.util.function.Predicate; import static java.util.stream.Collectors.toSet; import java.util.stream.Stream; -import jdk.jpackage.internal.AppImageFile; -import jdk.jpackage.internal.ApplicationLayout; -import jdk.jpackage.internal.PackageFile; import jdk.jpackage.test.Annotations; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.AppImageFile; +import jdk.jpackage.test.ApplicationLayout; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageCommand.AppLayoutAssert; +import jdk.jpackage.test.PackageFile; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE_AND_UNPACK; From 80db60171520c420e2a97af898e31c520ff4d6e2 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 11:19:18 -0500 Subject: [PATCH 0106/1101] Remove copied to FilUtils function from IOUtils. Get rid of dependency on AtomicReference from FilUtils.deleteRecursive() --- .../jdk/jpackage/internal/IOUtils.java | 107 -------------- .../jdk/jpackage/internal/util/FileUtils.java | 131 ++++++++++++------ 2 files changed, 85 insertions(+), 153 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java index 72d360791ea3b..090e50c2cf60f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java @@ -31,17 +31,11 @@ import java.io.InputStreamReader; import java.io.IOException; import java.io.PrintStream; -import java.nio.file.CopyOption; -import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; -import jdk.internal.util.OperatingSystem; /** * IOUtils @@ -50,107 +44,6 @@ */ public class IOUtils { - public static void deleteRecursive(Path directory) throws IOException { - final AtomicReference exception = new AtomicReference<>(); - - if (!Files.exists(directory)) { - return; - } - - Files.walkFileTree(directory, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, - BasicFileAttributes attr) throws IOException { - if (OperatingSystem.isWindows()) { - Files.setAttribute(file, "dos:readonly", false); - } - try { - Files.delete(file); - } catch (IOException ex) { - exception.compareAndSet(null, ex); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, - BasicFileAttributes attr) throws IOException { - if (OperatingSystem.isWindows()) { - Files.setAttribute(dir, "dos:readonly", false); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException e) - throws IOException { - try { - Files.delete(dir); - } catch (IOException ex) { - exception.compareAndSet(null, ex); - } - return FileVisitResult.CONTINUE; - } - }); - if (exception.get() != null) { - throw exception.get(); - } - } - - public static void copyRecursive(Path src, Path dest, CopyOption... options) - throws IOException { - copyRecursive(src, dest, List.of(), options); - } - - public static void copyRecursive(Path src, Path dest, - final List excludes, CopyOption... options) - throws IOException { - - List copyActions = new ArrayList<>(); - - Files.walkFileTree(src, new SimpleFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(final Path dir, - final BasicFileAttributes attrs) { - if (isPathMatch(dir, excludes)) { - return FileVisitResult.SKIP_SUBTREE; - } else { - copyActions.add(new CopyAction(null, dest.resolve(src. - relativize(dir)))); - return FileVisitResult.CONTINUE; - } - } - - @Override - public FileVisitResult visitFile(final Path file, - final BasicFileAttributes attrs) { - if (!isPathMatch(file, excludes)) { - copyActions.add(new CopyAction(file, dest.resolve(src. - relativize(file)))); - } - return FileVisitResult.CONTINUE; - } - }); - - for (var copyAction : copyActions) { - copyAction.apply(options); - } - } - - private static record CopyAction(Path src, Path dest) { - void apply(CopyOption... options) throws IOException { - if (src == null) { - Files.createDirectories(dest); - } else { - Files.copy(src, dest, options); - } - } - } - - private static boolean isPathMatch(Path what, List paths) { - return paths.stream().anyMatch(what::endsWith); - } - public static void copyFile(Path sourceFile, Path destFile) throws IOException { Files.createDirectories(getParent(destFile)); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java index d0d63ab0bc7ef..7329bb0cf6845 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java @@ -31,86 +31,125 @@ import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.util.function.ExceptionWrapper; +import jdk.jpackage.internal.util.function.ThrowingConsumer; public final class FileUtils { + public static void deleteRecursive(Path directory) throws IOException { + if (!Files.exists(directory)) { + return; + } + + var callback = new RecursiveDeleter(); + + Files.walkFileTree(directory, callback); + + if (callback.ex != null) { + throw callback.ex; + } + } + public static void copyRecursive(Path src, Path dest, CopyOption... options) throws IOException { copyRecursive(src, dest, List.of(), options); } public static void copyRecursive(Path src, Path dest, - final List excludes, CopyOption... options) throws - IOException { + final List excludes, CopyOption... options) + throws IOException { + + List copyActions = new ArrayList<>(); + Files.walkFileTree(src, new SimpleFileVisitor() { @Override public FileVisitResult preVisitDirectory(final Path dir, - final BasicFileAttributes attrs) throws IOException { - if (excludes.contains(dir.toFile().getName())) { + final BasicFileAttributes attrs) { + if (isPathMatch(dir, excludes)) { return FileVisitResult.SKIP_SUBTREE; } else { - Files.createDirectories(dest.resolve(src.relativize(dir))); + copyActions.add(new CopyAction(null, dest.resolve(src. + relativize(dir)))); return FileVisitResult.CONTINUE; } } @Override public FileVisitResult visitFile(final Path file, - final BasicFileAttributes attrs) throws IOException { - if (!excludes.contains(file.toFile().getName())) { - Files.copy(file, dest.resolve(src.relativize(file)), options); + final BasicFileAttributes attrs) { + if (!isPathMatch(file, excludes)) { + copyActions.add(new CopyAction(file, dest.resolve(src. + relativize(file)))); } return FileVisitResult.CONTINUE; } }); - } - public static void deleteRecursive(Path directory) throws IOException { - final AtomicReference exception = new AtomicReference<>(); - if (!Files.exists(directory)) { - return; + for (var copyAction : copyActions) { + copyAction.apply(options); } - Files.walkFileTree(directory, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attr) - throws IOException { - if (OperatingSystem.isWindows()) { - Files.setAttribute(file, "dos:readonly", false); - } - try { - Files.delete(file); - } catch (IOException ex) { - exception.compareAndSet(null, ex); - } - return FileVisitResult.CONTINUE; + } + + private static boolean isPathMatch(Path what, List paths) { + return paths.stream().anyMatch(what::endsWith); + } + + private static record CopyAction(Path src, Path dest) { + + void apply(CopyOption... options) throws IOException { + if (src == null) { + Files.createDirectories(dest); + } else { + Files.copy(src, dest, options); } + } + } - @Override - public FileVisitResult preVisitDirectory(Path dir, - BasicFileAttributes attr) throws IOException { - if (OperatingSystem.isWindows()) { - Files.setAttribute(dir, "dos:readonly", false); - } - return FileVisitResult.CONTINUE; + private static class RecursiveDeleter extends SimpleFileVisitor { + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attr) throws IOException { + adjustAttributes(file); + runActionOnPath(Files::delete, file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, + BasicFileAttributes attr) throws IOException { + adjustAttributes(dir); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException e) + throws IOException { + runActionOnPath(Files::delete, dir); + return FileVisitResult.CONTINUE; + } + + private static void adjustAttributes(Path path) throws IOException { + if (OperatingSystem.isWindows()) { + Files.setAttribute(path, "dos:readonly", false); } + } - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException e) - throws IOException { - try { - Files.delete(dir); - } catch (IOException ex) { - exception.compareAndSet(null, ex); + private void runActionOnPath(ThrowingConsumer action, Path path) { + try { + action.accept(path); + } catch (IOException ex) { + if (this.ex == null) { + this.ex = ex; } - return FileVisitResult.CONTINUE; + } catch (Throwable t) { + throw ExceptionWrapper.rethrowUnchecked(t); } - }); - - if (exception.get() != null) { - throw exception.get(); } + + private IOException ex; } } From 217424a1d963e3c4a3a7fdfd831b93a8f2f66f32 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 11:20:21 -0500 Subject: [PATCH 0107/1101] Fix arguments for FileUtils.copyRecursive() --- .../classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java index a88987ef6c58c..df528d106ce2c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java @@ -111,7 +111,7 @@ private static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, return appImageLayout -> { // copy whole runtime, need to skip jmods and src.zip - final List excludes = Arrays.asList("jmods", "src.zip"); + final List excludes = List.of(Path.of("jmods"), Path.of("src.zip")); FileUtils.copyRecursive(runtimeDir, appImageLayout.runtimeDirectory(), excludes, From 0daa34f4ade3ff3ac00430b808edd78f7c89eea3 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 11:21:20 -0500 Subject: [PATCH 0108/1101] Fix to make InOutPath test pass --- .../jpackage/internal/LinuxAppBundler.java | 4 +- .../internal/AbstractAppImageBuilder.java | 2 +- .../jpackage/internal/AppImageBuilder.java | 47 ++++++++++++++----- .../jdk/jpackage/internal/WinAppBundler.java | 5 +- .../jdk/jpackage/internal/WinMsiBundler.java | 8 ++-- 5 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java index d6d17f747f261..2bca3fef0418f 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java @@ -31,7 +31,9 @@ public LinuxAppBundler() { // Order is important! var app = LinuxFromParams.APPLICATION.fetchFrom(params); var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - LinuxAppImageBuilder.build().create(app).execute(BuildEnv.withAppImageDir(env, output)); + LinuxAppImageBuilder.build() + .excludeDirFromCopying(output.getParent()) + .create(app).execute(BuildEnv.withAppImageDir(env, output)); }); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java index 8461f606d8cb0..04c5af8b35406 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java @@ -106,7 +106,7 @@ protected void copyApplication(Map params) } } - IOUtils.copyRecursive(inputPath, + FileUtils.copyRecursive(inputPath, appLayout.appDirectory().toAbsolutePath(), excludes); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java index ba18f8f1bbb29..9cf470e83110a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -35,8 +35,10 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; +import java.util.stream.Stream; import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.PathUtils; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; @@ -51,14 +53,25 @@ Builder launcherCallback(LauncherCallback v) { return this; } + Builder excludeDirFromCopying(Path path) { + Objects.requireNonNull(path); + + if (excludeCopyDirs == null) { + excludeCopyDirs = new ArrayList<>(); + } + excludeCopyDirs.add(path); + return this; + } + AppImageBuilder create(Application app) { - return new AppImageBuilder(app, app.asApplicationLayout(), launcherCallback); + return new AppImageBuilder(app, app.asApplicationLayout(), excludeCopyDirs, launcherCallback); } AppImageBuilder create(Package pkg) { - return new AppImageBuilder(pkg, launcherCallback); + return new AppImageBuilder(pkg, excludeCopyDirs, launcherCallback); } + private List excludeCopyDirs; private LauncherCallback launcherCallback; } @@ -66,32 +79,38 @@ static Builder build() { return new Builder(); } - private AppImageBuilder(Application app, ApplicationLayout appLayout, LauncherCallback launcherCallback) { + private AppImageBuilder(Application app, ApplicationLayout appLayout, + List excludeCopyDirs, LauncherCallback launcherCallback) { + Objects.requireNonNull(app); + Objects.requireNonNull(appLayout); + this.app = app; this.appLayout = appLayout; this.withAppImageFile = true; this.launcherCallback = launcherCallback; + this.excludeCopyDirs = Optional.ofNullable(excludeCopyDirs).orElseGet(List::of); } - private AppImageBuilder(Package pkg, LauncherCallback launcherCallback) { - this(pkg.app(), pkg.asPackageApplicationLayout(), launcherCallback); + private AppImageBuilder(Package pkg, List excludeCopyDirs, + LauncherCallback launcherCallback) { + this(pkg.app(), pkg.asPackageApplicationLayout(), excludeCopyDirs, + launcherCallback); } - private static void copyRecursive(Path srcDir, Path dstDir, BuildEnv env) throws IOException { + private static void copyRecursive(Path srcDir, Path dstDir, List excludeDirs) throws IOException { srcDir = srcDir.toAbsolutePath(); List excludes = new ArrayList<>(); - for (var path : List.of(env.buildRoot(), env.appImageDir())) { + for (var path : excludeDirs) { if (Files.isDirectory(path)) { - path = path.toAbsolutePath(); if (path.startsWith(srcDir) && !Files.isSameFile(path, srcDir)) { excludes.add(path); } } } - FileUtils.copyRecursive(srcDir, dstDir.toAbsolutePath() /*, excludes */); + FileUtils.copyRecursive(srcDir, dstDir.toAbsolutePath(), excludes); } void execute(BuildEnv env) throws IOException, PackagerException { @@ -102,14 +121,19 @@ void execute(BuildEnv env) throws IOException, PackagerException { return; } + var excludeCandidates = Stream.concat( + excludeCopyDirs.stream(), + Stream.of(env.buildRoot(), env.appImageDir()) + ).map(Path::toAbsolutePath).toList(); + if (app.srcDir() != null) { - copyRecursive(app.srcDir(), resolvedAppLayout.appDirectory(), env); + copyRecursive(app.srcDir(), resolvedAppLayout.appDirectory(), excludeCandidates); } for (var srcDir : Optional.ofNullable(app.contentDirs()).orElseGet(List::of)) { copyRecursive(srcDir, resolvedAppLayout.contentDirectory().resolve(srcDir.getFileName()), - env); + excludeCandidates); } if (withAppImageFile) { @@ -204,5 +228,6 @@ public static IconType getLauncherIconType(Path iconPath) { private final boolean withAppImageFile; private final Application app; private final ApplicationLayout appLayout; + private final List excludeCopyDirs; private final LauncherCallback launcherCallback; } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java index 126f89cbdb2e3..b97599b4c373c 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java @@ -31,8 +31,9 @@ public WinAppBundler() { // Order is important! var app = WinFromParams.APPLICATION.fetchFrom(params); var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - WinAppImageBuilder.build().create(app).execute( - BuildEnv.withAppImageDir(env, output)); + WinAppImageBuilder.build() + .excludeDirFromCopying(output.getParent()) + .create(app).execute(BuildEnv.withAppImageDir(env, output)); }); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 26a426b03fbf2..ca3f9921ad6d3 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -205,7 +205,7 @@ public boolean validate(Map params) } } - private void prepareProto(WinMsiPackage pkg, BuildEnv env) throws + private void prepareProto(WinMsiPackage pkg, BuildEnv env, Path msiOutputDir) throws PackagerException, IOException { AppImageLayout appImageLayout; @@ -213,7 +213,9 @@ private void prepareProto(WinMsiPackage pkg, BuildEnv env) throws // We either have an application image or need to build one. if (pkg.app().runtimeBuilder() != null) { // Runtime builder is present, build app image. - WinAppImageBuilder.build().create(pkg.app()).execute(env); + WinAppImageBuilder.build() + .excludeDirFromCopying(msiOutputDir) + .create(pkg.app()).execute(env); appImageLayout = pkg.appImageLayout().resolveAt(env.appImageDir()); } else { Path srcAppImageDir = pkg.predefinedAppImage(); @@ -268,7 +270,7 @@ public Path execute(Map params, Path imageDir = env.appImageDir(); try { - prepareProto(pkg, env); + prepareProto(pkg, env, outputParentDir); for (var wixFragment : wixFragments) { wixFragment.initFromParams(env, pkg); wixFragment.addFilesToConfigRoot(); From d26f4941e83a51da42e3aef4d8c983d77a0a353a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 11:24:59 -0500 Subject: [PATCH 0109/1101] Fix copyright year --- .../classes/jdk/jpackage/internal/LinuxApplicationLayout.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java index 13dc7496c69e0..479c04632f36e 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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 From b7958f58ad1fce210353d49988e084f1fb1a70bf Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 11:42:56 -0500 Subject: [PATCH 0110/1101] Rename RuntimeLayout.INSTANCE -> RuntimeLayout.DEFAULT --- .../share/classes/jdk/jpackage/internal/FromParams.java | 2 +- .../classes/jdk/jpackage/internal/model/RuntimeLayout.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java index 326d178c63359..e8853f2313022 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -81,7 +81,7 @@ static ApplicationBuilder createApplicationBuilder(Map p var isRuntimeInstaller = isRuntimeInstaller(params); if (isRuntimeInstaller) { - appBuilder.appImageLayout(RuntimeLayout.INSTANCE); + appBuilder.appImageLayout(RuntimeLayout.DEFAULT); } else { appBuilder.appImageLayout(appLayout); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java index 9c98a4329bba7..7f17309af79f1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java @@ -32,5 +32,5 @@ */ public interface RuntimeLayout extends AppImageLayout { - static final RuntimeLayout INSTANCE = new RuntimeLayoutStub(new AppImageLayout.Stub(Path.of(""))); + static final RuntimeLayout DEFAULT = new RuntimeLayoutStub(new AppImageLayout.Stub(Path.of(""))); } From 82aef7726e39b97db7a813e7ff1fcdbe13531e69 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 13:08:00 -0500 Subject: [PATCH 0111/1101] Better standard option configuration --- .../jdk/jpackage/internal/cli/OptionSpec.java | 4 ++ .../internal/cli/OptionSpecBuilder.java | 4 ++ .../internal/cli/PackageTypeGroup.java | 6 +- .../jpackage/internal/cli/StandardOption.java | 58 +++++++++---------- 4 files changed, 39 insertions(+), 33 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java index ba69a71bed0c7..e3f669fb32526 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java @@ -38,4 +38,8 @@ public record OptionSpec(String name, ValueConverter valueConverter, String s throw new IllegalArgumentException("At least one package type must be set"); } } + + public boolean withValue() { + return valueConverter != null; + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java index a71076755667a..281097fea1470 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java @@ -65,6 +65,10 @@ OptionSpecBuilder ofUrl() { return ofString().valueValidator(StandardValueValidator::validateUrl); } + OptionSpecBuilder noValue() { + return valueValidator(null); + } + OptionSpecBuilder name(String v) { name = v; return this; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/PackageTypeGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/PackageTypeGroup.java index 5a7422db3cb14..d4d6ffa10b53b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/PackageTypeGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/PackageTypeGroup.java @@ -55,8 +55,8 @@ enum PackageTypeGroup { }), ALL_PACKAGE_TYPES(name -> { return Stream.of( - APP_IMAGE.forForOptionName(name), - NATIVE_PACKAGE.forForOptionName(name) + APP_IMAGE.forOptionName(name), + NATIVE_PACKAGE.forOptionName(name) ).flatMap(Set::stream).collect(toSet()); }); @@ -64,7 +64,7 @@ enum PackageTypeGroup { this.conv = conv; } - Set forForOptionName(String name) { + Set forOptionName(String name) { return conv.apply(name); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index dd80c9184810e..f371e055b8dad 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -44,7 +44,7 @@ import static jdk.jpackage.internal.cli.PackageTypeGroup.NATIVE_PACKAGE; public enum StandardOption implements Option { - TYPE(build().name("type").shortName("t").valueConverter(new ValueConverter() { + TYPE(build("type").shortName("t").valueConverter(new ValueConverter() { @Override public PackageType convert(String value) { if ("app-image".equals(value)) { @@ -60,13 +60,13 @@ public Class valueType() { } })), - INPUT(build().name("input").shortName("i").ofDirectory(), APP_IMAGE), - DEST(build().name("dest").shortName("d").ofDirectory()), + INPUT(build("input").shortName("i").ofDirectory(), APP_IMAGE), + DEST(build("dest").shortName("d").ofDirectory()), DESCRIPTION("description"), VENDOR("vendor"), APPCLASS("main-class"), - NAME(build().name("input").shortName("i").ofString()), - VERBOSE(build().name("verbose").valueConverter(null)), + NAME(build("input").shortName("i").ofString()), + VERBOSE(build("verbose").noValue()), RESOURCE_DIR("resource-dir", OptionSpecBuilder::ofDirectory), ARGUMENTS("arguments", OptionSpecBuilder::ofStringArray), JLINK_OPTIONS("arguments", OptionSpecBuilder::ofStringArray), @@ -78,21 +78,19 @@ public Class valueType() { JAVA_OPTIONS("java-options", OptionSpecBuilder::ofStringArray), APP_CONTENT("app-content", OptionSpecBuilder::ofPathArray), FILE_ASSOCIATIONS("file-associations", OptionSpecBuilder::ofPath), - ADD_LAUNCHER(build().name("add-launcher").valueConverter(new ValueConverter() { + ADD_LAUNCHER(build("add-launcher").valueConverter(new ValueConverter() { @Override - public jdk.jpackage.internal.cli.AdditionalLauncher convert(String value) { + public AdditionalLauncher convert(String value) { var components = value.split("=", 2); if (components.length == 1) { - return new AdditionalLauncher(null, - StandardValueConverter.PATH_CONV.convert(components[0])); - } else { - return new AdditionalLauncher(components[0], - StandardValueConverter.PATH_CONV.convert(components[1])); + components = new String[] { null, components[0] }; } + return new AdditionalLauncher(components[0], + StandardValueConverter.PATH_CONV.convert(components[1])); } @Override - public Class valueType() { + public Class valueType() { return AdditionalLauncher.class; } })), @@ -101,10 +99,10 @@ public Class valueType() PREDEFINED_APP_IMAGE("app-image", OptionSpecBuilder::ofDirectory, NATIVE_PACKAGE), PREDEFINED_RUNTIME_IMAGE("runtime-image", OptionSpecBuilder::ofDirectory), MAIN_JAR("main-jar", OptionSpecBuilder::ofPath), - MODULE(build().name("module").shortName("m").ofString()), + MODULE(build("module").shortName("m").ofString()), ADD_MODULES("add-modules", OptionSpecBuilder::ofStringArray), - MODULE_PATH(build().name("module-path").shortName("p").ofDirectoryArray()), - LAUNCHER_AS_SERVICE(build().name("launcher-as-service").valueConverter(null)), + MODULE_PATH(build("module-path").shortName("p").ofDirectoryArray()), + LAUNCHER_AS_SERVICE(build("launcher-as-service").noValue()), // Linux-specific LINUX_RELEASE("linux-app-release", NATIVE_PACKAGE), LINUX_BUNDLE_NAME("linux-package-name", NATIVE_PACKAGE), @@ -112,12 +110,12 @@ public Class valueType() LINUX_CATEGORY("linux-app-category", NATIVE_PACKAGE), LINUX_RPM_LICENSE_TYPE("linux-rpm-license-type", NATIVE_PACKAGE), LINUX_PACKAGE_DEPENDENCIES("linux-package-deps", NATIVE_PACKAGE), - LINUX_SHORTCUT_HINT(build().name("linux-shortcut").valueConverter(null), NATIVE_PACKAGE), + LINUX_SHORTCUT_HINT(build("linux-shortcut").noValue(), NATIVE_PACKAGE), LINUX_MENU_GROUP("linux-package-deps", NATIVE_PACKAGE), // MacOS-specific - DMG_CONTENT(build().name("mac-dmg-content").ofPathArray()), - MAC_SIGN(build().name("mac-sign").shortName("s").valueConverter(null)), - MAC_APP_STORE(build().name("mac-app-store").shortName("s").valueConverter(null), NATIVE_PACKAGE), + DMG_CONTENT(build("mac-dmg-content").ofPathArray()), + MAC_SIGN(build("mac-sign").shortName("s").noValue()), + MAC_APP_STORE(build("mac-app-store").shortName("s").noValue(), NATIVE_PACKAGE), MAC_CATEGORY("mac-app-category"), MAC_BUNDLE_NAME("mac-package-name"), MAC_BUNDLE_IDENTIFIER("mac-package-identifier"), @@ -130,14 +128,14 @@ public Class valueType() // Windows-specific WIN_HELP_URL("win-help-url", OptionSpecBuilder::ofUrl, NATIVE_PACKAGE), WIN_UPDATE_URL("win-update-url", OptionSpecBuilder::ofUrl, NATIVE_PACKAGE), - WIN_MENU_HINT(build().name("win-menu").valueConverter(null), NATIVE_PACKAGE), + WIN_MENU_HINT(build("win-menu").noValue(), NATIVE_PACKAGE), WIN_MENU_GROUP("win-menu-group", NATIVE_PACKAGE), - WIN_SHORTCUT_HINT(build().name("win-shortcut").valueConverter(null), NATIVE_PACKAGE), + WIN_SHORTCUT_HINT(build("win-shortcut").noValue(), NATIVE_PACKAGE), WIN_SHORTCUT_PROMPT("win-shortcut-prompt", NATIVE_PACKAGE), - WIN_PER_USER_INSTALLATION(build().name("win-per-user-install").valueConverter(null), NATIVE_PACKAGE), - WIN_DIR_CHOOSER(build().name("win-dir-chooser").valueConverter(null), NATIVE_PACKAGE), + WIN_PER_USER_INSTALLATION(build("win-per-user-install").noValue(), NATIVE_PACKAGE), + WIN_DIR_CHOOSER(build("win-dir-chooser").noValue(), NATIVE_PACKAGE), WIN_UPGRADE_UUID("win-upgrade-uuid", NATIVE_PACKAGE), - WIN_CONSOLE_HINT(build().name("win-console").valueConverter(null)), + WIN_CONSOLE_HINT(build("win-console").noValue()), ; StandardOption(OptionSpecBuilder builder) { @@ -153,7 +151,7 @@ public Class valueType() } StandardOption(String name, PackageTypeGroup packageTypeGroup) { - this(name, OptionSpecBuilder::ofString, ALL_PACKAGE_TYPES); + this(name, OptionSpecBuilder::ofString, packageTypeGroup); } StandardOption(String name, UnaryOperator conv) { @@ -162,7 +160,7 @@ public Class valueType() StandardOption(String name, UnaryOperator conv, PackageTypeGroup packageTypeGroup) { - this(conv.apply(build()).name(name)); + this(conv.apply(build(name)), packageTypeGroup); } @Override @@ -177,8 +175,8 @@ public static List filterOptions(PackageType... packageTypes) { }).toList(); } - private static OptionSpecBuilder build() { - return new OptionSpecBuilder(); + private static OptionSpecBuilder build(String name) { + return new OptionSpecBuilder().name(name); } private static OptionSpec createOptionSpec(OptionSpecBuilder builder, @@ -200,7 +198,7 @@ private static OptionSpec createOptionSpec(OptionSpecBuilder builder, } else if (name.startsWith("mac-pkg")) { builder.supportedPackageTypes(MAC_PKG); } else { - builder.supportedPackageTypes(packageTypeGroup.forForOptionName(name)); + builder.supportedPackageTypes(packageTypeGroup.forOptionName(name)); } } return builder.create(); From 189250d93476872f181c6b89fa8e7c2a1680c681 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 13:08:57 -0500 Subject: [PATCH 0112/1101] Define interface to parse and write app images and packages --- .../internal/cli/CliApplicationBuilder.java | 35 +++++++++++++++++++ .../internal/cli/CliPackageBuilder.java | 35 +++++++++++++++++++ .../internal/model/ApplicationWriter.java | 34 ++++++++++++++++++ .../internal/model/PackageWriter.java | 34 ++++++++++++++++++ 4 files changed, 138 insertions(+) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliApplicationBuilder.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliPackageBuilder.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliApplicationBuilder.java new file mode 100644 index 0000000000000..07a183f0427ae --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliApplicationBuilder.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.cli; + +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationWriter; +import jdk.jpackage.internal.model.ConfigException; + + +public interface CliApplicationBuilder extends ApplicationWriter { + Application createAppFromCmdline(ParsedOptions options) throws ConfigException; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliPackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliPackageBuilder.java new file mode 100644 index 0000000000000..35bab0803580d --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliPackageBuilder.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.cli; + +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackageWriter; + + +public interface CliPackageBuilder extends PackageWriter { + Package createPackageFromCmdline(ParsedOptions options) throws ConfigException; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java new file mode 100644 index 0000000000000..dbc55b7b914aa --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.model; + +import java.io.IOException; +import java.nio.file.Path; + + +public interface ApplicationWriter { + void write(Application app, Path dst) throws PackagerException, IOException; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java new file mode 100644 index 0000000000000..a0ed855ae21ce --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.model; + +import java.io.IOException; +import java.nio.file.Path; + + +public interface PackageWriter { + void write(Package pkg, Path dst) throws PackagerException, IOException; +} From 3c66c983d846a68caed9be145f1017e136566f8a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 15:13:07 -0500 Subject: [PATCH 0113/1101] Add BuildEnvBuilder, fix resource dir configuration in BuildEnv.createResource() --- .../jdk/jpackage/internal/BuildEnv.java | 41 ++++++---- .../jpackage/internal/BuildEnvBuilder.java | 82 +++++++++++++++++++ .../jpackage/internal/BuildEnvFromParams.java | 26 +++--- 3 files changed, 121 insertions(+), 28 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java index d4b58fa2c8f93..bba0813ca33ee 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java @@ -25,9 +25,8 @@ package jdk.jpackage.internal; import java.nio.file.Path; -import java.util.Optional; -public interface BuildEnv { +interface BuildEnv { Path buildRoot(); @@ -49,7 +48,7 @@ default Path configDir() { OverridableResource createResource(String defaultName); - public static BuildEnv withAppImageDir(BuildEnv env, Path appImageDir) { + static BuildEnv withAppImageDir(BuildEnv env, Path appImageDir) { return new Proxy(env) { @Override public Path appImageDir() { @@ -58,15 +57,29 @@ public Path appImageDir() { }; } - public static record Impl(Path buildRoot, Path resourceDir, Class resourceLocator) implements BuildEnv { - @Override - public OverridableResource createResource(String defaultName) { - if (defaultName != null) { - return new OverridableResource(defaultName, resourceLocator); - } else { - return new OverridableResource(); + static BuildEnv create(Path buildRoot, Path resourceDir, Class resourceLocator) { + return new BuildEnv() { + @Override + public Path buildRoot() { + return buildRoot; } - } + + @Override + public Path resourceDir() { + return resourceDir; + } + + @Override + public OverridableResource createResource(String defaultName) { + final OverridableResource resource; + if (defaultName != null) { + resource = new OverridableResource(defaultName, resourceLocator); + } else { + resource = new OverridableResource(); + } + return resource.setResourceDir(resourceDir); + } + }; } static class Proxy implements BuildEnv { @@ -76,17 +89,17 @@ static class Proxy implements BuildEnv { } @Override - public Path buildRoot() { + final public Path buildRoot() { return target.buildRoot(); } @Override - public Path resourceDir() { + final public Path resourceDir() { return target.resourceDir(); } @Override - public OverridableResource createResource(String defaultName) { + final public OverridableResource createResource(String defaultName) { return target.createResource(defaultName); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java new file mode 100644 index 0000000000000..daaa97d756444 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.io.IOException; +import java.nio.file.Files; +import jdk.jpackage.internal.model.ConfigException; +import java.nio.file.Path; +import java.util.Objects; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.resources.ResourceLocator; + +final class BuildEnvBuilder { + + BuildEnvBuilder(Path root) { + Objects.requireNonNull(root); + this.root = root; + } + + BuildEnv create() throws ConfigException { + Objects.requireNonNull(appImageDir); + + var exceptionBuilder = ConfigException.build().message("ERR_BuildRootInvalid", root); + if (!Files.exists(root)) { + } else if (!Files.isDirectory(root)) { + throw exceptionBuilder.create(); + } else { + try (var rootDirContents = Files.list(root)) { + if (rootDirContents.findAny().isPresent()) { + throw exceptionBuilder.create(); + } + } catch (IOException ioe) { + throw exceptionBuilder.cause(ioe).create(); + } + } + + return BuildEnv.withAppImageDir(BuildEnv.create(root, resourceDir, + ResourceLocator.class), appImageDir); + } + + BuildEnvBuilder resourceDir(Path v) { + resourceDir = v; + return this; + } + + BuildEnvBuilder appImageDir(Path v) { + appImageDir = v; + return this; + } + + BuildEnvBuilder appImageDirFor(Application app) { + appImageDir = root.resolve("image").resolve(app.appImageDirName()); + return this; + } + + private Path appImageDir; + private Path resourceDir; + + private final Path root; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java index 89f6787ab82fd..2c782ea9eb0eb 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java @@ -25,31 +25,29 @@ package jdk.jpackage.internal; import jdk.jpackage.internal.model.ConfigException; -import java.nio.file.Path; import java.util.Map; -import jdk.jpackage.internal.BuildEnv.Impl; -import static jdk.jpackage.internal.BuildEnv.withAppImageDir; -import jdk.jpackage.internal.resources.ResourceLocator; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; +import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; +import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; final class BuildEnvFromParams { static BuildEnv create(Map params) throws ConfigException { - var root = StandardBundlerParam.TEMP_ROOT.fetchFrom(params); - var resourceDir = StandardBundlerParam.RESOURCE_DIR.fetchFrom(params); - var defaultEnv = new Impl(root, resourceDir, ResourceLocator.class); + var builder = new BuildEnvBuilder(TEMP_ROOT.fetchFrom(params)) + .resourceDir(RESOURCE_DIR.fetchFrom(params)); - Path appImageDir; - if (StandardBundlerParam.isRuntimeInstaller(params)) { - appImageDir = StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); + var app = FromParams.APPLICATION.fetchFrom(params); + + if (app.isRuntime()) { + builder.appImageDir(PREDEFINED_RUNTIME_IMAGE.fetchFrom(params)); } else if (StandardBundlerParam.hasPredefinedAppImage(params)) { - appImageDir = StandardBundlerParam.getPredefinedAppImage(params); + builder.appImageDir(StandardBundlerParam.getPredefinedAppImage(params)); } else { - Path dir = FromParams.APPLICATION.fetchFrom(params).appImageDirName(); - appImageDir = defaultEnv.buildRoot().resolve("image").resolve(dir); + builder.appImageDirFor(app); } - return withAppImageDir(defaultEnv, appImageDir); + return builder.create(); } static final BundlerParamInfo BUILD_ENV = BundlerParamInfo.createBundlerParam( From a74a41485f0bd5252ae67314789309f8ca39446d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 15:21:25 -0500 Subject: [PATCH 0114/1101] Remove wrong null ptr assert from FileAssociation.Stub ctor --- .../classes/jdk/jpackage/internal/model/FileAssociation.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java index 4f2932ac298ef..c0f11a40340af 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; -import java.util.Objects; public interface FileAssociation { @@ -38,10 +37,6 @@ public interface FileAssociation { String extension(); record Stub(String description, Path icon, String mimeType, String extension) implements FileAssociation { - - public Stub { - Objects.requireNonNull(description); - } } class Proxy extends ProxyBase implements FileAssociation { From 88186134225323952fb0cb3066842198bf9a80ce Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 15:22:21 -0500 Subject: [PATCH 0115/1101] WixAppImageFragmentBuilder: don't write empty fa description in .wxs output --- .../jdk/jpackage/internal/WixAppImageFragmentBuilder.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index e482d761e2815..88985359a4a16 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -523,7 +523,10 @@ private String addFaComponent(XMLStreamWriter xml, Path path = INSTALLDIR.resolve(String.format("%s_%s", fa.extension(), launcherExe)); return addComponent(xml, path, Component.ProgId, unused -> { - xml.writeAttribute("Description", fa.description()); + final String description = fa.description(); + if (description != null && !description.isEmpty()) { + xml.writeAttribute("Description", description); + } if (fa.icon() != null) { xml.writeAttribute("Icon", Id.File.of(getInstalledFaIcoPath(fa))); From 30ff3346eff70554e3381faf7442ed1aaa92f196 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 15:47:57 -0500 Subject: [PATCH 0116/1101] Don't create Application twice when packaging a package --- .../linux/classes/jdk/jpackage/internal/LinuxFromParams.java | 2 +- .../windows/classes/jdk/jpackage/internal/WinFromParams.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java index e207094830686..04a199dfefe51 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java @@ -63,7 +63,7 @@ private static LinuxApplication createLinuxApplication( private static LinuxPackageBuilder createLinuxPackageBuilder( Map params, StandardPackageType type) throws ConfigException, IOException { - var app = createLinuxApplication(params); + var app = APPLICATION.fetchFrom(params); var pkgBuilder = createPackageBuilder(params, app, type) .name(LINUX_PACKAGE_NAME.fetchFrom(params)); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java index a75342fc7beaf..0087b1ee647e0 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java @@ -78,7 +78,7 @@ private static WinApplication createWinApplication( private static WinMsiPackage createWinMsiPackage(Map params) throws ConfigException, IOException { - var app = createWinApplication(params); + var app = APPLICATION.fetchFrom(params); var pkgBuilder = createPackageBuilder(params, app, WIN_MSI); From 56883f29cf21039af83291a9b4c071dc79261ccc Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 16:24:51 -0500 Subject: [PATCH 0117/1101] Add FileAssociation.hasIcon(), FileAssociation.hasNonEmptyDescription(). Bugfix in WixAppImageFragmentBuilder to pass FileAssociationsTest.test(...) tests --- .../jpackage/internal/DesktopIntegration.java | 22 +++++++++---------- .../internal/model/FileAssociation.java | 11 ++++++++++ .../internal/WixAppImageFragmentBuilder.java | 11 +++++----- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 68c9fc774af64..10d0201559a0e 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -349,10 +349,9 @@ private void appendFileAssociation(XMLStreamWriter xml, xml.writeStartElement("mime-type"); xml.writeAttribute("type", fa.mimeType()); - final String description = fa.description(); - if (description != null && !description.isEmpty()) { + if (fa.hasNonEmptyDescription()) { xml.writeStartElement("comment"); - xml.writeCharacters(description); + xml.writeCharacters(fa.description()); xml.writeEndElement(); } @@ -381,7 +380,7 @@ private void addFileAssociationIconFiles(ShellCommands shellCommands) throws IOException { Set processedMimeTypes = new HashSet<>(); for (var fa : associations) { - if (fa.icon() == null) { + if (!fa.hasIcon()) { // No icon. continue; } @@ -418,9 +417,9 @@ private List getMimeTypeNamesFromFileAssociations() { return associations.stream().map(FileAssociation::mimeType).toList(); } - private static int getSquareSizeOfImage(File f) { + private static int getSquareSizeOfImage(Path path) { try { - BufferedImage bi = ImageIO.read(f); + BufferedImage bi = ImageIO.read(path.toFile()); return Math.max(bi.getWidth(), bi.getHeight()); } catch (IOException e) { Log.verbose(e); @@ -466,12 +465,11 @@ private LinuxFileAssociation(FileAssociation fa, int iconSize) { } private static int getIconSize(FileAssociation fa) { - var icon = fa.icon(); - if (icon != null && Files.isReadable(icon)) { - return getSquareSizeOfImage(icon.toFile()); - } else { - return -1; - } + return Optional.of(fa) + .filter(FileAssociation::hasIcon) + .map(FileAssociation::icon) + .map(DesktopIntegration::getSquareSizeOfImage) + .orElse(-1); } private final int iconSize; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java index c0f11a40340af..def53071d8bef 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java @@ -25,12 +25,23 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Predicate; public interface FileAssociation { String description(); Path icon(); + + default boolean hasIcon() { + return Objects.nonNull(icon()); + } + + default boolean hasNonEmptyDescription() { + return Optional.ofNullable(description()).filter(Predicate.not(String::isEmpty)).isPresent(); + } String mimeType(); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index 88985359a4a16..29955428b5538 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -181,10 +181,10 @@ private void initFileAssociations() { Launcher::executableNameWithSuffix, WinLauncher::fileAssociations)); - associations.values().stream().flatMap(List::stream).filter(fa -> fa.icon() != null).forEach(fa -> { + associations.values().stream().flatMap(List::stream).filter(FileAssociation::hasIcon).forEach(fa -> { // Need to add fa icon in the image. Object key = new Object(); - appImagePathGroup.setPath(key, fa.icon()); + appImagePathGroup.setPath(key, fa.icon().toAbsolutePath().normalize()); installedAppImagePathGroup.setPath(key, getInstalledFaIcoPath(fa)); }); } @@ -523,12 +523,11 @@ private String addFaComponent(XMLStreamWriter xml, Path path = INSTALLDIR.resolve(String.format("%s_%s", fa.extension(), launcherExe)); return addComponent(xml, path, Component.ProgId, unused -> { - final String description = fa.description(); - if (description != null && !description.isEmpty()) { - xml.writeAttribute("Description", description); + if (fa.hasNonEmptyDescription()) { + xml.writeAttribute("Description", fa.description()); } - if (fa.icon() != null) { + if (fa.hasIcon()) { xml.writeAttribute("Icon", Id.File.of(getInstalledFaIcoPath(fa))); xml.writeAttribute("IconIndex", "0"); } From fd38fed4e3869ce9a0fd8e231189ae188d7f8101 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 21:05:04 -0500 Subject: [PATCH 0118/1101] Add ConfigException.rethrowConfigException(), and ConfigException.Builder.noformat() --- .../internal/model/ConfigException.java | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java index c6406f914489c..bdfa122d4f095 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java @@ -34,7 +34,7 @@ public ConfigException(String msg, String advice) { this.advice = advice; } - public ConfigException(String msg, String advice, Exception cause) { + public ConfigException(String msg, String advice, Throwable cause) { super(msg, cause); this.advice = advice; } @@ -58,27 +58,55 @@ public ConfigException create() { return new ConfigException(msg, advice, cause); } + public Builder format(boolean v) { + noFormat = !v; + return this; + } + + public Builder noformat() { + return format(false); + } + public Builder message(String msgId, Object ... args) { - msg = I18N.format(msgId, args); + msg = formatString(msgId, args); return this; } public Builder advice(String adviceId, Object ... args) { - advice = I18N.format(adviceId, args); + advice = formatString(adviceId, args); return this; } - public Builder cause(Exception v) { + public Builder cause(Throwable v) { cause = v; return this; } - + public Builder causeAndMessage(Exception ex) { return message(ex.getLocalizedMessage()).cause(ex); } + private String formatString(String keyId, Object ... args) { + if (!noFormat) { + return I18N.format(keyId, args); + } if (args.length == 0) { + return keyId; + } else { + throw new IllegalArgumentException("Formatting arguments not allowed in no format mode"); + } + } + + private boolean noFormat; private String msg; private String advice; - private Exception cause; + private Throwable cause; + } + + public static RuntimeException rethrowConfigException(RuntimeException ex) throws ConfigException { + if (ex.getCause() instanceof ConfigException configEx) { + throw configEx; + } else { + throw ex; + } } } From fbec2fb684de66fd06fad5f94eedcee15a61be44 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 21:06:26 -0500 Subject: [PATCH 0119/1101] Use ConfigException.rethrowConfigException() --- .../classes/jdk/jpackage/internal/WinMsiBundler.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index ca3f9921ad6d3..3fcc41698938b 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -59,6 +59,7 @@ import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +import static jdk.jpackage.internal.model.ConfigException.rethrowConfigException; /** * WinMsiBundler @@ -197,11 +198,7 @@ public boolean validate(Map params) return true; } catch (RuntimeException re) { - if (re.getCause() instanceof ConfigException) { - throw (ConfigException) re.getCause(); - } else { - throw new ConfigException(re); - } + throw rethrowConfigException(re); } } From 234b01d939b01bbcd5d69e41e7966cacb5a1e893 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 21:09:13 -0500 Subject: [PATCH 0120/1101] FileAssociationsTest test is a pass --- .../internal/FileAssociationGroup.java | 118 ++++++++++++++++++ .../jpackage/internal/LauncherBuilder.java | 98 ++++++++++----- .../jpackage/internal/LauncherFromParams.java | 49 ++------ 3 files changed, 195 insertions(+), 70 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java new file mode 100644 index 0000000000000..3de8c27fb3063 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import static java.util.stream.Collectors.toSet; +import java.util.stream.Stream; +import jdk.jpackage.internal.model.FileAssociation; + +final record FileAssociationGroup(List items) { + boolean isEmpty() { + return items.isEmpty(); + } + + static Stream flatMap(Stream groups) { + return groups.map(FileAssociationGroup::items).flatMap(List::stream); + } + + static UnaryOperator map(UnaryOperator mapper) { + return group -> { + return new FileAssociationGroup(group.items.stream().map(mapper).filter(Objects::nonNull).toList()); + }; + } + + static UnaryOperator filter(Predicate filter) { + return group -> { + return new FileAssociationGroup(group.items.stream().filter(filter).toList()); + }; + } + + static Builder build() { + return new Builder(); + } + + static final class Builder { + + FileAssociationGroup create() { + Function> forExtension = ext -> { + if (mimeTypes.isEmpty()) { + return Stream.of((FileAssociation)new FileAssociation.Stub(description, icon, null, ext)); + } else { + return mimeTypes.stream().map(faMimeType -> { + return (FileAssociation)new FileAssociation.Stub(description, icon, faMimeType, ext); + }); + } + }; + + Stream faStream; + if (extensions.isEmpty()) { + faStream = forExtension.apply(null); + } else { + faStream = extensions.stream().map(forExtension).flatMap(x -> x); + } + + return new FileAssociationGroup(faStream.toList()); + } + + Builder icon(Path v) { + icon = v; + return this; + } + + Builder description(String v) { + description = v; + return this; + } + + Builder mimeTypes(Collection v) { + mimeTypes = conv(v); + return this; + } + + Builder extensions(Collection v) { + extensions = conv(v); + return this; + } + + private static Set conv(Collection col) { + return Optional.ofNullable(col).map(Collection::stream).orElseGet( + Stream::of).collect(toSet()); + } + + private Path icon; + private String description; + private Set mimeTypes; + private Set extensions; + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java index 2935ad8829503..15129e544d1de 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java @@ -26,11 +26,11 @@ import java.nio.file.Path; import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.Optional; -import java.util.function.Function; -import static java.util.stream.Collectors.groupingBy; -import static java.util.stream.Collectors.mapping; -import static java.util.stream.Collectors.toList; +import java.util.function.Predicate; +import java.util.stream.IntStream; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import static jdk.internal.util.OperatingSystem.LINUX; @@ -41,7 +41,11 @@ import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.Launcher.Stub; import jdk.jpackage.internal.model.LauncherStartupInfo; +import jdk.jpackage.internal.util.function.ExceptionWrapper; +import static jdk.jpackage.internal.util.function.ExceptionWrapper.rethrowUnchecked; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; +import static jdk.jpackage.internal.model.ConfigException.rethrowConfigException; final class LauncherBuilder { @@ -61,13 +65,13 @@ LauncherBuilder startupInfo(LauncherStartupInfo v) { return this; } - LauncherBuilder faSources(List v) { + LauncherBuilder faSources(List v) { faSources = v; return this; } - LauncherBuilder faMapper(Function> v) { - faMapper = v; + LauncherBuilder faPrediacate(Predicate v) { + faPrediacate = v; return this; } @@ -86,18 +90,10 @@ LauncherBuilder icon(Path v) { return this; } - static Optional mapFileAssociation(FileAssociation src) { - var mimeType = src.mimeType(); - if (mimeType == null) { - return Optional.empty(); - } - - var extension = src.extension(); - if (extension == null) { - return Optional.empty(); - } + static boolean isFileAssociationValid(FileAssociation src) { + toConsumer(LauncherBuilder::verifyFileAssociation).accept(src); - return Optional.of(new FileAssociation.Stub(src.description(), src.icon(), mimeType, extension)); + return Optional.ofNullable(src.extension()).isPresent(); } static void validateIcon(Path icon) throws ConfigException { @@ -125,28 +121,64 @@ static void validateIcon(Path icon) throws ConfigException { } private Stream createFileAssociations( - Stream sources) throws ConfigException { - var fas = sources.map(faMapper).filter(Optional::isPresent).map(Optional::get).toList(); - - // Check extension to mime type relationship is 1:1 - var mimeTypeToExtension = fas.stream().collect(groupingBy( - FileAssociation::extension, mapping(FileAssociation::mimeType, - toList()))); - for (var entry : mimeTypeToExtension.entrySet()) { - if (entry.getValue().size() != 1) { - var extension = entry.getKey(); - throw ConfigException.build().message( - "error.fa-extension-with-multiple-mime-types", extension).create(); + Stream sources) throws ConfigException { + + var sourcesAsArray = sources.toArray(FileAssociationGroup[]::new); + + var stream = IntStream.range(0, sourcesAsArray.length).mapToObj(idx -> { + return Map.entry(idx + 1, sourcesAsArray[idx]); + }).map(entry -> { + try { + var faGroup = FileAssociationGroup.filter(faPrediacate).apply(entry.getValue()); + if (faGroup.isEmpty()) { + return null; + } else { + return Map.entry(entry.getKey(), faGroup); + } + } catch (ExceptionWrapper ex) { + if (ex.getCause() instanceof ConfigException cfgException) { + throw rethrowUnchecked(ConfigException.build() + .cause(cfgException.getCause()) + .message(cfgException.getMessage(), entry.getKey()) + .advice(cfgException.getAdvice(), entry.getKey()) + .create()); + } else { + throw ex; + } + } + }).filter(Objects::nonNull).peek(entry -> { + var faGroup = entry.getValue(); + if (faGroup.items().size() != faGroup.items().stream().map(FileAssociation::extension).distinct().count()) { + throw rethrowUnchecked(ConfigException.build() + .message("error.too-many-content-types-for-file-association", entry.getKey()) + .advice("error.too-many-content-types-for-file-association.advice", entry.getKey()) + .create()); } + }).map(entry -> { + return entry.getValue().items().stream(); + }).flatMap(x -> x); + + try { + return stream.toList().stream(); + } catch (RuntimeException ex) { + throw rethrowConfigException(ex); } + } - return fas.stream(); + static void verifyFileAssociation(FileAssociation src) throws ConfigException { + if (Optional.ofNullable(src.mimeType()).isEmpty()) { + throw ConfigException.build() + .noformat() + .message("error.no-content-types-for-file-association") + .advice("error.no-content-types-for-file-association.advice") + .create(); + } } private String name; private LauncherStartupInfo startupInfo; - private List faSources; - private Function> faMapper = LauncherBuilder::mapFileAssociation; + private List faSources; + private Predicate faPrediacate = LauncherBuilder::isFileAssociationValid; private boolean isService; private String description; private Path icon; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java index 271e70c9151e7..0b3e8df571eac 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java @@ -24,13 +24,12 @@ */ package jdk.jpackage.internal; -import java.nio.file.Path; import java.util.List; import jdk.jpackage.internal.model.Launcher; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.function.Function; +import java.util.function.Predicate; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.ARGUMENTS; import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; @@ -46,14 +45,14 @@ import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.FileAssociation; -record LauncherFromParams(Function> faMapper) { +record LauncherFromParams(Predicate faPredicate) { LauncherFromParams { - Objects.requireNonNull(faMapper); + Objects.requireNonNull(faPredicate); } LauncherFromParams() { - this(LauncherBuilder::mapFileAssociation); + this(LauncherBuilder::isFileAssociationValid); } Launcher create(Map params) throws ConfigException { @@ -62,7 +61,7 @@ Launcher create(Map params) throws ConfigException { .icon(ICON.fetchFrom(params)) .isService(LAUNCHER_AS_SERVICE.fetchFrom(params)) .name(APP_NAME.fetchFrom(params)) - .faMapper(faMapper); + .faPrediacate(faPredicate); if (PREDEFINED_APP_IMAGE.fetchFrom(params) == null) { builder.startupInfo(new LauncherStartupInfoBuilder() @@ -74,37 +73,13 @@ Launcher create(Map params) throws ConfigException { var faSources = Optional.ofNullable( FILE_ASSOCIATIONS.fetchFrom(params)).orElseGet(List::of).stream().map(faParams -> { - var faDesc = FA_DESCRIPTION.fetchFrom(faParams); - var faIcon = FA_ICON.fetchFrom(faParams); - var faExtensions = FA_EXTENSIONS.fetchFrom(faParams); - var faMimeTypes = FA_CONTENT_TYPE.fetchFrom(faParams); - - return faExtensions.stream().map(faExtension -> { - return faMimeTypes.stream().map(faMimeType -> { - return (FileAssociation)new FileAssociation() { - @Override - public String description() { - return faDesc; - } - - @Override - public Path icon() { - return faIcon; - } - - @Override - public String mimeType() { - return faMimeType; - } - - @Override - public String extension() { - return faExtension; - } - }; - }); - }).flatMap(x -> x); - }).flatMap(x -> x).toList(); + return FileAssociationGroup.build() + .description(FA_DESCRIPTION.fetchFrom(faParams)) + .icon(FA_ICON.fetchFrom(faParams)) + .extensions(FA_EXTENSIONS.fetchFrom(faParams)) + .mimeTypes(FA_CONTENT_TYPE.fetchFrom(faParams)) + .create(); + }).toList(); return builder.faSources(faSources).create(); } From 004f682305c2b35e9f0f3c7572e6f9c40719fb42 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 22:23:16 -0500 Subject: [PATCH 0121/1101] Support @command-file --- .../helpers/jdk/jpackage/test/Main.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java index 37aca48ac1703..4c884c7fe08cf 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java @@ -23,11 +23,17 @@ package jdk.jpackage.test; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Deque; import java.util.List; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; +import static java.util.stream.Collectors.toCollection; +import java.util.stream.Stream; import static jdk.jpackage.test.TestBuilder.CMDLINE_ARG_PREFIX; @@ -36,7 +42,9 @@ public static void main(String args[]) throws Throwable { boolean listTests = false; List tests = new ArrayList<>(); try (TestBuilder testBuilder = new TestBuilder(tests::add)) { - for (var arg : args) { + Deque argsAsList = new ArrayDeque<>(List.of(args)); + while (!argsAsList.isEmpty()) { + var arg = argsAsList.pop(); TestBuilder.trace(String.format("Parsing [%s]...", arg)); if ((CMDLINE_ARG_PREFIX + "list").equals(arg)) { @@ -44,6 +52,16 @@ public static void main(String args[]) throws Throwable { continue; } + if (arg.startsWith("@")) { + // Command file + var newArgs = Files.readAllLines(Path.of(arg.substring(1))).stream().map(line -> { + return Stream.of(line.split("\\s+")); + }).flatMap(x -> x).collect(toCollection(ArrayDeque::new)); + newArgs.addAll(argsAsList); + argsAsList = newArgs; + continue; + } + boolean success = false; try { testBuilder.processCmdLineArg(arg); From 717b522b57e72c1fac96c2ad2f7a3649247aad8e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 22:25:26 -0500 Subject: [PATCH 0122/1101] Fix ErrorTest failure when external runtime is specified in testing --- test/jdk/tools/jpackage/share/jdk/jpackage/tests/ErrorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ErrorTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ErrorTest.java index 8fcd3c8a73057..349ef5b7b5527 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/ErrorTest.java @@ -116,7 +116,7 @@ public ErrorTest(String javaAppDesc, String[] jpackageArgs, this.expectedError = expectedError; cmd = JPackageCommand.helloAppImage(javaAppDesc) - .saveConsoleOutput(true).dumpOutput(true); + .saveConsoleOutput(true).dumpOutput(true).ignoreDefaultRuntime(true); if (jpackageArgs != null) { cmd.addArguments(jpackageArgs); } if (removeArgs != null) { From d005a16a427faa30df9bd0b7d9b75dd58e6ca0ff Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 22:47:28 -0500 Subject: [PATCH 0123/1101] Remove unnecessary "public" modifier from OverridableResource class members --- .../internal/OverridableResource.java | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java index 7740c0eecf547..c5f37d8ec356f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java @@ -70,13 +70,13 @@ */ final class OverridableResource { - public OverridableResource() { + OverridableResource() { defaultName = ""; defaultResourceSupplier = null; setSourceOrder(Source.External, Source.ResourceDir); } - public OverridableResource(String defaultName, + OverridableResource(String defaultName, Supplier defaultResourceSupplier) { Objects.requireNonNull(defaultName); Objects.requireNonNull(defaultResourceSupplier); @@ -85,29 +85,29 @@ public OverridableResource(String defaultName, setSourceOrder(Source.values()); } - public OverridableResource(String defaultName, Class resourceLocator) { + OverridableResource(String defaultName, Class resourceLocator) { this(defaultName, () -> { return resourceLocator.getResourceAsStream(defaultName); }); } - public Path getResourceDir() { + Path getResourceDir() { return resourceDir; } - public String getDefaultName() { + String getDefaultName() { return defaultName; } - public Path getPublicName() { + Path getPublicName() { return publicName; } - public Path getExternalPath() { + Path getExternalPath() { return externalPath; } - public OverridableResource setSubstitutionData(Map v) { + OverridableResource setSubstitutionData(Map v) { if (v != null) { // Disconnect `v` substitutionData = new HashMap<>(v); @@ -117,30 +117,30 @@ public OverridableResource setSubstitutionData(Map v) { return this; } - public OverridableResource addSubstitutionDataEntry(String key, String value) { + OverridableResource addSubstitutionDataEntry(String key, String value) { var entry = Map.of(key, value); Optional.ofNullable(substitutionData).ifPresentOrElse(v -> v.putAll( entry), () -> setSubstitutionData(entry)); return this; } - public OverridableResource setCategory(String v) { + OverridableResource setCategory(String v) { category = v; return this; } - public OverridableResource setResourceDir(Path v) { + OverridableResource setResourceDir(Path v) { resourceDir = v; return this; } - public OverridableResource setResourceDir(File v) { + OverridableResource setResourceDir(File v) { return setResourceDir(toPath(v)); } - public enum Source { External, ResourceDir, DefaultResource }; + enum Source { External, ResourceDir, DefaultResource }; - public OverridableResource setSourceOrder(Source... v) { + OverridableResource setSourceOrder(Source... v) { sources = Stream.of(v) .map(source -> Map.entry(source, getHandler(source))) .toList(); @@ -152,12 +152,12 @@ public OverridableResource setSourceOrder(Source... v) { * * @return this */ - public OverridableResource setPublicName(Path v) { + OverridableResource setPublicName(Path v) { publicName = v; return this; } - public OverridableResource setPublicName(String v) { + OverridableResource setPublicName(String v) { return setPublicName(Path.of(v)); } @@ -166,25 +166,25 @@ public OverridableResource setPublicName(String v) { * * @return this */ - public OverridableResource setLogPublicName(Path v) { + OverridableResource setLogPublicName(Path v) { logPublicName = v; return this; } - public OverridableResource setLogPublicName(String v) { + OverridableResource setLogPublicName(String v) { return setLogPublicName(Path.of(v)); } - public OverridableResource setExternal(Path v) { + OverridableResource setExternal(Path v) { externalPath = v; return this; } - public OverridableResource setExternal(File v) { + OverridableResource setExternal(File v) { return setExternal(toPath(v)); } - public Source saveToStream(OutputStream dest) throws IOException { + Source saveToStream(OutputStream dest) throws IOException { if (dest == null) { return sendToConsumer(null); } @@ -201,11 +201,11 @@ public void consume(InputStream in) throws IOException { }); } - public Source saveInFolder(Path folderPath) throws IOException { + Source saveInFolder(Path folderPath) throws IOException { return saveToFile(folderPath.resolve(getPublicName())); } - public Source saveToFile(Path dest) throws IOException { + Source saveToFile(Path dest) throws IOException { if (dest == null) { return sendToConsumer(null); } @@ -223,7 +223,7 @@ public void consume(InputStream in) throws IOException { }); } - public Source saveToFile(File dest) throws IOException { + Source saveToFile(File dest) throws IOException { return saveToFile(toPath(dest)); } @@ -393,11 +393,11 @@ private SourceHandler getHandler(Source sourceType) { @FunctionalInterface private static interface SourceHandler { - public boolean apply(ResourceConsumer dest) throws IOException; + boolean apply(ResourceConsumer dest) throws IOException; } private static interface ResourceConsumer { - public Path publicName(); - public void consume(InputStream in) throws IOException; + Path publicName(); + void consume(InputStream in) throws IOException; } } From 0e0f1c057f7cb025261e1d2883a26a25dce029b5 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 3 Nov 2024 23:03:39 -0500 Subject: [PATCH 0124/1101] Add shortcuts to ConfigException.Builder --- .../jdk/jpackage/internal/AppImageFile2.java | 8 ++------ .../jpackage/internal/ApplicationBuilder.java | 2 +- .../jdk/jpackage/internal/BuildEnvBuilder.java | 2 +- .../jdk/jpackage/internal/LauncherBuilder.java | 6 +++--- .../jdk/jpackage/internal/PackageBuilder.java | 3 +-- .../internal/model/ConfigException.java | 18 +++++++++++++++--- .../internal/WinMsiPackageBuilder.java | 3 +-- 7 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index 7725452aac176..f5bb82bd3534a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -248,14 +248,10 @@ public Map extraAppImageFileData() { // Exception reading input XML (probably malformed XML) throw new IOException(ex); } catch (NoSuchFileException ex) { - throw ConfigException.build() - .message("error.foreign-app-image", FILENAME) - .create(); + throw ConfigException.build("error.foreign-app-image", FILENAME).create(); } catch (InavlidAppImageFileException ex) { // Invalid input XML - throw ConfigException.build() - .message("error.invalid-app-image-file", FILENAME) - .create(); + throw ConfigException.build("error.invalid-app-image-file", FILENAME).create(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index ff81a187abd51..b4dafb39c1882 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -50,7 +50,7 @@ Application create() throws ConfigException { final var launcherCount = launchersAsList.size(); if (launcherCount != launchersAsList.stream().map(Launcher::name).distinct().count()) { - throw ConfigException.build().message("ERR_NoUniqueName").create(); + throw ConfigException.build("ERR_NoUniqueName").create(); } final String effectiveName; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java index daaa97d756444..34e8185ed0291 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java @@ -42,7 +42,7 @@ final class BuildEnvBuilder { BuildEnv create() throws ConfigException { Objects.requireNonNull(appImageDir); - var exceptionBuilder = ConfigException.build().message("ERR_BuildRootInvalid", root); + var exceptionBuilder = ConfigException.build("ERR_BuildRootInvalid", root); if (!Files.exists(root)) { } else if (!Files.isDirectory(root)) { throw exceptionBuilder.create(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java index 15129e544d1de..0fd28b4c0fa77 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java @@ -104,17 +104,17 @@ static void validateIcon(Path icon) throws ConfigException { switch (OperatingSystem.current()) { case WINDOWS -> { if (!icon.getFileName().toString().toLowerCase().endsWith(".ico")) { - throw ConfigException.build().message("message.icon-not-ico", icon).create(); + throw ConfigException.build("message.icon-not-ico", icon).create(); } } case LINUX -> { if (!icon.getFileName().toString().endsWith(".png")) { - throw ConfigException.build().message("message.icon-not-png", icon).create(); + throw ConfigException.build("message.icon-not-png", icon).create(); } } case MACOS -> { if (!icon.getFileName().toString().endsWith(".icns")) { - throw ConfigException.build().message("message.icon-not-icns", icon).create(); + throw ConfigException.build("message.icon-not-icns", icon).create(); } } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index 5380948ab1bd6..bb36fd678121e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -140,8 +140,7 @@ PackageBuilder installDir(Path v) { private static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigException { - var ex = ConfigException.build().message("error.invalid-install-dir", - installDir).create(); + var ex = ConfigException.build("error.invalid-install-dir", installDir).create(); if (installDir.getNameCount() == 0) { throw ex; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java index bdfa122d4f095..9934f42590efc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java @@ -39,7 +39,7 @@ public ConfigException(String msg, String advice, Throwable cause) { this.advice = advice; } - public ConfigException(Exception cause) { + public ConfigException(Throwable cause) { super(cause); this.advice = null; } @@ -51,9 +51,20 @@ public String getAdvice() { public static Builder build() { return new Builder(); } + + public static Builder build(String msgId, Object ... args) { + return build().message(msgId, args); + } + + public static Builder build(Throwable t) { + return build().causeAndMessage(t); + } public static final class Builder { + private Builder() { + } + public ConfigException create() { return new ConfigException(msg, advice, cause); } @@ -82,8 +93,9 @@ public Builder cause(Throwable v) { return this; } - public Builder causeAndMessage(Exception ex) { - return message(ex.getLocalizedMessage()).cause(ex); + public Builder causeAndMessage(Throwable t) { + var oldNoFormat = noFormat; + return noformat().message(t.getMessage()).cause(t).format(oldNoFormat); } private String formatString(String keyId, Object ... args) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java index 88cd76bcd2c77..b0b9857e140d4 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java @@ -48,8 +48,7 @@ WinMsiPackage create() throws ConfigException { try { MsiVersion.of(pkg.version()); } catch (IllegalArgumentException ex) { - throw ConfigException.build() - .causeAndMessage(ex) + throw ConfigException.build(ex) .advice("error.version-string-wrong-format.advice") .create(); } From 45b6e295da8ff9dad97171d8ba547771bb12bb18 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 4 Nov 2024 00:45:11 -0500 Subject: [PATCH 0125/1101] Shortcuts to create localized exceptions --- .../internal/LinuxPackageBuilder.java | 5 +- .../jdk/jpackage/internal/AppImageFile2.java | 5 +- .../jpackage/internal/ApplicationBuilder.java | 5 +- .../jpackage/internal/BuildEnvBuilder.java | 3 +- .../classes/jdk/jpackage/internal/I18N.java | 29 ++++--- .../jpackage/internal/LauncherBuilder.java | 16 ++-- .../jdk/jpackage/internal/PackageBuilder.java | 3 +- .../internal/RuntimeBuilderBuilder.java | 4 +- .../internal/model/ConfigException.java | 70 ++++++---------- .../jdk/jpackage/internal/model/I18N.java | 21 +++-- .../internal/model/PackagerException.java | 8 ++ .../util/LocalizedExceptionBuilder.java | 41 ++++++++++ .../util/LocalizedExceptionBuilderBase.java | 80 +++++++++++++++++++ .../jpackage/internal/util/StringBundle.java | 47 +++++++++++ .../internal/WinMsiPackageBuilder.java | 5 +- .../jpackage/internal/model/MsiVersion.java | 20 +++-- 16 files changed, 268 insertions(+), 94 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilderBase.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index 30bf1030f98d2..fc813de0fed8f 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -28,6 +28,7 @@ import java.util.Objects; import java.util.Optional; import java.util.regex.Pattern; +import static jdk.jpackage.internal.I18N.buildConfigException; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.ConfigException; @@ -121,7 +122,7 @@ private static void validatePackageName(String packageName, // var regexp = Pattern.compile("^[a-z][a-z\\d\\+\\-\\.]+"); if (!regexp.matcher(packageName).matches()) { - throw ConfigException.build() + throw buildConfigException() .message("error.deb-invalid-value-for-package-name", packageName) .advice("error.deb-invalid-value-for-package-name.advice") .create(); @@ -139,7 +140,7 @@ private static void validatePackageName(String packageName, // var regexp = Pattern.compile("[a-z\\d\\+\\-\\.\\_]+", Pattern.CASE_INSENSITIVE); if (!regexp.matcher(packageName).matches()) { - throw ConfigException.build() + throw buildConfigException() .message("error.rpm-invalid-value-for-package-name", packageName) .advice("error.rpm-invalid-value-for-package-name.advice") .create(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index f5bb82bd3534a..faaaf37d80ce1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -47,6 +47,7 @@ import javax.xml.xpath.XPathFactory; import jdk.internal.util.OperatingSystem; +import static jdk.jpackage.internal.I18N.buildConfigException; import jdk.jpackage.internal.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; @@ -248,10 +249,10 @@ public Map extraAppImageFileData() { // Exception reading input XML (probably malformed XML) throw new IOException(ex); } catch (NoSuchFileException ex) { - throw ConfigException.build("error.foreign-app-image", FILENAME).create(); + throw buildConfigException("error.foreign-app-image", FILENAME).create(); } catch (InavlidAppImageFileException ex) { // Invalid input XML - throw ConfigException.build("error.invalid-app-image-file", FILENAME).create(); + throw buildConfigException("error.invalid-app-image-file", FILENAME).create(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index b4dafb39c1882..47c34f67c3625 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -31,6 +31,7 @@ import java.util.Objects; import java.util.Optional; import java.util.function.Function; +import static jdk.jpackage.internal.I18N.buildConfigException; import jdk.jpackage.internal.AppImageFile2.LauncherInfo; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; @@ -50,7 +51,7 @@ Application create() throws ConfigException { final var launcherCount = launchersAsList.size(); if (launcherCount != launchersAsList.stream().map(Launcher::name).distinct().count()) { - throw ConfigException.build("ERR_NoUniqueName").create(); + throw buildConfigException("ERR_NoUniqueName").create(); } final String effectiveName; @@ -59,7 +60,7 @@ Application create() throws ConfigException { } else if (!launchersAsList.isEmpty()) { effectiveName = launchers.mainLauncher().name(); } else { - throw ConfigException.build() + throw buildConfigException() .message("error.no.name") .advice("error.no.name.advice") .create(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java index 34e8185ed0291..9836126f3d46b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java @@ -29,6 +29,7 @@ import jdk.jpackage.internal.model.ConfigException; import java.nio.file.Path; import java.util.Objects; +import static jdk.jpackage.internal.I18N.buildConfigException; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.resources.ResourceLocator; @@ -42,7 +43,7 @@ final class BuildEnvBuilder { BuildEnv create() throws ConfigException { Objects.requireNonNull(appImageDir); - var exceptionBuilder = ConfigException.build("ERR_BuildRootInvalid", root); + var exceptionBuilder = buildConfigException("ERR_BuildRootInvalid", root); if (!Files.exists(root)) { } else if (!Files.isDirectory(root)) { throw exceptionBuilder.create(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java index b127e8c6c117d..ab572784531bb 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java @@ -24,12 +24,12 @@ */ package jdk.jpackage.internal; -import java.text.MessageFormat; import java.util.List; import java.util.Map; -import java.util.ResourceBundle; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.util.MultiResourceBundle; +import jdk.jpackage.internal.util.StringBundle; final class I18N { @@ -38,25 +38,32 @@ static String getString(String key) { } static String format(String key, Object ... args) { - var str = getString(key); - if (args.length != 0) { - return MessageFormat.format(str, args); - } else { - return str; - } + return BUNDLE.format(key, args); } - private static final ResourceBundle BUNDLE; + static ConfigException.Builder buildConfigException() { + return ConfigException.build(BUNDLE); + } + + static ConfigException.Builder buildConfigException(String msgId, Object ... args) { + return ConfigException.build(BUNDLE, msgId, args); + } + + static ConfigException.Builder buildConfigException(Throwable t) { + return ConfigException.build(BUNDLE, t); + } + + private static final StringBundle BUNDLE; static { var prefix = "jdk.jpackage.internal.resources."; - BUNDLE = MultiResourceBundle.create( + BUNDLE = StringBundle.fromResourceBundle(MultiResourceBundle.create( prefix + "MainResources", Map.of( OperatingSystem.LINUX, List.of(prefix + "LinuxResources"), OperatingSystem.MACOS, List.of(prefix + "MacResources"), OperatingSystem.WINDOWS, List.of(prefix + "WinResources", prefix + "WinResourcesNoL10N") ) - ); + )); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java index 0fd28b4c0fa77..7f7c8732ecc7d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java @@ -36,6 +36,7 @@ import static jdk.internal.util.OperatingSystem.LINUX; import static jdk.internal.util.OperatingSystem.MACOS; import static jdk.internal.util.OperatingSystem.WINDOWS; +import static jdk.jpackage.internal.I18N.buildConfigException; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.model.Launcher; @@ -104,17 +105,20 @@ static void validateIcon(Path icon) throws ConfigException { switch (OperatingSystem.current()) { case WINDOWS -> { if (!icon.getFileName().toString().toLowerCase().endsWith(".ico")) { - throw ConfigException.build("message.icon-not-ico", icon).create(); + throw buildConfigException() + .message("message.icon-not-ico", icon).create(); } } case LINUX -> { if (!icon.getFileName().toString().endsWith(".png")) { - throw ConfigException.build("message.icon-not-png", icon).create(); + throw buildConfigException() + .message("message.icon-not-png", icon).create(); } } case MACOS -> { if (!icon.getFileName().toString().endsWith(".icns")) { - throw ConfigException.build("message.icon-not-icns", icon).create(); + throw buildConfigException() + .message("message.icon-not-icns", icon).create(); } } } @@ -137,7 +141,7 @@ private Stream createFileAssociations( } } catch (ExceptionWrapper ex) { if (ex.getCause() instanceof ConfigException cfgException) { - throw rethrowUnchecked(ConfigException.build() + throw rethrowUnchecked(buildConfigException() .cause(cfgException.getCause()) .message(cfgException.getMessage(), entry.getKey()) .advice(cfgException.getAdvice(), entry.getKey()) @@ -149,7 +153,7 @@ private Stream createFileAssociations( }).filter(Objects::nonNull).peek(entry -> { var faGroup = entry.getValue(); if (faGroup.items().size() != faGroup.items().stream().map(FileAssociation::extension).distinct().count()) { - throw rethrowUnchecked(ConfigException.build() + throw rethrowUnchecked(buildConfigException() .message("error.too-many-content-types-for-file-association", entry.getKey()) .advice("error.too-many-content-types-for-file-association.advice", entry.getKey()) .create()); @@ -167,7 +171,7 @@ private Stream createFileAssociations( static void verifyFileAssociation(FileAssociation src) throws ConfigException { if (Optional.ofNullable(src.mimeType()).isEmpty()) { - throw ConfigException.build() + throw buildConfigException() .noformat() .message("error.no-content-types-for-file-association") .advice("error.no-content-types-for-file-association.advice") diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index bb36fd678121e..958d55f495472 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -29,6 +29,7 @@ import java.nio.file.Path; import java.util.Objects; import java.util.Optional; +import static jdk.jpackage.internal.I18N.buildConfigException; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.Package.Stub; import jdk.jpackage.internal.model.PackageType; @@ -140,7 +141,7 @@ PackageBuilder installDir(Path v) { private static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigException { - var ex = ConfigException.build("error.invalid-install-dir", installDir).create(); + var ex = buildConfigException("error.invalid-install-dir", installDir).create(); if (installDir.getNameCount() == 0) { throw ex; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java index df528d106ce2c..60384ed7476cd 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java @@ -27,12 +27,12 @@ import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; -import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; +import static jdk.jpackage.internal.I18N.buildConfigException; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LauncherStartupInfo; @@ -101,7 +101,7 @@ public RuntimeBuilderConfigBuilder options(List v) { private static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, Path... modulePath) throws ConfigException { if (!Files.exists(runtimeDir)) { - throw ConfigException.build() + throw buildConfigException() .message("message.runtime-image-dir-does-not-exist", "--runtime-image", runtimeDir) .advice("message.runtime-image-dir-does-not-exist.advice", diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java index 9934f42590efc..354e6a93f36b3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java @@ -25,6 +25,9 @@ package jdk.jpackage.internal.model; +import jdk.jpackage.internal.util.LocalizedExceptionBuilderBase; +import jdk.jpackage.internal.util.StringBundle; + public class ConfigException extends Exception { private static final long serialVersionUID = 1L; final String advice; @@ -48,70 +51,43 @@ public String getAdvice() { return advice; } - public static Builder build() { - return new Builder(); - } - - public static Builder build(String msgId, Object ... args) { - return build().message(msgId, args); - } - - public static Builder build(Throwable t) { - return build().causeAndMessage(t); + public static Builder build(StringBundle i18n) { + return new Builder(i18n); } - public static final class Builder { - - private Builder() { - } - - public ConfigException create() { - return new ConfigException(msg, advice, cause); - } - - public Builder format(boolean v) { - noFormat = !v; - return this; - } + public static Builder build(StringBundle i18n, String msgId, Object ... args) { + return build(i18n).message(msgId, args); + } - public Builder noformat() { - return format(false); - } + public static Builder build(StringBundle i18n, Throwable t) { + return build(i18n).causeAndMessage(t); + } - public Builder message(String msgId, Object ... args) { - msg = formatString(msgId, args); - return this; - } + public static class Builder extends LocalizedExceptionBuilderBase { public Builder advice(String adviceId, Object ... args) { advice = formatString(adviceId, args); return this; } - public Builder cause(Throwable v) { - cause = v; - return this; + private Builder(StringBundle i18n) { + super(i18n); } - public Builder causeAndMessage(Throwable t) { - var oldNoFormat = noFormat; - return noformat().message(t.getMessage()).cause(t).format(oldNoFormat); + public ConfigException create() { + return create(this::create); } - private String formatString(String keyId, Object ... args) { - if (!noFormat) { - return I18N.format(keyId, args); - } if (args.length == 0) { - return keyId; - } else { - throw new IllegalArgumentException("Formatting arguments not allowed in no format mode"); - } + @Override + protected Builder thiz() { + return this; + } + + private ConfigException create(String msg, Throwable cause) { + return new ConfigException(msg, advice, cause); } - private boolean noFormat; - private String msg; private String advice; - private Throwable cause; } public static RuntimeException rethrowConfigException(RuntimeException ex) throws ConfigException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java index aceede7c02b36..7e303e7d76dbe 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java @@ -24,12 +24,12 @@ */ package jdk.jpackage.internal.model; -import java.text.MessageFormat; import java.util.List; import java.util.Map; -import java.util.ResourceBundle; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.util.LocalizedExceptionBuilder; import jdk.jpackage.internal.util.MultiResourceBundle; +import jdk.jpackage.internal.util.StringBundle; final class I18N { @@ -38,25 +38,24 @@ static String getString(String key) { } static String format(String key, Object ... args) { - var str = getString(key); - if (args.length != 0) { - return MessageFormat.format(str, args); - } else { - return str; - } + return BUNDLE.format(key, args); + } + + static LocalizedExceptionBuilder buildLocalizedException() { + return LocalizedExceptionBuilder.buildLocalizedException(BUNDLE); } - private static final ResourceBundle BUNDLE; + private static final StringBundle BUNDLE; static { var prefix = "jdk.jpackage.internal.resources."; - BUNDLE = MultiResourceBundle.create( + BUNDLE = StringBundle.fromResourceBundle(MultiResourceBundle.create( prefix + "MainResources", Map.of( OperatingSystem.LINUX, List.of(prefix + "LinuxResources"), OperatingSystem.MACOS, List.of(prefix + "MacResources"), OperatingSystem.WINDOWS, List.of(prefix + "WinResources") ) - ); + )); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java index 733face432ce8..d2595112b3b09 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java @@ -48,4 +48,12 @@ public PackagerException(Throwable cause, String key, Object... arguments) { super(I18N.format(key, arguments), cause); } + public static RuntimeException rethrowPackagerException(RuntimeException ex) throws PackagerException { + if (ex.getCause() instanceof PackagerException pkgEx) { + throw pkgEx; + } else { + throw ex; + } + } + } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java new file mode 100644 index 0000000000000..299b3e9d082e6 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +public class LocalizedExceptionBuilder extends LocalizedExceptionBuilderBase { + + public static LocalizedExceptionBuilder buildLocalizedException(StringBundle l18n) { + return new LocalizedExceptionBuilder(l18n); + } + + private LocalizedExceptionBuilder(StringBundle l18n) { + super(l18n); + } + + @Override + protected LocalizedExceptionBuilder thiz() { + return this; + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilderBase.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilderBase.java new file mode 100644 index 0000000000000..14ea3faeb75cc --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilderBase.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.util.function.BiFunction; + +public abstract class LocalizedExceptionBuilderBase> { + + protected LocalizedExceptionBuilderBase(StringBundle l18n) { + this.l18n = l18n; + } + + final public T create(BiFunction exceptionCtor) { + return exceptionCtor.apply(msg, cause); + } + + final public U format(boolean v) { + noFormat = !v; + return thiz(); + } + + final public U noformat() { + return format(false); + } + + final public U message(String msgId, Object... args) { + msg = formatString(msgId, args); + return thiz(); + } + + final public U cause(Throwable v) { + cause = v; + return thiz(); + } + + final public U causeAndMessage(Throwable t) { + boolean oldNoFormat = noFormat; + return noformat().message(t.getMessage()).cause(t).format(oldNoFormat); + } + + final protected String formatString(String keyId, Object... args) { + if (!noFormat) { + return l18n.format(keyId, args); + } else if (args.length == 0) { + return keyId; + } else { + throw new IllegalArgumentException("Formatting arguments not allowed in no format mode"); + } + } + + protected abstract U thiz(); + + private boolean noFormat; + private String msg; + private Throwable cause; + + private final StringBundle l18n; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java new file mode 100644 index 0000000000000..76b8d95a0c2cf --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.text.MessageFormat; +import java.util.ResourceBundle; + + +@FunctionalInterface +public interface StringBundle { + String getString(String key); + + default String format(String key, Object ... args) { + var str = getString(key); + if (args.length != 0) { + return MessageFormat.format(str, args); + } else { + return str; + } + } + + public static StringBundle fromResourceBundle(ResourceBundle bundle) { + return bundle::getString; + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java index b0b9857e140d4..6758dbd36f94f 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java @@ -30,6 +30,7 @@ import java.util.Objects; import java.util.Optional; import java.util.UUID; +import static jdk.jpackage.internal.I18N.buildConfigException; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.MsiVersion; @@ -48,13 +49,13 @@ WinMsiPackage create() throws ConfigException { try { MsiVersion.of(pkg.version()); } catch (IllegalArgumentException ex) { - throw ConfigException.build(ex) + throw buildConfigException(ex) .advice("error.version-string-wrong-format.advice") .create(); } if (pkg.app().isService() && (serviceInstaller == null || !Files.exists(serviceInstaller))) { - throw ConfigException.build() + throw buildConfigException() .message("error.missing-service-installer") .advice("error.missing-service-installer.advice") .create(); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java index 9ae4f2d751861..5e3aa6dd4f2f2 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal.model; import java.math.BigInteger; +import static jdk.jpackage.internal.model.I18N.buildLocalizedException; public final class MsiVersion { @@ -44,24 +45,29 @@ public static DottedVersion of(String value) { BigInteger[] components = ver.getComponents(); if (components.length < 2 || components.length > 4) { - throw new IllegalArgumentException(I18N.format("error.msi-product-version-components", value)); + throw buildLocalizedException() + .message("error.msi-product-version-components", value) + .create(IllegalArgumentException::new); } if (BigInteger.valueOf(255).compareTo(components[0]) < 0) { - throw new IllegalArgumentException(I18N.getString( - "error.msi-product-version-major-out-of-range")); + throw buildLocalizedException() + .message("error.msi-product-version-major-out-of-range") + .create(IllegalArgumentException::new); } if (components.length > 1 && BigInteger.valueOf(255).compareTo( components[1]) < 0) { - throw new IllegalArgumentException(I18N.getString( - "error.msi-product-version-minor-out-of-range")); + throw buildLocalizedException() + .message("error.msi-product-version-minor-out-of-range") + .create(IllegalArgumentException::new); } if (components.length > 2 && BigInteger.valueOf(65535).compareTo( components[2]) < 0) { - throw new IllegalArgumentException(I18N.getString( - "error.msi-product-version-build-out-of-range")); + throw buildLocalizedException() + .message("error.msi-product-version-build-out-of-range") + .create(IllegalArgumentException::new); } return ver; From 3038d6a8f213088d3bded4bf8ca47a309aafd7ac Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 7 Nov 2024 14:02:39 -0500 Subject: [PATCH 0126/1101] Try mixin and dynamic proxy on Windows model. It works! --- .../jpackage/internal/util/DynamicProxy.java | 110 ++++++++++++++++++ .../internal/WinExePackageBuilder.java | 2 +- .../jdk/jpackage/internal/WinFromParams.java | 9 +- .../internal/WinMsiPackageBuilder.java | 6 +- .../internal/WixAppImageFragmentBuilder.java | 2 +- .../internal/model/WinApplication.java | 8 +- .../internal/model/WinExePackage.java | 56 +++------ .../internal/model/WinExePackageMixin.java | 36 ++++++ .../jpackage/internal/model/WinLauncher.java | 44 +------ .../internal/model/WinLauncherMixin.java | 53 +++++++++ .../internal/model/WinMsiPackage.java | 99 +--------------- .../internal/model/WinMsiPackageMixin.java | 54 +++++++++ 12 files changed, 293 insertions(+), 186 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java create mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackageMixin.java create mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncherMixin.java create mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java new file mode 100644 index 0000000000000..67e32815703f5 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; +import static java.util.stream.Collectors.toMap; +import java.util.stream.Stream; + +public final class DynamicProxy { + + public static T createProxyFromPieces(Class interfaceType, Object ... pieces) { + if (!interfaceType.isInterface()) { + throw new IllegalArgumentException(String.format( + "Type %s must be an interface", interfaceType.getName())); + } + + final Class[] interfaces = interfaceType.getInterfaces(); + if (interfaces.length != pieces.length) { + throw new IllegalArgumentException(String.format( + "Type %s must extend %d interfaces", + interfaceType.getName(), pieces.length)); + } + + final Map, Object> interfaceDispatch; + try { + interfaceDispatch = Stream.of(interfaces).collect(toMap(x -> x, iface -> { + return Stream.of(pieces).filter(obj -> { + return Set.of(obj.getClass().getInterfaces()).contains(iface); + }).reduce((a, b) -> { + throw new IllegalArgumentException(String.format( + "Both [%s] and [%s] objects implement %s", a, b, + iface)); + }).orElseThrow(() -> createInterfaceNotImplementedException(List.of(iface))); + })); + } catch (IllegalStateException ex) { + throw new IllegalArgumentException(String.format( + "Multiple pieces implement the same interface")); + } + + if (interfaceDispatch.size() != interfaces.length) { + final List> missingInterfaces = new ArrayList<>(Set.of(interfaces)); + missingInterfaces.removeAll(interfaceDispatch.entrySet()); + throw createInterfaceNotImplementedException(missingInterfaces); + } + + var methodDispatch = Stream.of(interfaces) + .map(Class::getMethods) + .flatMap(Stream::of) + .filter(Predicate.not(Method::isDefault)) + .collect(toMap(x -> x, method -> { + return interfaceDispatch.get(method.getDeclaringClass()); + })); + + return createProxy(interfaceType, methodDispatch); + } + + @SuppressWarnings("unchecked") + private static T createProxy(Class interfaceType, Map dispatch) { + return (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), + new Class[]{interfaceType}, + new DynamicMixinInvocationHandler(dispatch)); + } + + private static IllegalArgumentException createInterfaceNotImplementedException( + Collection> missingInterfaces) { + return new IllegalArgumentException(String.format( + "None of the pieces implement %s", missingInterfaces)); + } + + private record DynamicMixinInvocationHandler(Map dispatch) implements InvocationHandler { + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (method.isDefault()) { + return InvocationHandler.invokeDefault(proxy, method, args); + } else { + var handler = dispatch.get(method); + return method.invoke(handler, args); + } + } + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java index eb248f2a06a40..b5cddf24a50e4 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java @@ -39,7 +39,7 @@ final class WinExePackageBuilder { WinExePackage create() throws ConfigException { LauncherBuilder.validateIcon(icon); - return new WinExePackage.Stub(pkg, icon); + return WinExePackage.create(pkg, icon); } WinExePackageBuilder icon(Path v) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java index 0087b1ee647e0..ba85415c2a3ff 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java @@ -45,8 +45,9 @@ import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; import jdk.jpackage.internal.model.WinApplication; import jdk.jpackage.internal.model.WinLauncher; -import static jdk.jpackage.internal.model.WinLauncher.WinShortcut.WIN_SHORTCUT_DESKTOP; -import static jdk.jpackage.internal.model.WinLauncher.WinShortcut.WIN_SHORTCUT_START_MENU; +import static jdk.jpackage.internal.model.WinLauncherMixin.WinShortcut.WIN_SHORTCUT_DESKTOP; +import static jdk.jpackage.internal.model.WinLauncherMixin.WinShortcut.WIN_SHORTCUT_START_MENU; +import jdk.jpackage.internal.model.WinLauncherMixin; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; final class WinFromParams { @@ -71,9 +72,9 @@ private static WinApplication createWinApplication( } }).map(Map.Entry::getKey).collect(toSet()); - return new WinLauncher.Stub(launcher, isConsole, shortcuts); + return WinLauncher.create(launcher, new WinLauncherMixin.Stub(isConsole, shortcuts)); }), APPLICATION_LAYOUT).create(); - return new WinApplication.Stub(app); + return WinApplication.create(app); } private static WinMsiPackage createWinMsiPackage(Map params) throws ConfigException, IOException { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java index 6758dbd36f94f..0447711c955da 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java @@ -35,6 +35,7 @@ import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.MsiVersion; import jdk.jpackage.internal.model.WinMsiPackage; +import jdk.jpackage.internal.model.WinMsiPackageMixin; final class WinMsiPackageBuilder { @@ -61,8 +62,7 @@ WinMsiPackage create() throws ConfigException { .create(); } - return new WinMsiPackage.Stub( - pkg, + return WinMsiPackage.create(pkg, new WinMsiPackageMixin.Stub( withInstallDirChooser, withShortcutPrompt, helpURL, @@ -71,7 +71,7 @@ WinMsiPackage create() throws ConfigException { isSystemWideInstall, Optional.ofNullable(upgradeCode).orElseGet(() -> upgradeCode(pkg.app())), productCode(pkg.app(), pkg.version()), - serviceInstaller); + serviceInstaller)); } private static UUID upgradeCode(Application app) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index 29955428b5538..3ac7ab0d5db68 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -61,7 +61,7 @@ import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import static jdk.jpackage.internal.util.CollectionUtils.toCollection; -import jdk.jpackage.internal.model.WinLauncher.WinShortcut; +import jdk.jpackage.internal.model.WinLauncherMixin.WinShortcut; import jdk.jpackage.internal.WixToolset.WixToolsetType; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.FileAssociation; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java index d056c35fda0c8..5cab551049e6e 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java @@ -24,15 +24,15 @@ */ package jdk.jpackage.internal.model; +import jdk.jpackage.internal.util.DynamicProxy; + public interface WinApplication extends Application { default DottedVersion winVersion() { return DottedVersion.lazy(version()); } - final class Stub extends Application.Proxy implements WinApplication { - public Stub(Application app) { - super(app); - } + public static WinApplication create(Application app) { + return DynamicProxy.createProxyFromPieces(WinApplication.class, app); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java index 684615d237f03..6921965d7ca07 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java @@ -26,45 +26,25 @@ import java.nio.file.Path; import static jdk.jpackage.internal.model.StandardPackageType.WIN_EXE; +import jdk.jpackage.internal.util.DynamicProxy; -public interface WinExePackage extends Package { +public interface WinExePackage extends Package, WinExePackageMixin { - WinMsiPackage msiPackage(); - - Path icon(); - - final class Stub extends Package.Proxy implements WinExePackage { - - public Stub(WinMsiPackage msiPackage, Path icon) throws ConfigException { - super(createExePackage(msiPackage)); - this.msiPackage = msiPackage; - this.icon = icon; - } - - @Override - public WinMsiPackage msiPackage() { - return msiPackage; - } - - @Override - public Path icon() { - return icon; - } - - private static Package createExePackage(Package pkg) { - return new Package.Stub( - pkg.app(), - WIN_EXE, - pkg.packageName(), - pkg.description(), - pkg.version(), - pkg.aboutURL(), - pkg.licenseFile(), - pkg.predefinedAppImage(), - pkg.relativeInstallDir()); - } - - private final WinMsiPackage msiPackage; - private final Path icon; + public static WinExePackage create(WinMsiPackage msiPackage, Path icon) { + return DynamicProxy.createProxyFromPieces(WinExePackage.class, createExePackage( + msiPackage), new WinExePackageMixin.Stub(msiPackage, icon)); + } + + private static Package createExePackage(WinMsiPackage pkg) { + return new Package.Stub( + pkg.app(), + WIN_EXE, + pkg.packageName(), + pkg.description(), + pkg.version(), + pkg.aboutURL(), + pkg.licenseFile(), + pkg.predefinedAppImage(), + pkg.relativeInstallDir()); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackageMixin.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackageMixin.java new file mode 100644 index 0000000000000..c24af4dd30693 --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackageMixin.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.nio.file.Path; + +public interface WinExePackageMixin { + + WinMsiPackage msiPackage(); + + Path icon(); + + record Stub(WinMsiPackage msiPackage, Path icon) implements WinExePackageMixin {} +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java index b67a7e3d557fa..2c6fdb7bdd371 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java @@ -30,16 +30,15 @@ import java.util.Set; import static java.util.stream.Collectors.toMap; import jdk.jpackage.internal.resources.ResourceLocator; +import jdk.jpackage.internal.util.DynamicProxy; -public interface WinLauncher extends Launcher { +public interface WinLauncher extends Launcher, WinLauncherMixin { @Override default String executableSuffix() { return ".exe"; } - boolean isConsole(); - @Override default InputStream executableResource() { return ResourceLocator.class.getResourceAsStream( @@ -57,42 +56,7 @@ default String defaultIconResourceName() { return "JavaApp.ico"; } - enum WinShortcut { - WIN_SHORTCUT_DESKTOP("shortcut"), - WIN_SHORTCUT_START_MENU("menu"), - ; - - WinShortcut(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - private final String name; - } - - Set shortcuts(); - - final class Stub extends Launcher.Proxy implements WinLauncher { - public Stub(Launcher launcher, boolean isConsole, Set shortcuts) { - super(launcher); - this.isConsole = isConsole; - this.shortcuts = shortcuts; - } - - @Override - public boolean isConsole() { - return isConsole; - } - - @Override - public Set shortcuts() { - return shortcuts; - } - - private final boolean isConsole; - private final Set shortcuts; + public static WinLauncher create(Launcher launcher, WinLauncherMixin mixin) { + return DynamicProxy.createProxyFromPieces(WinLauncher.class, launcher, mixin); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncherMixin.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncherMixin.java new file mode 100644 index 0000000000000..89990b749e104 --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncherMixin.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.util.Set; + +public interface WinLauncherMixin { + + boolean isConsole(); + + enum WinShortcut { + WIN_SHORTCUT_DESKTOP("shortcut"), + WIN_SHORTCUT_START_MENU("menu"), + ; + + WinShortcut(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + private final String name; + } + + Set shortcuts(); + + record Stub(boolean isConsole, Set shortcuts) implements WinLauncherMixin { + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java index 7c7b069221e48..e30f9bedb3bd0 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java @@ -24,106 +24,15 @@ */ package jdk.jpackage.internal.model; -import java.nio.file.Path; -import java.util.UUID; +import jdk.jpackage.internal.util.DynamicProxy; -public interface WinMsiPackage extends Package { +public interface WinMsiPackage extends Package, WinMsiPackageMixin { default DottedVersion msiVersion() { return MsiVersion.of(version()); } - boolean withInstallDirChooser(); - - boolean withShortcutPrompt(); - - String helpURL(); - - String updateURL(); - - String startMenuGroupName(); - - boolean isSystemWideInstall(); - - UUID upgradeCode(); - - UUID productCode(); - - Path serviceInstaller(); - - final class Stub extends Package.Proxy implements WinMsiPackage { - - public Stub(Package pkg, boolean withInstallDirChooser, - boolean withShortcutPrompt, String helpURL, String updateURL, - String startMenuGroupName, boolean isSystemWideInstall, - UUID upgradeCode, UUID productCode, Path serviceInstaller) - throws ConfigException { - super(pkg); - - this.withInstallDirChooser = withInstallDirChooser; - this.withShortcutPrompt = withShortcutPrompt; - this.helpURL = helpURL; - this.updateURL = updateURL; - this.startMenuGroupName = startMenuGroupName; - this.isSystemWideInstall = isSystemWideInstall; - this.upgradeCode = upgradeCode; - this.productCode = productCode; - this.serviceInstaller = serviceInstaller; - } - - @Override - public boolean withInstallDirChooser() { - return withInstallDirChooser; - } - - @Override - public boolean withShortcutPrompt() { - return withShortcutPrompt; - } - - @Override - public String helpURL() { - return helpURL; - } - - @Override - public String updateURL() { - return updateURL; - } - - @Override - public String startMenuGroupName() { - return startMenuGroupName; - } - - @Override - public boolean isSystemWideInstall() { - return isSystemWideInstall; - } - - @Override - public UUID upgradeCode() { - return upgradeCode; - } - - @Override - public UUID productCode() { - return productCode; - } - - @Override - public Path serviceInstaller() { - return serviceInstaller; - } - - private final boolean withInstallDirChooser; - private final boolean withShortcutPrompt; - private final String helpURL; - private final String updateURL; - private final String startMenuGroupName; - private final boolean isSystemWideInstall; - private final UUID upgradeCode; - private final UUID productCode; - private final Path serviceInstaller; + public static WinMsiPackage create(Package pkg, WinMsiPackageMixin mixin) { + return DynamicProxy.createProxyFromPieces(WinMsiPackage.class, pkg, mixin); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java new file mode 100644 index 0000000000000..f2a26b081de6f --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.nio.file.Path; +import java.util.UUID; + +public interface WinMsiPackageMixin { + + boolean withInstallDirChooser(); + + boolean withShortcutPrompt(); + + String helpURL(); + + String updateURL(); + + String startMenuGroupName(); + + boolean isSystemWideInstall(); + + UUID upgradeCode(); + + UUID productCode(); + + Path serviceInstaller(); + + record Stub(boolean withInstallDirChooser, boolean withShortcutPrompt, + String helpURL, String updateURL, String startMenuGroupName, + boolean isSystemWideInstall, UUID upgradeCode, UUID productCode, + Path serviceInstaller) implements WinMsiPackageMixin {} +} From 35378b893b61b649f2e269d45d34dda084f4c3a3 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 7 Nov 2024 15:25:22 -0500 Subject: [PATCH 0127/1101] Remove LocalizedExceptionBuilderBase. All its functionality fits well in LocalizedExceptionBuilder. Patch TEST.properties to make jtreg tests work with the new jpackage package structure --- .../jpackage/internal/LauncherBuilder.java | 2 +- .../internal/model/ConfigException.java | 9 +-- .../jdk/jpackage/internal/model/I18N.java | 4 +- .../util/LocalizedExceptionBuilder.java | 62 ++++++++++++-- .../util/LocalizedExceptionBuilderBase.java | 80 ------------------- test/jdk/tools/jpackage/TEST.properties | 3 +- 6 files changed, 61 insertions(+), 99 deletions(-) delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilderBase.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java index 7f7c8732ecc7d..33adbab507d5b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java @@ -169,7 +169,7 @@ private Stream createFileAssociations( } } - static void verifyFileAssociation(FileAssociation src) throws ConfigException { + private static void verifyFileAssociation(FileAssociation src) throws ConfigException { if (Optional.ofNullable(src.mimeType()).isEmpty()) { throw buildConfigException() .noformat() diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java index 354e6a93f36b3..44e8d1ff0ad26 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java @@ -25,7 +25,7 @@ package jdk.jpackage.internal.model; -import jdk.jpackage.internal.util.LocalizedExceptionBuilderBase; +import jdk.jpackage.internal.util.LocalizedExceptionBuilder; import jdk.jpackage.internal.util.StringBundle; public class ConfigException extends Exception { @@ -63,7 +63,7 @@ public static Builder build(StringBundle i18n, Throwable t) { return build(i18n).causeAndMessage(t); } - public static class Builder extends LocalizedExceptionBuilderBase { + public static class Builder extends LocalizedExceptionBuilder { public Builder advice(String adviceId, Object ... args) { advice = formatString(adviceId, args); @@ -78,11 +78,6 @@ public ConfigException create() { return create(this::create); } - @Override - protected Builder thiz() { - return this; - } - private ConfigException create(String msg, Throwable cause) { return new ConfigException(msg, advice, cause); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java index 7e303e7d76dbe..18913117a5095 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java @@ -40,8 +40,8 @@ static String getString(String key) { static String format(String key, Object ... args) { return BUNDLE.format(key, args); } - - static LocalizedExceptionBuilder buildLocalizedException() { + + static LocalizedExceptionBuilder buildLocalizedException() { return LocalizedExceptionBuilder.buildLocalizedException(BUNDLE); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java index 299b3e9d082e6..39864beb8aef2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java @@ -24,18 +24,64 @@ */ package jdk.jpackage.internal.util; -public class LocalizedExceptionBuilder extends LocalizedExceptionBuilderBase { +import java.util.function.BiFunction; - public static LocalizedExceptionBuilder buildLocalizedException(StringBundle l18n) { - return new LocalizedExceptionBuilder(l18n); +public class LocalizedExceptionBuilder> { + + protected LocalizedExceptionBuilder(StringBundle l18n) { + this.l18n = l18n; + } + + public static > R buildLocalizedException(StringBundle l18n) { + return new LocalizedExceptionBuilder(l18n).thiz(); + } + + final public T create(BiFunction exceptionCtor) { + return exceptionCtor.apply(msg, cause); + } + + final public T format(boolean v) { + noFormat = !v; + return thiz(); + } + + final public T noformat() { + return format(false); } - private LocalizedExceptionBuilder(StringBundle l18n) { - super(l18n); + final public T message(String msgId, Object... args) { + msg = formatString(msgId, args); + return thiz(); } - @Override - protected LocalizedExceptionBuilder thiz() { - return this; + final public T cause(Throwable v) { + cause = v; + return thiz(); } + + final public T causeAndMessage(Throwable t) { + boolean oldNoFormat = noFormat; + return noformat().message(t.getMessage()).cause(t).format(oldNoFormat); + } + + final protected String formatString(String keyId, Object... args) { + if (!noFormat) { + return l18n.format(keyId, args); + } else if (args.length == 0) { + return keyId; + } else { + throw new IllegalArgumentException("Formatting arguments not allowed in no format mode"); + } + } + + @SuppressWarnings("unchecked") + private T thiz() { + return (T)this; + } + + private boolean noFormat; + private String msg; + private Throwable cause; + + private final StringBundle l18n; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilderBase.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilderBase.java deleted file mode 100644 index 14ea3faeb75cc..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilderBase.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal.util; - -import java.util.function.BiFunction; - -public abstract class LocalizedExceptionBuilderBase> { - - protected LocalizedExceptionBuilderBase(StringBundle l18n) { - this.l18n = l18n; - } - - final public T create(BiFunction exceptionCtor) { - return exceptionCtor.apply(msg, cause); - } - - final public U format(boolean v) { - noFormat = !v; - return thiz(); - } - - final public U noformat() { - return format(false); - } - - final public U message(String msgId, Object... args) { - msg = formatString(msgId, args); - return thiz(); - } - - final public U cause(Throwable v) { - cause = v; - return thiz(); - } - - final public U causeAndMessage(Throwable t) { - boolean oldNoFormat = noFormat; - return noformat().message(t.getMessage()).cause(t).format(oldNoFormat); - } - - final protected String formatString(String keyId, Object... args) { - if (!noFormat) { - return l18n.format(keyId, args); - } else if (args.length == 0) { - return keyId; - } else { - throw new IllegalArgumentException("Formatting arguments not allowed in no format mode"); - } - } - - protected abstract U thiz(); - - private boolean noFormat; - private String msg; - private Throwable cause; - - private final StringBundle l18n; -} diff --git a/test/jdk/tools/jpackage/TEST.properties b/test/jdk/tools/jpackage/TEST.properties index e01036f0ed36c..38280c02c3c9d 100644 --- a/test/jdk/tools/jpackage/TEST.properties +++ b/test/jdk/tools/jpackage/TEST.properties @@ -12,4 +12,5 @@ maxOutputSize=2000000 exclusiveAccess.dirs=share windows modules=jdk.jpackage/jdk.jpackage.internal:+open \ - java.base/jdk.internal.util + jdk.jpackage/jdk.jpackage.internal.util:+open \ + java.base/jdk.internal.util \ From 446d9baf9f7f85f2ba4ff15db92bd2b22f8945d4 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 7 Nov 2024 21:29:29 -0500 Subject: [PATCH 0128/1101] Bugfix for Linux --- .../internal/LinuxPackageBuilder.java | 4 ++-- .../jpackage/internal/AppImageBuilder.java | 20 +++++++++++++------ .../jdk/jpackage/internal/PackageBuilder.java | 16 +++++++++------ .../jdk/jpackage/test/ApplicationLayout.java | 6 +++--- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index fc813de0fed8f..6e2c7769b2e2d 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -33,6 +33,7 @@ import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.StandardPackageType; import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; @@ -62,8 +63,7 @@ LinuxPackage create() throws ConfigException { return reply; } - private LinuxPackage create(jdk.jpackage.internal.model.Package pkg, - AppImageLayout pkgLayout) throws ConfigException { + private LinuxPackage create(Package pkg, AppImageLayout pkgLayout) throws ConfigException { return new LinuxPackage.Stub(pkg, pkgLayout, Optional.ofNullable(menuGroupName).orElseGet(DEFAULTS::menuGroupName), diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java index 9cf470e83110a..2ab587a3981e1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -64,7 +64,7 @@ Builder excludeDirFromCopying(Path path) { } AppImageBuilder create(Application app) { - return new AppImageBuilder(app, app.asApplicationLayout(), excludeCopyDirs, launcherCallback); + return new AppImageBuilder(app, excludeCopyDirs, launcherCallback); } AppImageBuilder create(Package pkg) { @@ -80,24 +80,31 @@ static Builder build() { } private AppImageBuilder(Application app, ApplicationLayout appLayout, - List excludeCopyDirs, LauncherCallback launcherCallback) { + List excludeCopyDirs, LauncherCallback launcherCallback, + boolean withAppImageFile) { Objects.requireNonNull(app); Objects.requireNonNull(appLayout); this.app = app; this.appLayout = appLayout; - this.withAppImageFile = true; + this.withAppImageFile = withAppImageFile; this.launcherCallback = launcherCallback; this.excludeCopyDirs = Optional.ofNullable(excludeCopyDirs).orElseGet(List::of); } + private AppImageBuilder(Application app, List excludeCopyDirs, + LauncherCallback launcherCallback) { + this(app, app.asApplicationLayout(), excludeCopyDirs, launcherCallback, false); + } + private AppImageBuilder(Package pkg, List excludeCopyDirs, LauncherCallback launcherCallback) { this(pkg.app(), pkg.asPackageApplicationLayout(), excludeCopyDirs, - launcherCallback); + launcherCallback, false); } - private static void copyRecursive(Path srcDir, Path dstDir, List excludeDirs) throws IOException { + private static void copyRecursive(Path srcDir, Path dstDir, + List excludeDirs) throws IOException { srcDir = srcDir.toAbsolutePath(); List excludes = new ArrayList<>(); @@ -194,7 +201,8 @@ static OverridableResource createLauncherIconResource(Application app, } static interface LauncherCallback { - default public void onLauncher(Application app, LauncherContext ctx) throws IOException, PackagerException { + default public void onLauncher(Application app, LauncherContext ctx) + throws IOException, PackagerException { var iconResource = createLauncherIconResource(app, ctx.launcher, ctx.env::createResource); if (iconResource != null) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index 958d55f495472..960d5c0e81ca9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -53,7 +53,7 @@ final class PackageBuilder { Package create() throws ConfigException { final var effectiveName = Optional.ofNullable(name).orElseGet(app::name); - final Path relativeInstallDir; + Path relativeInstallDir; if (installDir != null) { var normalizedInstallDir = mapInstallDir(installDir, type); if (type instanceof StandardPackageType stdType) { @@ -78,11 +78,15 @@ Package create() throws ConfigException { } relativeInstallDir = normalizedInstallDir; } else if (type instanceof StandardPackageType stdType) { - relativeInstallDir = defaultRelativeInstallDir(stdType, effectiveName, app); + relativeInstallDir = defaultInstallDir(stdType, effectiveName, app); } else { throw new UnsupportedOperationException(); } + if (relativeInstallDir.isAbsolute()) { + relativeInstallDir = Path.of("/").relativize(relativeInstallDir); + } + return new Stub( app, type, @@ -177,20 +181,20 @@ private static Path mapInstallDir(Path installDir, PackageType pkgType) return installDir; } - private static Path defaultRelativeInstallDir(StandardPackageType pkgType, String pkgName, Application app) { + private static Path defaultInstallDir(StandardPackageType pkgType, String pkgName, Application app) { switch (pkgType) { case WIN_EXE, WIN_MSI -> { return Path.of(app.name()); } case LINUX_DEB, LINUX_RPM -> { - return Path.of("opt").resolve(pkgName); + return Path.of("/opt").resolve(pkgName); } case MAC_DMG, MAC_PKG -> { Path base; if (app.isRuntime()) { - base = Path.of("Library/Java/JavaVirtualMachines"); + base = Path.of("/Library/Java/JavaVirtualMachines"); } else { - base = Path.of("Applications"); + base = Path.of("/Applications"); } return base.resolve(pkgName); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java index 3f1005b2496da..b297982ab3c12 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java @@ -48,8 +48,8 @@ public static ApplicationLayout linuxAppImage() { Path.of("lib/app"), Path.of("lib/runtime"), Path.of("lib/runtime"), - Path.of("lib"), Path.of("lib/app/mods"), + Path.of("lib"), Path.of("lib") ); } @@ -60,8 +60,8 @@ public static ApplicationLayout windowsAppImage() { Path.of("app"), Path.of("runtime"), Path.of("runtime"), - Path.of(""), Path.of("app/mods"), + Path.of(""), Path.of("") ); } @@ -72,8 +72,8 @@ public static ApplicationLayout macAppImage() { Path.of("Contents/app"), Path.of("Contents/runtime"), Path.of("Contents/runtime/Contents/Home"), - Path.of("Contents/Resources"), Path.of("Contents/app/mods"), + Path.of("Contents/Resources"), Path.of("Contents") ); } From 46dee150506e4c8d7d2e2d6286dd78a66dcbeb33 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 7 Nov 2024 23:36:57 -0500 Subject: [PATCH 0129/1101] Linux bugfixes --- .../classes/jdk/jpackage/internal/LinuxFromParams.java | 6 +++--- .../jdk/jpackage/internal/LinuxPackageBuilder.java | 10 +++++++++- .../classes/jdk/jpackage/internal/AppImageBuilder.java | 2 +- .../classes/jdk/jpackage/internal/PackageBuilder.java | 4 ---- .../helpers/jdk/jpackage/test/ApplicationLayout.java | 2 +- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java index 04a199dfefe51..1304d9bb0a006 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java @@ -65,14 +65,14 @@ private static LinuxPackageBuilder createLinuxPackageBuilder( var app = APPLICATION.fetchFrom(params); - var pkgBuilder = createPackageBuilder(params, app, type) - .name(LINUX_PACKAGE_NAME.fetchFrom(params)); + var pkgBuilder = createPackageBuilder(params, app, type); return new LinuxPackageBuilder(pkgBuilder) .additionalDependencies(LINUX_PACKAGE_DEPENDENCIES.fetchFrom(params)) .category(LINUX_CATEGORY.fetchFrom(params)) .menuGroupName(LINUX_MENU_GROUP.fetchFrom(params)) - .release(RELEASE.fetchFrom(params)); + .release(RELEASE.fetchFrom(params)) + .directName(LINUX_PACKAGE_NAME.fetchFrom(params)); } private static LinuxPackage createLinuxRpmPackage( diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index 6e2c7769b2e2d..216014b943002 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -46,7 +46,9 @@ final class LinuxPackageBuilder { } LinuxPackage create() throws ConfigException { - if (pkgBuilder.isNameDefault()) { + if (directName != null) { + pkgBuilder.name(directName); + } else { // Lower case and turn spaces/underscores into dashes pkgBuilder.name(pkgBuilder.create().packageName().toLowerCase().replaceAll("[ _]", "-")); } @@ -73,6 +75,11 @@ private LinuxPackage create(Package pkg, AppImageLayout pkgLayout) throws Config LinuxPackageArch.getValue(pkg.asStandardPackageType())); } + LinuxPackageBuilder directName(String v) { + directName = v; + return this; + } + LinuxPackageBuilder menuGroupName(String v) { menuGroupName = v; return this; @@ -152,6 +159,7 @@ private static void validatePackageName(String packageName, private record Defaults(String release, String menuGroupName, String category) { } + private String directName; private String menuGroupName; private String category; private String additionalDependencies; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java index 2ab587a3981e1..8fb2cfc484d1b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -94,7 +94,7 @@ private AppImageBuilder(Application app, ApplicationLayout appLayout, private AppImageBuilder(Application app, List excludeCopyDirs, LauncherCallback launcherCallback) { - this(app, app.asApplicationLayout(), excludeCopyDirs, launcherCallback, false); + this(app, app.asApplicationLayout(), excludeCopyDirs, launcherCallback, true); } private AppImageBuilder(Package pkg, List excludeCopyDirs, diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index 960d5c0e81ca9..f26f724c54e6d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -104,10 +104,6 @@ PackageBuilder name(String v) { return this; } - boolean isNameDefault() { - return name == null; - } - PackageBuilder fileName(Path v) { fileName = v; return this; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java index b297982ab3c12..7f2bb44e73e9e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java @@ -114,8 +114,8 @@ public static ApplicationLayout linuxUsrTreePackageImage(Path prefix, lib.resolve("app"), lib.resolve("runtime"), lib.resolve("runtime"), - lib, lib.resolve("app/mods"), + lib, lib ); } From 3de5af6a83e7d52f2d4d38e82cd886cfd19967d8 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 9 Nov 2024 18:52:39 -0500 Subject: [PATCH 0130/1101] Fix InOutPath test failures --- .../classes/jdk/jpackage/internal/LinuxPackageBundler.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 4199ab9374c91..fa92bd3d16b32 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -113,7 +113,9 @@ public final Path execute(Map params, // We either have an application image or need to build one. if (pkg.app().runtimeBuilder() != null) { // Runtime builder is present, build app image. - LinuxAppImageBuilder.build().create(pkg).execute(pkgEnv); + LinuxAppImageBuilder.build() + .excludeDirFromCopying(outputParentDir) + .create(pkg).execute(pkgEnv); } else { Path srcAppImageDir = pkg.predefinedAppImage(); if (srcAppImageDir == null) { From 314041946d940dfafb7cc4a1bd48a61a5e7ea334 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 9 Nov 2024 19:24:02 -0500 Subject: [PATCH 0131/1101] Use dynamic proxies on linux --- .../internal/LinuxDebPackageBuilder.java | 7 +- .../jpackage/internal/LinuxFromParams.java | 5 +- .../internal/LinuxPackageBuilder.java | 5 +- .../internal/LinuxRpmPackageBuilder.java | 6 +- .../internal/model/LinuxApplication.java | 11 +- .../internal/model/LinuxDebPackage.java | 20 +--- .../internal/model/LinuxDebPackageMixin.java | 33 ++++++ .../internal/model/LinuxLauncher.java | 23 +--- .../internal/model/LinuxLauncherMixin.java | 35 ++++++ .../jpackage/internal/model/LinuxPackage.java | 103 +----------------- .../internal/model/LinuxPackageMixin.java | 43 ++++++++ .../internal/model/LinuxRpmPackage.java | 19 +--- .../internal/model/LinuxRpmPackageMixin.java | 33 ++++++ .../jpackage/internal/model/Application.java | 57 ---------- .../jdk/jpackage/internal/model/Launcher.java | 74 +------------ 15 files changed, 182 insertions(+), 292 deletions(-) create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackageMixin.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java index fcd730b31bea0..899d8874d8c10 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java @@ -28,6 +28,7 @@ import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxRpmPackage; +import jdk.jpackage.internal.model.LinuxRpmPackageMixin; final class LinuxDebPackageBuilder { @@ -38,9 +39,9 @@ final class LinuxDebPackageBuilder { LinuxRpmPackage create() throws ConfigException { var pkg = pkgBuilder.create(); - return new LinuxRpmPackage.Stub( - pkg, - Optional.ofNullable(maintainerEmail).orElseGet(DEFAULTS::maintainerEmail)); + return LinuxRpmPackage.create(pkg, new LinuxRpmPackageMixin.Stub( + Optional.ofNullable(maintainerEmail).orElseGet( + DEFAULTS::maintainerEmail))); } LinuxDebPackageBuilder maintainerEmail(String v) { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java index 1304d9bb0a006..44508415d8ac1 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java @@ -37,6 +37,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; import jdk.jpackage.internal.model.LinuxApplication; import jdk.jpackage.internal.model.LinuxLauncher; +import jdk.jpackage.internal.model.LinuxLauncherMixin; import jdk.jpackage.internal.model.LinuxPackage; import jdk.jpackage.internal.model.StandardPackageType; import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; @@ -55,9 +56,9 @@ private static LinuxApplication createLinuxApplication( }).map(param -> { return param.fetchFrom(launcherParams); }).findFirst(); - return new LinuxLauncher.Stub(launcher, shortcut); + return LinuxLauncher.create(launcher, new LinuxLauncherMixin.Stub(shortcut)); }), APPLICATION_LAYOUT).create(); - return new LinuxApplication.Stub(app); + return LinuxApplication.create(app); } private static LinuxPackageBuilder createLinuxPackageBuilder( diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index 216014b943002..1d28332b9cb70 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -33,6 +33,7 @@ import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.LinuxPackageMixin; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.StandardPackageType; import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; @@ -66,13 +67,13 @@ LinuxPackage create() throws ConfigException { } private LinuxPackage create(Package pkg, AppImageLayout pkgLayout) throws ConfigException { - return new LinuxPackage.Stub(pkg, + return LinuxPackage.create(pkg, new LinuxPackageMixin.Stub( pkgLayout, Optional.ofNullable(menuGroupName).orElseGet(DEFAULTS::menuGroupName), Optional.ofNullable(category).orElseGet(DEFAULTS::category), additionalDependencies, Optional.ofNullable(release).orElseGet(DEFAULTS::release), - LinuxPackageArch.getValue(pkg.asStandardPackageType())); + LinuxPackageArch.getValue(pkg.asStandardPackageType()))); } LinuxPackageBuilder directName(String v) { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java index aeaa7d1d41b5c..3d713bc727f1e 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java @@ -28,6 +28,7 @@ import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxRpmPackage; +import jdk.jpackage.internal.model.LinuxRpmPackageMixin; final class LinuxRpmPackageBuilder { @@ -38,9 +39,8 @@ final class LinuxRpmPackageBuilder { LinuxRpmPackage create() throws ConfigException { var pkg = pkgBuilder.create(); - return new LinuxRpmPackage.Stub( - pkg, - Optional.ofNullable(licenseType).orElseGet(DEFAULTS::licenseType)); + return LinuxRpmPackage.create(pkg, new LinuxRpmPackageMixin.Stub( + Optional.ofNullable(licenseType).orElseGet(DEFAULTS::licenseType))); } LinuxRpmPackageBuilder licenseType(String v) { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java index e4024ea165d0e..ce895bd82da16 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java @@ -25,10 +25,11 @@ package jdk.jpackage.internal.model; +import jdk.jpackage.internal.util.DynamicProxy; + public interface LinuxApplication extends Application { - final class Stub extends Application.Proxy implements LinuxApplication { - public Stub(Application app) { - super(app); - } - } + + public static LinuxApplication create(Application app) { + return DynamicProxy.createProxyFromPieces(LinuxApplication.class, app); + } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java index e7496ad6a4159..de2f3f2c5d513 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java @@ -25,10 +25,9 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import jdk.jpackage.internal.util.DynamicProxy; -public interface LinuxDebPackage extends LinuxPackage { - - String maintainerEmail(); +public interface LinuxDebPackage extends LinuxPackage, LinuxDebPackageMixin { default String maintainer() { return String.format("%s <%s>", app().vendor(), maintainerEmail()); @@ -49,18 +48,7 @@ default Path relativeCopyrightFilePath() { } } - final class Stub extends LinuxPackage.Proxy implements LinuxDebPackage { - - public Stub(LinuxPackage target, String maintainerEmail) { - super(target); - this.maintainerEmail = maintainerEmail; - } - - @Override - public String maintainerEmail() { - return maintainerEmail; - } - - private final String maintainerEmail; + public static LinuxDebPackage create(LinuxPackage pkg, LinuxDebPackageMixin mixin) { + return DynamicProxy.createProxyFromPieces(LinuxDebPackage.class, pkg, mixin); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java new file mode 100644 index 0000000000000..b4065407763e2 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +public interface LinuxDebPackageMixin { + + String maintainerEmail(); + + record Stub(String maintainerEmail) { + } +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java index 9988fbc9a5b6e..ab67927d96853 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java @@ -25,11 +25,9 @@ package jdk.jpackage.internal.model; import java.util.Map; -import java.util.Optional; +import jdk.jpackage.internal.util.DynamicProxy; -public interface LinuxLauncher extends Launcher { - - Optional shortcut(); +public interface LinuxLauncher extends Launcher, LinuxLauncherMixin { @Override default Map extraAppImageFileData() { @@ -37,24 +35,13 @@ default Map extraAppImageFileData() { return Map.of("shortcut", Boolean.toString(v)); }).orElseGet(Map::of); } - + @Override default String defaultIconResourceName() { return "JavaApp.png"; } - final class Stub extends Launcher.Proxy implements LinuxLauncher { - - public Stub(Launcher launcher, Optional shortcut) { - super(launcher); - this.shortcut = shortcut; - } - - @Override - public Optional shortcut() { - return shortcut; - } - - private final Optional shortcut; + public static LinuxLauncher create(Launcher launcher, LinuxLauncherMixin mixin) { + return DynamicProxy.createProxyFromPieces(LinuxLauncher.class, launcher, mixin); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java new file mode 100644 index 0000000000000..abf2c43eb00d2 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.util.Optional; + +public interface LinuxLauncherMixin { + + Optional shortcut(); + + record Stub(Optional shortcut) implements LinuxLauncherMixin { + } +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java index 5ef5d74c9de05..de7eba3d125b5 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java @@ -25,18 +25,9 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import jdk.jpackage.internal.util.DynamicProxy; -public interface LinuxPackage extends Package { - - String menuGroupName(); - - String category(); - - String additionalDependencies(); - - String release(); - - String arch(); +public interface LinuxPackage extends Package, LinuxPackageMixin { @Override AppImageLayout packageLayout(); @@ -63,93 +54,7 @@ default boolean isInstallDirInUsrTree() { return !relativeInstallDir().getFileName().equals(Path.of(packageName())); } - final class Stub extends Package.Proxy implements LinuxPackage { - - public Stub(Package target, AppImageLayout packageLayout, - String menuGroupName, String category, - String additionalDependencies, String release, String arch) - throws ConfigException { - super(target); - this.packageLayout = packageLayout; - this.menuGroupName = menuGroupName; - this.category = category; - this.release = release; - this.additionalDependencies = additionalDependencies; - this.arch = arch; - } - - @Override - public AppImageLayout packageLayout() { - return packageLayout; - } - - @Override - public String menuGroupName() { - return menuGroupName; - } - - @Override - public String category() { - return category; - } - - @Override - public String additionalDependencies() { - return additionalDependencies; - } - - @Override - public String release() { - return release; - } - - @Override - public String arch() { - return arch; - } - - private final AppImageLayout packageLayout; - private final String menuGroupName; - private final String category; - private final String additionalDependencies; - private final String release; - private final String arch; - } - - class Proxy extends Package.Proxy implements LinuxPackage { - - public Proxy(T target) { - super(target); - } - - @Override - final public AppImageLayout packageLayout() { - return target.packageLayout(); - } - - @Override - final public String menuGroupName() { - return target.menuGroupName(); - } - - @Override - final public String category() { - return target.category(); - } - - @Override - final public String additionalDependencies() { - return target.additionalDependencies(); - } - - @Override - final public String release() { - return target.release(); - } - - @Override - final public String arch() { - return target.arch(); - } + public static LinuxPackage create(Package pkg, LinuxPackageMixin mixin) { + return DynamicProxy.createProxyFromPieces(LinuxPackage.class, pkg, mixin); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java new file mode 100644 index 0000000000000..417a35bdc15f4 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +public interface LinuxPackageMixin { + + String menuGroupName(); + + String category(); + + String additionalDependencies(); + + String release(); + + String arch(); + + record Stub(AppImageLayout packageLayout, String menuGroupName, + String category, String additionalDependencies, String release, + String arch) implements LinuxPackageMixin { + } +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java index af3fd9e1b6cb6..c8a239a28a170 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java @@ -24,22 +24,11 @@ */ package jdk.jpackage.internal.model; -public interface LinuxRpmPackage extends LinuxPackage { +import jdk.jpackage.internal.util.DynamicProxy; - String licenseType(); +public interface LinuxRpmPackage extends LinuxPackage, LinuxRpmPackageMixin { - final class Stub extends LinuxPackage.Proxy implements LinuxRpmPackage { - - public Stub(LinuxPackage target, String licenseType) { - super(target); - this.licenseType = licenseType; - } - - @Override - public String licenseType() { - return licenseType; - } - - private final String licenseType; + public static LinuxRpmPackage create(LinuxPackage pkg, LinuxRpmPackageMixin mixin) { + return DynamicProxy.createProxyFromPieces(LinuxRpmPackage.class, pkg, mixin); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackageMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackageMixin.java new file mode 100644 index 0000000000000..e599fe42390fc --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackageMixin.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +public interface LinuxRpmPackageMixin { + + String licenseType(); + + record Stub(String licenseType) implements LinuxRpmPackageMixin { + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index a47ee5c1d91ea..1b7a3ce9e03e1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -90,63 +90,6 @@ record Stub(String name, String description, String version, String vendor, List launchers) implements Application { } - class Proxy extends ProxyBase implements Application { - - Proxy(T target) { - super(target); - } - - @Override - final public String name() { - return target.name(); - } - - @Override - final public String description() { - return target.description(); - } - - @Override - final public String version() { - return target.version(); - } - - @Override - final public String vendor() { - return target.vendor(); - } - - @Override - final public String copyright() { - return target.copyright(); - } - - @Override - final public Path srcDir() { - return target.srcDir(); - } - - @Override - final public List contentDirs() { - return target.contentDirs(); - } - - @Override - final public AppImageLayout imageLayout() { - return target.imageLayout(); - } - - @Override - final public RuntimeBuilder runtimeBuilder() { - return target.runtimeBuilder(); - } - - @Override - final public List launchers() { - return target.launchers(); - } - } - class Unsupported implements Application { @Override diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java index 04ae424f392f0..1d977191a3cbd 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java @@ -70,83 +70,13 @@ default Map extraAppImageFileData() { * other value for custom icon. */ Path icon(); - + default String defaultIconResourceName() { return null; } record Stub(String name, LauncherStartupInfo startupInfo, List fileAssociations, boolean isService, - String description, Path icon) implements Launcher { - } - - class Proxy extends ProxyBase implements Launcher { - - public Proxy(T target) { - super(target); - } - - @Override - final public String name() { - return target.name(); - } - - @Override - final public LauncherStartupInfo startupInfo() { - return target.startupInfo(); - } - - @Override - final public List fileAssociations() { - return target.fileAssociations(); - } - - @Override - final public boolean isService() { - return target.isService(); - } - - @Override - final public String description() { - return target.description(); - } - - @Override - final public Path icon() { - return target.icon(); - } - } - - class Unsupported implements Launcher { - - @Override - public String name() { - throw new UnsupportedOperationException(); - } - - @Override - public LauncherStartupInfo startupInfo() { - throw new UnsupportedOperationException(); - } - - @Override - public List fileAssociations() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isService() { - throw new UnsupportedOperationException(); - } - - @Override - public String description() { - throw new UnsupportedOperationException(); - } - - @Override - public Path icon() { - throw new UnsupportedOperationException(); - } + String description, Path icon) implements Launcher { } } From 5879eaf1e8d1f66a38caee71d55f5b97a56f921c Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 10 Nov 2024 10:04:33 -0500 Subject: [PATCH 0132/1101] Bugfix --- .../jdk/jpackage/internal/model/Launcher.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java index 1d977191a3cbd..3af830fc15a86 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java @@ -79,4 +79,38 @@ record Stub(String name, LauncherStartupInfo startupInfo, List fileAssociations, boolean isService, String description, Path icon) implements Launcher { } + + class Unsupported implements Launcher { + + @Override + public String name() { + throw new UnsupportedOperationException(); + } + + @Override + public LauncherStartupInfo startupInfo() { + throw new UnsupportedOperationException(); + } + + @Override + public List fileAssociations() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isService() { + throw new UnsupportedOperationException(); + } + + @Override + public String description() { + throw new UnsupportedOperationException(); + } + + @Override + public Path icon() { + throw new UnsupportedOperationException(); + } + + } } From e339359289109e61626aad9c9f6ffdd5f2c97d8d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 10 Nov 2024 22:40:50 -0500 Subject: [PATCH 0133/1101] Revert property name change --- .../jdk/jpackage/internal/resources/MainResources.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index f32fd4850a380..4b68afba97159 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -80,7 +80,7 @@ error.no.name.advice=Specify name with --name warning.no.jdk.modules.found=Warning: No JDK Modules found error.foreign-app-image=Error: Missing {0} file in app-image dir -error.invalid-app-image-file=app-image dir generated by another jpackage version or malformed {0} file +error.invalid-app-image=app-image dir generated by another jpackage version or malformed {0} file error.invalid-install-dir=Invalid installation directory "{0}" From 11e6321ad9893b05572b738ffaef52b86194ae36 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 11 Nov 2024 15:01:19 -0500 Subject: [PATCH 0134/1101] Added unit tests for DynamicProxy and fixed revealed bugs. --- .../jpackage/internal/util/DynamicProxy.java | 109 +++++++++++++--- .../internal/util/DynamicProxyTest.java | 121 ++++++++++++++++++ 2 files changed, 214 insertions(+), 16 deletions(-) create mode 100644 test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java index 67e32815703f5..4b2175ebe26a1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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,14 +29,21 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; -import java.util.function.Predicate; +import java.util.function.BinaryOperator; import static java.util.stream.Collectors.toMap; import java.util.stream.Stream; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; public final class DynamicProxy { public static T createProxyFromPieces(Class interfaceType, Object ... pieces) { + return createProxyFromPieces(interfaceType, STANDARD_CONFLICT_RESOLVER, pieces); + } + + public static T createProxyFromPieces(Class interfaceType, + BinaryOperator conflictResolver, Object... pieces) { if (!interfaceType.isInterface()) { throw new IllegalArgumentException(String.format( "Type %s must be an interface", interfaceType.getName())); @@ -56,7 +63,7 @@ public static T createProxyFromPieces(Class interfaceType, Object ... pie return Set.of(obj.getClass().getInterfaces()).contains(iface); }).reduce((a, b) -> { throw new IllegalArgumentException(String.format( - "Both [%s] and [%s] objects implement %s", a, b, + "Both [%s] and [%s] pieces implement %s", a, b, iface)); }).orElseThrow(() -> createInterfaceNotImplementedException(List.of(iface))); })); @@ -71,22 +78,56 @@ public static T createProxyFromPieces(Class interfaceType, Object ... pie throw createInterfaceNotImplementedException(missingInterfaces); } - var methodDispatch = Stream.of(interfaces) - .map(Class::getMethods) - .flatMap(Stream::of) - .filter(Predicate.not(Method::isDefault)) - .collect(toMap(x -> x, method -> { - return interfaceDispatch.get(method.getDeclaringClass()); - })); + Map methodDispatch = Stream.of(interfaceType.getMethods()) + .map(method -> { + final var methodDeclaringClass = method.getDeclaringClass(); + if (!methodDeclaringClass.equals(interfaceType)) { + var piece = interfaceDispatch.get(methodDeclaringClass); + var pieceMethod = toSupplier( + () -> piece.getClass().getMethod( + method.getName(), + method.getParameterTypes())).get(); + if (!method.isDefault()) { + return Map.entry(method, new Handler(piece, pieceMethod)); + } else if (method.equals(pieceMethod)) { + // The handler class doesn't override the default method + // of the interface, don't add it to the dispatch map. + return null; + } else { + return Map.entry(method, new Handler(piece, pieceMethod)); + } + } else if (method.isDefault()) { + return null; + } else { + // Find a piece handling the method. + var handler = interfaceDispatch.values().stream().map(piece -> { + try { + return new Handler(piece, + piece.getClass().getMethod( + method.getName(), + method.getParameterTypes())); + } catch (NoSuchMethodException ex) { + return null; + } + }).filter(Objects::nonNull).reduce(new ConflictResolverAdapter(conflictResolver)).orElseThrow(() -> { + return new IllegalArgumentException(String.format( + "None of the pieces can handle %s", method)); + }); + + return Map.entry(method, handler); + } + }) + .filter(Objects::nonNull) + .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); return createProxy(interfaceType, methodDispatch); } @SuppressWarnings("unchecked") - private static T createProxy(Class interfaceType, Map dispatch) { + private static T createProxy(Class interfaceType, Map dispatch) { return (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), new Class[]{interfaceType}, - new DynamicMixinInvocationHandler(dispatch)); + new DynamicProxyInvocationHandler(dispatch)); } private static IllegalArgumentException createInterfaceNotImplementedException( @@ -95,16 +136,52 @@ private static IllegalArgumentException createInterfaceNotImplementedException( "None of the pieces implement %s", missingInterfaces)); } - private record DynamicMixinInvocationHandler(Map dispatch) implements InvocationHandler { + private record DynamicProxyInvocationHandler(Map dispatch) implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (method.isDefault()) { + var handler = dispatch.get(method); + if (handler != null) { + return handler.invoke(args); + } else if (method.isDefault()) { return InvocationHandler.invokeDefault(proxy, method, args); } else { - var handler = dispatch.get(method); - return method.invoke(handler, args); + throw new UnsupportedOperationException(String.format("No handler for %s", method)); + } + } + } + + private record Handler(Object obj, Method method) { + Object invoke(Object[] args) throws Throwable { + return method.invoke(obj, args); + } + } + + private record ConflictResolverAdapter( + BinaryOperator conflictResolver) implements + BinaryOperator { + + @Override + public Handler apply(Handler a, Handler b) { + var m = conflictResolver.apply(a.method, b.method); + if (m == a.method) { + return a; + } else if (m == b.method) { + return b; + } else { + throw new UnsupportedOperationException(); } } } + + public static final BinaryOperator STANDARD_CONFLICT_RESOLVER = (a, b) -> { + if (a.isDefault() == b.isDefault()) { + throw new IllegalArgumentException(String.format( + "Ambiguous choice between %s and %s", a, b)); + } else if (!a.isDefault()) { + return a; + } else { + return b; + } + }; } diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java new file mode 100644 index 0000000000000..2a65c261411d7 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class DynamicProxyTest { + + static interface Smalltalk { + + default String sayHello() { + return "Hello"; + } + + default String sayBye() { + return "Bye"; + } + } + + static interface ConvoMixin { + + String sayThings(); + + record Stub(String sayThings) implements ConvoMixin { + } + } + + static interface Convo extends Smalltalk, ConvoMixin { + } + + static interface ConvoMixinWithOverrideSayBye { + + String sayThings(); + + String sayBye(); + + record Stub(String sayThings, String sayBye) implements ConvoMixinWithOverrideSayBye { + } + } + + static interface ConvoWithOverrideSayBye extends Smalltalk, ConvoMixinWithOverrideSayBye { + @Override + String sayBye(); + } + + @Test + public void testSmalltalk() { + var convo = DynamicProxy.createProxyFromPieces(Smalltalk.class); + assertEquals("Hello", convo.sayHello()); + assertEquals("Bye", convo.sayBye()); + } + + @Test + public void testConvo() { + final var otherThings = "How is your day?"; + var convo = DynamicProxy.createProxyFromPieces(Convo.class, + new Smalltalk() {}, new ConvoMixin.Stub(otherThings)); + assertEquals("Hello", convo.sayHello()); + assertEquals("Bye", convo.sayBye()); + assertEquals(otherThings, convo.sayThings()); + } + + @Test + public void testConvoWithDuke() { + final var otherThings = "How is your day?"; + var convo = DynamicProxy.createProxyFromPieces(Convo.class, new Smalltalk() { + @Override + public String sayHello() { + return "Hello, Duke"; + } + }, new ConvoMixin.Stub(otherThings)); + assertEquals("Hello, Duke", convo.sayHello()); + assertEquals("Bye", convo.sayBye()); + assertEquals(otherThings, convo.sayThings()); + } + + @Test + public void testConvoWithCustomSayBye() { + var mixin = new ConvoMixinWithOverrideSayBye.Stub("How is your day?", "See you"); + + var convo = DynamicProxy.createProxyFromPieces(ConvoWithOverrideSayBye.class, new Smalltalk() {}, mixin); + + var expectedConvo = new ConvoWithOverrideSayBye() { + @Override + public String sayBye() { + return mixin.sayBye; + } + + @Override + public String sayThings() { + return mixin.sayThings; + } + }; + + assertEquals(expectedConvo.sayHello(), convo.sayHello()); + assertEquals(expectedConvo.sayBye(), convo.sayBye()); + assertEquals(((Smalltalk)expectedConvo).sayBye(), convo.sayBye()); + assertEquals(expectedConvo.sayThings(), convo.sayThings()); + } +} From 9a8fd80ef091aa7b94a0b60dbc2dc957333735e8 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 11 Nov 2024 15:12:03 -0500 Subject: [PATCH 0135/1101] Add a test case for DynamicProxyTest --- .../internal/util/DynamicProxyTest.java | 57 +++++++++++++++---- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java index 2a65c261411d7..f548993c53c0e 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java @@ -48,22 +48,32 @@ record Stub(String sayThings) implements ConvoMixin { static interface Convo extends Smalltalk, ConvoMixin { } - + static interface ConvoMixinWithOverrideSayBye { String sayThings(); - + String sayBye(); record Stub(String sayThings, String sayBye) implements ConvoMixinWithOverrideSayBye { } } - + static interface ConvoWithOverrideSayBye extends Smalltalk, ConvoMixinWithOverrideSayBye { @Override - String sayBye(); + String sayBye(); + } + + static interface ConvoWithDefaultSayHelloWithOverrideSayBye extends Smalltalk, ConvoMixinWithOverrideSayBye { + @Override + String sayBye(); + + @Override + default String sayHello() { + return "Ciao"; + } } - + @Test public void testSmalltalk() { var convo = DynamicProxy.createProxyFromPieces(Smalltalk.class); @@ -80,7 +90,7 @@ public void testConvo() { assertEquals("Bye", convo.sayBye()); assertEquals(otherThings, convo.sayThings()); } - + @Test public void testConvoWithDuke() { final var otherThings = "How is your day?"; @@ -94,13 +104,13 @@ public String sayHello() { assertEquals("Bye", convo.sayBye()); assertEquals(otherThings, convo.sayThings()); } - + @Test public void testConvoWithCustomSayBye() { var mixin = new ConvoMixinWithOverrideSayBye.Stub("How is your day?", "See you"); - + var convo = DynamicProxy.createProxyFromPieces(ConvoWithOverrideSayBye.class, new Smalltalk() {}, mixin); - + var expectedConvo = new ConvoWithOverrideSayBye() { @Override public String sayBye() { @@ -110,12 +120,35 @@ public String sayBye() { @Override public String sayThings() { return mixin.sayThings; - } + } }; - + + assertEquals(expectedConvo.sayHello(), convo.sayHello()); + assertEquals(expectedConvo.sayBye(), convo.sayBye()); + assertEquals(expectedConvo.sayThings(), convo.sayThings()); + } + + @Test + public void testConvoWithCustomSayHelloAndSayBye() { + var mixin = new ConvoMixinWithOverrideSayBye.Stub("How is your day?", "See you"); + + var convo = DynamicProxy.createProxyFromPieces(ConvoWithDefaultSayHelloWithOverrideSayBye.class, new Smalltalk() {}, mixin); + + var expectedConvo = new ConvoWithDefaultSayHelloWithOverrideSayBye() { + @Override + public String sayBye() { + return mixin.sayBye; + } + + @Override + public String sayThings() { + return mixin.sayThings; + } + }; + + assertEquals("Ciao", expectedConvo.sayHello()); assertEquals(expectedConvo.sayHello(), convo.sayHello()); assertEquals(expectedConvo.sayBye(), convo.sayBye()); - assertEquals(((Smalltalk)expectedConvo).sayBye(), convo.sayBye()); assertEquals(expectedConvo.sayThings(), convo.sayThings()); } } From 7ee562cfcd6e758f7df4c6765a45964a66bc8a73 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 11 Nov 2024 16:53:25 -0500 Subject: [PATCH 0136/1101] Get rid of ProxyBase class --- .../jpackage/internal/DesktopIntegration.java | 31 ++-- .../internal/LinuxAppImageBuilder.java | 2 +- .../internal/LinuxApplicationLayout.java | 24 +-- .../LinuxApplicationLayoutMixin.java} | 18 +-- .../internal/LinuxPackageBuilder.java | 2 +- .../internal/model/LinuxPackageMixin.java | 2 + .../internal/LauncherStartupInfoBuilder.java | 10 +- .../internal/model/ApplicationLayout.java | 145 +++--------------- .../model/ApplicationLayoutMixin.java | 61 ++++++++ .../internal/model/FileAssociation.java | 31 +--- .../model/LauncherJarStartupInfo.java | 38 +---- .../model/LauncherJarStartupInfoMixin.java | 40 +++++ .../model/LauncherModularStartupInfo.java | 36 +---- ...a => LauncherModularStartupInfoMixin.java} | 15 +- .../internal/model/LauncherStartupInfo.java | 28 ---- .../jdk/jpackage/internal/model/Package.java | 100 ------------ .../internal/model/RuntimeLayout.java | 15 +- .../jpackage/internal/util/DynamicProxy.java | 2 + 18 files changed, 209 insertions(+), 391 deletions(-) rename src/jdk.jpackage/{share/classes/jdk/jpackage/internal/model/RuntimeLayoutStub.java => linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java} (78%) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/{ProxyBase.java => LauncherModularStartupInfoMixin.java} (82%) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 10d0201559a0e..c654a40bd0bdf 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -48,6 +48,7 @@ import javax.xml.stream.XMLStreamWriter; import static jdk.jpackage.internal.AppImageBuilder.createLauncherIconResource; import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.util.DynamicProxy; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.XmlUtils; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; @@ -68,7 +69,7 @@ final class DesktopIntegration extends ShellCustomAction { private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launcher) throws IOException { associations = launcher.fileAssociations().stream().map( - LinuxFileAssociation::new).toList(); + LinuxFileAssociation::create).toList(); this.env = env; this.pkg = pkg; @@ -398,8 +399,7 @@ private void addFileAssociationIconFiles(ShellCommands shellCommands) IOUtils.copyFile(fa.icon(), faIconFile.srcPath()); - shellCommands.addIcon(mimeType, faIconFile.installPath(), - fa.iconSize); + shellCommands.addIcon(mimeType, faIconFile.installPath(), fa.iconSize()); } } @@ -453,15 +453,22 @@ private static int normalizeIconSize(int iconSize) { return commonIconSize; } - private static class LinuxFileAssociation extends FileAssociation.Proxy { - LinuxFileAssociation(FileAssociation fa) { - this(fa, getIconSize(fa)); - } + private interface LinuxFileAssociationMixin { + int iconSize(); + + record Stub(int iconSize) implements LinuxFileAssociationMixin {} + } - private LinuxFileAssociation(FileAssociation fa, int iconSize) { - super(iconSize > 0 ? fa : new FileAssociation.Stub(fa.description(), - fa.icon(), fa.mimeType(), fa.extension())); - this.iconSize = iconSize; + private static interface LinuxFileAssociation extends FileAssociation, LinuxFileAssociationMixin { + static LinuxFileAssociation create(FileAssociation fa) { + var iconSize = getIconSize(fa); + if (iconSize <= 0) { + // nullify the icon + fa = new FileAssociation.Stub(fa.description(), null, + fa.mimeType(), fa.extension()); + } + return DynamicProxy.createProxyFromPieces(LinuxFileAssociation.class, + fa, new LinuxFileAssociationMixin.Stub(iconSize)); } private static int getIconSize(FileAssociation fa) { @@ -471,8 +478,6 @@ private static int getIconSize(FileAssociation fa) { .map(DesktopIntegration::getSquareSizeOfImage) .orElse(-1); } - - private final int iconSize; } private final BuildEnv env; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index 3e3dd02be76b7..1617f920adbe1 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -62,6 +62,6 @@ public void onLauncher(Application app, } } - final static LinuxApplicationLayout APPLICATION_LAYOUT = new LinuxApplicationLayout( + final static LinuxApplicationLayout APPLICATION_LAYOUT = LinuxApplicationLayout.create( ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT, Path.of("lib/libapplauncher.so")); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java index 479c04632f36e..622ae6f1e75b5 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java @@ -26,27 +26,19 @@ import jdk.jpackage.internal.model.*; import java.nio.file.Path; +import jdk.jpackage.internal.util.DynamicProxy; import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; -final class LinuxApplicationLayout extends ApplicationLayout.Proxy { +interface LinuxApplicationLayout extends ApplicationLayout, LinuxApplicationLayoutMixin { - LinuxApplicationLayout(ApplicationLayout layout, Path libAppLauncher) { - super(layout); - this.libAppLauncher = libAppLauncher; + static LinuxApplicationLayout create(ApplicationLayout layout, Path libAppLauncher) { + return DynamicProxy.createProxyFromPieces(LinuxApplicationLayout.class, + layout, new LinuxApplicationLayoutMixin.Stub(libAppLauncher)); } @Override - public LinuxApplicationLayout resolveAt(Path root) { - return new LinuxApplicationLayout(target.resolveAt(root), - resolveNullablePath(root, libAppLauncher)); + default LinuxApplicationLayout resolveAt(Path root) { + return create(ApplicationLayout.super.resolveAt(root), + resolveNullablePath(root, libAppLauncher())); } - - /** - * Path to "libapplauncher.so". - */ - Path libAppLauncher() { - return libAppLauncher; - } - - private final Path libAppLauncher; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayoutStub.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java similarity index 78% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayoutStub.java rename to src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java index 69d12a21f43c3..a847fcd1690bb 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayoutStub.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java @@ -22,18 +22,16 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal.model; +package jdk.jpackage.internal; import java.nio.file.Path; -final class RuntimeLayoutStub extends AppImageLayout.Proxy implements RuntimeLayout { - - RuntimeLayoutStub(AppImageLayout target) { - super(target); - } +interface LinuxApplicationLayoutMixin { - @Override - public RuntimeLayout resolveAt(Path root) { - return new RuntimeLayoutStub(target.resolveAt(root)); - } + /** + * Path to "libapplauncher.so". + */ + Path libAppLauncher(); + + record Stub(Path libAppLauncher) implements LinuxApplicationLayoutMixin {} } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index 1d28332b9cb70..2dd26c3660f52 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -103,7 +103,7 @@ LinuxPackageBuilder release(String v) { private static LinuxApplicationLayout usrTreePackageLayout(Path prefix, String packageName) { final var lib = prefix.resolve(Path.of("lib", packageName)); - return new LinuxApplicationLayout( + return LinuxApplicationLayout.create( ApplicationLayout.build() .launchersDirectory(prefix.resolve("bin")) .appDirectory(lib.resolve("app")) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java index 417a35bdc15f4..d263d670f91af 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java @@ -26,6 +26,8 @@ public interface LinuxPackageMixin { + AppImageLayout packageLayout(); + String menuGroupName(); String category(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java index 73446b0540ba6..85a48ac4200e6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java @@ -28,7 +28,9 @@ import java.util.List; import java.util.function.UnaryOperator; import jdk.jpackage.internal.model.LauncherJarStartupInfo; +import jdk.jpackage.internal.model.LauncherJarStartupInfoMixin; import jdk.jpackage.internal.model.LauncherModularStartupInfo; +import jdk.jpackage.internal.model.LauncherModularStartupInfoMixin; import jdk.jpackage.internal.model.LauncherStartupInfo.Stub; import jdk.jpackage.internal.model.LauncherStartupInfo; @@ -67,7 +69,9 @@ private static record ModuleStartupInfo(String moduleName, @Override public LauncherStartupInfo apply(LauncherStartupInfo base) { - return new LauncherModularStartupInfo.Stub(base, moduleName, modulePath); + return LauncherModularStartupInfo.create(base, + new LauncherModularStartupInfoMixin.Stub(moduleName, + modulePath)); } } @@ -77,7 +81,9 @@ private static record JarStartupInfo(Path jarPath, @Override public LauncherStartupInfo apply(LauncherStartupInfo base) { - return new LauncherJarStartupInfo.Stub(base, jarPath, isClassNameFromMainJar); + return LauncherJarStartupInfo.create(base, + new LauncherJarStartupInfoMixin.Stub(jarPath, + isClassNameFromMainJar)); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index b37ee37b5965f..e6b530a33b9ee 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -25,94 +25,21 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import jdk.jpackage.internal.util.DynamicProxy; import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; /** * Application directory layout. */ -public interface ApplicationLayout extends AppImageLayout { - - /** - * Path to launchers directory. - */ - Path launchersDirectory(); - - /** - * Path to application data directory. - */ - Path appDirectory(); - - /** - * Path to application mods directory. - */ - Path appModsDirectory(); - - /** - * Path to directory with application's desktop integration files. - */ - Path destktopIntegrationDirectory(); - - /** - * Path to directory with additional application content. - */ - Path contentDirectory(); +public interface ApplicationLayout extends AppImageLayout, ApplicationLayoutMixin { @Override - ApplicationLayout resolveAt(Path root); - - final class Stub extends AppImageLayout.Proxy implements ApplicationLayout { - - public Stub(AppImageLayout target, Path launchersDirectory, - Path appDirectory, Path appModsDirectory, - Path destktopIntegrationDirectory, Path contentDirectory) { - super(target); - this.launchersDirectory = launchersDirectory; - this.appDirectory = appDirectory; - this.appModsDirectory = appModsDirectory; - this.destktopIntegrationDirectory = destktopIntegrationDirectory; - this.contentDirectory = contentDirectory; - } - - @Override - public Path launchersDirectory() { - return launchersDirectory; - } - - @Override - public Path appDirectory() { - return appDirectory; - } - - @Override - public Path appModsDirectory() { - return appModsDirectory; - } - - @Override - public Path destktopIntegrationDirectory() { - return destktopIntegrationDirectory; - } - - @Override - public Path contentDirectory() { - return contentDirectory; - } - - @Override - public ApplicationLayout resolveAt(Path base) { - return new ApplicationLayout.Stub(target.resolveAt(base), - resolveNullablePath(base, launchersDirectory), - resolveNullablePath(base, appDirectory), - resolveNullablePath(base, appModsDirectory), - resolveNullablePath(base, destktopIntegrationDirectory), - resolveNullablePath(base, contentDirectory)); - } + default ApplicationLayout resolveAt(Path root) { + return buildFrom(this).resolveAt(root).create(); + } - private final Path launchersDirectory; - private final Path appDirectory; - private final Path appModsDirectory; - private final Path destktopIntegrationDirectory; - private final Path contentDirectory; + static ApplicationLayout create(AppImageLayout appImage, ApplicationLayoutMixin mixin) { + return DynamicProxy.createProxyFromPieces(ApplicationLayout.class, appImage, mixin); } public static Builder build() { @@ -123,43 +50,6 @@ public static Builder buildFrom(ApplicationLayout appLayout) { return new Builder(appLayout); } - class Proxy extends AppImageLayout.Proxy implements ApplicationLayout { - - public Proxy(T target) { - super(target); - } - - @Override - final public Path launchersDirectory() { - return target.launchersDirectory(); - } - - @Override - final public Path appDirectory() { - return target.appDirectory(); - } - - @Override - final public Path appModsDirectory() { - return target.appModsDirectory(); - } - - @Override - final public Path destktopIntegrationDirectory() { - return target.destktopIntegrationDirectory(); - } - - @Override - final public Path contentDirectory() { - return target.contentDirectory(); - } - - @Override - public ApplicationLayout resolveAt(Path root) { - return target.resolveAt(root); - } - } - final class Builder { private Builder() { } @@ -174,13 +64,10 @@ private Builder(ApplicationLayout appLayout) { } public ApplicationLayout create() { - return new ApplicationLayout.Stub( - new AppImageLayout.Stub(runtimeDirectory), - launchersDirectory, - appDirectory, - appModsDirectory, - destktopIntegrationDirectory, - contentDirectory); + return ApplicationLayout.create(new AppImageLayout.Stub( + runtimeDirectory), new ApplicationLayoutMixin.Stub( + launchersDirectory, appDirectory, appModsDirectory, + destktopIntegrationDirectory, contentDirectory)); } public Builder setAll(String path) { @@ -197,6 +84,16 @@ public Builder setAll(Path path) { return this; } + public Builder resolveAt(Path base) { + launchersDirectory(resolveNullablePath(base, launchersDirectory)); + appDirectory(resolveNullablePath(base, appDirectory)); + runtimeDirectory(resolveNullablePath(base, runtimeDirectory)); + appModsDirectory(resolveNullablePath(base, appModsDirectory)); + destktopIntegrationDirectory(resolveNullablePath(base, destktopIntegrationDirectory)); + contentDirectory(resolveNullablePath(base, contentDirectory)); + return this; + } + public Builder launchersDirectory(String v) { return launchersDirectory(Path.of(v)); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java new file mode 100644 index 0000000000000..590f61fc0c1cc --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.nio.file.Path; + +/** + * App image directory contents specific to application packaging. + */ +public interface ApplicationLayoutMixin { + + /** + * Path to launchers directory. + */ + Path launchersDirectory(); + + /** + * Path to application data directory. + */ + Path appDirectory(); + + /** + * Path to application mods directory. + */ + Path appModsDirectory(); + + /** + * Path to directory with application's desktop integration files. + */ + Path destktopIntegrationDirectory(); + + /** + * Path to directory with additional application content. + */ + Path contentDirectory(); + + record Stub(Path launchersDirectory, Path appDirectory, Path appModsDirectory, Path destktopIntegrationDirectory, Path contentDirectory) implements ApplicationLayoutMixin { + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java index def53071d8bef..3feb6384f0f39 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java @@ -34,11 +34,11 @@ public interface FileAssociation { String description(); Path icon(); - + default boolean hasIcon() { return Objects.nonNull(icon()); } - + default boolean hasNonEmptyDescription() { return Optional.ofNullable(description()).filter(Predicate.not(String::isEmpty)).isPresent(); } @@ -49,31 +49,4 @@ default boolean hasNonEmptyDescription() { record Stub(String description, Path icon, String mimeType, String extension) implements FileAssociation { } - - class Proxy extends ProxyBase implements FileAssociation { - - protected Proxy(T target) { - super(target); - } - - @Override - final public String description() { - return target.description(); - } - - @Override - final public Path icon() { - return target.icon(); - } - - @Override - final public String mimeType() { - return target.mimeType(); - } - - @Override - final public String extension() { - return target.extension(); - } - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java index e10ba7470a303..e7271330319cf 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java @@ -24,38 +24,14 @@ */ package jdk.jpackage.internal.model; -import java.nio.file.Path; +import jdk.jpackage.internal.util.DynamicProxy; -public interface LauncherJarStartupInfo extends LauncherStartupInfo { - /** - * Returns path to the main jar relative to app's main source directory. - * - * @see jdk.jpackage.internal.model.Application#srcDir() - */ - Path jarPath(); +public interface LauncherJarStartupInfo extends LauncherStartupInfo, + LauncherJarStartupInfoMixin { - boolean isClassNameFromMainJar(); - - final class Stub extends LauncherStartupInfo.Proxy - implements LauncherJarStartupInfo { - - public Stub(LauncherStartupInfo target, Path jarPath, boolean isClassNameFromMainJar) { - super(target); - this.jarPath = jarPath; - this.isClassNameFromMainJar = isClassNameFromMainJar; - } - - @Override - public Path jarPath() { - return jarPath; - } - - @Override - public boolean isClassNameFromMainJar() { - return isClassNameFromMainJar; - } - - private final Path jarPath; - private final boolean isClassNameFromMainJar; + public static LauncherJarStartupInfo create(LauncherStartupInfo info, + LauncherJarStartupInfoMixin mixin) { + return DynamicProxy.createProxyFromPieces(LauncherJarStartupInfo.class, + info, mixin); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java new file mode 100644 index 0000000000000..f75971b6d7b69 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.nio.file.Path; + +public interface LauncherJarStartupInfoMixin { + /** + * Returns path to the main jar relative to app's main source directory. + * + * @see jdk.jpackage.internal.model.Application#srcDir() + */ + Path jarPath(); + + boolean isClassNameFromMainJar(); + + record Stub(Path jarPath, boolean isClassNameFromMainJar) implements LauncherJarStartupInfoMixin {} +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java index 85fcaf396a5fc..45126ca0b186b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java @@ -24,36 +24,14 @@ */ package jdk.jpackage.internal.model; -import java.nio.file.Path; -import java.util.List; +import jdk.jpackage.internal.util.DynamicProxy; -public interface LauncherModularStartupInfo extends LauncherStartupInfo { +public interface LauncherModularStartupInfo extends LauncherStartupInfo, + LauncherModularStartupInfoMixin { - String moduleName(); - - List modulePath(); - - final class Stub extends LauncherStartupInfo.Proxy - implements LauncherModularStartupInfo { - - public Stub(LauncherStartupInfo target, String moduleName, - List modulePath) { - super(target); - this.moduleName = moduleName; - this.modulePath = modulePath; - } - - @Override - public String moduleName() { - return moduleName; - } - - @Override - public List modulePath() { - return modulePath; - } - - private final String moduleName; - private final List modulePath; + public static LauncherModularStartupInfo create(LauncherStartupInfo info, + LauncherModularStartupInfoMixin mixin) { + return DynamicProxy.createProxyFromPieces( + LauncherModularStartupInfo.class, info, mixin); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ProxyBase.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java similarity index 82% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ProxyBase.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java index 66e1b783506d4..81cc13ce3d773 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ProxyBase.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java @@ -24,10 +24,15 @@ */ package jdk.jpackage.internal.model; -abstract class ProxyBase { - protected ProxyBase(T target) { - this.target = target; - } +import java.nio.file.Path; +import java.util.List; + +public interface LauncherModularStartupInfoMixin { + + String moduleName(); - protected final T target; + List modulePath(); + + record Stub(String moduleName, List modulePath) implements LauncherModularStartupInfoMixin { + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java index 7a7f5a8015897..bba8525de5a3e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java @@ -58,34 +58,6 @@ record Stub(String qualifiedClassName, List javaOptions, } - class Proxy extends ProxyBase - implements LauncherStartupInfo { - - public Proxy(T target) { - super(target); - } - - @Override - final public String qualifiedClassName() { - return target.qualifiedClassName(); - } - - @Override - final public List javaOptions() { - return target.javaOptions(); - } - - @Override - final public List defaultParameters() { - return target.defaultParameters(); - } - - @Override - final public List classPath() { - return target.classPath(); - } - } - class Unsupported implements LauncherStartupInfo { @Override diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java index 392e45b87dfd6..53e03c48a7542 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java @@ -143,104 +143,4 @@ record Stub(Application app, PackageType type, String packageName, String description, String version, String aboutURL, Path licenseFile, Path predefinedAppImage, Path relativeInstallDir) implements Package { } - - class Proxy extends ProxyBase implements Package { - - Proxy(T target) { - super(target); - } - - @Override - final public Application app() { - return target.app(); - } - - @Override - final public PackageType type() { - return target.type(); - } - - @Override - final public String packageName() { - return target.packageName(); - } - - @Override - final public String description() { - return target.description(); - } - - @Override - final public String version() { - return target.version(); - } - - @Override - final public String aboutURL() { - return target.aboutURL(); - } - - @Override - final public Path licenseFile() { - return target.licenseFile(); - } - - @Override - final public Path predefinedAppImage() { - return target.predefinedAppImage(); - } - - @Override - final public Path relativeInstallDir() { - return target.relativeInstallDir(); - } - } - - class Unsupported implements Package { - - @Override - public Application app() { - throw new UnsupportedOperationException(); - } - - @Override - public PackageType type() { - throw new UnsupportedOperationException(); - } - - @Override - public String packageName() { - throw new UnsupportedOperationException(); - } - - @Override - public String description() { - throw new UnsupportedOperationException(); - } - - @Override - public String version() { - throw new UnsupportedOperationException(); - } - - @Override - public String aboutURL() { - throw new UnsupportedOperationException(); - } - - @Override - public Path licenseFile() { - throw new UnsupportedOperationException(); - } - - @Override - public Path predefinedAppImage() { - throw new UnsupportedOperationException(); - } - - @Override - public Path relativeInstallDir() { - throw new UnsupportedOperationException(); - } - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java index 7f17309af79f1..f3b9c8c6b76d1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java @@ -25,12 +25,23 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import jdk.jpackage.internal.util.DynamicProxy; +import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; /** - * App image directory layout. + * Runtime app image layout. */ public interface RuntimeLayout extends AppImageLayout { - static final RuntimeLayout DEFAULT = new RuntimeLayoutStub(new AppImageLayout.Stub(Path.of(""))); + @Override + default RuntimeLayout resolveAt(Path root) { + return create(new AppImageLayout.Stub(resolveNullablePath(root, runtimeDirectory()))); + } + + static RuntimeLayout create(AppImageLayout layout) { + return DynamicProxy.createProxyFromPieces(RuntimeLayout.class, layout); + } + + static final RuntimeLayout DEFAULT = create(new AppImageLayout.Stub(Path.of(""))); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java index 4b2175ebe26a1..65ffdcc7b9cab 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java @@ -24,6 +24,7 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Collection; @@ -79,6 +80,7 @@ public static T createProxyFromPieces(Class interfaceType, } Map methodDispatch = Stream.of(interfaceType.getMethods()) + .filter(method -> Modifier.isAbstract(method.getModifiers())) .map(method -> { final var methodDeclaringClass = method.getDeclaringClass(); if (!methodDeclaringClass.equals(interfaceType)) { From 8d3070a61df3cf25f68fca9da179bc065166e9ae Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 11 Nov 2024 16:55:20 -0500 Subject: [PATCH 0137/1101] Narrow down the set of methods from which to build an argument for PathGroup ctor to non-static methods of types derived from AppImageLayout interface. --- .../internal/model/AppImageLayout.java | 45 ++++++++----------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java index ec3f2aeb55b01..47ea5c1936af8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal.model; +import java.lang.reflect.Modifier; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; @@ -55,32 +56,24 @@ public AppImageLayout resolveAt(Path base) { } } - class Proxy extends ProxyBase implements AppImageLayout { - - public Proxy(T target) { - super(target); - } - - @Override - final public Path runtimeDirectory() { - return target.runtimeDirectory(); - } - - @Override - public AppImageLayout resolveAt(Path root) { - return target.resolveAt(root); - } - } - public static PathGroup toPathGroup(AppImageLayout appImageLayout) { - return new PathGroup(Stream.of(appImageLayout.getClass().getMethods()).filter(m -> { - return m.getReturnType().isAssignableFrom(Path.class) && m.getParameterCount() == 0; - }).>mapMulti((m, consumer) -> { - Optional.ofNullable(toFunction(m::invoke).apply(appImageLayout)).ifPresent(path -> { - consumer.accept(Map.entry(m.getName(), (Path)path)); - }); - }).collect(HashMap::new, (ctnr, e) -> { - ctnr.put(e.getKey(), e.getValue()); - }, Map::putAll)); + return new PathGroup(Stream.of(appImageLayout.getClass().getInterfaces()) + // For all interfaces (it should be one, but multiple is OK) + // extending AppImageLayout interface call all non-static methods + // without parameters and with java.nio.file.Path return type. + // Create a map from the names of methods called and return values. + .filter(AppImageLayout.class::isAssignableFrom) + .map(Class::getMethods) + .flatMap(Stream::of) + .filter(m -> !Modifier.isStatic(m.getModifiers())) + .filter(m -> { + return m.getReturnType().isAssignableFrom(Path.class) && m.getParameterCount() == 0; + }).>mapMulti((m, consumer) -> { + Optional.ofNullable(toFunction(m::invoke).apply(appImageLayout)).ifPresent(path -> { + consumer.accept(Map.entry(m.getName(), (Path)path)); + }); + }).collect(HashMap::new, (ctnr, e) -> { + ctnr.put(e.getKey(), e.getValue()); + }, Map::putAll)); } } From 0ebe7040db5180a58da9d740a6153b40eb9af356 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 11 Nov 2024 19:18:08 -0500 Subject: [PATCH 0138/1101] Fix DynamicProxy after running all test cases in DynamicProxyTest --- .../share/classes/jdk/jpackage/internal/util/DynamicProxy.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java index 65ffdcc7b9cab..26af5ea4223cb 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java @@ -80,7 +80,6 @@ public static T createProxyFromPieces(Class interfaceType, } Map methodDispatch = Stream.of(interfaceType.getMethods()) - .filter(method -> Modifier.isAbstract(method.getModifiers())) .map(method -> { final var methodDeclaringClass = method.getDeclaringClass(); if (!methodDeclaringClass.equals(interfaceType)) { From b970f8397e0c84d3e8946c1e34ecf9c94112bc36 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 11 Nov 2024 19:18:52 -0500 Subject: [PATCH 0139/1101] Remove unused bundle param --- .../classes/jdk/jpackage/internal/MacAppImageBuilder.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java index 3c19da08540a3..f4ece2b8a1b16 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -101,13 +101,6 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { private static List keyChains; - public static final BundlerParamInfo - MAC_CONFIGURE_LAUNCHER_IN_PLIST = new BundlerParamInfo<>( - "mac.configure-launcher-in-plist", - Boolean.class, - params -> Boolean.FALSE, - (s, p) -> Boolean.valueOf(s)); - public static final BundlerParamInfo MAC_CF_BUNDLE_NAME = new BundlerParamInfo<>( Arguments.CLIOptions.MAC_BUNDLE_NAME.getId(), From 58aedb0b58d4a366aba5ca619c25eda37e229818 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 11 Nov 2024 19:31:55 -0500 Subject: [PATCH 0140/1101] Add test case to DynamicProxyTest for interface with static method(s) --- .../classes/jdk/jpackage/internal/util/DynamicProxy.java | 1 + .../jdk/jpackage/internal/util/DynamicProxyTest.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java index 26af5ea4223cb..6f917673e9366 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java @@ -80,6 +80,7 @@ public static T createProxyFromPieces(Class interfaceType, } Map methodDispatch = Stream.of(interfaceType.getMethods()) + .filter(method-> !Modifier.isStatic(method.getModifiers())) .map(method -> { final var methodDeclaringClass = method.getDeclaringClass(); if (!methodDeclaringClass.equals(interfaceType)) { diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java index f548993c53c0e..289d534c98d36 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java @@ -72,6 +72,10 @@ static interface ConvoWithDefaultSayHelloWithOverrideSayBye extends Smalltalk, C default String sayHello() { return "Ciao"; } + + static String saySomething() { + return "blah"; + } } @Test From 3dd75114785d9e14c2e2bb3407b5e32143e40111 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 11 Nov 2024 21:39:00 -0500 Subject: [PATCH 0141/1101] Fix AppImageFileTest and make AppImageFile2 work with the current error message strings --- .../classes/jdk/jpackage/internal/AppImageFile2.java | 10 ++++++---- .../classes/jdk/jpackage/internal/FromParams.java | 2 +- .../jdk/jpackage/internal/StandardBundlerParam.java | 12 +++++------- .../internal/resources/MainResources.properties | 4 ++-- .../jdk/jpackage/internal/AppImageFileTest.java | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index faaaf37d80ce1..a841aaba33b0c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -166,10 +166,11 @@ static Path getPathInAppImage(ApplicationLayout appLayout) { /** * Loads application image info from application image. + * @param appImageDir - path at which to resolve the given application layout * @param appLayout - application layout */ - static AppImageFile2 load(ApplicationLayout appLayout) throws ConfigException, IOException { - var srcFilePath = getPathInAppImage(appLayout); + static AppImageFile2 load(Path appImageDir, ApplicationLayout appLayout) throws ConfigException, IOException { + var srcFilePath = getPathInAppImage(appLayout.resolveAt(appImageDir)); try { Document doc = XmlUtils.initDocumentBuilder().parse(Files.newInputStream(srcFilePath)); @@ -249,10 +250,11 @@ public Map extraAppImageFileData() { // Exception reading input XML (probably malformed XML) throw new IOException(ex); } catch (NoSuchFileException ex) { - throw buildConfigException("error.foreign-app-image", FILENAME).create(); + throw buildConfigException("error.foreign-app-image", appImageDir).create(); } catch (InavlidAppImageFileException ex) { // Invalid input XML - throw buildConfigException("error.invalid-app-image-file", FILENAME).create(); + throw buildConfigException("error.invalid-app-image", appImageDir, + FILENAME).create(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java index e8853f2313022..6ebd912942c02 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -90,7 +90,7 @@ static ApplicationBuilder createApplicationBuilder(Map p if (isRuntimeInstaller) { } else if (predefinedAppImage != null) { - var appIMafeFile = AppImageFile2.load(appLayout.resolveAt(predefinedAppImage)); + var appIMafeFile = AppImageFile2.load(predefinedAppImage, appLayout); appBuilder.initFromAppImage(appIMafeFile, launcherInfo -> { var launcherParams = mapLauncherInfo(launcherInfo); return launcherMapper.apply(mergeParams(params, launcherParams)); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index 204a99825464a..8c905ba3ee6f1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -40,13 +40,12 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.BiFunction; -import java.util.function.Function; import java.util.stream.Stream; import static jdk.jpackage.internal.ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT; import jdk.jpackage.internal.util.function.ThrowingFunction; import jdk.jpackage.internal.resources.ResourceLocator; import static jdk.jpackage.internal.model.RuntimeBuilder.getDefaultModulePath; +import static jdk.jpackage.internal.util.function.ThrowingBiFunction.toBiFunction; /** * Standard bundler parameters. @@ -117,8 +116,8 @@ final class StandardBundlerParam { return null; } else if (hasPredefinedAppImage(params)) { var appImage = getPredefinedAppImage(params); - var appLayout = PLATFORM_APPLICATION_LAYOUT.resolveAt(appImage); - return ThrowingFunction.toFunction(AppImageFile2::load).apply(appLayout).getMainClass(); + return toBiFunction(AppImageFile2::load).apply( + appImage, PLATFORM_APPLICATION_LAYOUT).getMainClass(); } return LAUNCHER_DATA.fetchFrom(params).qualifiedClassName(); }, @@ -159,9 +158,8 @@ final class StandardBundlerParam { Path appImage = PREDEFINED_APP_IMAGE.fetchFrom(params); String appName = NAME.fetchFrom(params); if (appImage != null) { - var appLayout = PLATFORM_APPLICATION_LAYOUT.resolveAt(appImage); - String name = ThrowingFunction.toFunction( - AppImageFile2::load).apply(appLayout).getLauncherName(); + String name = toBiFunction(AppImageFile2::load).apply( + appImage, PLATFORM_APPLICATION_LAYOUT).getLauncherName(); appName = (name != null) ? name : appName; } else if (appName == null) { String s = MAIN_CLASS.fetchFrom(params); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index 4b68afba97159..08d38a080f5ff 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -79,8 +79,8 @@ error.no.name.advice=Specify name with --name warning.no.jdk.modules.found=Warning: No JDK Modules found -error.foreign-app-image=Error: Missing {0} file in app-image dir -error.invalid-app-image=app-image dir generated by another jpackage version or malformed {0} file +error.foreign-app-image=Error: Missing .jpackage.xml file in app-image dir "{0}" +error.invalid-app-image=Error: app-image dir "{0}" generated by another jpackage version or malformed "{1}" file error.invalid-install-dir=Invalid installation directory "{0}" diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java index 4ecadf8600556..a72762a007c38 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java @@ -230,7 +230,7 @@ private void assertInvalid(ThrowingRunnable action) { Assert.assertTrue(ex.getMessage() .contains("generated by another jpackage version or malformed")); Assert.assertTrue(ex.getMessage() - .endsWith(".jpackage.xml\"")); + .endsWith(".jpackage.xml\" file")); } private AppImageFile createFromXml(String... xmlData) throws IOException { From 2d644d10e0b8cac80367ab00fb8a80db8d3771bd Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 12 Nov 2024 09:59:39 -0500 Subject: [PATCH 0142/1101] DynamicProxy refactored to work with LinuxApplicationLayout. It still doesn't work completely. --- .../internal/LinuxApplicationLayout.java | 19 +- .../jpackage/internal/util/DynamicProxy.java | 239 ++++++++++++------ .../internal/util/DynamicProxyTest.java | 31 ++- 3 files changed, 208 insertions(+), 81 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java index 622ae6f1e75b5..081fe06db1625 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java @@ -24,6 +24,9 @@ */ package jdk.jpackage.internal; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import jdk.jpackage.internal.model.*; import java.nio.file.Path; import jdk.jpackage.internal.util.DynamicProxy; @@ -31,9 +34,21 @@ interface LinuxApplicationLayout extends ApplicationLayout, LinuxApplicationLayoutMixin { + final static class Tunnel implements DynamicProxy.DefaultMethodInvoker { + + @Override + public Object invoke(Proxy proxy, Method method, Object[] args) throws + Throwable { + return InvocationHandler.invokeDefault(proxy, method, args); + } + + private final static Tunnel INSTANCE = new Tunnel(); + } + static LinuxApplicationLayout create(ApplicationLayout layout, Path libAppLauncher) { - return DynamicProxy.createProxyFromPieces(LinuxApplicationLayout.class, - layout, new LinuxApplicationLayoutMixin.Stub(libAppLauncher)); + return DynamicProxy.build() + .proxyDefaultMethodInvoker(Tunnel.INSTANCE) + .create(LinuxApplicationLayout.class, layout, new LinuxApplicationLayoutMixin.Stub(libAppLauncher)); } @Override diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java index 6f917673e9366..5f3e1849b527c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.BinaryOperator; import static java.util.stream.Collectors.toMap; @@ -39,12 +40,116 @@ public final class DynamicProxy { - public static T createProxyFromPieces(Class interfaceType, Object ... pieces) { - return createProxyFromPieces(interfaceType, STANDARD_CONFLICT_RESOLVER, pieces); + public final static class Builder { + + public T create(Class interfaceType, Object... pieces) { + return createProxyFromPieces(interfaceType, conflictResolver, + proxyDefaultMethodInvoker, pieces); + } + + public Builder conflictResolver(BinaryOperator v) { + conflictResolver = v; + return this; + } + + public Builder proxyDefaultMethodInvoker(DefaultMethodInvoker v) { + proxyDefaultMethodInvoker = v; + return this; + } + + private BinaryOperator conflictResolver = STANDARD_CONFLICT_RESOLVER; + private DefaultMethodInvoker proxyDefaultMethodInvoker; + } + + @FunctionalInterface + public interface DefaultMethodInvoker { + Object invoke(Proxy proxy, Method method, Object[] args) throws Throwable; + } + + public static Builder build() { + return new Builder(); } public static T createProxyFromPieces(Class interfaceType, - BinaryOperator conflictResolver, Object... pieces) { + Object... pieces) { + return build().create(interfaceType, pieces); + } + + private static T createProxyFromPieces(Class interfaceType, + BinaryOperator conflictResolver, + DefaultMethodInvoker proxyDefaultMethodInvoker, + Object... pieces) { + + final Map, Object> interfaceDispatch = createInterfaceDispatch( + interfaceType, pieces); + + final Map methodDispatch = getProxyableMethods(interfaceType) + .map(method -> { + var handler = createHandler(interfaceType, method, interfaceDispatch, + conflictResolver, proxyDefaultMethodInvoker); + if (handler != null) { + return Map.entry(method, handler); + } else { + return null; + } + }) + .filter(Objects::nonNull) + .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); + + @SuppressWarnings("unchecked") + T proxy = (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), + new Class[]{interfaceType}, + new DynamicProxyInvocationHandler(methodDispatch)); + + return proxy; + } + + private static IllegalArgumentException createInterfaceNotImplementedException( + Collection> missingInterfaces) { + return new IllegalArgumentException(String.format( + "None of the pieces implement %s", missingInterfaces)); + } + + private static Handler createHandler(Class interfaceType, Method method, + Map, Object> interfaceDispatch, + BinaryOperator conflictResolver, + DefaultMethodInvoker proxyDefaultMethodInvoker) { + + final var methodDeclaringClass = method.getDeclaringClass(); + + if (!methodDeclaringClass.equals(interfaceType)) { + // The method is declared in one of the superintarfaces. + var piece = interfaceDispatch.get(methodDeclaringClass); + var pieceMethod = toSupplier(() -> piece.getClass().getMethod( + method.getName(), method.getParameterTypes())).get(); + if (method.isDefault() && method.equals(pieceMethod)) { + // The handler class doesn't override the default method + // of the interface. + return createDefaultMethodInvoker(method, proxyDefaultMethodInvoker); + } else { + return new MethodInvoker(piece, pieceMethod); + } + } else if (method.isDefault()) { + return createDefaultMethodInvoker(method, proxyDefaultMethodInvoker); + } else { + // Find a piece handling the method. + var handler = interfaceDispatch.values().stream().map(piece -> { + try { + return new MethodInvoker(piece, piece.getClass().getMethod( + method.getName(), method.getParameterTypes())); + } catch (NoSuchMethodException ex) { + return null; + } + }).filter(Objects::nonNull).reduce(new ConflictResolverAdapter(conflictResolver)).orElseThrow(() -> { + return new IllegalArgumentException(String.format( + "None of the pieces can handle %s", method)); + }); + + return handler; + } + } + + private static Map, Object> createInterfaceDispatch(Class interfaceType, Object ... pieces) { if (!interfaceType.isInterface()) { throw new IllegalArgumentException(String.format( "Type %s must be an interface", interfaceType.getName())); @@ -57,21 +162,14 @@ public static T createProxyFromPieces(Class interfaceType, interfaceType.getName(), pieces.length)); } - final Map, Object> interfaceDispatch; - try { - interfaceDispatch = Stream.of(interfaces).collect(toMap(x -> x, iface -> { - return Stream.of(pieces).filter(obj -> { - return Set.of(obj.getClass().getInterfaces()).contains(iface); - }).reduce((a, b) -> { - throw new IllegalArgumentException(String.format( - "Both [%s] and [%s] pieces implement %s", a, b, - iface)); - }).orElseThrow(() -> createInterfaceNotImplementedException(List.of(iface))); - })); - } catch (IllegalStateException ex) { - throw new IllegalArgumentException(String.format( - "Multiple pieces implement the same interface")); - } + final Map, Object> interfaceDispatch = Stream.of(interfaces).collect(toMap(x -> x, iface -> { + return Stream.of(pieces).filter(obj -> { + return Set.of(obj.getClass().getInterfaces()).contains(iface); + }).reduce((a, b) -> { + throw new IllegalArgumentException(String.format( + "Both [%s] and [%s] pieces implement %s", a, b, iface)); + }).orElseThrow(() -> createInterfaceNotImplementedException(List.of(iface))); + })); if (interfaceDispatch.size() != interfaces.length) { final List> missingInterfaces = new ArrayList<>(Set.of(interfaces)); @@ -79,63 +177,22 @@ public static T createProxyFromPieces(Class interfaceType, throw createInterfaceNotImplementedException(missingInterfaces); } - Map methodDispatch = Stream.of(interfaceType.getMethods()) - .filter(method-> !Modifier.isStatic(method.getModifiers())) - .map(method -> { - final var methodDeclaringClass = method.getDeclaringClass(); - if (!methodDeclaringClass.equals(interfaceType)) { - var piece = interfaceDispatch.get(methodDeclaringClass); - var pieceMethod = toSupplier( - () -> piece.getClass().getMethod( - method.getName(), - method.getParameterTypes())).get(); - if (!method.isDefault()) { - return Map.entry(method, new Handler(piece, pieceMethod)); - } else if (method.equals(pieceMethod)) { - // The handler class doesn't override the default method - // of the interface, don't add it to the dispatch map. - return null; - } else { - return Map.entry(method, new Handler(piece, pieceMethod)); - } - } else if (method.isDefault()) { - return null; - } else { - // Find a piece handling the method. - var handler = interfaceDispatch.values().stream().map(piece -> { - try { - return new Handler(piece, - piece.getClass().getMethod( - method.getName(), - method.getParameterTypes())); - } catch (NoSuchMethodException ex) { - return null; - } - }).filter(Objects::nonNull).reduce(new ConflictResolverAdapter(conflictResolver)).orElseThrow(() -> { - return new IllegalArgumentException(String.format( - "None of the pieces can handle %s", method)); - }); - - return Map.entry(method, handler); - } - }) - .filter(Objects::nonNull) - .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); - - return createProxy(interfaceType, methodDispatch); + return Stream.of(interfaces).flatMap(iface -> { + return unfoldInterface(iface).map(unfoldedIface -> { + return Map.entry(unfoldedIface, interfaceDispatch.get(iface)); + }); + }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); } - @SuppressWarnings("unchecked") - private static T createProxy(Class interfaceType, Map dispatch) { - return (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), - new Class[]{interfaceType}, - new DynamicProxyInvocationHandler(dispatch)); + private static Stream> unfoldInterface(Class interfaceType) { + return Stream.concat(Stream.of(interfaceType), Stream.of( + interfaceType.getInterfaces()).flatMap( + DynamicProxy::unfoldInterface)); } - private static IllegalArgumentException createInterfaceNotImplementedException( - Collection> missingInterfaces) { - return new IllegalArgumentException(String.format( - "None of the pieces implement %s", missingInterfaces)); + private static Stream getProxyableMethods(Class interfaceType) { + return Stream.of(interfaceType.getMethods()).filter( + method -> !Modifier.isStatic(method.getModifiers())); } private record DynamicProxyInvocationHandler(Map dispatch) implements InvocationHandler { @@ -144,8 +201,8 @@ private record DynamicProxyInvocationHandler(Map dispatch) impl public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { var handler = dispatch.get(method); if (handler != null) { - return handler.invoke(args); - } else if (method.isDefault()) { + return handler.invoke(proxy, args); + } else if(method.isDefault()) { return InvocationHandler.invokeDefault(proxy, method, args); } else { throw new UnsupportedOperationException(String.format("No handler for %s", method)); @@ -153,18 +210,44 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl } } - private record Handler(Object obj, Method method) { - Object invoke(Object[] args) throws Throwable { + private static Handler createDefaultMethodInvoker(Method method, + DefaultMethodInvoker proxyDefaultMethodInvoker) { + if (proxyDefaultMethodInvoker != null) { + return new DefaultMethodInvokerAdapter(proxyDefaultMethodInvoker, + method); + } else { + return null; + } + } + + private interface Handler { + + Object invoke(Object proxy, Object[] args) throws Throwable; + } + + private record MethodInvoker(Object obj, Method method) implements Handler { + + @Override + public Object invoke(Object proxy, Object[] args) throws Throwable { return method.invoke(obj, args); } } + private record DefaultMethodInvokerAdapter(DefaultMethodInvoker invoker, + Method method) implements Handler { + + @Override + public Object invoke(Object proxy, Object[] args) throws Throwable { + return invoker.invoke((Proxy) proxy, method, args); + } + } + private record ConflictResolverAdapter( BinaryOperator conflictResolver) implements - BinaryOperator { + BinaryOperator { @Override - public Handler apply(Handler a, Handler b) { + public MethodInvoker apply(MethodInvoker a, MethodInvoker b) { var m = conflictResolver.apply(a.method, b.method); if (m == a.method) { return a; @@ -176,7 +259,7 @@ public Handler apply(Handler a, Handler b) { } } - public static final BinaryOperator STANDARD_CONFLICT_RESOLVER = (a, b) -> { + private static final BinaryOperator STANDARD_CONFLICT_RESOLVER = (a, b) -> { if (a.isDefault() == b.isDefault()) { throw new IllegalArgumentException(String.format( "Ambiguous choice between %s and %s", a, b)); diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java index 289d534c98d36..51c15047280b1 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java @@ -72,7 +72,7 @@ static interface ConvoWithDefaultSayHelloWithOverrideSayBye extends Smalltalk, C default String sayHello() { return "Ciao"; } - + static String saySomething() { return "blah"; } @@ -155,4 +155,33 @@ public String sayThings() { assertEquals(expectedConvo.sayBye(), convo.sayBye()); assertEquals(expectedConvo.sayThings(), convo.sayThings()); } + + @Test + public void testInhereted() { + interface Base { + String doSome(); + } + + interface Next extends Base { + String doNext(); + } + + interface Last extends Next { + } + + var last = DynamicProxy.createProxyFromPieces(Last.class, new Next() { + @Override + public String doNext() { + return "next"; + } + + @Override + public String doSome() { + return "some"; + } + }); + + assertEquals("next", last.doNext()); + assertEquals("some", last.doSome()); + } } From 4387754c035d319b28afb8cc7d9e9d1fe0ed4c9a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 12 Nov 2024 10:28:38 -0500 Subject: [PATCH 0143/1101] DynamicProxy finally works on Linux --- .../jpackage/internal/util/DynamicProxy.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java index 5f3e1849b527c..da2d66cf6f498 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java @@ -120,22 +120,16 @@ private static Handler createHandler(Class interfaceType, Method method, if (!methodDeclaringClass.equals(interfaceType)) { // The method is declared in one of the superintarfaces. var piece = interfaceDispatch.get(methodDeclaringClass); - var pieceMethod = toSupplier(() -> piece.getClass().getMethod( - method.getName(), method.getParameterTypes())).get(); - if (method.isDefault() && method.equals(pieceMethod)) { - // The handler class doesn't override the default method - // of the interface. - return createDefaultMethodInvoker(method, proxyDefaultMethodInvoker); - } else { - return new MethodInvoker(piece, pieceMethod); - } + return new MethodInvoker(piece, method); } else if (method.isDefault()) { return createDefaultMethodInvoker(method, proxyDefaultMethodInvoker); } else { // Find a piece handling the method. - var handler = interfaceDispatch.values().stream().map(piece -> { + var handler = interfaceDispatch.entrySet().stream().map(e -> { try { - return new MethodInvoker(piece, piece.getClass().getMethod( + Class iface = e.getKey(); + Object piece = e.getValue(); + return new MethodInvoker(piece, iface.getMethod( method.getName(), method.getParameterTypes())); } catch (NoSuchMethodException ex) { return null; @@ -226,6 +220,12 @@ private interface Handler { } private record MethodInvoker(Object obj, Method method) implements Handler { + + MethodInvoker { + if (!method.canAccess(obj)) { + method.setAccessible(true); + } + } @Override public Object invoke(Object proxy, Object[] args) throws Throwable { From 54c75b2eda67db25a5a35c014242b0bc2b42005a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 12 Nov 2024 11:06:06 -0500 Subject: [PATCH 0144/1101] Get rid of Method.setAccessible() in DynamicProxy --- .../internal/LinuxApplicationLayout.java | 15 ++- .../jpackage/internal/util/DynamicProxy.java | 114 +++++++++--------- 2 files changed, 67 insertions(+), 62 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java index 081fe06db1625..e2ef2bed91490 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java @@ -26,19 +26,22 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import jdk.jpackage.internal.model.*; import java.nio.file.Path; +import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.util.DynamicProxy; import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; interface LinuxApplicationLayout extends ApplicationLayout, LinuxApplicationLayoutMixin { - final static class Tunnel implements DynamicProxy.DefaultMethodInvoker { + final static class Tunnel implements DynamicProxy.InvokeTunnel { @Override - public Object invoke(Proxy proxy, Method method, Object[] args) throws - Throwable { + public Object invoke(Object obj, Method method, Object[] args) throws Throwable { + return method.invoke(obj, args); + } + + @Override + public Object invokeDefault(Object proxy, Method method, Object[] args) throws Throwable { return InvocationHandler.invokeDefault(proxy, method, args); } @@ -47,7 +50,7 @@ public Object invoke(Proxy proxy, Method method, Object[] args) throws static LinuxApplicationLayout create(ApplicationLayout layout, Path libAppLauncher) { return DynamicProxy.build() - .proxyDefaultMethodInvoker(Tunnel.INSTANCE) + .invokeTunnel(Tunnel.INSTANCE) .create(LinuxApplicationLayout.class, layout, new LinuxApplicationLayoutMixin.Stub(libAppLauncher)); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java index da2d66cf6f498..964daa80df1a6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java @@ -31,12 +31,10 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.Set; import java.util.function.BinaryOperator; import static java.util.stream.Collectors.toMap; import java.util.stream.Stream; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; public final class DynamicProxy { @@ -44,7 +42,7 @@ public final static class Builder { public T create(Class interfaceType, Object... pieces) { return createProxyFromPieces(interfaceType, conflictResolver, - proxyDefaultMethodInvoker, pieces); + invokeTunnel, pieces); } public Builder conflictResolver(BinaryOperator v) { @@ -52,18 +50,18 @@ public Builder conflictResolver(BinaryOperator v) { return this; } - public Builder proxyDefaultMethodInvoker(DefaultMethodInvoker v) { - proxyDefaultMethodInvoker = v; + public Builder invokeTunnel(InvokeTunnel v) { + invokeTunnel = v; return this; } private BinaryOperator conflictResolver = STANDARD_CONFLICT_RESOLVER; - private DefaultMethodInvoker proxyDefaultMethodInvoker; + private InvokeTunnel invokeTunnel; } - @FunctionalInterface - public interface DefaultMethodInvoker { - Object invoke(Proxy proxy, Method method, Object[] args) throws Throwable; + public interface InvokeTunnel { + Object invoke(Object obj, Method method, Object[] args) throws Throwable; + Object invokeDefault(Object proxy, Method method, Object[] args) throws Throwable; } public static Builder build() { @@ -76,25 +74,21 @@ public static T createProxyFromPieces(Class interfaceType, } private static T createProxyFromPieces(Class interfaceType, - BinaryOperator conflictResolver, - DefaultMethodInvoker proxyDefaultMethodInvoker, + BinaryOperator conflictResolver, InvokeTunnel invokeTunnel, Object... pieces) { final Map, Object> interfaceDispatch = createInterfaceDispatch( interfaceType, pieces); - final Map methodDispatch = getProxyableMethods(interfaceType) - .map(method -> { - var handler = createHandler(interfaceType, method, interfaceDispatch, - conflictResolver, proxyDefaultMethodInvoker); - if (handler != null) { - return Map.entry(method, handler); - } else { - return null; - } - }) - .filter(Objects::nonNull) - .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); + final Map methodDispatch = getProxyableMethods(interfaceType).map(method -> { + var handler = createHandler(interfaceType, method, interfaceDispatch, + conflictResolver, invokeTunnel); + if (handler != null) { + return Map.entry(method, handler); + } else { + return null; + } + }).filter(Objects::nonNull).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); @SuppressWarnings("unchecked") T proxy = (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), @@ -113,24 +107,25 @@ private static IllegalArgumentException createInterfaceNotImplementedException( private static Handler createHandler(Class interfaceType, Method method, Map, Object> interfaceDispatch, BinaryOperator conflictResolver, - DefaultMethodInvoker proxyDefaultMethodInvoker) { + InvokeTunnel invokeTunnel) { final var methodDeclaringClass = method.getDeclaringClass(); if (!methodDeclaringClass.equals(interfaceType)) { // The method is declared in one of the superintarfaces. var piece = interfaceDispatch.get(methodDeclaringClass); - return new MethodInvoker(piece, method); + return createHandlerForMethod(piece, method, invokeTunnel); } else if (method.isDefault()) { - return createDefaultMethodInvoker(method, proxyDefaultMethodInvoker); + return createHandlerForDefaultMethod(method, invokeTunnel); } else { // Find a piece handling the method. var handler = interfaceDispatch.entrySet().stream().map(e -> { try { Class iface = e.getKey(); Object piece = e.getValue(); - return new MethodInvoker(piece, iface.getMethod( - method.getName(), method.getParameterTypes())); + return createHandlerForMethod(piece, iface.getMethod( + method.getName(), method.getParameterTypes()), + invokeTunnel); } catch (NoSuchMethodException ex) { return null; } @@ -204,50 +199,57 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl } } - private static Handler createDefaultMethodInvoker(Method method, - DefaultMethodInvoker proxyDefaultMethodInvoker) { - if (proxyDefaultMethodInvoker != null) { - return new DefaultMethodInvokerAdapter(proxyDefaultMethodInvoker, - method); + private static HandlerOfMethod createHandlerForDefaultMethod(Method method, InvokeTunnel invokeTunnel) { + if (invokeTunnel != null) { + return new HandlerOfMethod(method) { + @Override + public Object invoke(Object proxy, Object[] args) throws Throwable { + return invokeTunnel.invokeDefault(proxy, this.method, args); + } + }; } else { return null; } } + + private static HandlerOfMethod createHandlerForMethod(Object obj, Method method, InvokeTunnel invokeTunnel) { + if (invokeTunnel != null) { + return new HandlerOfMethod(method) { + @Override + public Object invoke(Object proxy, Object[] args) throws Throwable { + return invokeTunnel.invoke(obj, this.method, args); + } + }; + } else { + return new HandlerOfMethod(method) { + @Override + public Object invoke(Object proxy, Object[] args) throws Throwable { + return this.method.invoke(obj, args); + } + }; + } + } + @FunctionalInterface private interface Handler { Object invoke(Object proxy, Object[] args) throws Throwable; } - - private record MethodInvoker(Object obj, Method method) implements Handler { - - MethodInvoker { - if (!method.canAccess(obj)) { - method.setAccessible(true); - } - } - - @Override - public Object invoke(Object proxy, Object[] args) throws Throwable { - return method.invoke(obj, args); - } - } - - private record DefaultMethodInvokerAdapter(DefaultMethodInvoker invoker, - Method method) implements Handler { - - @Override - public Object invoke(Object proxy, Object[] args) throws Throwable { - return invoker.invoke((Proxy) proxy, method, args); + + private abstract static class HandlerOfMethod implements Handler { + HandlerOfMethod(Method method) { + this.method = method; } + + protected final Method method; } private record ConflictResolverAdapter( BinaryOperator conflictResolver) implements - BinaryOperator { + BinaryOperator { @Override - public MethodInvoker apply(MethodInvoker a, MethodInvoker b) { + public HandlerOfMethod apply(HandlerOfMethod a, HandlerOfMethod b) { var m = conflictResolver.apply(a.method, b.method); if (m == a.method) { return a; From bdc8e61ed247403a2fd2be81481ed053a6c31511 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 12 Nov 2024 11:06:44 -0500 Subject: [PATCH 0145/1101] Typo fixed --- .../jdk/jpackage/internal/util/DynamicProxyTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java index 51c15047280b1..9346b9acaac32 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java @@ -157,7 +157,7 @@ public String sayThings() { } @Test - public void testInhereted() { + public void testInherited() { interface Base { String doSome(); } From a98bdad3f5bfc543f5a78f56179c7a96a469aacf Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 12 Nov 2024 11:22:48 -0500 Subject: [PATCH 0146/1101] SimplePackageTest is a pass on Linux --- .../classes/jdk/jpackage/internal/model/LinuxPackage.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java index de7eba3d125b5..ffa04be1b4086 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java @@ -50,6 +50,13 @@ default String packageFileName() { return String.format(packageFileNameTemlate, packageName(), version(), release(), arch()); } + // This override is needed to make Package.packageFileNameWithSuffix() invoke + // LinuxPackage.packageFileName() instead of the default Package.packageFileName(). + @Override + default String packageFileNameWithSuffix() { + return Package.super.packageFileNameWithSuffix(); + } + default boolean isInstallDirInUsrTree() { return !relativeInstallDir().getFileName().equals(Path.of(packageName())); } From 16039a48c2d819482021447b5d2f30f9b6514da7 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 12 Nov 2024 12:33:53 -0500 Subject: [PATCH 0147/1101] Add another DynamicProxyTest test case --- .../internal/util/DynamicProxyTest.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java index 9346b9acaac32..ae199a8d1a199 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java @@ -184,4 +184,42 @@ public String doSome() { assertEquals("next", last.doNext()); assertEquals("some", last.doSome()); } + + @Test + public void testNestedProxy() { + interface AddM { + String m(); + } + + interface AddN { + String n(); + } + + interface A extends AddM { + } + + interface B extends AddN { + } + + interface C extends A, B { + } + + var proxyA = DynamicProxy.createProxyFromPieces(A.class, new AddM() { + @Override + public String m() { + return "hello"; + } + }); + var proxyB = DynamicProxy.createProxyFromPieces(B.class, new AddN() { + @Override + public String n() { + return "bye"; + } + + }); + var proxyC = DynamicProxy.createProxyFromPieces(C.class, proxyA, proxyB); + + assertEquals("hello", proxyC.m()); + assertEquals("bye", proxyC.n()); + } } From 8081dea56266d1be91b5f185987a5fd4a994ce08 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 12 Nov 2024 13:28:04 -0500 Subject: [PATCH 0148/1101] LinuxApplicationLayoutMixin should be public to make it work with AppImageLayout.toPathGroup() --- .../jdk/jpackage/internal/LinuxApplicationLayoutMixin.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java index a847fcd1690bb..effbb95606678 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java @@ -26,7 +26,8 @@ import java.nio.file.Path; -interface LinuxApplicationLayoutMixin { +// Must be publc to allow access from AppImageLayout.toPathGroup() +public interface LinuxApplicationLayoutMixin { /** * Path to "libapplauncher.so". From d68326f44a8e0fc44bd6509b0f9f234abee22997 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 12 Nov 2024 16:26:29 -0500 Subject: [PATCH 0149/1101] - rename DynamicProxy -> CompositeProxy. Split CompositeProxy into CompositeProxySpec - add missing overrides to LinuxPackage and WinLauncher interfaces - move LinuxApplicationLayout.Tunnel into CompositeProxyTunnel so that it can be reused in DesktopIntegration --- .../internal/CompositeProxyTunnel.java | 45 +++++++ .../jpackage/internal/DesktopIntegration.java | 9 +- .../internal/LinuxApplicationLayout.java | 23 +--- .../internal/model/LinuxApplication.java | 4 +- .../internal/model/LinuxDebPackage.java | 4 +- .../internal/model/LinuxLauncher.java | 4 +- .../jpackage/internal/model/LinuxPackage.java | 29 +++-- .../internal/model/LinuxRpmPackage.java | 4 +- .../internal/model/ApplicationLayout.java | 4 +- .../model/LauncherJarStartupInfo.java | 4 +- .../model/LauncherModularStartupInfo.java | 4 +- .../internal/model/RuntimeLayout.java | 4 +- ...{DynamicProxy.java => CompositeProxy.java} | 84 +++---------- .../internal/util/CompositeProxySpec.java | 111 ++++++++++++++++++ .../internal/model/WinApplication.java | 4 +- .../internal/model/WinExePackage.java | 4 +- .../jpackage/internal/model/WinLauncher.java | 11 +- .../internal/model/WinMsiPackage.java | 4 +- ...ProxyTest.java => CompositeProxyTest.java} | 20 ++-- 19 files changed, 245 insertions(+), 131 deletions(-) create mode 100644 src/jdk.jpackage/linux/classes/jdk/jpackage/internal/CompositeProxyTunnel.java rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/{DynamicProxy.java => CompositeProxy.java} (71%) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxySpec.java rename test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/{DynamicProxyTest.java => CompositeProxyTest.java} (87%) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/CompositeProxyTunnel.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/CompositeProxyTunnel.java new file mode 100644 index 0000000000000..463b9ec07e55d --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/CompositeProxyTunnel.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import jdk.jpackage.internal.util.CompositeProxy; + +final class CompositeProxyTunnel implements CompositeProxy.InvokeTunnel { + + @Override + public Object invoke(Object obj, Method method, Object[] args) throws Throwable { + return method.invoke(obj, args); + } + + @Override + public Object invokeDefault(Object proxy, Method method, Object[] args) throws Throwable { + return InvocationHandler.invokeDefault(proxy, method, args); + } + + static final CompositeProxyTunnel INSTANCE = new CompositeProxyTunnel(); + +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index c654a40bd0bdf..55e16e84e165b 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -31,7 +31,6 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; @@ -48,7 +47,7 @@ import javax.xml.stream.XMLStreamWriter; import static jdk.jpackage.internal.AppImageBuilder.createLauncherIconResource; import jdk.jpackage.internal.model.FileAssociation; -import jdk.jpackage.internal.util.DynamicProxy; +import jdk.jpackage.internal.util.CompositeProxy; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.XmlUtils; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; @@ -467,8 +466,10 @@ static LinuxFileAssociation create(FileAssociation fa) { fa = new FileAssociation.Stub(fa.description(), null, fa.mimeType(), fa.extension()); } - return DynamicProxy.createProxyFromPieces(LinuxFileAssociation.class, - fa, new LinuxFileAssociationMixin.Stub(iconSize)); + return CompositeProxy.build() + .invokeTunnel(CompositeProxyTunnel.INSTANCE) + .create(LinuxFileAssociation.class, fa, + new LinuxFileAssociationMixin.Stub(iconSize)); } private static int getIconSize(FileAssociation fa) { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java index e2ef2bed91490..9072504e0d800 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java @@ -24,33 +24,16 @@ */ package jdk.jpackage.internal; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; import java.nio.file.Path; import jdk.jpackage.internal.model.ApplicationLayout; -import jdk.jpackage.internal.util.DynamicProxy; +import jdk.jpackage.internal.util.CompositeProxy; import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; interface LinuxApplicationLayout extends ApplicationLayout, LinuxApplicationLayoutMixin { - final static class Tunnel implements DynamicProxy.InvokeTunnel { - - @Override - public Object invoke(Object obj, Method method, Object[] args) throws Throwable { - return method.invoke(obj, args); - } - - @Override - public Object invokeDefault(Object proxy, Method method, Object[] args) throws Throwable { - return InvocationHandler.invokeDefault(proxy, method, args); - } - - private final static Tunnel INSTANCE = new Tunnel(); - } - static LinuxApplicationLayout create(ApplicationLayout layout, Path libAppLauncher) { - return DynamicProxy.build() - .invokeTunnel(Tunnel.INSTANCE) + return CompositeProxy.build() + .invokeTunnel(CompositeProxyTunnel.INSTANCE) .create(LinuxApplicationLayout.class, layout, new LinuxApplicationLayoutMixin.Stub(libAppLauncher)); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java index ce895bd82da16..221788240f8ba 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java @@ -25,11 +25,11 @@ package jdk.jpackage.internal.model; -import jdk.jpackage.internal.util.DynamicProxy; +import jdk.jpackage.internal.util.CompositeProxy; public interface LinuxApplication extends Application { public static LinuxApplication create(Application app) { - return DynamicProxy.createProxyFromPieces(LinuxApplication.class, app); + return CompositeProxy.create(LinuxApplication.class, app); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java index de2f3f2c5d513..9d0d1a2273516 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java @@ -25,7 +25,7 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; -import jdk.jpackage.internal.util.DynamicProxy; +import jdk.jpackage.internal.util.CompositeProxy; public interface LinuxDebPackage extends LinuxPackage, LinuxDebPackageMixin { @@ -49,6 +49,6 @@ default Path relativeCopyrightFilePath() { } public static LinuxDebPackage create(LinuxPackage pkg, LinuxDebPackageMixin mixin) { - return DynamicProxy.createProxyFromPieces(LinuxDebPackage.class, pkg, mixin); + return CompositeProxy.create(LinuxDebPackage.class, pkg, mixin); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java index ab67927d96853..3ac1b9d0df53a 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java @@ -25,7 +25,7 @@ package jdk.jpackage.internal.model; import java.util.Map; -import jdk.jpackage.internal.util.DynamicProxy; +import jdk.jpackage.internal.util.CompositeProxy; public interface LinuxLauncher extends Launcher, LinuxLauncherMixin { @@ -42,6 +42,6 @@ default String defaultIconResourceName() { } public static LinuxLauncher create(Launcher launcher, LinuxLauncherMixin mixin) { - return DynamicProxy.createProxyFromPieces(LinuxLauncher.class, launcher, mixin); + return CompositeProxy.create(LinuxLauncher.class, launcher, mixin); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java index ffa04be1b4086..4d540a10156dc 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java @@ -25,7 +25,7 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; -import jdk.jpackage.internal.util.DynamicProxy; +import jdk.jpackage.internal.util.CompositeProxy; public interface LinuxPackage extends Package, LinuxPackageMixin { @@ -50,18 +50,33 @@ default String packageFileName() { return String.format(packageFileNameTemlate, packageName(), version(), release(), arch()); } - // This override is needed to make Package.packageFileNameWithSuffix() invoke - // LinuxPackage.packageFileName() instead of the default Package.packageFileName(). + default boolean isInstallDirInUsrTree() { + return !relativeInstallDir().getFileName().equals(Path.of(packageName())); + } + + public static LinuxPackage create(Package pkg, LinuxPackageMixin mixin) { + return CompositeProxy.create(LinuxPackage.class, pkg, mixin); + } + + // These overrides are needed to make default Package methods invoke overriden + // LinuxPackage methods. @Override default String packageFileNameWithSuffix() { return Package.super.packageFileNameWithSuffix(); } - default boolean isInstallDirInUsrTree() { - return !relativeInstallDir().getFileName().equals(Path.of(packageName())); + @Override + default AppImageLayout installedPackageLayout() { + return Package.super.installedPackageLayout(); } - public static LinuxPackage create(Package pkg, LinuxPackageMixin mixin) { - return DynamicProxy.createProxyFromPieces(LinuxPackage.class, pkg, mixin); + @Override + default ApplicationLayout asInstalledPackageApplicationLayout() { + return Package.super.asInstalledPackageApplicationLayout(); + } + + @Override + default ApplicationLayout asPackageApplicationLayout() { + return Package.super.asPackageApplicationLayout(); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java index c8a239a28a170..90ecc0b9e8453 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java @@ -24,11 +24,11 @@ */ package jdk.jpackage.internal.model; -import jdk.jpackage.internal.util.DynamicProxy; +import jdk.jpackage.internal.util.CompositeProxy; public interface LinuxRpmPackage extends LinuxPackage, LinuxRpmPackageMixin { public static LinuxRpmPackage create(LinuxPackage pkg, LinuxRpmPackageMixin mixin) { - return DynamicProxy.createProxyFromPieces(LinuxRpmPackage.class, pkg, mixin); + return CompositeProxy.create(LinuxRpmPackage.class, pkg, mixin); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index e6b530a33b9ee..ef34a63f3fbf1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -25,7 +25,7 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; -import jdk.jpackage.internal.util.DynamicProxy; +import jdk.jpackage.internal.util.CompositeProxy; import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; /** @@ -39,7 +39,7 @@ default ApplicationLayout resolveAt(Path root) { } static ApplicationLayout create(AppImageLayout appImage, ApplicationLayoutMixin mixin) { - return DynamicProxy.createProxyFromPieces(ApplicationLayout.class, appImage, mixin); + return CompositeProxy.create(ApplicationLayout.class, appImage, mixin); } public static Builder build() { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java index e7271330319cf..486b7e64e7508 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java @@ -24,14 +24,14 @@ */ package jdk.jpackage.internal.model; -import jdk.jpackage.internal.util.DynamicProxy; +import jdk.jpackage.internal.util.CompositeProxy; public interface LauncherJarStartupInfo extends LauncherStartupInfo, LauncherJarStartupInfoMixin { public static LauncherJarStartupInfo create(LauncherStartupInfo info, LauncherJarStartupInfoMixin mixin) { - return DynamicProxy.createProxyFromPieces(LauncherJarStartupInfo.class, + return CompositeProxy.create(LauncherJarStartupInfo.class, info, mixin); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java index 45126ca0b186b..8d2abe1baf2af 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java @@ -24,14 +24,14 @@ */ package jdk.jpackage.internal.model; -import jdk.jpackage.internal.util.DynamicProxy; +import jdk.jpackage.internal.util.CompositeProxy; public interface LauncherModularStartupInfo extends LauncherStartupInfo, LauncherModularStartupInfoMixin { public static LauncherModularStartupInfo create(LauncherStartupInfo info, LauncherModularStartupInfoMixin mixin) { - return DynamicProxy.createProxyFromPieces( + return CompositeProxy.create( LauncherModularStartupInfo.class, info, mixin); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java index f3b9c8c6b76d1..da36c1009c40a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java @@ -25,7 +25,7 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; -import jdk.jpackage.internal.util.DynamicProxy; +import jdk.jpackage.internal.util.CompositeProxy; import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; @@ -40,7 +40,7 @@ default RuntimeLayout resolveAt(Path root) { } static RuntimeLayout create(AppImageLayout layout) { - return DynamicProxy.createProxyFromPieces(RuntimeLayout.class, layout); + return CompositeProxy.create(RuntimeLayout.class, layout); } static final RuntimeLayout DEFAULT = create(new AppImageLayout.Stub(Path.of(""))); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java similarity index 71% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java index 964daa80df1a6..fa9651a29a1e6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/DynamicProxy.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java @@ -26,22 +26,18 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.function.BinaryOperator; import static java.util.stream.Collectors.toMap; import java.util.stream.Stream; -public final class DynamicProxy { +public final class CompositeProxy { public final static class Builder { public T create(Class interfaceType, Object... pieces) { - return createProxyFromPieces(interfaceType, conflictResolver, + return CompositeProxy.createCompositeProxy(interfaceType, conflictResolver, invokeTunnel, pieces); } @@ -68,17 +64,16 @@ public static Builder build() { return new Builder(); } - public static T createProxyFromPieces(Class interfaceType, - Object... pieces) { + public static T create(Class interfaceType, Object... pieces) { return build().create(interfaceType, pieces); } - private static T createProxyFromPieces(Class interfaceType, + private static T createCompositeProxy(Class interfaceType, BinaryOperator conflictResolver, InvokeTunnel invokeTunnel, Object... pieces) { - final Map, Object> interfaceDispatch = createInterfaceDispatch( - interfaceType, pieces); + final Map, Object> interfaceDispatch = CompositeProxySpec.createForPieces( + interfaceType, pieces).getInterfaceDispatch(); final Map methodDispatch = getProxyableMethods(interfaceType).map(method -> { var handler = createHandler(interfaceType, method, interfaceDispatch, @@ -92,17 +87,12 @@ private static T createProxyFromPieces(Class interfaceType, @SuppressWarnings("unchecked") T proxy = (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), - new Class[]{interfaceType}, + new Class[]{interfaceType, DynamicProxyTag.class}, new DynamicProxyInvocationHandler(methodDispatch)); return proxy; } - private static IllegalArgumentException createInterfaceNotImplementedException( - Collection> missingInterfaces) { - return new IllegalArgumentException(String.format( - "None of the pieces implement %s", missingInterfaces)); - } private static Handler createHandler(Class interfaceType, Method method, Map, Object> interfaceDispatch, @@ -131,54 +121,13 @@ private static Handler createHandler(Class interfaceType, Method method, } }).filter(Objects::nonNull).reduce(new ConflictResolverAdapter(conflictResolver)).orElseThrow(() -> { return new IllegalArgumentException(String.format( - "None of the pieces can handle %s", method)); + "none of the pieces can handle %s", method)); }); return handler; } } - private static Map, Object> createInterfaceDispatch(Class interfaceType, Object ... pieces) { - if (!interfaceType.isInterface()) { - throw new IllegalArgumentException(String.format( - "Type %s must be an interface", interfaceType.getName())); - } - - final Class[] interfaces = interfaceType.getInterfaces(); - if (interfaces.length != pieces.length) { - throw new IllegalArgumentException(String.format( - "Type %s must extend %d interfaces", - interfaceType.getName(), pieces.length)); - } - - final Map, Object> interfaceDispatch = Stream.of(interfaces).collect(toMap(x -> x, iface -> { - return Stream.of(pieces).filter(obj -> { - return Set.of(obj.getClass().getInterfaces()).contains(iface); - }).reduce((a, b) -> { - throw new IllegalArgumentException(String.format( - "Both [%s] and [%s] pieces implement %s", a, b, iface)); - }).orElseThrow(() -> createInterfaceNotImplementedException(List.of(iface))); - })); - - if (interfaceDispatch.size() != interfaces.length) { - final List> missingInterfaces = new ArrayList<>(Set.of(interfaces)); - missingInterfaces.removeAll(interfaceDispatch.entrySet()); - throw createInterfaceNotImplementedException(missingInterfaces); - } - - return Stream.of(interfaces).flatMap(iface -> { - return unfoldInterface(iface).map(unfoldedIface -> { - return Map.entry(unfoldedIface, interfaceDispatch.get(iface)); - }); - }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); - } - - private static Stream> unfoldInterface(Class interfaceType) { - return Stream.concat(Stream.of(interfaceType), Stream.of( - interfaceType.getInterfaces()).flatMap( - DynamicProxy::unfoldInterface)); - } - private static Stream getProxyableMethods(Class interfaceType) { return Stream.of(interfaceType.getMethods()).filter( method -> !Modifier.isStatic(method.getModifiers())); @@ -205,27 +154,27 @@ private static HandlerOfMethod createHandlerForDefaultMethod(Method method, Invo @Override public Object invoke(Object proxy, Object[] args) throws Throwable { return invokeTunnel.invokeDefault(proxy, this.method, args); - } + } }; } else { return null; } } - + private static HandlerOfMethod createHandlerForMethod(Object obj, Method method, InvokeTunnel invokeTunnel) { if (invokeTunnel != null) { return new HandlerOfMethod(method) { @Override public Object invoke(Object proxy, Object[] args) throws Throwable { return invokeTunnel.invoke(obj, this.method, args); - } + } }; } else { return new HandlerOfMethod(method) { @Override public Object invoke(Object proxy, Object[] args) throws Throwable { return this.method.invoke(obj, args); - } + } }; } } @@ -235,12 +184,12 @@ private interface Handler { Object invoke(Object proxy, Object[] args) throws Throwable; } - + private abstract static class HandlerOfMethod implements Handler { HandlerOfMethod(Method method) { this.method = method; } - + protected final Method method; } @@ -264,11 +213,14 @@ public HandlerOfMethod apply(HandlerOfMethod a, HandlerOfMethod b) { private static final BinaryOperator STANDARD_CONFLICT_RESOLVER = (a, b) -> { if (a.isDefault() == b.isDefault()) { throw new IllegalArgumentException(String.format( - "Ambiguous choice between %s and %s", a, b)); + "ambiguous choice between %s and %s", a, b)); } else if (!a.isDefault()) { return a; } else { return b; } }; + + public static interface DynamicProxyTag { + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxySpec.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxySpec.java new file mode 100644 index 0000000000000..55338b5265eae --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxySpec.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import static java.util.stream.Collectors.toMap; +import java.util.stream.Stream; + +final class CompositeProxySpec { + + Map, Object> getInterfaceDispatch() { + return interfaceDispatch; + } + + static CompositeProxySpec createForImpl(Class interfaceType, Object obj) { + validateTypeIsInterface(interfaceType); + if (!interfaceType.isAssignableFrom(interfaceType)) { + throw new IllegalArgumentException(String.format( + "supplied object must implement %s interface", obj)); + } + return new CompositeProxySpec(interfaceType, new Class[]{interfaceType}, + new Object[]{obj}); + } + + static CompositeProxySpec createForPieces(Class interfaceType, Object... pieces) { + validateTypeIsInterface(interfaceType); + return new CompositeProxySpec(interfaceType, interfaceType.getInterfaces(), + pieces); + } + + private CompositeProxySpec(Class interfaceType, Class[] interfaces, Object[] pieces) { + List.of(interfaces).forEach(CompositeProxySpec::validateTypeIsInterface); + + if (interfaces.length != pieces.length) { + throw new IllegalArgumentException(String.format( + "type %s must extend %d interfaces", interfaceType.getName(), + pieces.length)); + } + + this.interfaceDispatch = createInterfaceDispatch(interfaces, pieces); + } + + private static Map, Object> createInterfaceDispatch( + Class[] interfaces, Object[] pieces) { + + final Map, Object> interfaceDispatch = Stream.of(interfaces).collect(toMap(x -> x, iface -> { + return Stream.of(pieces).filter(obj -> { + return Set.of(obj.getClass().getInterfaces()).contains(iface); + }).reduce((a, b) -> { + throw new IllegalArgumentException(String.format( + "both [%s] and [%s] pieces implement %s", a, b, iface)); + }).orElseThrow(() -> createInterfaceNotImplementedException(List.of(iface))); + })); + + if (interfaceDispatch.size() != interfaces.length) { + final List> missingInterfaces = new ArrayList<>(Set.of(interfaces)); + missingInterfaces.removeAll(interfaceDispatch.entrySet()); + throw createInterfaceNotImplementedException(missingInterfaces); + } + + return Stream.of(interfaces).flatMap(iface -> { + return unfoldInterface(iface).map(unfoldedIface -> { + return Map.entry(unfoldedIface, interfaceDispatch.get(iface)); + }); + }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + private static Stream> unfoldInterface(Class interfaceType) { + return Stream.concat(Stream.of(interfaceType), Stream.of( + interfaceType.getInterfaces()).flatMap(CompositeProxySpec::unfoldInterface)); + } + + private static IllegalArgumentException createInterfaceNotImplementedException( + Collection> missingInterfaces) { + return new IllegalArgumentException(String.format( + "none of the pieces implement %s", missingInterfaces)); + } + + private static void validateTypeIsInterface(Class type) { + if (!type.isInterface()) { + throw new IllegalArgumentException(String.format( + "type %s must be an interface", type.getName())); + } + } + + final Map, Object> interfaceDispatch; +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java index 5cab551049e6e..83c1179f37955 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java @@ -24,7 +24,7 @@ */ package jdk.jpackage.internal.model; -import jdk.jpackage.internal.util.DynamicProxy; +import jdk.jpackage.internal.util.CompositeProxy; public interface WinApplication extends Application { @@ -33,6 +33,6 @@ default DottedVersion winVersion() { } public static WinApplication create(Application app) { - return DynamicProxy.createProxyFromPieces(WinApplication.class, app); + return CompositeProxy.create(WinApplication.class, app); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java index 6921965d7ca07..ef20268a4f34b 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java @@ -26,12 +26,12 @@ import java.nio.file.Path; import static jdk.jpackage.internal.model.StandardPackageType.WIN_EXE; -import jdk.jpackage.internal.util.DynamicProxy; +import jdk.jpackage.internal.util.CompositeProxy; public interface WinExePackage extends Package, WinExePackageMixin { public static WinExePackage create(WinMsiPackage msiPackage, Path icon) { - return DynamicProxy.createProxyFromPieces(WinExePackage.class, createExePackage( + return CompositeProxy.create(WinExePackage.class, createExePackage( msiPackage), new WinExePackageMixin.Stub(msiPackage, icon)); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java index 2c6fdb7bdd371..9f7161c413ebf 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java @@ -30,7 +30,7 @@ import java.util.Set; import static java.util.stream.Collectors.toMap; import jdk.jpackage.internal.resources.ResourceLocator; -import jdk.jpackage.internal.util.DynamicProxy; +import jdk.jpackage.internal.util.CompositeProxy; public interface WinLauncher extends Launcher, WinLauncherMixin { @@ -57,6 +57,13 @@ default String defaultIconResourceName() { } public static WinLauncher create(Launcher launcher, WinLauncherMixin mixin) { - return DynamicProxy.createProxyFromPieces(WinLauncher.class, launcher, mixin); + return CompositeProxy.create(WinLauncher.class, launcher, mixin); + } + + // This override is needed to make default Launcher methods invoke overriden + // WinLauncher methods. + @Override + default String executableNameWithSuffix() { + return Launcher.super.executableNameWithSuffix(); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java index e30f9bedb3bd0..fdeb744c1c9fe 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java @@ -24,7 +24,7 @@ */ package jdk.jpackage.internal.model; -import jdk.jpackage.internal.util.DynamicProxy; +import jdk.jpackage.internal.util.CompositeProxy; public interface WinMsiPackage extends Package, WinMsiPackageMixin { @@ -33,6 +33,6 @@ default DottedVersion msiVersion() { } public static WinMsiPackage create(Package pkg, WinMsiPackageMixin mixin) { - return DynamicProxy.createProxyFromPieces(WinMsiPackage.class, pkg, mixin); + return CompositeProxy.create(WinMsiPackage.class, pkg, mixin); } } diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java similarity index 87% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java rename to test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java index ae199a8d1a199..b89001aa7437c 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/DynamicProxyTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java @@ -25,7 +25,7 @@ import static org.junit.Assert.assertEquals; import org.junit.Test; -public class DynamicProxyTest { +public class CompositeProxyTest { static interface Smalltalk { @@ -80,7 +80,7 @@ static String saySomething() { @Test public void testSmalltalk() { - var convo = DynamicProxy.createProxyFromPieces(Smalltalk.class); + var convo = CompositeProxy.create(Smalltalk.class); assertEquals("Hello", convo.sayHello()); assertEquals("Bye", convo.sayBye()); } @@ -88,7 +88,7 @@ public void testSmalltalk() { @Test public void testConvo() { final var otherThings = "How is your day?"; - var convo = DynamicProxy.createProxyFromPieces(Convo.class, + var convo = CompositeProxy.create(Convo.class, new Smalltalk() {}, new ConvoMixin.Stub(otherThings)); assertEquals("Hello", convo.sayHello()); assertEquals("Bye", convo.sayBye()); @@ -98,7 +98,7 @@ public void testConvo() { @Test public void testConvoWithDuke() { final var otherThings = "How is your day?"; - var convo = DynamicProxy.createProxyFromPieces(Convo.class, new Smalltalk() { + var convo = CompositeProxy.create(Convo.class, new Smalltalk() { @Override public String sayHello() { return "Hello, Duke"; @@ -113,7 +113,7 @@ public String sayHello() { public void testConvoWithCustomSayBye() { var mixin = new ConvoMixinWithOverrideSayBye.Stub("How is your day?", "See you"); - var convo = DynamicProxy.createProxyFromPieces(ConvoWithOverrideSayBye.class, new Smalltalk() {}, mixin); + var convo = CompositeProxy.create(ConvoWithOverrideSayBye.class, new Smalltalk() {}, mixin); var expectedConvo = new ConvoWithOverrideSayBye() { @Override @@ -136,7 +136,7 @@ public String sayThings() { public void testConvoWithCustomSayHelloAndSayBye() { var mixin = new ConvoMixinWithOverrideSayBye.Stub("How is your day?", "See you"); - var convo = DynamicProxy.createProxyFromPieces(ConvoWithDefaultSayHelloWithOverrideSayBye.class, new Smalltalk() {}, mixin); + var convo = CompositeProxy.create(ConvoWithDefaultSayHelloWithOverrideSayBye.class, new Smalltalk() {}, mixin); var expectedConvo = new ConvoWithDefaultSayHelloWithOverrideSayBye() { @Override @@ -169,7 +169,7 @@ interface Next extends Base { interface Last extends Next { } - var last = DynamicProxy.createProxyFromPieces(Last.class, new Next() { + var last = CompositeProxy.create(Last.class, new Next() { @Override public String doNext() { return "next"; @@ -204,20 +204,20 @@ interface B extends AddN { interface C extends A, B { } - var proxyA = DynamicProxy.createProxyFromPieces(A.class, new AddM() { + var proxyA = CompositeProxy.create(A.class, new AddM() { @Override public String m() { return "hello"; } }); - var proxyB = DynamicProxy.createProxyFromPieces(B.class, new AddN() { + var proxyB = CompositeProxy.create(B.class, new AddN() { @Override public String n() { return "bye"; } }); - var proxyC = DynamicProxy.createProxyFromPieces(C.class, proxyA, proxyB); + var proxyC = CompositeProxy.create(C.class, proxyA, proxyB); assertEquals("hello", proxyC.m()); assertEquals("bye", proxyC.n()); From be06804149a563b4d507003ee23808ba3f890d15 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 12 Nov 2024 16:27:34 -0500 Subject: [PATCH 0150/1101] bugfix --- .../classes/jdk/jpackage/internal/model/Package.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java index 53e03c48a7542..3936b9e72141e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java @@ -89,15 +89,17 @@ default ApplicationLayout asPackageApplicationLayout() { * Returns app image layout of the installed package. */ default AppImageLayout installedPackageLayout() { - Path root = relativeInstallDir(); if (type() instanceof StandardPackageType type) { switch (type) { case LINUX_DEB, LINUX_RPM, MAC_DMG, MAC_PKG -> { - root = Path.of("/").resolve(root); + return packageLayout().resolveAt(Path.of("/")); + } + case WIN_EXE, WIN_MSI -> { + return packageLayout(); } } } - return appImageLayout().resolveAt(root); + throw new UnsupportedOperationException(); } default ApplicationLayout asInstalledPackageApplicationLayout() { From dd8bd2daf18b7dffd78ba469bd68a78280ee0503 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 12 Nov 2024 16:27:34 -0500 Subject: [PATCH 0151/1101] bugfix --- .../classes/jdk/jpackage/internal/model/Package.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java index 392e45b87dfd6..6e9d3b854838a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java @@ -89,15 +89,17 @@ default ApplicationLayout asPackageApplicationLayout() { * Returns app image layout of the installed package. */ default AppImageLayout installedPackageLayout() { - Path root = relativeInstallDir(); if (type() instanceof StandardPackageType type) { switch (type) { case LINUX_DEB, LINUX_RPM, MAC_DMG, MAC_PKG -> { - root = Path.of("/").resolve(root); + return packageLayout().resolveAt(Path.of("/")); + } + case WIN_EXE, WIN_MSI -> { + return packageLayout(); } } } - return appImageLayout().resolveAt(root); + throw new UnsupportedOperationException(); } default ApplicationLayout asInstalledPackageApplicationLayout() { From 493caac8adfe3aa513790f9096fa3a2bd2ff770e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 12 Nov 2024 20:54:31 -0500 Subject: [PATCH 0152/1101] Make CompositeProxy work correctly without the need to add default methods calling superinterface default methods in case of other interface method overrides. --- .../jpackage/internal/model/LinuxPackage.java | 22 ------ .../internal/util/CompositeProxy.java | 72 ++++++++++++++----- .../internal/util/CompositeProxySpec.java | 31 +++----- .../jpackage/internal/model/WinLauncher.java | 7 -- .../internal/util/CompositeProxyTest.java | 32 +++++++++ 5 files changed, 95 insertions(+), 69 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java index 4d540a10156dc..9e3154052137c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java @@ -57,26 +57,4 @@ default boolean isInstallDirInUsrTree() { public static LinuxPackage create(Package pkg, LinuxPackageMixin mixin) { return CompositeProxy.create(LinuxPackage.class, pkg, mixin); } - - // These overrides are needed to make default Package methods invoke overriden - // LinuxPackage methods. - @Override - default String packageFileNameWithSuffix() { - return Package.super.packageFileNameWithSuffix(); - } - - @Override - default AppImageLayout installedPackageLayout() { - return Package.super.installedPackageLayout(); - } - - @Override - default ApplicationLayout asInstalledPackageApplicationLayout() { - return Package.super.asInstalledPackageApplicationLayout(); - } - - @Override - default ApplicationLayout asPackageApplicationLayout() { - return Package.super.asPackageApplicationLayout(); - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java index fa9651a29a1e6..2e2c5dee0e0f0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java @@ -26,9 +26,11 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; +import java.util.Arrays; import java.util.Map; import java.util.Objects; import java.util.function.BinaryOperator; +import java.util.function.Predicate; import static java.util.stream.Collectors.toMap; import java.util.stream.Stream; @@ -36,9 +38,9 @@ public final class CompositeProxy { public final static class Builder { - public T create(Class interfaceType, Object... pieces) { + public T create(Class interfaceType, Object... slices) { return CompositeProxy.createCompositeProxy(interfaceType, conflictResolver, - invokeTunnel, pieces); + invokeTunnel, slices); } public Builder conflictResolver(BinaryOperator v) { @@ -64,16 +66,16 @@ public static Builder build() { return new Builder(); } - public static T create(Class interfaceType, Object... pieces) { - return build().create(interfaceType, pieces); + public static T create(Class interfaceType, Object... slices) { + return build().create(interfaceType, slices); } private static T createCompositeProxy(Class interfaceType, BinaryOperator conflictResolver, InvokeTunnel invokeTunnel, - Object... pieces) { + Object... slices) { - final Map, Object> interfaceDispatch = CompositeProxySpec.createForPieces( - interfaceType, pieces).getInterfaceDispatch(); + final Map, Object> interfaceDispatch = CompositeProxySpec.create( + interfaceType, slices).getInterfaceDispatch(); final Map methodDispatch = getProxyableMethods(interfaceType).map(method -> { var handler = createHandler(interfaceType, method, interfaceDispatch, @@ -87,13 +89,12 @@ private static T createCompositeProxy(Class interfaceType, @SuppressWarnings("unchecked") T proxy = (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), - new Class[]{interfaceType, DynamicProxyTag.class}, + new Class[]{interfaceType}, new DynamicProxyInvocationHandler(methodDispatch)); return proxy; } - private static Handler createHandler(Class interfaceType, Method method, Map, Object> interfaceDispatch, BinaryOperator conflictResolver, @@ -102,18 +103,23 @@ private static Handler createHandler(Class interfaceType, Method method, final var methodDeclaringClass = method.getDeclaringClass(); if (!methodDeclaringClass.equals(interfaceType)) { - // The method is declared in one of the superintarfaces. - var piece = interfaceDispatch.get(methodDeclaringClass); - return createHandlerForMethod(piece, method, invokeTunnel); + // The method is declared in one of the superinterfaces. + final var slice = interfaceDispatch.get(methodDeclaringClass); + + if (isInvokeDefault(method, slice)) { + return createHandlerForDefaultMethod(method, invokeTunnel); + } else { + return createHandlerForMethod(slice, method, invokeTunnel); + } } else if (method.isDefault()) { return createHandlerForDefaultMethod(method, invokeTunnel); } else { - // Find a piece handling the method. + // Find a slice handling the method. var handler = interfaceDispatch.entrySet().stream().map(e -> { try { Class iface = e.getKey(); - Object piece = e.getValue(); - return createHandlerForMethod(piece, iface.getMethod( + Object slice = e.getValue(); + return createHandlerForMethod(slice, iface.getMethod( method.getName(), method.getParameterTypes()), invokeTunnel); } catch (NoSuchMethodException ex) { @@ -121,7 +127,7 @@ private static Handler createHandler(Class interfaceType, Method method, } }).filter(Objects::nonNull).reduce(new ConflictResolverAdapter(conflictResolver)).orElseThrow(() -> { return new IllegalArgumentException(String.format( - "none of the pieces can handle %s", method)); + "none of the slices can handle %s", method)); }); return handler; @@ -133,6 +139,37 @@ private static Stream getProxyableMethods(Class interfaceType) { method -> !Modifier.isStatic(method.getModifiers())); } + private static boolean isInvokeDefault(Method method, Object slice) { + if (!method.isDefault()) { + return false; + } + + // The "method" is default. + // See if is overriden by any non-abstract method in the "slice". + // If it is, InvocationHandler.invokeDefault() should not be used to call it. + + final var sliceClass = slice.getClass(); + + final var methodOverriden = Stream.of(sliceClass.getMethods()) + .filter(Predicate.not(Predicate.isEqual(method))) + .filter(sliceMethod -> !Modifier.isAbstract(sliceMethod.getModifiers())) + .anyMatch(sliceMethod -> signatureEquals(sliceMethod, method)); + + return !methodOverriden; + } + + private static boolean signatureEquals(Method a, Method b) { + if (!Objects.equals(a.getName(), b.getName())) { + return false; + } + + if (!Arrays.equals(a.getParameterTypes(), b.getParameterTypes())) { + return false; + } + + return Objects.equals(a.getReturnType(), b.getReturnType()); + } + private record DynamicProxyInvocationHandler(Map dispatch) implements InvocationHandler { @Override @@ -220,7 +257,4 @@ public HandlerOfMethod apply(HandlerOfMethod a, HandlerOfMethod b) { return b; } }; - - public static interface DynamicProxyTag { - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxySpec.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxySpec.java index 55338b5265eae..a6ba46c7e2b59 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxySpec.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxySpec.java @@ -36,43 +36,32 @@ Map, Object> getInterfaceDispatch() { return interfaceDispatch; } - static CompositeProxySpec createForImpl(Class interfaceType, Object obj) { + static CompositeProxySpec create(Class interfaceType, Object... slices) { validateTypeIsInterface(interfaceType); - if (!interfaceType.isAssignableFrom(interfaceType)) { - throw new IllegalArgumentException(String.format( - "supplied object must implement %s interface", obj)); - } - return new CompositeProxySpec(interfaceType, new Class[]{interfaceType}, - new Object[]{obj}); - } - - static CompositeProxySpec createForPieces(Class interfaceType, Object... pieces) { - validateTypeIsInterface(interfaceType); - return new CompositeProxySpec(interfaceType, interfaceType.getInterfaces(), - pieces); + return new CompositeProxySpec(interfaceType, interfaceType.getInterfaces(), slices); } - private CompositeProxySpec(Class interfaceType, Class[] interfaces, Object[] pieces) { + private CompositeProxySpec(Class interfaceType, Class[] interfaces, Object[] slices) { List.of(interfaces).forEach(CompositeProxySpec::validateTypeIsInterface); - if (interfaces.length != pieces.length) { + if (interfaces.length != slices.length) { throw new IllegalArgumentException(String.format( "type %s must extend %d interfaces", interfaceType.getName(), - pieces.length)); + slices.length)); } - this.interfaceDispatch = createInterfaceDispatch(interfaces, pieces); + this.interfaceDispatch = createInterfaceDispatch(interfaces, slices); } private static Map, Object> createInterfaceDispatch( - Class[] interfaces, Object[] pieces) { + Class[] interfaces, Object[] slices) { final Map, Object> interfaceDispatch = Stream.of(interfaces).collect(toMap(x -> x, iface -> { - return Stream.of(pieces).filter(obj -> { + return Stream.of(slices).filter(obj -> { return Set.of(obj.getClass().getInterfaces()).contains(iface); }).reduce((a, b) -> { throw new IllegalArgumentException(String.format( - "both [%s] and [%s] pieces implement %s", a, b, iface)); + "both [%s] and [%s] slices implement %s", a, b, iface)); }).orElseThrow(() -> createInterfaceNotImplementedException(List.of(iface))); })); @@ -97,7 +86,7 @@ private static Stream> unfoldInterface(Class interfaceType) { private static IllegalArgumentException createInterfaceNotImplementedException( Collection> missingInterfaces) { return new IllegalArgumentException(String.format( - "none of the pieces implement %s", missingInterfaces)); + "none of the slices implement %s", missingInterfaces)); } private static void validateTypeIsInterface(Class type) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java index 9f7161c413ebf..ee1955fe75ac9 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java @@ -59,11 +59,4 @@ default String defaultIconResourceName() { public static WinLauncher create(Launcher launcher, WinLauncherMixin mixin) { return CompositeProxy.create(WinLauncher.class, launcher, mixin); } - - // This override is needed to make default Launcher methods invoke overriden - // WinLauncher methods. - @Override - default String executableNameWithSuffix() { - return Launcher.super.executableNameWithSuffix(); - } } diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java index b89001aa7437c..7154895cce427 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java @@ -222,4 +222,36 @@ public String n() { assertEquals("hello", proxyC.m()); assertEquals("bye", proxyC.n()); } + + @Test + public void testComposite() { + interface A { + String sayHello(); + String sayBye(); + default String talk() { + return String.join(",", sayHello(), sayBye()); + } + } + + interface B extends A { + @Override + default String sayHello() { + return "ciao"; + } + } + + var proxy = CompositeProxy.create(B.class, new A() { + @Override + public String sayHello() { + return "hello"; + } + + @Override + public String sayBye() { + return "bye"; + } + }); + + assertEquals("ciao,bye", proxy.talk()); + } } From 3444966929cf0427e3c5dcba3be39033cacebb29 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 15 Nov 2024 20:25:58 -0500 Subject: [PATCH 0153/1101] - Split IOUtils into PathUtils, FileUtils, and XmlUtils classes in jdk.jpackage.internal.util package - Moved jdk.jpackage.test.Functional in jdk.jpackage.internal.util.function package and moved internal classes to outer level --- .../jpackage/internal/DesktopIntegration.java | 8 +- .../internal/LinuxAppImageBuilder.java | 3 +- .../internal/LinuxPackageBundler.java | 3 +- .../internal/MacBaseInstallerBundler.java | 9 +- .../jdk/jpackage/internal/MacDmgBundler.java | 9 +- .../internal/MacLaunchersAsServices.java | 3 +- .../jdk/jpackage/internal/MacPkgBundler.java | 6 +- .../internal/AbstractAppImageBuilder.java | 10 +- .../jpackage/internal/AbstractBundler.java | 3 +- .../jdk/jpackage/internal/AppImageFile.java | 3 +- .../jdk/jpackage/internal/IOUtils.java | 294 +----------------- .../jdk/jpackage/internal/PathGroup.java | 3 +- .../internal/StandardBundlerParam.java | 5 +- .../jdk/jpackage/internal/util/FileUtils.java | 156 ++++++++++ .../jdk/jpackage/internal/util/PathUtils.java | 34 ++ .../internal/util/PrettyPrintHandler.java | 89 ++++++ .../internal/util/SkipDocumentHandler.java | 48 +++ .../jpackage/internal/util/XmlConsumer.java | 34 ++ .../jdk/jpackage/internal/util/XmlUtils.java | 104 +++++++ .../internal/util/function/ExceptionBox.java | 45 +++ .../util/function/FunctionalUtils.java | 56 ++++ .../util/function/ThrowingBiFunction.java | 43 +++ .../util/function/ThrowingConsumer.java | 42 +++ .../util/function/ThrowingFunction.java | 42 +++ .../util/function/ThrowingRunnable.java | 40 +++ .../util/function/ThrowingSupplier.java | 42 +++ .../util/function/ThrowingUnaryOperator.java | 43 +++ .../jdk/jpackage/internal/WinExeBundler.java | 3 +- .../jdk/jpackage/internal/WinMsiBundler.java | 5 +- .../internal/WixAppImageFragmentBuilder.java | 11 +- .../jpackage/internal/WixFragmentBuilder.java | 5 +- .../internal/WixLauncherAsService.java | 5 +- .../jdk/jpackage/internal/WixPipeline.java | 3 +- .../jpackage/internal/WixSourceConverter.java | 3 +- .../jdk/jpackage/internal/WixTool.java | 3 +- .../internal/WixUiFragmentBuilder.java | 2 +- .../jdk/jpackage/test/TKitTest.java | 6 +- .../jdk/jpackage/test/AdditionalLauncher.java | 7 +- .../helpers/jdk/jpackage/test/Executor.java | 2 +- .../jdk/jpackage/test/FileAssociations.java | 4 +- .../helpers/jdk/jpackage/test/Functional.java | 168 ---------- .../helpers/jdk/jpackage/test/HelloApp.java | 9 +- .../jdk/jpackage/test/JPackageCommand.java | 17 +- .../jdk/jpackage/test/JavaAppDesc.java | 9 +- .../test/LauncherAsServiceVerifier.java | 12 +- .../jpackage/test/LauncherIconVerifier.java | 5 +- .../jdk/jpackage/test/LinuxHelper.java | 6 +- .../helpers/jdk/jpackage/test/MacHelper.java | 8 +- .../helpers/jdk/jpackage/test/MethodCall.java | 2 +- .../jdk/jpackage/test/PackageTest.java | 17 +- .../jdk/jpackage/test/PackageType.java | 6 +- .../helpers/jdk/jpackage/test/TKit.java | 19 +- .../jdk/jpackage/test/TestBuilder.java | 4 +- .../jdk/jpackage/test/TestInstance.java | 12 +- .../jdk/jpackage/test/WindowsHelper.java | 2 +- .../tools/jpackage/linux/AppAboutUrlTest.java | 2 +- .../tools/jpackage/share/AppContentTest.java | 6 +- test/jdk/tools/jpackage/share/BasicTest.java | 2 +- test/jdk/tools/jpackage/share/IconTest.java | 4 +- .../tools/jpackage/share/InOutPathTest.java | 2 +- .../tools/jpackage/share/InstallDirTest.java | 4 +- .../tools/jpackage/share/MainClassTest.java | 2 +- .../tools/jpackage/share/PerUserCfgTest.java | 2 +- .../share/RuntimeImageSymbolicLinksTest.java | 9 - .../jpackage/windows/WinLongVersionTest.java | 7 +- .../tools/jpackage/windows/WinScriptTest.java | 5 +- 66 files changed, 975 insertions(+), 602 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PrettyPrintHandler.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/SkipDocumentHandler.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlConsumer.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionBox.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/FunctionalUtils.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java delete mode 100644 test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Functional.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 6a5b200f8f304..548694b4de39a 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -54,6 +54,8 @@ import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; +import jdk.jpackage.internal.util.PathUtils; +import jdk.jpackage.internal.util.XmlUtils; /** * Helper to create files for desktop integration. @@ -119,7 +121,7 @@ private DesktopIntegration(PlatformPackage thePackage, if (withDesktopFile) { desktopFile = new DesktopFile(desktopFileName); iconFile = new DesktopFile(escapedAppFileName - + IOUtils.getSuffix(Path.of(DEFAULT_ICON))); + + PathUtils.getSuffix(Path.of(DEFAULT_ICON))); if (curIconResource == null) { // Create default icon. @@ -420,7 +422,7 @@ private void appendFileAssociation(XMLStreamWriter xml, } private void createFileAssociationsMimeInfoFile() throws IOException { - IOUtils.createXml(mimeInfoFile.srcPath(), xml -> { + XmlUtils.createXml(mimeInfoFile.srcPath(), xml -> { xml.writeStartElement("mime-info"); xml.writeDefaultNamespace( "http://www.freedesktop.org/standards/shared-mime-info"); @@ -451,7 +453,7 @@ private void addFileAssociationIconFiles(ShellCommands shellCommands) // Create icon name for mime type from mime type. DesktopFile faIconFile = new DesktopFile(mimeType.replace( - File.separatorChar, '-') + IOUtils.getSuffix( + File.separatorChar, '-') + PathUtils.getSuffix( assoc.data.iconPath)); IOUtils.copyFile(assoc.data.iconPath, diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index 7291d56218a21..fe427a3dfae64 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -35,6 +35,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; +import jdk.jpackage.internal.util.PathUtils; public class LinuxAppImageBuilder extends AbstractAppImageBuilder { @@ -127,7 +128,7 @@ private void createLauncherForEntryPoint(Map params, mainParams); if (iconResource != null) { Path iconTarget = appLayout.destktopIntegrationDirectory().resolve( - APP_NAME.fetchFrom(params) + IOUtils.getSuffix(Path.of( + APP_NAME.fetchFrom(params) + PathUtils.getSuffix(Path.of( DEFAULT_ICON))); iconResource.saveToFile(iconTarget); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index b510ed414118b..01fb8cc83e29c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -44,6 +44,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; +import jdk.jpackage.internal.util.FileUtils; abstract class LinuxPackageBundler extends AbstractBundler { @@ -144,7 +145,7 @@ public final Path execute(Map params, // Application image is a newly created directory tree. // Move it. srcAppLayout.move(thePackage.sourceApplicationLayout()); - IOUtils.deleteRecursive(srcAppImageRoot); + FileUtils.deleteRecursive(srcAppImageRoot); } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index 8d9db0a007783..75acd426f87d7 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -25,25 +25,20 @@ package jdk.jpackage.internal; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.PrintStream; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; +import jdk.jpackage.internal.util.FileUtils; public abstract class MacBaseInstallerBundler extends AbstractBundler { @@ -187,7 +182,7 @@ protected Path prepareAppBundle(Map params) StandardBundlerParam.getPredefinedAppImage(params); if (predefinedImage != null) { appDir = appImageRoot.resolve(APP_NAME.fetchFrom(params) + ".app"); - IOUtils.copyRecursive(predefinedImage, appDir, + FileUtils.copyRecursive(predefinedImage, appDir, LinkOption.NOFOLLOW_LINKS); // Create PackageFile if predefined app image is not signed diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java index 7d100832dbaf4..d4a10bf1cd4be 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java @@ -48,6 +48,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; import static jdk.jpackage.internal.StandardBundlerParam.VERBOSE; import static jdk.jpackage.internal.StandardBundlerParam.DMG_CONTENT; +import jdk.jpackage.internal.util.FileUtils; public class MacDmgBundler extends MacBaseInstallerBundler { @@ -294,7 +295,7 @@ private Path buildDMG( Map params, MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params)); Path dest = root.resolve("Contents/Home"); - IOUtils.copyRecursive(source, dest); + FileUtils.copyRecursive(source, dest); srcFolder = newRoot; } @@ -319,7 +320,7 @@ private Path buildDMG( Map params, List dmgContent = DMG_CONTENT.fetchFrom(params); for (String content : dmgContent) { Path path = Path.of(content); - IOUtils.copyRecursive(path, srcFolder.resolve(path.getFileName())); + FileUtils.copyRecursive(path, srcFolder.resolve(path.getFileName())); } // create temp image ProcessBuilder pb = new ProcessBuilder( @@ -381,9 +382,9 @@ private Path buildDMG( Map params, Path destPath = mountedRoot .resolve(srcFolder.getFileName()); Files.createDirectory(destPath); - IOUtils.copyRecursive(srcFolder, destPath); + FileUtils.copyRecursive(srcFolder, destPath); } else { - IOUtils.copyRecursive(srcFolder, mountedRoot); + FileUtils.copyRecursive(srcFolder, mountedRoot); } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index b0ee96e2ee3a7..07c4404a8df27 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -33,6 +33,7 @@ import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import jdk.jpackage.internal.util.PathUtils; /** * Helper to install launchers as services using "launchd". @@ -95,7 +96,7 @@ private static class Launcher extends UnixLauncherAsService { // It is recommended to set value of "label" property in launchd // .plist file equal to the name of this .plist file without the suffix. - String label = IOUtils.replaceSuffix(plistFilename.getFileName(), "").toString(); + String label = PathUtils.replaceSuffix(plistFilename.getFileName(), "").toString(); getResource() .setPublicName(plistFilename) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 6ac84975451b4..03ff15b2fe228 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -62,6 +62,8 @@ import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; +import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.XmlUtils; public class MacPkgBundler extends MacBaseInstallerBundler { @@ -267,7 +269,7 @@ private void prepareDistributionXMLFile(Map params) Log.verbose(MessageFormat.format(I18N.getString( "message.preparing-distribution-dist"), f.toAbsolutePath().toString())); - IOUtils.createXml(f, xml -> { + XmlUtils.createXml(f, xml -> { xml.writeStartElement("installer-gui-script"); xml.writeAttribute("minSpecVersion", "1"); @@ -452,7 +454,7 @@ private String getRoot(Map params, source = appLocation; dest = newRoot.resolve(appLocation.getFileName()); } - IOUtils.copyRecursive(source, dest); + FileUtils.copyRecursive(source, dest); return newRoot.toString(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java index b507cc955bd75..b523e43f5aad8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java @@ -32,8 +32,6 @@ import java.util.ArrayList; import java.util.Map; import java.util.List; -import java.util.Objects; -import java.util.stream.Stream; import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.ICON; @@ -42,6 +40,8 @@ import static jdk.jpackage.internal.StandardBundlerParam.OUTPUT_DIR; import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; import jdk.jpackage.internal.resources.ResourceLocator; +import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.PathUtils; /* * AbstractAppImageBuilder @@ -92,7 +92,7 @@ protected void copyApplication(Map params) } } - IOUtils.copyRecursive(inputPath, + FileUtils.copyRecursive(inputPath, appLayout.appDirectory().toAbsolutePath(), excludes); } @@ -100,7 +100,7 @@ protected void copyApplication(Map params) List items = APP_CONTENT.fetchFrom(params); for (String item : items) { - IOUtils.copyRecursive(Path.of(item), + FileUtils.copyRecursive(Path.of(item), appLayout.contentDirectory().resolve(Path.of(item).getFileName())); } } @@ -115,7 +115,7 @@ public static OverridableResource createIconResource(String defaultIconName, } final String resourcePublicName = APP_NAME.fetchFrom(params) - + IOUtils.getSuffix(Path.of(defaultIconName)); + + PathUtils.getSuffix(Path.of(defaultIconName)); IconType iconType = getLauncherIconType(params); if (iconType == IconType.NoIcon) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java index b615176fd15cf..b38c8f0971898 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.nio.file.Path; import java.util.Map; +import jdk.jpackage.internal.util.FileUtils; /** @@ -55,7 +56,7 @@ public String toString() { @Override public void cleanup(Map params) { try { - IOUtils.deleteRecursive( + FileUtils.deleteRecursive( StandardBundlerParam.TEMP_ROOT.fetchFrom(params)); } catch (IOException e) { Log.verbose(e.getMessage()); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index 31228a8f5a3e4..ca73e97671dc8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -59,6 +59,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; +import jdk.jpackage.internal.util.XmlUtils; public final class AppImageFile { @@ -247,7 +248,7 @@ private static void save(Path appImageDir, addLauncherInfoSave = appImage.getAddLaunchers(); } - IOUtils.createXml(getPathInAppImage(appImageDir), xml -> { + XmlUtils.createXml(getPathInAppImage(appImageDir), xml -> { xml.writeStartElement("jpackage-state"); xml.writeAttribute("version", getVersion()); xml.writeAttribute("platform", getPlatform()); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java index 573109a004bc0..534786ada13c9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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,41 +25,15 @@ package jdk.jpackage.internal; -import jdk.internal.util.OperatingSystem; - import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.io.PrintStream; -import java.io.Writer; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.nio.file.FileVisitResult; import java.nio.file.Files; -import java.nio.file.CopyOption; import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.stream.XMLOutputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.stax.StAXResult; /** * IOUtils @@ -68,107 +42,6 @@ */ public class IOUtils { - public static void deleteRecursive(Path directory) throws IOException { - final AtomicReference exception = new AtomicReference<>(); - - if (!Files.exists(directory)) { - return; - } - - Files.walkFileTree(directory, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, - BasicFileAttributes attr) throws IOException { - if (OperatingSystem.isWindows()) { - Files.setAttribute(file, "dos:readonly", false); - } - try { - Files.delete(file); - } catch (IOException ex) { - exception.compareAndSet(null, ex); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, - BasicFileAttributes attr) throws IOException { - if (OperatingSystem.isWindows()) { - Files.setAttribute(dir, "dos:readonly", false); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException e) - throws IOException { - try { - Files.delete(dir); - } catch (IOException ex) { - exception.compareAndSet(null, ex); - } - return FileVisitResult.CONTINUE; - } - }); - if (exception.get() != null) { - throw exception.get(); - } - } - - public static void copyRecursive(Path src, Path dest, CopyOption... options) - throws IOException { - copyRecursive(src, dest, List.of(), options); - } - - public static void copyRecursive(Path src, Path dest, - final List excludes, CopyOption... options) - throws IOException { - - List copyActions = new ArrayList<>(); - - Files.walkFileTree(src, new SimpleFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(final Path dir, - final BasicFileAttributes attrs) { - if (isPathMatch(dir, excludes)) { - return FileVisitResult.SKIP_SUBTREE; - } else { - copyActions.add(new CopyAction(null, dest.resolve(src. - relativize(dir)))); - return FileVisitResult.CONTINUE; - } - } - - @Override - public FileVisitResult visitFile(final Path file, - final BasicFileAttributes attrs) { - if (!isPathMatch(file, excludes)) { - copyActions.add(new CopyAction(file, dest.resolve(src. - relativize(file)))); - } - return FileVisitResult.CONTINUE; - } - }); - - for (var copyAction : copyActions) { - copyAction.apply(options); - } - } - - private static record CopyAction(Path src, Path dest) { - void apply(CopyOption... options) throws IOException { - if (src == null) { - Files.createDirectories(dest); - } else { - Files.copy(src, dest, options); - } - } - } - - private static boolean isPathMatch(Path what, List paths) { - return paths.stream().anyMatch(what::endsWith); - } - public static void copyFile(Path sourceFile, Path destFile) throws IOException { Files.createDirectories(getParent(destFile)); @@ -314,90 +187,6 @@ static void writableOutputDir(Path outdir) throws PackagerException { } } - public static Path replaceSuffix(Path path, String suffix) { - Path parent = path.getParent(); - String filename = getFileName(path).toString().replaceAll("\\.[^.]*$", "") - + Optional.ofNullable(suffix).orElse(""); - return parent != null ? parent.resolve(filename) : Path.of(filename); - } - - public static Path addSuffix(Path path, String suffix) { - Path parent = path.getParent(); - String filename = getFileName(path).toString() + suffix; - return parent != null ? parent.resolve(filename) : Path.of(filename); - } - - public static String getSuffix(Path path) { - String filename = replaceSuffix(getFileName(path), null).toString(); - return getFileName(path).toString().substring(filename.length()); - } - - @FunctionalInterface - public static interface XmlConsumer { - void accept(XMLStreamWriter xml) throws IOException, XMLStreamException; - } - - public static void createXml(Path dstFile, XmlConsumer xmlConsumer) throws - IOException { - XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance(); - Files.createDirectories(getParent(dstFile)); - try (Writer w = Files.newBufferedWriter(dstFile)) { - // Wrap with pretty print proxy - XMLStreamWriter xml = (XMLStreamWriter) Proxy.newProxyInstance( - XMLStreamWriter.class.getClassLoader(), new Class[]{ - XMLStreamWriter.class}, new PrettyPrintHandler( - xmlFactory.createXMLStreamWriter(w))); - - xml.writeStartDocument(); - xmlConsumer.accept(xml); - xml.writeEndDocument(); - xml.flush(); - xml.close(); - } catch (XMLStreamException ex) { - throw new IOException(ex); - } catch (IOException ex) { - throw ex; - } - } - - public static void mergeXmls(XMLStreamWriter xml, Collection sources) - throws XMLStreamException, IOException { - xml = (XMLStreamWriter) Proxy.newProxyInstance( - XMLStreamWriter.class.getClassLoader(), new Class[]{ - XMLStreamWriter.class}, new SkipDocumentHandler(xml)); - - try { - TransformerFactory tf = TransformerFactory.newInstance(); - Result result = new StAXResult(xml); - for (var src : sources) { - tf.newTransformer().transform(src, result); - } - } catch (TransformerException ex) { - // Should never happen - throw new RuntimeException(ex); - } - } - - public static DocumentBuilderFactory initDocumentBuilderFactory() { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); - try { - dbf.setFeature( - "http://apache.org/xml/features/nonvalidating/load-external-dtd", - false); - } catch (ParserConfigurationException ex) { - throw new IllegalStateException(ex); - } - return dbf; - } - - public static DocumentBuilder initDocumentBuilder() { - try { - return initDocumentBuilderFactory().newDocumentBuilder(); - } catch (ParserConfigurationException ex) { - throw new IllegalStateException(ex); - } - } - public static Path getParent(Path p) { Path parent = p.getParent(); if (parent == null) { @@ -430,85 +219,4 @@ public static long getPID(Process p) { return -1; } } - - private static class PrettyPrintHandler implements InvocationHandler { - - PrettyPrintHandler(XMLStreamWriter target) { - this.target = target; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws - Throwable { - switch (method.getName()) { - case "writeStartElement": - // update state of parent node - if (depth > 0) { - hasChildElement.put(depth - 1, true); - } - // reset state of current node - hasChildElement.put(depth, false); - // indent for current depth - target.writeCharacters(EOL); - target.writeCharacters(repeat(depth, INDENT)); - depth++; - break; - case "writeEndElement": - depth--; - if (hasChildElement.get(depth) == true) { - target.writeCharacters(EOL); - target.writeCharacters(repeat(depth, INDENT)); - } - break; - case "writeProcessingInstruction": - case "writeEmptyElement": - // update state of parent node - if (depth > 0) { - hasChildElement.put(depth - 1, true); - } - // indent for current depth - target.writeCharacters(EOL); - target.writeCharacters(repeat(depth, INDENT)); - break; - default: - break; - } - method.invoke(target, args); - return null; - } - - private static String repeat(int d, String s) { - StringBuilder sb = new StringBuilder(); - while (d-- > 0) { - sb.append(s); - } - return sb.toString(); - } - - private final XMLStreamWriter target; - private int depth = 0; - private final Map hasChildElement = new HashMap<>(); - private static final String INDENT = " "; - private static final String EOL = "\n"; - } - - private static class SkipDocumentHandler implements InvocationHandler { - - SkipDocumentHandler(XMLStreamWriter target) { - this.target = target; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws - Throwable { - switch (method.getName()) { - case "writeStartDocument", "writeEndDocument" -> { - } - default -> method.invoke(target, args); - } - return null; - } - - private final XMLStreamWriter target; - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java index 24fb394e100d0..b7681d73c5a0b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java @@ -35,6 +35,7 @@ import java.util.function.BiFunction; import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.jpackage.internal.util.FileUtils; /** @@ -232,7 +233,7 @@ public void createDirectory(Path dir) throws IOException { for (var entry: entries) { Path srcFile = entry.getKey(); if (Files.isDirectory(srcFile)) { - IOUtils.deleteRecursive(srcFile); + FileUtils.deleteRecursive(srcFile); } } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index 718f186c9547a..0209eea584aee 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -44,6 +44,7 @@ import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Stream; +import jdk.jpackage.internal.util.FileUtils; /** * StandardBundlerParam @@ -604,7 +605,7 @@ static void copyPredefinedRuntimeImage(Map params, // copy whole runtime, need to skip jmods and src.zip final List excludes = Arrays.asList(Path.of("jmods"), Path.of("src.zip")); - IOUtils.copyRecursive(topImage, appLayout.runtimeHomeDirectory(), + FileUtils.copyRecursive(topImage, appLayout.runtimeHomeDirectory(), excludes, LinkOption.NOFOLLOW_LINKS); // if module-path given - copy modules to appDir/mods @@ -616,7 +617,7 @@ static void copyPredefinedRuntimeImage(Map params, for (Path mp : modulePath) { if (!defaultModulePath.contains(mp)) { Files.createDirectories(dest); - IOUtils.copyRecursive(mp, dest); + FileUtils.copyRecursive(mp, dest); } } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java new file mode 100644 index 0000000000000..4f0192c21f4b6 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.io.IOException; +import java.nio.file.CopyOption; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.List; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.util.function.ExceptionBox; +import jdk.jpackage.internal.util.function.FunctionalUtils; +import jdk.jpackage.internal.util.function.ThrowingConsumer; + +public final class FileUtils { + + public static void deleteRecursive(Path directory) throws IOException { + if (!Files.exists(directory)) { + return; + } + + var callback = new RecursiveDeleter(); + + Files.walkFileTree(directory, callback); + + if (callback.ex != null) { + throw callback.ex; + } + } + + public static void copyRecursive(Path src, Path dest, CopyOption... options) + throws IOException { + copyRecursive(src, dest, List.of(), options); + } + + public static void copyRecursive(Path src, Path dest, + final List excludes, CopyOption... options) + throws IOException { + + List copyActions = new ArrayList<>(); + + Files.walkFileTree(src, new SimpleFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(final Path dir, + final BasicFileAttributes attrs) { + if (isPathMatch(dir, excludes)) { + return FileVisitResult.SKIP_SUBTREE; + } else { + copyActions.add(new CopyAction(null, dest.resolve(src. + relativize(dir)))); + return FileVisitResult.CONTINUE; + } + } + + @Override + public FileVisitResult visitFile(final Path file, + final BasicFileAttributes attrs) { + if (!isPathMatch(file, excludes)) { + copyActions.add(new CopyAction(file, dest.resolve(src. + relativize(file)))); + } + return FileVisitResult.CONTINUE; + } + }); + + for (var copyAction : copyActions) { + copyAction.apply(options); + } + } + + private static boolean isPathMatch(Path what, List paths) { + return paths.stream().anyMatch(what::endsWith); + } + + private static record CopyAction(Path src, Path dest) { + + void apply(CopyOption... options) throws IOException { + if (src == null) { + Files.createDirectories(dest); + } else { + Files.copy(src, dest, options); + } + } + } + + private static class RecursiveDeleter extends SimpleFileVisitor { + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attr) throws IOException { + adjustAttributes(file); + runActionOnPath(Files::delete, file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, + BasicFileAttributes attr) throws IOException { + adjustAttributes(dir); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException e) + throws IOException { + runActionOnPath(Files::delete, dir); + return FileVisitResult.CONTINUE; + } + + private static void adjustAttributes(Path path) throws IOException { + if (OperatingSystem.isWindows()) { + Files.setAttribute(path, "dos:readonly", false); + } + } + + private void runActionOnPath(ThrowingConsumer action, Path path) { + try { + action.accept(path); + } catch (IOException ex) { + if (this.ex == null) { + this.ex = ex; + } + } catch (Throwable t) { + throw ExceptionBox.rethrowUnchecked(t); + } + } + + private IOException ex; + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java new file mode 100644 index 0000000000000..c8f80835deac8 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java @@ -0,0 +1,34 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package jdk.jpackage.internal.util; + +import java.nio.file.Path; +import java.util.Optional; +import jdk.jpackage.internal.IOUtils; + +public final class PathUtils { + + public static String getSuffix(Path path) { + String filename = replaceSuffix(IOUtils.getFileName(path), null).toString(); + return IOUtils.getFileName(path).toString().substring(filename.length()); + } + + public static Path addSuffix(Path path, String suffix) { + Path parent = path.getParent(); + String filename = IOUtils.getFileName(path).toString() + suffix; + return parent != null ? parent.resolve(filename) : Path.of(filename); + } + + public static Path replaceSuffix(Path path, String suffix) { + Path parent = path.getParent(); + String filename = IOUtils.getFileName(path).toString().replaceAll("\\.[^.]*$", + "") + Optional.ofNullable(suffix).orElse(""); + return parent != null ? parent.resolve(filename) : Path.of(filename); + } + + public static Path resolveNullablePath(Path base, Path path) { + return Optional.ofNullable(path).map(base::resolve).orElse(null); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PrettyPrintHandler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PrettyPrintHandler.java new file mode 100644 index 0000000000000..b3fd3c0643a89 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PrettyPrintHandler.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.xml; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import javax.xml.stream.XMLStreamWriter; + +public class PrettyPrintHandler implements InvocationHandler { + + public PrettyPrintHandler(XMLStreamWriter target) { + this.target = target; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + switch (method.getName()) { + case "writeStartElement": + // update state of parent node + if (depth > 0) { + hasChildElement.put(depth - 1, true); + } + // reset state of current node + hasChildElement.put(depth, false); + // indent for current depth + target.writeCharacters(EOL); + target.writeCharacters(repeat(depth, INDENT)); + depth++; + break; + case "writeEndElement": + depth--; + if (hasChildElement.get(depth) == true) { + target.writeCharacters(EOL); + target.writeCharacters(repeat(depth, INDENT)); + } + break; + case "writeProcessingInstruction": + case "writeEmptyElement": + // update state of parent node + if (depth > 0) { + hasChildElement.put(depth - 1, true); + } + // indent for current depth + target.writeCharacters(EOL); + target.writeCharacters(repeat(depth, INDENT)); + break; + default: + break; + } + method.invoke(target, args); + return null; + } + + private static String repeat(int d, String s) { + StringBuilder sb = new StringBuilder(); + while (d-- > 0) { + sb.append(s); + } + return sb.toString(); + } + + private final XMLStreamWriter target; + private int depth = 0; + private final Map hasChildElement = new HashMap<>(); + private static final String INDENT = " "; + private static final String EOL = "\n"; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/SkipDocumentHandler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/SkipDocumentHandler.java new file mode 100644 index 0000000000000..79a927ff766b8 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/SkipDocumentHandler.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.xml; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import javax.xml.stream.XMLStreamWriter; + +public class SkipDocumentHandler implements InvocationHandler { + + public SkipDocumentHandler(XMLStreamWriter target) { + this.target = target; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + switch (method.getName()) { + case "writeStartDocument", "writeEndDocument" -> { + } + default -> method.invoke(target, args); + } + return null; + } + + private final XMLStreamWriter target; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlConsumer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlConsumer.java new file mode 100644 index 0000000000000..429be6aba05ce --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlConsumer.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.io.IOException; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +@FunctionalInterface +public interface XmlConsumer { + + void accept(XMLStreamWriter xml) throws IOException, XMLStreamException; + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java new file mode 100644 index 0000000000000..ae11995039fb6 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.io.IOException; +import java.io.Writer; +import java.lang.reflect.Proxy; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collection; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stax.StAXResult; +import jdk.jpackage.internal.IOUtils; +import jdk.jpackage.internal.util.xml.PrettyPrintHandler; +import jdk.jpackage.internal.util.xml.SkipDocumentHandler; + +public final class XmlUtils { + + public static void createXml(Path dstFile, XmlConsumer xmlConsumer) throws + IOException { + XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance(); + Files.createDirectories(IOUtils.getParent(dstFile)); + try (Writer w = Files.newBufferedWriter(dstFile)) { + // Wrap with pretty print proxy + XMLStreamWriter xml = (XMLStreamWriter) Proxy.newProxyInstance(XMLStreamWriter.class.getClassLoader(), + new Class[]{XMLStreamWriter.class}, + new PrettyPrintHandler(xmlFactory.createXMLStreamWriter(w))); + xml.writeStartDocument(); + xmlConsumer.accept(xml); + xml.writeEndDocument(); + xml.flush(); + xml.close(); + } catch (XMLStreamException ex) { + throw new IOException(ex); + } catch (IOException ex) { + throw ex; + } + } + + public static void mergeXmls(XMLStreamWriter xml, Collection sources) + throws XMLStreamException, IOException { + xml = (XMLStreamWriter) Proxy.newProxyInstance(XMLStreamWriter.class.getClassLoader(), + new Class[]{XMLStreamWriter.class}, + new SkipDocumentHandler(xml)); + try { + TransformerFactory tf = TransformerFactory.newInstance(); + Result result = new StAXResult(xml); + for (Source src : sources) { + tf.newTransformer().transform(src, result); + } + } catch (TransformerException ex) { + // Should never happen + throw new RuntimeException(ex); + } + } + + public static DocumentBuilder initDocumentBuilder() { + try { + return initDocumentBuilderFactory().newDocumentBuilder(); + } catch (ParserConfigurationException ex) { + throw new IllegalStateException(ex); + } + } + + public static DocumentBuilderFactory initDocumentBuilderFactory() { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); + try { + dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", + false); + } catch (ParserConfigurationException ex) { + throw new IllegalStateException(ex); + } + return dbf; + } +} 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 new file mode 100644 index 0000000000000..112efcbb5233a --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionBox.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +import java.lang.reflect.InvocationTargetException; + +public class ExceptionBox extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public static RuntimeException rethrowUnchecked(Throwable throwable) throws + ExceptionBox { + if (throwable instanceof RuntimeException runtimeThrowable) { + throw runtimeThrowable; + } + if (throwable instanceof InvocationTargetException) { + throw new ExceptionBox(throwable.getCause()); + } + throw new ExceptionBox(throwable); + } + + private ExceptionBox(Throwable throwable) { + super(throwable); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/FunctionalUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/FunctionalUtils.java new file mode 100644 index 0000000000000..a06e071dd2a9d --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/FunctionalUtils.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; + +public final class FunctionalUtils { + + public static Supplier identity(Supplier v) { + return v; + } + + public static Consumer identity(Consumer v) { + return v; + } + + public static BiConsumer identity(BiConsumer v) { + return v; + } + + public static Runnable identity(Runnable v) { + return v; + } + + public static Function identityFunction(Function v) { + return v; + } + + public static Predicate identityPredicate(Predicate v) { + return v; + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java new file mode 100644 index 0000000000000..a8119f25bdb76 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +import java.util.function.BiFunction; + +@FunctionalInterface +public interface ThrowingBiFunction { + + R apply(T t, U u) throws Throwable; + + public static BiFunction toBiFunction( + ThrowingBiFunction v) { + return (t, u) -> { + try { + return v.apply(t, u); + } catch (Throwable ex) { + throw ExceptionBox.rethrowUnchecked(ex); + } + }; + } + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java new file mode 100644 index 0000000000000..5ca33c22d9232 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +import java.util.function.Consumer; + +@FunctionalInterface +public interface ThrowingConsumer { + + void accept(T t) throws Throwable; + + public static Consumer toConsumer(ThrowingConsumer v) { + return o -> { + try { + v.accept(o); + } catch (Throwable ex) { + throw ExceptionBox.rethrowUnchecked(ex); + } + }; + } + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java new file mode 100644 index 0000000000000..22e43548f4df6 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +import java.util.function.Function; + +@FunctionalInterface +public interface ThrowingFunction { + + R apply(T t) throws Throwable; + + public static Function toFunction(ThrowingFunction v) { + return t -> { + try { + return v.apply(t); + } catch (Throwable ex) { + throw ExceptionBox.rethrowUnchecked(ex); + } + }; + } + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java new file mode 100644 index 0000000000000..7f3fcda536ced --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +@FunctionalInterface +public interface ThrowingRunnable { + + void run() throws Throwable; + + public static Runnable toRunnable(ThrowingRunnable v) { + return () -> { + try { + v.run(); + } catch (Throwable ex) { + throw ExceptionBox.rethrowUnchecked(ex); + } + }; + } + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java new file mode 100644 index 0000000000000..2f5ef135875a9 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +import java.util.function.Supplier; + +@FunctionalInterface +public interface ThrowingSupplier { + + T get() throws Throwable; + + public static Supplier toSupplier(ThrowingSupplier v) { + return () -> { + try { + return v.get(); + } catch (Throwable ex) { + throw ExceptionBox.rethrowUnchecked(ex); + } + }; + } + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java new file mode 100644 index 0000000000000..27a3e2f30f5ab --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util.function; + +import java.util.function.UnaryOperator; + +@FunctionalInterface +public interface ThrowingUnaryOperator { + + T apply(T t) throws Throwable; + + public static UnaryOperator toUnaryOperator( + ThrowingUnaryOperator v) { + return t -> { + try { + return v.apply(t); + } catch (Throwable ex) { + throw ExceptionBox.rethrowUnchecked(ex); + } + }; + } + +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java index fa81b4278b06a..5bafe8df75ed2 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java @@ -30,6 +30,7 @@ import java.nio.file.Path; import java.text.MessageFormat; import java.util.Map; +import jdk.jpackage.internal.util.PathUtils; @SuppressWarnings("restricted") public class WinExeBundler extends AbstractBundler { @@ -127,7 +128,7 @@ private Path buildEXE(Map params, Path msi, outdir.toAbsolutePath().toString())); // Copy template msi wrapper next to msi file - final Path exePath = IOUtils.replaceSuffix(msi, ".exe"); + final Path exePath = PathUtils.replaceSuffix(msi, ".exe"); try (InputStream is = OverridableResource.readDefault(EXE_WRAPPER_NAME)) { Files.copy(is, exePath); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index c0ae65b3b0bcc..f6b0fb4be2074 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -36,7 +36,6 @@ import java.nio.file.PathMatcher; import java.text.MessageFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; @@ -67,7 +66,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import jdk.jpackage.internal.WixToolset.WixToolsetType; +import jdk.jpackage.internal.util.FileUtils; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; @@ -367,7 +366,7 @@ private void prepareProto(Map params) if (appImage != null) { appDir = MSI_IMAGE_DIR.fetchFrom(params).resolve(appName); // copy everything from appImage dir into appDir/name - IOUtils.copyRecursive(appImage, appDir); + FileUtils.copyRecursive(appImage, appDir); } else { appDir = appImageBundler.execute(params, MSI_IMAGE_DIR.fetchFrom( params)); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index 5bc20c1413c86..f4a3097719d0d 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -42,7 +42,6 @@ import java.util.Optional; import java.util.Set; import java.util.UUID; -import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -56,7 +55,6 @@ import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import jdk.jpackage.internal.AppImageFile.LauncherInfo; -import jdk.jpackage.internal.IOUtils.XmlConsumer; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; @@ -65,6 +63,9 @@ import static jdk.jpackage.internal.WinMsiBundler.SERVICE_INSTALLER; import static jdk.jpackage.internal.WinMsiBundler.WIN_APP_IMAGE; import jdk.jpackage.internal.WixToolset.WixToolsetType; +import jdk.jpackage.internal.util.PathUtils; +import jdk.jpackage.internal.util.XmlConsumer; +import jdk.jpackage.internal.util.XmlUtils; import org.w3c.dom.NodeList; /** @@ -202,7 +203,7 @@ private void normalizeFileAssociation(FileAssociation fa) { } private static Path addExeSuffixToPath(Path path) { - return IOUtils.addSuffix(path, ".exe"); + return PathUtils.addSuffix(path, ".exe"); } private Path getInstalledFaIcoPath(FileAssociation fa) { @@ -524,7 +525,7 @@ private String addShortcutComponent(XMLStreamWriter xml, Path launcherPath, throw throwInvalidPathException(launcherPath); } - String launcherBasename = IOUtils.replaceSuffix( + String launcherBasename = PathUtils.replaceSuffix( IOUtils.getFileName(launcherPath), "").toString(); Path shortcutPath = folder.getPath(this).resolve(launcherBasename); @@ -774,7 +775,7 @@ private List addServiceConfigs(XMLStreamWriter xml) throws } try { - var buffer = new DOMResult(IOUtils.initDocumentBuilder().newDocument()); + var buffer = new DOMResult(XmlUtils.initDocumentBuilder().newDocument()); var bufferWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( buffer); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java index 0276cc96e6521..f0a5840eb6fc3 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java @@ -37,13 +37,14 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.stream.XMLStreamWriter; -import jdk.jpackage.internal.IOUtils.XmlConsumer; +import jdk.jpackage.internal.util.XmlConsumer; import jdk.jpackage.internal.OverridableResource.Source; import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT; import jdk.internal.util.Architecture; import static jdk.jpackage.internal.OverridableResource.createResource; import jdk.jpackage.internal.WixSourceConverter.ResourceGroup; import jdk.jpackage.internal.WixToolset.WixToolsetType; +import jdk.jpackage.internal.util.XmlUtils; /** * Creates WiX fragment. @@ -159,7 +160,7 @@ final protected void addResource(OverridableResource resource, String saveAsName } private void createWixSource(Path file, XmlConsumer xmlConsumer) throws IOException { - IOUtils.createXml(file, xml -> { + XmlUtils.createXml(file, xml -> { xml.writeStartElement("Wix"); for (var ns : getWixNamespaces().entrySet()) { switch (ns.getKey()) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java index 9b737c8e1a4b6..1252cfdfd92d4 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java @@ -39,6 +39,7 @@ import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import static jdk.jpackage.internal.OverridableResource.createResource; +import jdk.jpackage.internal.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -95,7 +96,7 @@ private void writeResource(OverridableResource resource, XMLStreamWriter xml) resource.saveToStream(buffer); try { - Document doc = IOUtils.initDocumentBuilder().parse( + Document doc = XmlUtils.initDocumentBuilder().parse( new ByteArrayInputStream(buffer.toByteArray())); XPath xPath = XPathFactory.newInstance().newXPath(); @@ -109,7 +110,7 @@ private void writeResource(OverridableResource resource, XMLStreamWriter xml) sources.add(new DOMSource(n)); } - IOUtils.mergeXmls(xml, sources); + XmlUtils.mergeXmls(xml, sources); } catch (SAXException ex) { throw new IOException(ex); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixPipeline.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixPipeline.java index 835247ed1debb..5b626c8a565f5 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixPipeline.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixPipeline.java @@ -36,6 +36,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.jpackage.internal.util.PathUtils; /** * WiX pipeline. Compiles and links WiX sources. @@ -180,7 +181,7 @@ private void buildMsiWix3(Path msi) throws IOException { } private Path compileWix3(WixSource wixSource) throws IOException { - Path wixObj = wixObjDir.toAbsolutePath().resolve(IOUtils.replaceSuffix( + Path wixObj = wixObjDir.toAbsolutePath().resolve(PathUtils.replaceSuffix( IOUtils.getFileName(wixSource.source), ".wixobj")); List cmdline = new ArrayList<>(List.of( diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java index 7786d64a78693..86ef70442dcba 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java @@ -52,6 +52,7 @@ import javax.xml.transform.stax.StAXResult; import javax.xml.transform.stream.StreamSource; import jdk.jpackage.internal.WixToolset.WixToolsetType; +import jdk.jpackage.internal.util.XmlUtils; import org.w3c.dom.Document; import org.xml.sax.SAXException; @@ -98,7 +99,7 @@ Status appyTo(OverridableResource resource, Path resourceSaveAsFile) throws IOEx Document inputXmlDom; try { - inputXmlDom = IOUtils.initDocumentBuilder().parse(new ByteArrayInputStream(buf)); + inputXmlDom = XmlUtils.initDocumentBuilder().parse(new ByteArrayInputStream(buf)); } catch (SAXException ex) { // Malformed XML, don't run converter, save as is. resource.saveToFile(resourceSaveAsFile); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java index f16b28edf2448..ee98327b03233 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java @@ -41,6 +41,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.jpackage.internal.WixToolset.WixToolsetType; +import jdk.jpackage.internal.util.PathUtils; /** * WiX tool. @@ -51,7 +52,7 @@ public enum WixTool { Wix4("wix", DottedVersion.lazy("4.0.4")); WixTool(String commandName, DottedVersion minimalVersion) { - this.toolFileName = IOUtils.addSuffix(Path.of(commandName), ".exe"); + this.toolFileName = PathUtils.addSuffix(Path.of(commandName), ".exe"); this.minimalVersion = minimalVersion; } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java index 4f39a65e3b6ad..435cf8f8e4211 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java @@ -39,7 +39,7 @@ import java.util.stream.Stream; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import jdk.jpackage.internal.IOUtils.XmlConsumer; +import jdk.jpackage.internal.util.XmlConsumer; import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; import jdk.jpackage.internal.WixAppImageFragmentBuilder.ShortcutsFolder; diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java index 3f55c3c50aea9..98a7d8731901d 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java @@ -37,9 +37,9 @@ import java.util.stream.Stream; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Functional.ThrowingRunnable; -import static jdk.jpackage.test.Functional.ThrowingRunnable.toRunnable; -import static jdk.jpackage.test.Functional.ThrowingSupplier.toSupplier; +import jdk.jpackage.internal.util.function.ThrowingRunnable; +import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; public class TKitTest { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java index 6c388ac77ffb9..b5180720177f7 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java @@ -37,8 +37,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.test.Functional.ThrowingBiConsumer; -import static jdk.jpackage.test.Functional.ThrowingFunction.toFunction; +import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; +import jdk.jpackage.internal.util.function.ThrowingBiConsumer; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; public class AdditionalLauncher { @@ -189,7 +190,7 @@ private void initialize(JPackageCommand cmd) { propsFile = TKit.createTempFile(propsFile); TKit.deleteIfExists(propsFile); } catch (IOException ex) { - Functional.rethrowUnchecked(ex); + rethrowUnchecked(ex); } } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index 72ebb64a14294..5e54fa2f357a4 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -42,7 +42,7 @@ import java.util.spi.ToolProvider; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.test.Functional.ThrowingSupplier; +import jdk.jpackage.internal.util.function.ThrowingSupplier; public final class Executor extends CommandArguments { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java index 4908519782896..a3f5853f9e9d0 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java @@ -32,7 +32,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; -import jdk.jpackage.internal.IOUtils; +import jdk.jpackage.internal.util.PathUtils; final public class FileAssociations { @@ -79,7 +79,7 @@ Path getLinuxIconFileName() { if (icon == null) { return null; } - return Path.of(getMime().replace('/', '-') + IOUtils.getSuffix(icon)); + return Path.of(getMime().replace('/', '-') + PathUtils.getSuffix(icon)); } Path getPropertiesFile() { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Functional.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Functional.java deleted file mode 100644 index a57caa92cb20e..0000000000000 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Functional.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.test; - -import java.lang.reflect.InvocationTargetException; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.Supplier; - - -public class Functional { - @FunctionalInterface - public interface ThrowingConsumer { - void accept(T t) throws Throwable; - - public static Consumer toConsumer(ThrowingConsumer v) { - return o -> { - try { - v.accept(o); - } catch (Throwable ex) { - rethrowUnchecked(ex); - } - }; - } - } - - @FunctionalInterface - public interface ThrowingBiConsumer { - void accept(T t, U u) throws Throwable; - - public static BiConsumer toBiConsumer(ThrowingBiConsumer v) { - return (t, u) -> { - try { - v.accept(t, u); - } catch (Throwable ex) { - rethrowUnchecked(ex); - } - }; - } - } - - @FunctionalInterface - public interface ThrowingSupplier { - T get() throws Throwable; - - public static Supplier toSupplier(ThrowingSupplier v) { - return () -> { - try { - return v.get(); - } catch (Throwable ex) { - rethrowUnchecked(ex); - } - // Unreachable - return null; - }; - } - } - - @FunctionalInterface - public interface ThrowingFunction { - R apply(T t) throws Throwable; - - public static Function toFunction(ThrowingFunction v) { - return (t) -> { - try { - return v.apply(t); - } catch (Throwable ex) { - rethrowUnchecked(ex); - } - // Unreachable - return null; - }; - } - } - - @FunctionalInterface - public interface ThrowingRunnable { - void run() throws Throwable; - - public static Runnable toRunnable(ThrowingRunnable v) { - return () -> { - try { - v.run(); - } catch (Throwable ex) { - rethrowUnchecked(ex); - } - }; - } - } - - public static Supplier identity(Supplier v) { - return v; - } - - public static Consumer identity(Consumer v) { - return v; - } - - public static BiConsumer identity(BiConsumer v) { - return v; - } - - public static Runnable identity(Runnable v) { - return v; - } - - public static Function identity(Function v) { - return v; - } - - public static Function identityFunction(Function v) { - return v; - } - - public static Predicate identity(Predicate v) { - return v; - } - - public static Predicate identityPredicate(Predicate v) { - return v; - } - - public static class ExceptionBox extends RuntimeException { - public ExceptionBox(Throwable throwable) { - super(throwable); - } - } - - @SuppressWarnings("unchecked") - public static RuntimeException rethrowUnchecked(Throwable throwable) throws - ExceptionBox { - if (throwable instanceof RuntimeException err) { - throw err; - } - - if (throwable instanceof Error err) { - throw err; - } - - if (throwable instanceof InvocationTargetException err) { - throw rethrowUnchecked(err.getCause()); - } - - throw new ExceptionBox(throwable); - } -} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java index bc722e7acd925..cce373dd9c0d3 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java @@ -40,9 +40,10 @@ import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import jdk.jpackage.test.Functional.ThrowingConsumer; -import jdk.jpackage.test.Functional.ThrowingFunction; -import jdk.jpackage.test.Functional.ThrowingSupplier; +import jdk.jpackage.internal.util.function.FunctionalUtils; +import jdk.jpackage.internal.util.function.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingFunction; +import jdk.jpackage.internal.util.function.ThrowingSupplier; public final class HelloApp { @@ -87,7 +88,7 @@ private JarBuilder prepareSources(Path srcDir) throws IOException { AtomicBoolean classDeclared = new AtomicBoolean(); AtomicBoolean packageInserted = new AtomicBoolean(packageName == null); - var packageInserter = Functional.identityFunction((line) -> { + var packageInserter = FunctionalUtils.identityFunction((line) -> { packageInserted.setPlain(true); return String.format("package %s;%s%s", packageName, System.lineSeparator(), line); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 9b25c9058d184..e6931ecf4b692 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -45,15 +45,16 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.IOUtils; import jdk.jpackage.internal.AppImageFile; import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.internal.PackageFile; +import jdk.jpackage.internal.util.XmlUtils; +import jdk.jpackage.internal.util.function.FunctionalUtils; import static jdk.jpackage.test.AdditionalLauncher.forEachAdditionalLauncher; -import jdk.jpackage.test.Functional.ThrowingConsumer; -import jdk.jpackage.test.Functional.ThrowingFunction; -import jdk.jpackage.test.Functional.ThrowingRunnable; -import jdk.jpackage.test.Functional.ThrowingSupplier; +import jdk.jpackage.internal.util.function.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingFunction; +import jdk.jpackage.internal.util.function.ThrowingRunnable; +import jdk.jpackage.internal.util.function.ThrowingSupplier; /** * jpackage command line with prerequisite actions. Prerequisite actions can be @@ -314,7 +315,7 @@ public void createJPackageXMLFile(String mainLauncher, String mainClass) "Error: --app-image expected"); })); - IOUtils.createXml(jpackageXMLFile, xml -> { + XmlUtils.createXml(jpackageXMLFile, xml -> { xml.writeStartElement("jpackage-state"); xml.writeAttribute("version", AppImageFile.getVersion()); xml.writeAttribute("platform", AppImageFile.getPlatform()); @@ -1189,7 +1190,7 @@ public void run() { private Set appLayoutAsserts = Set.of(AppLayoutAssert.values()); private static boolean defaultWithToolProvider; - private static final Map PACKAGE_TYPES = Functional.identity( + private static final Map PACKAGE_TYPES = FunctionalUtils.identity( () -> { Map reply = new HashMap<>(); for (PackageType type : PackageType.values()) { @@ -1198,7 +1199,7 @@ public void run() { return reply; }).get(); - public static final Path DEFAULT_RUNTIME_IMAGE = Functional.identity(() -> { + public static final Path DEFAULT_RUNTIME_IMAGE = FunctionalUtils.identity(() -> { // Set the property to the path of run-time image to speed up // building app images and platform bundles by avoiding running jlink // The value of the property will be automativcally appended to diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java index 3cc2458ce2acc..e55136e093e5f 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java @@ -25,6 +25,7 @@ import java.nio.file.Path; import java.util.Objects; import java.util.stream.Stream; +import jdk.jpackage.internal.util.function.FunctionalUtils; public final class JavaAppDesc { @@ -237,7 +238,7 @@ public static JavaAppDesc parse(final String javaAppDesc) { return desc; } - String srcJavaPathAndOther = Functional.identity(() -> { + String srcJavaPathAndOther = FunctionalUtils.identity(() -> { String[] components = javaAppDesc.split("\\*", 2); if (components.length == 2) { desc.setSrcJavaPath(Path.of(components[0])); @@ -245,7 +246,7 @@ public static JavaAppDesc parse(final String javaAppDesc) { return components[components.length - 1]; }).get(); - String moduleNameAndOther = Functional.identity(() -> { + String moduleNameAndOther = FunctionalUtils.identity(() -> { String[] components = srcJavaPathAndOther.split(":", 2); if (components.length == 2) { desc.setBundleFileName(components[0]); @@ -253,7 +254,7 @@ public static JavaAppDesc parse(final String javaAppDesc) { return components[components.length - 1]; }).get(); - String classNameAndOther = Functional.identity(() -> { + String classNameAndOther = FunctionalUtils.identity(() -> { String[] components = moduleNameAndOther.split("/", 2); if (components.length == 2) { desc.setModuleName(components[0]); @@ -261,7 +262,7 @@ public static JavaAppDesc parse(final String javaAppDesc) { return components[components.length - 1]; }).get(); - Functional.identity(() -> { + FunctionalUtils.identity(() -> { String[] components = classNameAndOther.split("@", 2); if (components[0].endsWith("!")) { components[0] = components[0].substring(0, diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java index 026da0df0eb08..d73029ab153c3 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java @@ -35,8 +35,10 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.IOUtils; -import static jdk.jpackage.test.Functional.ThrowingConsumer.toConsumer; +import jdk.jpackage.internal.util.PathUtils; +import jdk.jpackage.internal.util.function.ThrowingBiConsumer; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; +import jdk.jpackage.internal.util.function.ThrowingRunnable; import static jdk.jpackage.test.PackageType.LINUX; import static jdk.jpackage.test.PackageType.MAC_PKG; import static jdk.jpackage.test.PackageType.WINDOWS; @@ -187,7 +189,7 @@ static List getLaunchersAsServices(JPackageCommand cmd) { } AdditionalLauncher.forEachAdditionalLauncher(cmd, - Functional.ThrowingBiConsumer.toBiConsumer( + ThrowingBiConsumer.toBiConsumer( (launcherName, propFilePath) -> { if (Files.readAllLines(propFilePath).stream().anyMatch( line -> { @@ -335,14 +337,14 @@ private static void verifyMacDaemonPlistFile(JPackageCommand cmd, TKit.assertEquals(installedLauncherPath.toString(), args.get(0), "Check path to launcher in 'ProgramArguments' property in the property file"); - var expectedLabel = IOUtils.replaceSuffix(servicePlistFile.getFileName(), "").toString(); + var expectedLabel = PathUtils.replaceSuffix(servicePlistFile.getFileName(), "").toString(); TKit.assertEquals(expectedLabel, servicePlist.queryValue("Label"), "Check value of 'Label' property in the property file"); } private static void delayInstallVerify() { // Sleep a bit to let system launch the service - Functional.ThrowingRunnable.toRunnable(() -> Thread.sleep(5 * 1000)).run(); + ThrowingRunnable.toRunnable(() -> Thread.sleep(5 * 1000)).run(); } private Path appOutputFilePathInitialize() { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java index 2de2e002a9470..b71bb1b2ec94d 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java @@ -31,6 +31,7 @@ import java.nio.file.Path; import java.util.Optional; import javax.imageio.ImageIO; +import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; public final class LauncherIconVerifier { public LauncherIconVerifier() { @@ -176,7 +177,7 @@ private WinIconVerifier() { iconSwapWrapper.setAccessible(true); } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) { - throw Functional.rethrowUnchecked(ex); + throw rethrowUnchecked(ex); } } @@ -254,7 +255,7 @@ private void setIcon(Path iconPath, Path launcherPath) { } } } catch (IllegalAccessException | InvocationTargetException ex) { - throw Functional.rethrowUnchecked(ex); + throw rethrowUnchecked(ex); } } finally { launcherPath.toFile().setWritable(false, true); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index bf5ced09bc771..fc494fffc38a6 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -40,8 +40,8 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.IOUtils; -import jdk.jpackage.test.Functional.ThrowingConsumer; +import jdk.jpackage.internal.util.PathUtils; +import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.test.PackageTest.PackageHandlers; @@ -553,7 +553,7 @@ private static String queryMimeTypeDefaultHandler(String mimeType) { private static void verifyIconInScriptlet(Scriptlet scriptletType, List scriptletBody, Path iconPathInPackage) { - final String dashMime = IOUtils.replaceSuffix( + final String dashMime = PathUtils.replaceSuffix( iconPathInPackage.getFileName(), null).toString(); final String xdgCmdName = "xdg-icon-resource"; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index 63afb6cf9f765..9cadd419ca135 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -43,11 +43,11 @@ import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.IOUtils; -import jdk.jpackage.test.Functional.ThrowingConsumer; -import jdk.jpackage.test.Functional.ThrowingSupplier; +import jdk.jpackage.internal.util.function.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingSupplier; import jdk.jpackage.test.PackageTest.PackageHandlers; import jdk.jpackage.internal.RetryExecutor; +import jdk.jpackage.internal.util.PathUtils; import org.xml.sax.SAXException; import org.w3c.dom.NodeList; @@ -212,7 +212,7 @@ static PackageHandlers createPkgPackageHandlers() { // Unpack all ".pkg" files from $dataDir folder in $unpackDir folder try (var dataListing = Files.list(dataDir)) { dataListing.filter(file -> { - return ".pkg".equals(IOUtils.getSuffix(file.getFileName())); + return ".pkg".equals(PathUtils.getSuffix(file.getFileName())); }).forEach(ThrowingConsumer.toConsumer(pkgDir -> { // Installation root of the package is stored in // /pkg-info@install-location attribute in $pkgDir/PackageInfo xml file diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java index 2aaba054a9bc7..24e5d5802f7dc 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java @@ -33,7 +33,7 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.test.Functional.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.test.TestInstance.TestDesc; class MethodCall implements ThrowingConsumer { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index 6f486425e7316..b025a3a0a7b97 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -46,13 +46,14 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; import jdk.jpackage.internal.ApplicationLayout; -import jdk.jpackage.test.Functional.ThrowingBiConsumer; -import static jdk.jpackage.test.Functional.ThrowingBiConsumer.toBiConsumer; -import jdk.jpackage.test.Functional.ThrowingConsumer; -import static jdk.jpackage.test.Functional.ThrowingConsumer.toConsumer; -import jdk.jpackage.test.Functional.ThrowingRunnable; -import static jdk.jpackage.test.Functional.ThrowingSupplier.toSupplier; -import static jdk.jpackage.test.Functional.rethrowUnchecked; +import jdk.jpackage.internal.util.function.ThrowingBiConsumer; +import static jdk.jpackage.internal.util.function.ThrowingBiConsumer.toBiConsumer; +import jdk.jpackage.internal.util.function.ThrowingConsumer; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; +import jdk.jpackage.internal.util.function.ThrowingRunnable; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; +import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; +import jdk.jpackage.internal.util.function.FunctionalUtils; import static jdk.jpackage.test.PackageType.LINUX; import static jdk.jpackage.test.PackageType.LINUX_DEB; import static jdk.jpackage.test.PackageType.LINUX_RPM; @@ -532,7 +533,7 @@ private void handleAction(Action action, T handler, private Path unpackDir; private Action unhandledAction; private boolean terminated; - private final JPackageCommand cmd = Functional.identity(() -> { + private final JPackageCommand cmd = FunctionalUtils.identity(() -> { JPackageCommand result = new JPackageCommand(); result.setDefaultInputOutput().setDefaultAppName(); if (BUNDLE_OUTPUT_DIR != null && !ignoreBundleOutputDir) { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageType.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageType.java index 71637ef7134a6..f8121c1a4c09b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageType.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageType.java @@ -32,6 +32,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.jpackage.internal.Log; +import static jdk.jpackage.internal.util.function.ExceptionWrapper.rethrowUnchecked; +import jdk.jpackage.internal.util.function.FunctionalUtils; /** * jpackage type traits. @@ -103,7 +105,7 @@ private static boolean isBundlerSupportedImpl(String bundlerClass) { } catch (ClassNotFoundException | IllegalAccessException ex) { } catch (InstantiationException | NoSuchMethodException | InvocationTargetException ex) { - Functional.rethrowUnchecked(ex); + rethrowUnchecked(ex); } return false; } @@ -127,7 +129,7 @@ private static boolean isBundlerSupported(String bundlerClass) { thread.run(); thread.join(); } catch (InterruptedException ex) { - Functional.rethrowUnchecked(ex); + rethrowUnchecked(ex); } return reply.get(); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index 28c58a4db3dd3..a829d3e32c2c5 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -61,14 +61,15 @@ import static java.util.stream.Collectors.toSet; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; -import jdk.jpackage.test.Functional.ExceptionBox; -import jdk.jpackage.test.Functional.ThrowingConsumer; -import jdk.jpackage.test.Functional.ThrowingRunnable; -import jdk.jpackage.test.Functional.ThrowingSupplier; +import jdk.jpackage.internal.util.function.ExceptionBox; +import jdk.jpackage.internal.util.function.FunctionalUtils; +import jdk.jpackage.internal.util.function.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingRunnable; +import jdk.jpackage.internal.util.function.ThrowingSupplier; public final class TKit { - public static final Path TEST_SRC_ROOT = Functional.identity(() -> { + public static final Path TEST_SRC_ROOT = FunctionalUtils.identity(() -> { Path root = Path.of(System.getProperty("test.src")); for (int i = 0; i != 10; ++i) { @@ -81,11 +82,11 @@ public final class TKit { throw new RuntimeException("Failed to locate apps directory"); }).get(); - public static final Path SRC_ROOT = Functional.identity(() -> { + public static final Path SRC_ROOT = FunctionalUtils.identity(() -> { return TEST_SRC_ROOT.resolve("../../../../src/jdk.jpackage").normalize().toAbsolutePath(); }).get(); - public static final String ICON_SUFFIX = Functional.identity(() -> { + public static final String ICON_SUFFIX = FunctionalUtils.identity(() -> { if (isOSX()) { return ".icns"; } @@ -869,7 +870,7 @@ public static void assertStringListEquals(List expected, traceAssert(concatMessages("assertStringListEquals()", msg)); - String idxFieldFormat = Functional.identity(() -> { + String idxFieldFormat = FunctionalUtils.identity(() -> { int listSize = expected.size(); int width = 0; while (listSize != 0) { @@ -1055,7 +1056,7 @@ static Set tokenizeConfigProperty(String propertyName) { return tokens.stream().collect(Collectors.toSet()); } - static final Path LOG_FILE = Functional.identity(() -> { + static final Path LOG_FILE = FunctionalUtils.identity(() -> { String val = getConfigProperty("logfile"); if (val == null) { return null; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java index bb699ba3b9c9f..096e8160c9734 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java @@ -47,8 +47,8 @@ import jdk.jpackage.test.Annotations.ParameterGroup; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Functional.ThrowingConsumer; -import jdk.jpackage.test.Functional.ThrowingFunction; +import jdk.jpackage.internal.util.function.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingFunction; final class TestBuilder implements AutoCloseable { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java index 105c8f707cd4d..cb60de9a3634c 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java @@ -38,9 +38,11 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.test.Functional.ThrowingConsumer; -import jdk.jpackage.test.Functional.ThrowingFunction; -import jdk.jpackage.test.Functional.ThrowingRunnable; +import jdk.jpackage.internal.util.function.FunctionalUtils; +import jdk.jpackage.internal.util.function.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingFunction; +import jdk.jpackage.internal.util.function.ThrowingRunnable; +import jdk.jpackage.internal.util.function.ThrowingSupplier; final class TestInstance implements ThrowingRunnable { @@ -260,7 +262,7 @@ private static Class enclosingMainMethodClass() { StackTraceElement st[] = Thread.currentThread().getStackTrace(); for (StackTraceElement ste : st) { if ("main".equals(ste.getMethodName())) { - return Functional.ThrowingSupplier.toSupplier(() -> Class.forName( + return ThrowingSupplier.toSupplier(() -> Class.forName( ste.getClassName())).get(); } } @@ -331,7 +333,7 @@ public String toString() { private final boolean dryRun; private final Path workDir; - private final static Set KEEP_WORK_DIR = Functional.identity( + private final static Set KEEP_WORK_DIR = FunctionalUtils.identity( () -> { final String propertyName = "keep-work-dir"; Set keepWorkDir = TKit.tokenizeConfigProperty( diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java index 1976a5cf72c19..42ea9e3e9a74f 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java @@ -36,7 +36,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.test.Functional.ThrowingRunnable; +import jdk.jpackage.internal.util.function.ThrowingRunnable; import jdk.jpackage.test.PackageTest.PackageHandlers; public class WindowsHelper { diff --git a/test/jdk/tools/jpackage/linux/AppAboutUrlTest.java b/test/jdk/tools/jpackage/linux/AppAboutUrlTest.java index 0d8f0ec4805e1..aef46e2972519 100644 --- a/test/jdk/tools/jpackage/linux/AppAboutUrlTest.java +++ b/test/jdk/tools/jpackage/linux/AppAboutUrlTest.java @@ -22,7 +22,7 @@ */ import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Functional.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java index e056070a5fca4..0d097e05d2c0a 100644 --- a/test/jdk/tools/jpackage/share/AppContentTest.java +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -33,8 +33,8 @@ import java.util.List; import static java.util.stream.Collectors.joining; import java.util.stream.Stream; -import jdk.jpackage.internal.IOUtils; -import jdk.jpackage.test.Functional.ThrowingFunction; +import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.function.ThrowingFunction; import jdk.jpackage.test.JPackageCommand; @@ -148,7 +148,7 @@ private static Path copyAppContentPath(Path appContentPath) throws IOException { var srcPath = TKit.TEST_SRC_ROOT.resolve(appContentPath); var dstPath = appContentArg.resolve(srcPath.getFileName()); Files.createDirectories(dstPath.getParent()); - IOUtils.copyRecursive(srcPath, dstPath); + FileUtils.copyRecursive(srcPath, dstPath); return appContentArg; } diff --git a/test/jdk/tools/jpackage/share/BasicTest.java b/test/jdk/tools/jpackage/share/BasicTest.java index 61668b9e87896..c6e4e93015519 100644 --- a/test/jdk/tools/jpackage/share/BasicTest.java +++ b/test/jdk/tools/jpackage/share/BasicTest.java @@ -41,7 +41,7 @@ import jdk.jpackage.test.JavaTool; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Annotations.Parameter; -import jdk.jpackage.test.Functional.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingConsumer; import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE_AND_UNPACK; /* diff --git a/test/jdk/tools/jpackage/share/IconTest.java b/test/jdk/tools/jpackage/share/IconTest.java index 2d6469f5f2e8b..676b062ed66ac 100644 --- a/test/jdk/tools/jpackage/share/IconTest.java +++ b/test/jdk/tools/jpackage/share/IconTest.java @@ -41,8 +41,8 @@ import jdk.jpackage.test.Executor; import jdk.jpackage.test.LinuxHelper; import jdk.jpackage.test.AdditionalLauncher; -import jdk.jpackage.test.Functional.ThrowingConsumer; -import jdk.jpackage.test.Functional.ThrowingBiConsumer; +import jdk.jpackage.internal.util.function.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingBiConsumer; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java index f8cb983bd1657..1d5bb39bde316 100644 --- a/test/jdk/tools/jpackage/share/InOutPathTest.java +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -36,7 +36,7 @@ import jdk.jpackage.internal.PackageFile; import jdk.jpackage.test.Annotations; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Functional.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageCommand.AppLayoutAssert; import jdk.jpackage.test.PackageTest; diff --git a/test/jdk/tools/jpackage/share/InstallDirTest.java b/test/jdk/tools/jpackage/share/InstallDirTest.java index 7047f35e87bf0..a53a080c33023 100644 --- a/test/jdk/tools/jpackage/share/InstallDirTest.java +++ b/test/jdk/tools/jpackage/share/InstallDirTest.java @@ -27,7 +27,7 @@ import jdk.jpackage.test.TKit; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; -import jdk.jpackage.test.Functional; +import jdk.jpackage.internal.util.function.FunctionalUtils; import jdk.jpackage.test.Annotations.Parameter; /** @@ -77,7 +77,7 @@ public class InstallDirTest { public static void testCommon() { - final Map INSTALL_DIRS = Functional.identity(() -> { + final Map INSTALL_DIRS = FunctionalUtils.identity(() -> { Map reply = new HashMap<>(); reply.put(PackageType.WIN_MSI, Path.of("TestVendor\\InstallDirTest1234")); reply.put(PackageType.WIN_EXE, reply.get(PackageType.WIN_MSI)); diff --git a/test/jdk/tools/jpackage/share/MainClassTest.java b/test/jdk/tools/jpackage/share/MainClassTest.java index d9188e8f18fd3..a031bbc278802 100644 --- a/test/jdk/tools/jpackage/share/MainClassTest.java +++ b/test/jdk/tools/jpackage/share/MainClassTest.java @@ -44,7 +44,7 @@ import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.CfgFile; -import jdk.jpackage.test.Functional.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingConsumer; diff --git a/test/jdk/tools/jpackage/share/PerUserCfgTest.java b/test/jdk/tools/jpackage/share/PerUserCfgTest.java index 0fff7eb3a2de7..2e62aa5c5d631 100644 --- a/test/jdk/tools/jpackage/share/PerUserCfgTest.java +++ b/test/jdk/tools/jpackage/share/PerUserCfgTest.java @@ -29,7 +29,7 @@ import jdk.jpackage.test.AdditionalLauncher; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Functional.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.test.HelloApp; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.LinuxHelper; diff --git a/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java b/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java index 0e48df630afc9..649ac0a369513 100644 --- a/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java +++ b/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java @@ -21,20 +21,11 @@ * questions. */ -import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.test.TKit; -import jdk.jpackage.test.PackageTest; -import jdk.jpackage.test.PackageType; -import jdk.jpackage.test.Functional; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JavaTool; import jdk.jpackage.test.Executor; diff --git a/test/jdk/tools/jpackage/windows/WinLongVersionTest.java b/test/jdk/tools/jpackage/windows/WinLongVersionTest.java index 0d52da65630e5..7a915b5c123fd 100644 --- a/test/jdk/tools/jpackage/windows/WinLongVersionTest.java +++ b/test/jdk/tools/jpackage/windows/WinLongVersionTest.java @@ -24,7 +24,6 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Set; import java.util.UUID; import java.util.function.Supplier; import javax.xml.transform.Result; @@ -36,7 +35,7 @@ import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.IOUtils; +import jdk.jpackage.internal.util.XmlUtils; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Executor; import jdk.jpackage.test.PackageTest; @@ -148,7 +147,7 @@ public static void test() throws IOException { Path scriptPath = resourceDir.resolve(String.format( "%s-post-msi.wsf", cmd.name())); - IOUtils.createXml(scriptPath, xml -> { + XmlUtils.createXml(scriptPath, xml -> { xml.writeStartElement("job"); xml.writeAttribute("id", "main"); xml.writeStartElement("script"); @@ -194,7 +193,7 @@ public static void testNoUpgradeTable() throws IOException { cmd.setFakeRuntime(); // Create package without Upgrade table - Document doc = IOUtils.initDocumentBuilder().parse( + Document doc = XmlUtils.initDocumentBuilder().parse( Files.newInputStream(TKit.SRC_ROOT.resolve( "windows/classes/jdk/jpackage/internal/resources/main.wxs"))); XPath xPath = XPathFactory.newInstance().newXPath(); diff --git a/test/jdk/tools/jpackage/windows/WinScriptTest.java b/test/jdk/tools/jpackage/windows/WinScriptTest.java index 296da482bb075..98b4922826dda 100644 --- a/test/jdk/tools/jpackage/windows/WinScriptTest.java +++ b/test/jdk/tools/jpackage/windows/WinScriptTest.java @@ -24,8 +24,7 @@ import java.io.IOException; import java.nio.file.Path; import java.util.List; -import java.util.ArrayList; -import jdk.jpackage.internal.IOUtils; +import jdk.jpackage.internal.util.XmlUtils; import jdk.jpackage.test.TKit; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; @@ -147,7 +146,7 @@ void assertJPackageOutput(List output) { } void createScript(JPackageCommand cmd) throws IOException { - IOUtils.createXml(Path.of(cmd.getArgumentValue("--resource-dir"), + XmlUtils.createXml(Path.of(cmd.getArgumentValue("--resource-dir"), String.format("%s-%s.wsf", cmd.name(), scriptSuffixName)), xml -> { xml.writeStartElement("job"); xml.writeAttribute("id", "main"); From dc5a0cdd374378e195d6b8f5dc0969275d1d010a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 15 Nov 2024 20:28:17 -0500 Subject: [PATCH 0154/1101] Copyright year updated --- .../linux/classes/jdk/jpackage/internal/DesktopIntegration.java | 2 +- .../classes/jdk/jpackage/internal/LinuxAppImageBuilder.java | 2 +- .../classes/jdk/jpackage/internal/LinuxPackageBundler.java | 2 +- .../classes/jdk/jpackage/internal/MacBaseInstallerBundler.java | 2 +- .../macosx/classes/jdk/jpackage/internal/MacDmgBundler.java | 2 +- .../classes/jdk/jpackage/internal/MacLaunchersAsServices.java | 2 +- .../macosx/classes/jdk/jpackage/internal/MacPkgBundler.java | 2 +- .../share/classes/jdk/jpackage/internal/AbstractBundler.java | 2 +- .../share/classes/jdk/jpackage/internal/AppImageFile.java | 2 +- .../share/classes/jdk/jpackage/internal/PathGroup.java | 2 +- .../windows/classes/jdk/jpackage/internal/WinExeBundler.java | 2 +- .../classes/jdk/jpackage/internal/WixLauncherAsService.java | 2 +- .../classes/jdk/jpackage/internal/WixUiFragmentBuilder.java | 2 +- .../jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java | 2 +- test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java | 2 +- .../jpackage/helpers/jdk/jpackage/test/FileAssociations.java | 2 +- .../helpers/jdk/jpackage/test/LauncherIconVerifier.java | 2 +- .../tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java | 2 +- .../tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java | 2 +- .../tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java | 2 +- .../tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 548694b4de39a..a9cf2682cd700 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index fe427a3dfae64..ab97e327003ca 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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 diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 01fb8cc83e29c..5d160d4128c85 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index 75acd426f87d7..69ecce068e733 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, 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 diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java index d4a10bf1cd4be..3de8ef5ee2b7e 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index 07c4404a8df27..4f069921f459d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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 diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 03ff15b2fe228..a4345ecf764e6 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, 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 diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java index b38c8f0971898..e28a444a0456b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, 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 diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index ca73e97671dc8..256d292350af4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java index b7681d73c5a0b..296164551a118 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java index 5bafe8df75ed2..cc2e9298e9954 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java index 1252cfdfd92d4..ffd5e35b15c99 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, 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 diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java index 435cf8f8e4211..5eb23fc58c4e3 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, 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 diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java index b5180720177f7..e00a0e974c471 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index 5e54fa2f357a4..f182f4f7f7dc4 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java index a3f5853f9e9d0..f551ed0109777 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java index b71bb1b2ec94d..0b71af53e9e77 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index fc494fffc38a6..1b1fd8fea1a1d 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java index 24e5d5802f7dc..b630193664138 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java index 096e8160c9734..199fe2620c3ed 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java index cb60de9a3634c..9a5a97f6fce9a 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 From 211f3b94b24c263dfa56e8db890fbe47d76c2cdc Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 15 Nov 2024 20:29:08 -0500 Subject: [PATCH 0155/1101] Applied blessed-modifier-order.sh --- .../jdk/jpackage/test/AdditionalLauncher.java | 36 +++++++++---------- .../jdk/jpackage/test/FileAssociations.java | 4 +-- .../jpackage/test/LauncherIconVerifier.java | 2 +- .../jdk/jpackage/test/LinuxHelper.java | 6 ++-- .../helpers/jdk/jpackage/test/MethodCall.java | 2 +- .../jdk/jpackage/test/PackageType.java | 12 +++---- .../jdk/jpackage/test/TestBuilder.java | 4 +-- .../jdk/jpackage/test/TestInstance.java | 2 +- .../tools/jpackage/share/AppContentTest.java | 2 +- test/jdk/tools/jpackage/share/IconTest.java | 4 +-- 10 files changed, 37 insertions(+), 37 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java index e00a0e974c471..70b0e160d24cc 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java @@ -49,12 +49,12 @@ public AdditionalLauncher(String name) { setPersistenceHandler(null); } - final public AdditionalLauncher setDefaultArguments(String... v) { + public final AdditionalLauncher setDefaultArguments(String... v) { defaultArguments = new ArrayList<>(List.of(v)); return this; } - final public AdditionalLauncher addDefaultArguments(String... v) { + public final AdditionalLauncher addDefaultArguments(String... v) { if (defaultArguments == null) { return setDefaultArguments(v); } @@ -63,12 +63,12 @@ final public AdditionalLauncher addDefaultArguments(String... v) { return this; } - final public AdditionalLauncher setJavaOptions(String... v) { + public final AdditionalLauncher setJavaOptions(String... v) { javaOptions = new ArrayList<>(List.of(v)); return this; } - final public AdditionalLauncher addJavaOptions(String... v) { + public final AdditionalLauncher addJavaOptions(String... v) { if (javaOptions == null) { return setJavaOptions(v); } @@ -77,27 +77,27 @@ final public AdditionalLauncher addJavaOptions(String... v) { return this; } - final public AdditionalLauncher setVerifyUninstalled(boolean value) { + public final AdditionalLauncher setVerifyUninstalled(boolean value) { verifyUninstalled = value; return this; } - final public AdditionalLauncher setLauncherAsService() { + public final AdditionalLauncher setLauncherAsService() { return addRawProperties(LAUNCHER_AS_SERVICE); } - final public AdditionalLauncher addRawProperties( + public final AdditionalLauncher addRawProperties( Map.Entry... v) { return addRawProperties(List.of(v)); } - final public AdditionalLauncher addRawProperties( + public final AdditionalLauncher addRawProperties( Collection> v) { rawProperties.addAll(v); return this; } - final public String getRawPropertyValue( + public final String getRawPropertyValue( String key, Supplier getDefault) { return rawProperties.stream() .filter(item -> item.getKey().equals(key)) @@ -109,13 +109,13 @@ private String getDesciption(JPackageCommand cmd) { "--description", unused -> cmd.name())); } - final public AdditionalLauncher setShortcuts(boolean menu, boolean shortcut) { + public final AdditionalLauncher setShortcuts(boolean menu, boolean shortcut) { withMenuShortcut = menu; withShortcut = shortcut; return this; } - final public AdditionalLauncher setIcon(Path iconPath) { + public final AdditionalLauncher setIcon(Path iconPath) { if (iconPath == NO_ICON) { throw new IllegalArgumentException(); } @@ -124,12 +124,12 @@ final public AdditionalLauncher setIcon(Path iconPath) { return this; } - final public AdditionalLauncher setNoIcon() { + public final AdditionalLauncher setNoIcon() { icon = NO_ICON; return this; } - final public AdditionalLauncher setPersistenceHandler( + public final AdditionalLauncher setPersistenceHandler( ThrowingBiConsumer>> handler) { if (handler != null) { createFileHandler = ThrowingBiConsumer.toBiConsumer(handler); @@ -139,12 +139,12 @@ final public AdditionalLauncher setPersistenceHandler( return this; } - final public void applyTo(JPackageCommand cmd) { + public final void applyTo(JPackageCommand cmd) { cmd.addPrerequisiteAction(this::initialize); cmd.addVerifyAction(this::verify); } - final public void applyTo(PackageTest test) { + public final void applyTo(PackageTest test) { test.addInitializer(this::initialize); test.addInstallVerifier(this::verify); if (verifyUninstalled) { @@ -152,7 +152,7 @@ final public void applyTo(PackageTest test) { } } - final public void verifyRemovedInUpgrade(PackageTest test) { + public final void verifyRemovedInUpgrade(PackageTest test) { test.addInstallVerifier(this::verifyUninstalled); } @@ -447,7 +447,7 @@ private static String resolveVariables(JPackageCommand cmd, String str) { private Boolean withMenuShortcut; private Boolean withShortcut; - private final static Path NO_ICON = Path.of(""); - private final static Map.Entry LAUNCHER_AS_SERVICE = Map.entry( + private static final Path NO_ICON = Path.of(""); + private static final Map.Entry LAUNCHER_AS_SERVICE = Map.entry( "launcher-as-service", "true"); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java index f551ed0109777..091a2206b173b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java @@ -35,7 +35,7 @@ import jdk.jpackage.internal.util.PathUtils; -final public class FileAssociations { +public final class FileAssociations { public FileAssociations(String faSuffixName) { suffixName = faSuffixName; setFilename("fa"); @@ -243,7 +243,7 @@ public static enum InvocationType { } private Path file; - final private String suffixName; + private final String suffixName; private String description; private Path icon; private Collection testRuns; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java index 0b71af53e9e77..39e483f1feeb3 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java @@ -262,7 +262,7 @@ private void setIcon(Path iconPath, Path launcherPath) { } } - final static WinIconVerifier instance = new WinIconVerifier(); + static final WinIconVerifier instance = new WinIconVerifier(); private final Class executableRebranderClass; private final Method lockResource; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index 1b1fd8fea1a1d..f57bd5a9a0dbd 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -725,10 +725,10 @@ private static Method initGetServiceUnitFileName() { private static Map archs; - private final static Pattern XDG_CMD_ICON_SIZE_PATTERN = Pattern.compile("\\s--size\\s+(\\d+)\\b"); + private static final Pattern XDG_CMD_ICON_SIZE_PATTERN = Pattern.compile("\\s--size\\s+(\\d+)\\b"); // Values grabbed from https://linux.die.net/man/1/xdg-icon-resource - private final static Set XDG_CMD_VALID_ICON_SIZES = Set.of(16, 22, 32, 48, 64, 128); + private static final Set XDG_CMD_VALID_ICON_SIZES = Set.of(16, 22, 32, 48, 64, 128); - private final static Method getServiceUnitFileName = initGetServiceUnitFileName(); + private static final Method getServiceUnitFileName = initGetServiceUnitFileName(); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java index b630193664138..599e626d7d085 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java @@ -149,5 +149,5 @@ public void accept(Object thiz) throws Throwable { private final Method method; private final Object[] ctorArgs; - final static Object[] DEFAULT_CTOR_ARGS = new Object[0]; + static final Object[] DEFAULT_CTOR_ARGS = new Object[0]; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageType.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageType.java index f8121c1a4c09b..0dfc979397eb5 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageType.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageType.java @@ -138,15 +138,15 @@ private static boolean isBundlerSupported(String bundlerClass) { private final String suffix; private final boolean supported; - public final static Set LINUX = Set.of(LINUX_DEB, LINUX_RPM); - public final static Set WINDOWS = Set.of(WIN_EXE, WIN_MSI); - public final static Set MAC = Set.of(MAC_PKG, MAC_DMG); - public final static Set NATIVE = Stream.concat( + public static final Set LINUX = Set.of(LINUX_DEB, LINUX_RPM); + public static final Set WINDOWS = Set.of(WIN_EXE, WIN_MSI); + public static final Set MAC = Set.of(MAC_PKG, MAC_DMG); + public static final Set NATIVE = Stream.concat( Stream.concat(LINUX.stream(), WINDOWS.stream()), MAC.stream()).collect(Collectors.toUnmodifiableSet()); - private final static class Inner { - private final static Set DISABLED_PACKAGERS = Optional.ofNullable( + private static final class Inner { + private static final Set DISABLED_PACKAGERS = Optional.ofNullable( TKit.tokenizeConfigProperty("disabledPackagers")).orElse( TKit.isLinuxAPT() ? Set.of("rpm") : Collections.emptySet()); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java index 199fe2620c3ed..15893398511e2 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java @@ -458,7 +458,7 @@ static void trace(String msg) { private String spaceSubstitute; private boolean dryRun; - private final static Map> conv = Map.of( + private static final Map> conv = Map.of( boolean.class, Boolean::valueOf, Boolean.class, Boolean::valueOf, int.class, Integer::valueOf, @@ -467,5 +467,5 @@ static void trace(String msg) { Long.class, Long::valueOf, String.class, String::valueOf); - final static String CMDLINE_ARG_PREFIX = "--jpt-"; + static final String CMDLINE_ARG_PREFIX = "--jpt-"; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java index 9a5a97f6fce9a..1eb99fcfbb85c 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java @@ -333,7 +333,7 @@ public String toString() { private final boolean dryRun; private final Path workDir; - private final static Set KEEP_WORK_DIR = FunctionalUtils.identity( + private static final Set KEEP_WORK_DIR = FunctionalUtils.identity( () -> { final String propertyName = "keep-work-dir"; Set keepWorkDir = TKit.tokenizeConfigProperty( diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java index 0d097e05d2c0a..d33960092ee88 100644 --- a/test/jdk/tools/jpackage/share/AppContentTest.java +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -65,7 +65,7 @@ public class AppContentTest { // In particular, random files should be placed in "Contents/Resources" folder // otherwise "codesign" will fail to sign. // Need to prepare arguments for `--app-content` accordingly. - private final static boolean copyInResources = TKit.isOSX(); + private static final boolean copyInResources = TKit.isOSX(); private final List testPathArgs; diff --git a/test/jdk/tools/jpackage/share/IconTest.java b/test/jdk/tools/jpackage/share/IconTest.java index 676b062ed66ac..d5edbc9324566 100644 --- a/test/jdk/tools/jpackage/share/IconTest.java +++ b/test/jdk/tools/jpackage/share/IconTest.java @@ -428,7 +428,7 @@ private enum Launcher { private final Path cmdlineIcon; private final Path resourceDirIcon; - private final static Set PRIMARY = Set.of(Main, Additional); + private static final Set PRIMARY = Set.of(Main, Additional); } private final boolean appImage; @@ -440,7 +440,7 @@ private static Path iconPath(String name) { + TKit.ICON_SUFFIX)); } - private final static Path[] ICONS = Stream.of("icon", "icon2", "icon3", + private static final Path[] ICONS = Stream.of("icon", "icon2", "icon3", "icon4") .map(IconTest::iconPath) .collect(Collectors.toList()).toArray(Path[]::new); From 01f6c74ce230e71bdebf0bdd20f1be1c15c8aade Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 15 Nov 2024 20:40:55 -0500 Subject: [PATCH 0156/1101] Fix bad merge --- .../internal/util/function/ExceptionBox.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) 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 112efcbb5233a..55f2964445fdc 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 @@ -25,21 +25,26 @@ import java.lang.reflect.InvocationTargetException; public class ExceptionBox extends RuntimeException { - + private static final long serialVersionUID = 1L; - public static RuntimeException rethrowUnchecked(Throwable throwable) throws - ExceptionBox { - if (throwable instanceof RuntimeException runtimeThrowable) { - throw runtimeThrowable; + public static RuntimeException rethrowUnchecked(Throwable throwable) { + if (throwable instanceof RuntimeException err) { + throw err; + } + + if (throwable instanceof Error err) { + throw err; } - if (throwable instanceof InvocationTargetException) { - throw new ExceptionBox(throwable.getCause()); + + if (throwable instanceof InvocationTargetException err) { + throw rethrowUnchecked(err.getCause()); } + throw new ExceptionBox(throwable); } private ExceptionBox(Throwable throwable) { super(throwable); - } + } } From 0f739f57f40d9a8f390ab115f53a30a968769aa5 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 15 Nov 2024 20:41:19 -0500 Subject: [PATCH 0157/1101] Clear trailing whitespaces --- .../share/classes/jdk/jpackage/internal/util/PathUtils.java | 4 ++-- .../jdk/jpackage/internal/util/PrettyPrintHandler.java | 4 ++-- .../jdk/jpackage/internal/util/SkipDocumentHandler.java | 6 +++--- .../jpackage/internal/util/function/FunctionalUtils.java | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java index c8f80835deac8..3f5db83d4a4b5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java @@ -27,8 +27,8 @@ public static Path replaceSuffix(Path path, String suffix) { "") + Optional.ofNullable(suffix).orElse(""); return parent != null ? parent.resolve(filename) : Path.of(filename); } - + public static Path resolveNullablePath(Path base, Path path) { return Optional.ofNullable(path).map(base::resolve).orElse(null); - } + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PrettyPrintHandler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PrettyPrintHandler.java index b3fd3c0643a89..38d47d7e2a31a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PrettyPrintHandler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PrettyPrintHandler.java @@ -29,7 +29,7 @@ import javax.xml.stream.XMLStreamWriter; public class PrettyPrintHandler implements InvocationHandler { - + public PrettyPrintHandler(XMLStreamWriter target) { this.target = target; } @@ -85,5 +85,5 @@ private static String repeat(int d, String s) { private int depth = 0; private final Map hasChildElement = new HashMap<>(); private static final String INDENT = " "; - private static final String EOL = "\n"; + private static final String EOL = "\n"; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/SkipDocumentHandler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/SkipDocumentHandler.java index 79a927ff766b8..918387baf8f45 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/SkipDocumentHandler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/SkipDocumentHandler.java @@ -29,7 +29,7 @@ import javax.xml.stream.XMLStreamWriter; public class SkipDocumentHandler implements InvocationHandler { - + public SkipDocumentHandler(XMLStreamWriter target) { this.target = target; } @@ -43,6 +43,6 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl } return null; } - - private final XMLStreamWriter target; + + private final XMLStreamWriter target; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/FunctionalUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/FunctionalUtils.java index a06e071dd2a9d..ee2cd99b8977a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/FunctionalUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/FunctionalUtils.java @@ -29,7 +29,7 @@ import java.util.function.Supplier; public final class FunctionalUtils { - + public static Supplier identity(Supplier v) { return v; } From 8267daf67b321f7cc8d3624160014a3a81003351 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 15 Nov 2024 21:29:27 -0500 Subject: [PATCH 0158/1101] Remove references to AppImageFile, PackageFile, and ApplicationLayout internal jpackage classes from the tests --- .../jdk/jpackage/test/AppImageFile.java | 126 ++++++++++++++++++ .../jdk/jpackage/test/ApplicationLayout.java | 126 ++++++++++++++++++ .../jdk/jpackage/test/JPackageCommand.java | 57 ++------ .../jdk/jpackage/test/PackageFile.java | 37 +++++ .../jdk/jpackage/test/PackageTest.java | 1 - .../jpackage/share/AppImagePackageTest.java | 4 +- .../share/PredefinedAppImageErrorTest.java | 3 +- .../share/RuntimeImageSymbolicLinksTest.java | 2 +- 8 files changed, 302 insertions(+), 54 deletions(-) create mode 100644 test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java create mode 100644 test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java create mode 100644 test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageFile.java diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java new file mode 100644 index 0000000000000..690da93b74926 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; +import java.util.Optional; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.util.XmlUtils; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +public record AppImageFile(String mainLauncherName, String mainLauncherClassName, + String version, boolean macSigned, boolean macAppStore) { + + public static Path getPathInAppImage(Path appImageDir) { + return ApplicationLayout.platformAppImage() + .resolveAt(appImageDir) + .appDirectory() + .resolve(FILENAME); + } + + public AppImageFile(String mainLauncherName, String mainLauncherClassName) { + this(mainLauncherName, mainLauncherClassName, "1.0", false, false); + } + + public void save(Path appImageDir) throws IOException { + XmlUtils.createXml(getPathInAppImage(appImageDir), xml -> { + xml.writeStartElement("jpackage-state"); + xml.writeAttribute("version", getVersion()); + xml.writeAttribute("platform", getPlatform()); + + xml.writeStartElement("app-version"); + xml.writeCharacters(version); + xml.writeEndElement(); + + xml.writeStartElement("main-launcher"); + xml.writeCharacters(mainLauncherName); + xml.writeEndElement(); + + xml.writeStartElement("main-class"); + xml.writeCharacters(mainLauncherClassName); + xml.writeEndElement(); + + xml.writeStartElement("signed"); + xml.writeCharacters(Boolean.toString(macSigned)); + xml.writeEndElement(); + + xml.writeStartElement("app-store"); + xml.writeCharacters(Boolean.toString(macAppStore)); + xml.writeEndElement(); + }); + } + + public static AppImageFile load(Path appImageDir) { + try { + Document doc = XmlUtils.initDocumentBuilder().parse( + Files.newInputStream(getPathInAppImage(appImageDir))); + + XPath xPath = XPathFactory.newInstance().newXPath(); + + var version = xPath.evaluate("/jpackage-state/app-version/text()", doc); + + var mainLauncherName = xPath.evaluate( + "/jpackage-state/main-launcher/text()", doc); + + var mainLauncherClassName = xPath.evaluate( + "/jpackage-state/main-class/text()", doc); + + var macSigned = Optional.ofNullable(xPath.evaluate( + "/jpackage-state/signed/text()", doc)).map( + Boolean::parseBoolean).orElse(false); + + var macAppStore = Optional.ofNullable(xPath.evaluate( + "/jpackage-state/app-store/text()", doc)).map( + Boolean::parseBoolean).orElse(false); + + return new AppImageFile(mainLauncherName, mainLauncherClassName, + version, macSigned, macAppStore); + + } catch (XPathExpressionException | SAXException | IOException ex) { + // This should never happen as XPath expressions should be correct + throw new RuntimeException(ex); + } + } + + private static String getVersion() { + return System.getProperty("java.version"); + } + + private static String getPlatform() { + return PLATFORM_LABELS.get(OperatingSystem.current()); + } + + private static final String FILENAME = ".jpackage.xml"; + + private static final Map PLATFORM_LABELS = Map.of( + OperatingSystem.LINUX, "linux", + OperatingSystem.WINDOWS, "windows", + OperatingSystem.MACOS, "macOS"); +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java new file mode 100644 index 0000000000000..88ce7169da71e --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import java.nio.file.Path; +import java.util.Optional; + +public record ApplicationLayout(Path launchersDirectory, Path appDirectory, + Path runtimeDirectory, Path runtimeHomeDirectory, Path appModsDirectory, + Path destktopIntegrationDirectory, Path contentDirectory) { + + public ApplicationLayout resolveAt(Path root) { + return new ApplicationLayout( + resolve(root, launchersDirectory), + resolve(root, appDirectory), + resolve(root, runtimeDirectory), + resolve(root, runtimeHomeDirectory), + resolve(root, appModsDirectory), + resolve(root, destktopIntegrationDirectory), + resolve(root, contentDirectory)); + } + + public static ApplicationLayout linuxAppImage() { + return new ApplicationLayout( + Path.of("bin"), + Path.of("lib/app"), + Path.of("lib/runtime"), + Path.of("lib/runtime"), + Path.of("lib/app/mods"), + Path.of("lib"), + Path.of("lib") + ); + } + + public static ApplicationLayout windowsAppImage() { + return new ApplicationLayout( + Path.of(""), + Path.of("app"), + Path.of("runtime"), + Path.of("runtime"), + Path.of("app/mods"), + Path.of(""), + Path.of("") + ); + } + + public static ApplicationLayout macAppImage() { + return new ApplicationLayout( + Path.of("Contents/MacOS"), + Path.of("Contents/app"), + Path.of("Contents/runtime"), + Path.of("Contents/runtime/Contents/Home"), + Path.of("Contents/app/mods"), + Path.of("Contents/Resources"), + Path.of("Contents") + ); + } + + public static ApplicationLayout platformAppImage() { + if (TKit.isWindows()) { + return windowsAppImage(); + } + + if (TKit.isLinux()) { + return linuxAppImage(); + } + + if (TKit.isOSX()) { + return macAppImage(); + } + + throw new IllegalArgumentException("Unknown platform"); + } + + public static ApplicationLayout javaRuntime() { + return new ApplicationLayout( + null, + null, + Path.of(""), + null, + null, + null, + null + ); + } + + public static ApplicationLayout linuxUsrTreePackageImage(Path prefix, + String packageName) { + final Path lib = prefix.resolve(Path.of("lib", packageName)); + return new ApplicationLayout( + prefix.resolve("bin"), + lib.resolve("app"), + lib.resolve("runtime"), + lib.resolve("runtime"), + lib.resolve("app/mods"), + lib, + lib + ); + } + + private static Path resolve(Path base, Path path) { + return Optional.ofNullable(path).map(base::resolve).orElse(null); + } +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index e6931ecf4b692..149ce71aea765 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -45,10 +45,6 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.AppImageFile; -import jdk.jpackage.internal.ApplicationLayout; -import jdk.jpackage.internal.PackageFile; -import jdk.jpackage.internal.util.XmlUtils; import jdk.jpackage.internal.util.function.FunctionalUtils; import static jdk.jpackage.test.AdditionalLauncher.forEachAdditionalLauncher; import jdk.jpackage.internal.util.function.ThrowingConsumer; @@ -217,9 +213,9 @@ public String version() { } public String name() { - String appImage = getArgumentValue("--app-image", () -> null); + String appImage = getArgumentValue("--app-image"); if (appImage != null) { - String name = AppImageFile.extractAppName(Path.of(appImage)); + String name = AppImageFile.load(Path.of(appImage)).mainLauncherName(); // can be null if using foreign app-image return ((name != null) ? name : getArgumentValue("--name")); } @@ -233,7 +229,7 @@ public String installerName() { if (installerName == null) { String appImage = getArgumentValue("--app-image"); if (appImage != null) { - installerName = AppImageFile.extractAppName(Path.of(appImage)); + installerName = AppImageFile.load(Path.of(appImage)).mainLauncherName(); } } return installerName; @@ -306,42 +302,6 @@ public JPackageCommand setFakeRuntime() { return this; } - public void createJPackageXMLFile(String mainLauncher, String mainClass) - throws IOException { - Path jpackageXMLFile = AppImageFile.getPathInAppImage( - Optional.ofNullable(getArgumentValue("--app-image")).map( - Path::of).orElseThrow(() -> { - return new RuntimeException( - "Error: --app-image expected"); - })); - - XmlUtils.createXml(jpackageXMLFile, xml -> { - xml.writeStartElement("jpackage-state"); - xml.writeAttribute("version", AppImageFile.getVersion()); - xml.writeAttribute("platform", AppImageFile.getPlatform()); - - xml.writeStartElement("app-version"); - xml.writeCharacters("1.0"); - xml.writeEndElement(); - - xml.writeStartElement("main-launcher"); - xml.writeCharacters(mainLauncher); - xml.writeEndElement(); - - xml.writeStartElement("main-class"); - xml.writeCharacters(mainClass); - xml.writeEndElement(); - - xml.writeStartElement("signed"); - xml.writeCharacters("false"); - xml.writeEndElement(); - - xml.writeStartElement("app-store"); - xml.writeCharacters("false"); - xml.writeEndElement(); - }); - } - JPackageCommand addPrerequisiteAction(ThrowingConsumer action) { verifyMutable(); prerequisiteActions.add(action); @@ -913,7 +873,7 @@ JPackageCommand assertAppLayout() { private void assertAppImageFile() { Path appImageDir = Path.of(""); if (isImagePackageType() && hasArgument("--app-image")) { - appImageDir = Path.of(getArgumentValue("--app-image", () -> null)); + appImageDir = Path.of(getArgumentValue("--app-image")); } final Path lookupPath = AppImageFile.getPathInAppImage(appImageDir); @@ -934,12 +894,12 @@ private void assertAppImageFile() { AppImageFile aif = AppImageFile.load(rootDir); boolean expectedValue = hasArgument("--mac-sign"); - boolean actualValue = aif.isSigned(); + boolean actualValue = aif.macSigned(); TKit.assertEquals(Boolean.toString(expectedValue), Boolean.toString(actualValue), "Check for unexptected value in app image file for "); expectedValue = hasArgument("--mac-app-store"); - actualValue = aif.isAppStore(); + actualValue = aif.macAppStore(); TKit.assertEquals(Boolean.toString(expectedValue), Boolean.toString(actualValue), "Check for unexptected value in app image file for "); } @@ -953,9 +913,8 @@ private void assertPackageFile() { assertFileInAppImage(lookupPath, null); } else { if (TKit.isOSX() && hasArgument("--app-image")) { - String appImage = getArgumentValue("--app-image", - () -> null); - if (AppImageFile.load(Path.of(appImage)).isSigned()) { + String appImage = getArgumentValue("--app-image"); + if (AppImageFile.load(Path.of(appImage)).macSigned()) { assertFileInAppImage(lookupPath, null); } else { assertFileInAppImage(lookupPath, lookupPath); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageFile.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageFile.java new file mode 100644 index 0000000000000..a0285201174f4 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageFile.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import java.nio.file.Path; + +public class PackageFile { + + public static Path getPathInAppImage(Path appImageDir) { + return ApplicationLayout.platformAppImage() + .resolveAt(appImageDir) + .appDirectory() + .resolve(FILENAME); + } + + private static final String FILENAME = ".package"; +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index b025a3a0a7b97..9a311eceec819 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -45,7 +45,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; -import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.internal.util.function.ThrowingBiConsumer; import static jdk.jpackage.internal.util.function.ThrowingBiConsumer.toBiConsumer; import jdk.jpackage.internal.util.function.ThrowingConsumer; diff --git a/test/jdk/tools/jpackage/share/AppImagePackageTest.java b/test/jdk/tools/jpackage/share/AppImagePackageTest.java index 62d5e974f86ae..7185e63145f01 100644 --- a/test/jdk/tools/jpackage/share/AppImagePackageTest.java +++ b/test/jdk/tools/jpackage/share/AppImagePackageTest.java @@ -25,7 +25,7 @@ import java.nio.file.Files; import java.io.IOException; import java.util.List; -import jdk.jpackage.internal.AppImageFile; +import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.TKit; import jdk.jpackage.test.JPackageCommand; @@ -87,7 +87,7 @@ public static void testEmpty(boolean withIcon) throws IOException { cmd.addArguments("--icon", iconPath("icon")); } cmd.removeArgumentWithValue("--input"); - cmd.createJPackageXMLFile("EmptyAppImagePackageTest", "Hello"); + new AppImageFile("EmptyAppImagePackageTest", "Hello").save(appImageDir); // on mac, with --app-image and without --mac-package-identifier, // will try to infer it from the image, so foreign image needs it. diff --git a/test/jdk/tools/jpackage/share/PredefinedAppImageErrorTest.java b/test/jdk/tools/jpackage/share/PredefinedAppImageErrorTest.java index bdb4f6bfbd760..0e1d358dae46b 100644 --- a/test/jdk/tools/jpackage/share/PredefinedAppImageErrorTest.java +++ b/test/jdk/tools/jpackage/share/PredefinedAppImageErrorTest.java @@ -28,6 +28,7 @@ import java.util.Collection; import java.util.List; +import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; @@ -111,7 +112,7 @@ private void getDummyAppImage(JPackageCommand cmd) throws IOException { Files.createFile(dummyAppFile); cmd.addArguments("--app-image", dummyAppFolder.toString()); - cmd.createJPackageXMLFile("PredefinedAppImageErrorTest", "Hello"); + new AppImageFile("PredefinedAppImageErrorTest", "Hello").save(dummyAppFolder); } } diff --git a/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java b/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java index 649ac0a369513..404cd3b6d3a47 100644 --- a/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java +++ b/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java @@ -23,7 +23,7 @@ import java.nio.file.Files; import java.nio.file.Path; -import jdk.jpackage.internal.ApplicationLayout; +import jdk.jpackage.test.ApplicationLayout; import jdk.jpackage.test.TKit; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; From e1ef473fc557db1f175c87aadd1c0f6a35cc61b7 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 15 Nov 2024 21:30:54 -0500 Subject: [PATCH 0159/1101] Update TEST.properties with the new jpackage packages --- test/jdk/tools/jpackage/TEST.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/jdk/tools/jpackage/TEST.properties b/test/jdk/tools/jpackage/TEST.properties index e01036f0ed36c..a34532d6695c6 100644 --- a/test/jdk/tools/jpackage/TEST.properties +++ b/test/jdk/tools/jpackage/TEST.properties @@ -12,4 +12,6 @@ maxOutputSize=2000000 exclusiveAccess.dirs=share windows modules=jdk.jpackage/jdk.jpackage.internal:+open \ + jdk.jpackage/jdk.jpackage.internal.util \ + jdk.jpackage/jdk.jpackage.internal.util.function \ java.base/jdk.internal.util From a8eedc4c9482e4c6b4a315149febfbf335063197 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 15 Nov 2024 21:53:46 -0500 Subject: [PATCH 0160/1101] Remove trailing whitespaces --- .../internal/model/LinuxLauncher.java | 2 +- .../jdk/jpackage/internal/AppImageFile2.java | 2 +- .../internal/ApplicationLayoutUtils.java | 4 +- .../internal/FileAssociationGroup.java | 2 +- .../internal/cli/AdditionalLauncher.java | 64 +-- .../internal/cli/CliApplicationBuilder.java | 70 +-- .../internal/cli/CliPackageBuilder.java | 70 +-- .../jdk/jpackage/internal/cli/Option.java | 62 +-- .../jdk/jpackage/internal/cli/OptionSpec.java | 90 ++-- .../internal/cli/OptionSpecBuilder.java | 252 +++++------ .../internal/cli/PackageTypeGroup.java | 2 +- .../jpackage/internal/cli/ParsedOptions.java | 66 +-- .../jpackage/internal/cli/StandardOption.java | 416 +++++++++--------- .../internal/cli/StandardValueConverter.java | 166 +++---- .../internal/cli/StandardValueValidator.java | 106 ++--- .../jpackage/internal/cli/ValueConverter.java | 92 ++-- .../internal/model/AppImageLayout.java | 4 +- .../internal/model/AppImagePackageType.java | 4 +- .../internal/model/ApplicationWriter.java | 68 +-- .../internal/model/FileAssociation.java | 4 +- .../jdk/jpackage/internal/model/Launcher.java | 6 +- .../model/LauncherJarStartupInfo.java | 4 +- .../internal/model/LauncherStartupInfo.java | 8 +- .../jdk/jpackage/internal/model/Package.java | 6 +- .../internal/model/PackageWriter.java | 68 +-- .../internal/model/RuntimeLayoutStub.java | 4 +- .../internal/model/StandardPackageType.java | 10 +- .../jdk/jpackage/internal/util/FileUtils.java | 310 ++++++------- .../internal/util/MultiResourceBundle.java | 150 +++---- .../jdk/jpackage/internal/util/PathUtils.java | 68 +-- .../jpackage/internal/util/StringBundle.java | 2 +- .../jdk/jpackage/internal/util/XmlUtils.java | 4 +- .../util/function/ExceptionWrapper.java | 4 +- .../internal/util/xml/PrettyPrintHandler.java | 4 +- .../util/xml/SkipDocumentHandler.java | 6 +- .../internal/WinExePackageBuilder.java | 2 +- .../jdk/jpackage/test/ApplicationLayout.java | 252 +++++------ .../internal/OverridableResourceTest.java | 2 +- .../share/PredefinedAppImageErrorTest.java | 2 +- 39 files changed, 1229 insertions(+), 1229 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java index 9988fbc9a5b6e..d426b838ac9b3 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java @@ -37,7 +37,7 @@ default Map extraAppImageFileData() { return Map.of("shortcut", Boolean.toString(v)); }).orElseGet(Map::of); } - + @Override default String defaultIconResourceName() { return "JavaApp.png"; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index a841aaba33b0c..3eb4abd82cbee 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -330,7 +330,7 @@ record LauncherInfo(String name, boolean service, Map extra) { throw new InavlidAppImageFileException(); } } - + Launcher asLauncher() { return new Launcher.Stub(name, null, null, service, null, null); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java index a8be8acadfb12..3c43d4d8d65b2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java @@ -39,7 +39,7 @@ final class ApplicationLayoutUtils { .runtimeDirectory("runtime") .appModsDirectory(Path.of("app", "mods")) .create(); - + private final static ApplicationLayout MAC_APPLICATION_LAYOUT = ApplicationLayout.build() .launchersDirectory("Contents/MacOS") .appDirectory("Contents/app") @@ -48,7 +48,7 @@ final class ApplicationLayoutUtils { .appModsDirectory("Contents/app/mods") .contentDirectory("Contents") .create(); - + private final static ApplicationLayout LINUX_APPLICATION_LAYOUT = ApplicationLayout.build() .launchersDirectory("bin") .appDirectory("lib/app") diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java index 3de8c27fb3063..6eedeab6bed31 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java @@ -61,7 +61,7 @@ static UnaryOperator filter(Predicate fil static Builder build() { return new Builder(); } - + static final class Builder { FileAssociationGroup create() { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/AdditionalLauncher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/AdditionalLauncher.java index 01f964fc5241c..edfd8dbf1068e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/AdditionalLauncher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/AdditionalLauncher.java @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.cli; - -import java.nio.file.Path; - - -public record AdditionalLauncher(String name, Path propertyFile) { -} +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.cli; + +import java.nio.file.Path; + + +public record AdditionalLauncher(String name, Path propertyFile) { +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliApplicationBuilder.java index 07a183f0427ae..7631940e3ef48 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliApplicationBuilder.java @@ -1,35 +1,35 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.cli; - -import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.ApplicationWriter; -import jdk.jpackage.internal.model.ConfigException; - - -public interface CliApplicationBuilder extends ApplicationWriter { - Application createAppFromCmdline(ParsedOptions options) throws ConfigException; -} +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.cli; + +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationWriter; +import jdk.jpackage.internal.model.ConfigException; + + +public interface CliApplicationBuilder extends ApplicationWriter { + Application createAppFromCmdline(ParsedOptions options) throws ConfigException; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliPackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliPackageBuilder.java index 35bab0803580d..dc6766bac8691 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliPackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliPackageBuilder.java @@ -1,35 +1,35 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.cli; - -import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.PackageWriter; - - -public interface CliPackageBuilder extends PackageWriter { - Package createPackageFromCmdline(ParsedOptions options) throws ConfigException; -} +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.cli; + +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackageWriter; + + +public interface CliPackageBuilder extends PackageWriter { + Package createPackageFromCmdline(ParsedOptions options) throws ConfigException; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Option.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Option.java index edc140cad0fb8..e5df9cbc318bb 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Option.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Option.java @@ -1,31 +1,31 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.cli; - - -public interface Option { - OptionSpec getSpec(); -} +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.cli; + + +public interface Option { + OptionSpec getSpec(); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java index e3f669fb32526..519b8537a1d84 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java @@ -1,45 +1,45 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.cli; - -import java.util.Objects; -import java.util.Set; -import java.util.function.Consumer; -import jdk.jpackage.internal.model.PackageType; - - -public record OptionSpec(String name, ValueConverter valueConverter, String shortName, Set supportedPackageTypes, Consumer valueValidator) { - public OptionSpec { - Objects.requireNonNull(name); - if (supportedPackageTypes.isEmpty()) { - throw new IllegalArgumentException("At least one package type must be set"); - } - } - - public boolean withValue() { - return valueConverter != null; - } -} +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.cli; + +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; +import jdk.jpackage.internal.model.PackageType; + + +public record OptionSpec(String name, ValueConverter valueConverter, String shortName, Set supportedPackageTypes, Consumer valueValidator) { + public OptionSpec { + Objects.requireNonNull(name); + if (supportedPackageTypes.isEmpty()) { + throw new IllegalArgumentException("At least one package type must be set"); + } + } + + public boolean withValue() { + return valueConverter != null; + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java index 281097fea1470..22501666d4b85 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java @@ -1,126 +1,126 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal.cli; - -import java.util.Set; -import java.util.function.Consumer; -import jdk.jpackage.internal.model.PackageType; -import static jdk.jpackage.internal.cli.StandardValueConverter.IDENTITY_CONV; -import static jdk.jpackage.internal.cli.StandardValueConverter.PATH_ARRAY_CONV; -import static jdk.jpackage.internal.cli.StandardValueConverter.PATH_CONV; -import static jdk.jpackage.internal.cli.StandardValueConverter.STRING_ARRAY_CONV; - -final class OptionSpecBuilder { - OptionSpec create() { - return new OptionSpec(name, valueConverter, shortName, supportedPackageTypes, valueValidator); - } - - OptionSpecBuilder ofString() { - return valueConverter(IDENTITY_CONV); - } - - OptionSpecBuilder ofPath() { - return valueConverter(PATH_CONV); - } - - OptionSpecBuilder ofDirectory() { - return ofPath().valueValidator(StandardValueValidator::validateDirectory); - } - - OptionSpecBuilder ofStringArray() { - return valueConverter(STRING_ARRAY_CONV); - } - - OptionSpecBuilder ofPathArray() { - return valueConverter(PATH_ARRAY_CONV); - } - - OptionSpecBuilder ofDirectoryArray() { - return ofPathArray().valueValidator(StandardValueValidator::validateDirectoryArray); - } - - OptionSpecBuilder ofUrl() { - return ofString().valueValidator(StandardValueValidator::validateUrl); - } - - OptionSpecBuilder noValue() { - return valueValidator(null); - } - - OptionSpecBuilder name(String v) { - name = v; - return this; - } - - OptionSpecBuilder valueConverter(ValueConverter v) { - valueConverter = v; - return this; - } - - OptionSpecBuilder valueValidator(Consumer v) { - valueValidator = v; - return this; - } - - OptionSpecBuilder shortName(String v) { - shortName = v; - return this; - } - - final OptionSpecBuilder supportedPackageTypes(PackageType... v) { - return supportedPackageTypes(Set.of(v)); - } - - OptionSpecBuilder supportedPackageTypes(Set v) { - supportedPackageTypes = v; - return this; - } - - String getName() { - return name; - } - - ValueConverter getValueConverter() { - return valueConverter; - } - - Consumer getValueValidator() { - return valueValidator; - } - - String getShortName() { - return shortName; - } - - Set getSupportedPackageTypes() { - return supportedPackageTypes; - } - - private String name; - private ValueConverter valueConverter; - private Consumer valueValidator; - private String shortName; - private Set supportedPackageTypes; -} +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.cli; + +import java.util.Set; +import java.util.function.Consumer; +import jdk.jpackage.internal.model.PackageType; +import static jdk.jpackage.internal.cli.StandardValueConverter.IDENTITY_CONV; +import static jdk.jpackage.internal.cli.StandardValueConverter.PATH_ARRAY_CONV; +import static jdk.jpackage.internal.cli.StandardValueConverter.PATH_CONV; +import static jdk.jpackage.internal.cli.StandardValueConverter.STRING_ARRAY_CONV; + +final class OptionSpecBuilder { + OptionSpec create() { + return new OptionSpec(name, valueConverter, shortName, supportedPackageTypes, valueValidator); + } + + OptionSpecBuilder ofString() { + return valueConverter(IDENTITY_CONV); + } + + OptionSpecBuilder ofPath() { + return valueConverter(PATH_CONV); + } + + OptionSpecBuilder ofDirectory() { + return ofPath().valueValidator(StandardValueValidator::validateDirectory); + } + + OptionSpecBuilder ofStringArray() { + return valueConverter(STRING_ARRAY_CONV); + } + + OptionSpecBuilder ofPathArray() { + return valueConverter(PATH_ARRAY_CONV); + } + + OptionSpecBuilder ofDirectoryArray() { + return ofPathArray().valueValidator(StandardValueValidator::validateDirectoryArray); + } + + OptionSpecBuilder ofUrl() { + return ofString().valueValidator(StandardValueValidator::validateUrl); + } + + OptionSpecBuilder noValue() { + return valueValidator(null); + } + + OptionSpecBuilder name(String v) { + name = v; + return this; + } + + OptionSpecBuilder valueConverter(ValueConverter v) { + valueConverter = v; + return this; + } + + OptionSpecBuilder valueValidator(Consumer v) { + valueValidator = v; + return this; + } + + OptionSpecBuilder shortName(String v) { + shortName = v; + return this; + } + + final OptionSpecBuilder supportedPackageTypes(PackageType... v) { + return supportedPackageTypes(Set.of(v)); + } + + OptionSpecBuilder supportedPackageTypes(Set v) { + supportedPackageTypes = v; + return this; + } + + String getName() { + return name; + } + + ValueConverter getValueConverter() { + return valueConverter; + } + + Consumer getValueValidator() { + return valueValidator; + } + + String getShortName() { + return shortName; + } + + Set getSupportedPackageTypes() { + return supportedPackageTypes; + } + + private String name; + private ValueConverter valueConverter; + private Consumer valueValidator; + private String shortName; + private Set supportedPackageTypes; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/PackageTypeGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/PackageTypeGroup.java index d4d6ffa10b53b..04b6bee1dc2e7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/PackageTypeGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/PackageTypeGroup.java @@ -55,7 +55,7 @@ enum PackageTypeGroup { }), ALL_PACKAGE_TYPES(name -> { return Stream.of( - APP_IMAGE.forOptionName(name), + APP_IMAGE.forOptionName(name), NATIVE_PACKAGE.forOptionName(name) ).flatMap(Set::stream).collect(toSet()); }); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ParsedOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ParsedOptions.java index 219abf17d60e8..8d40d1bb6a79d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ParsedOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ParsedOptions.java @@ -1,33 +1,33 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.cli; - -import java.util.Optional; - - -public interface ParsedOptions { - public Optional get(Option id); -} +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.cli; + +import java.util.Optional; + + +public interface ParsedOptions { + public Optional get(Option id); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index f371e055b8dad..5599ad3922660 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -1,208 +1,208 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal.cli; - -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.function.UnaryOperator; -import java.util.stream.Stream; -import jdk.jpackage.internal.model.AppImagePackageType; -import jdk.jpackage.internal.model.PackageType; -import jdk.jpackage.internal.model.StandardPackageType; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; -import static jdk.jpackage.internal.model.StandardPackageType.MAC_DMG; -import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG; -import static jdk.jpackage.internal.model.StandardPackageType.WIN_EXE; -import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; -import static jdk.jpackage.internal.cli.PackageTypeGroup.ALL_PACKAGE_TYPES; -import static jdk.jpackage.internal.cli.PackageTypeGroup.APP_IMAGE; -import static jdk.jpackage.internal.cli.PackageTypeGroup.NATIVE_PACKAGE; - -public enum StandardOption implements Option { - TYPE(build("type").shortName("t").valueConverter(new ValueConverter() { - @Override - public PackageType convert(String value) { - if ("app-image".equals(value)) { - return AppImagePackageType.APP_IMAGE; - } else { - return StandardPackageType.fromCmdLineType(value); - } - } - - @Override - public Class valueType() { - return PackageType.class; - } - - })), - INPUT(build("input").shortName("i").ofDirectory(), APP_IMAGE), - DEST(build("dest").shortName("d").ofDirectory()), - DESCRIPTION("description"), - VENDOR("vendor"), - APPCLASS("main-class"), - NAME(build("input").shortName("i").ofString()), - VERBOSE(build("verbose").noValue()), - RESOURCE_DIR("resource-dir", OptionSpecBuilder::ofDirectory), - ARGUMENTS("arguments", OptionSpecBuilder::ofStringArray), - JLINK_OPTIONS("arguments", OptionSpecBuilder::ofStringArray), - ICON("icon", OptionSpecBuilder::ofPath), - COPYRIGHT("copyright"), - LICENSE_FILE("license-file", OptionSpecBuilder::ofPath), - VERSION("app-version"), - ABOUT_URL("about-url", OptionSpecBuilder::ofUrl), - JAVA_OPTIONS("java-options", OptionSpecBuilder::ofStringArray), - APP_CONTENT("app-content", OptionSpecBuilder::ofPathArray), - FILE_ASSOCIATIONS("file-associations", OptionSpecBuilder::ofPath), - ADD_LAUNCHER(build("add-launcher").valueConverter(new ValueConverter() { - @Override - public AdditionalLauncher convert(String value) { - var components = value.split("=", 2); - if (components.length == 1) { - components = new String[] { null, components[0] }; - } - return new AdditionalLauncher(components[0], - StandardValueConverter.PATH_CONV.convert(components[1])); - } - - @Override - public Class valueType() { - return AdditionalLauncher.class; - } - })), - TEMP_ROOT("temp", OptionSpecBuilder::ofDirectory), - INSTALL_DIR("install-dir", OptionSpecBuilder::ofPath), - PREDEFINED_APP_IMAGE("app-image", OptionSpecBuilder::ofDirectory, NATIVE_PACKAGE), - PREDEFINED_RUNTIME_IMAGE("runtime-image", OptionSpecBuilder::ofDirectory), - MAIN_JAR("main-jar", OptionSpecBuilder::ofPath), - MODULE(build("module").shortName("m").ofString()), - ADD_MODULES("add-modules", OptionSpecBuilder::ofStringArray), - MODULE_PATH(build("module-path").shortName("p").ofDirectoryArray()), - LAUNCHER_AS_SERVICE(build("launcher-as-service").noValue()), - // Linux-specific - LINUX_RELEASE("linux-app-release", NATIVE_PACKAGE), - LINUX_BUNDLE_NAME("linux-package-name", NATIVE_PACKAGE), - LINUX_DEB_MAINTAINER("linux-deb-maintainer", NATIVE_PACKAGE), - LINUX_CATEGORY("linux-app-category", NATIVE_PACKAGE), - LINUX_RPM_LICENSE_TYPE("linux-rpm-license-type", NATIVE_PACKAGE), - LINUX_PACKAGE_DEPENDENCIES("linux-package-deps", NATIVE_PACKAGE), - LINUX_SHORTCUT_HINT(build("linux-shortcut").noValue(), NATIVE_PACKAGE), - LINUX_MENU_GROUP("linux-package-deps", NATIVE_PACKAGE), - // MacOS-specific - DMG_CONTENT(build("mac-dmg-content").ofPathArray()), - MAC_SIGN(build("mac-sign").shortName("s").noValue()), - MAC_APP_STORE(build("mac-app-store").shortName("s").noValue(), NATIVE_PACKAGE), - MAC_CATEGORY("mac-app-category"), - MAC_BUNDLE_NAME("mac-package-name"), - MAC_BUNDLE_IDENTIFIER("mac-package-identifier"), - MAC_BUNDLE_SIGNING_PREFIX("mac-package-signing-prefix"), - MAC_SIGNING_KEY_NAME("mac-signing-key-user-name"), - MAC_APP_IMAGE_SIGN_IDENTITY("mac-app-image-sign-identity", APP_IMAGE), - MAC_INSTALLER_SIGN_IDENTITY("mac-installer-sign-identity", NATIVE_PACKAGE), - MAC_SIGNING_KEYCHAIN("mac-signing-keychain", OptionSpecBuilder::ofPath), - MAC_ENTITLEMENTS("mac-entitlements"), - // Windows-specific - WIN_HELP_URL("win-help-url", OptionSpecBuilder::ofUrl, NATIVE_PACKAGE), - WIN_UPDATE_URL("win-update-url", OptionSpecBuilder::ofUrl, NATIVE_PACKAGE), - WIN_MENU_HINT(build("win-menu").noValue(), NATIVE_PACKAGE), - WIN_MENU_GROUP("win-menu-group", NATIVE_PACKAGE), - WIN_SHORTCUT_HINT(build("win-shortcut").noValue(), NATIVE_PACKAGE), - WIN_SHORTCUT_PROMPT("win-shortcut-prompt", NATIVE_PACKAGE), - WIN_PER_USER_INSTALLATION(build("win-per-user-install").noValue(), NATIVE_PACKAGE), - WIN_DIR_CHOOSER(build("win-dir-chooser").noValue(), NATIVE_PACKAGE), - WIN_UPGRADE_UUID("win-upgrade-uuid", NATIVE_PACKAGE), - WIN_CONSOLE_HINT(build("win-console").noValue()), - ; - - StandardOption(OptionSpecBuilder builder) { - this(builder, ALL_PACKAGE_TYPES); - } - - StandardOption(OptionSpecBuilder builder, PackageTypeGroup packageTypeGroup) { - this.spec = createOptionSpec(builder, packageTypeGroup); - } - - StandardOption(String name) { - this(name, ALL_PACKAGE_TYPES); - } - - StandardOption(String name, PackageTypeGroup packageTypeGroup) { - this(name, OptionSpecBuilder::ofString, packageTypeGroup); - } - - StandardOption(String name, UnaryOperator conv) { - this(name, conv, ALL_PACKAGE_TYPES); - } - - StandardOption(String name, UnaryOperator conv, - PackageTypeGroup packageTypeGroup) { - this(conv.apply(build(name)), packageTypeGroup); - } - - @Override - public OptionSpec getSpec() { - return spec; - } - - public static List filterOptions(PackageType... packageTypes) { - return Stream.of(values()).filter(option -> { - return Stream.of(packageTypes).anyMatch( - option.spec.supportedPackageTypes()::contains); - }).toList(); - } - - private static OptionSpecBuilder build(String name) { - return new OptionSpecBuilder().name(name); - } - - private static OptionSpec createOptionSpec(OptionSpecBuilder builder, - PackageTypeGroup packageTypeGroup) { - Objects.requireNonNull(packageTypeGroup); - if (Optional.ofNullable(builder.getSupportedPackageTypes()).map( - Collection::isEmpty).orElse(false)) { - var name = builder.getName(); - if (name.startsWith("win-exe")) { - builder.supportedPackageTypes(WIN_EXE); - } else if (name.startsWith("win-msi")) { - builder.supportedPackageTypes(WIN_MSI); - } else if (name.startsWith("linux-deb")) { - builder.supportedPackageTypes(LINUX_DEB); - } else if (name.startsWith("linux-rpm")) { - builder.supportedPackageTypes(LINUX_RPM); - } else if (name.startsWith("mac-dmg")) { - builder.supportedPackageTypes(MAC_DMG); - } else if (name.startsWith("mac-pkg")) { - builder.supportedPackageTypes(MAC_PKG); - } else { - builder.supportedPackageTypes(packageTypeGroup.forOptionName(name)); - } - } - return builder.create(); - } - - private final OptionSpec spec; -} +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.cli; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; +import jdk.jpackage.internal.model.AppImagePackageType; +import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.StandardPackageType; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; +import static jdk.jpackage.internal.model.StandardPackageType.MAC_DMG; +import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG; +import static jdk.jpackage.internal.model.StandardPackageType.WIN_EXE; +import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; +import static jdk.jpackage.internal.cli.PackageTypeGroup.ALL_PACKAGE_TYPES; +import static jdk.jpackage.internal.cli.PackageTypeGroup.APP_IMAGE; +import static jdk.jpackage.internal.cli.PackageTypeGroup.NATIVE_PACKAGE; + +public enum StandardOption implements Option { + TYPE(build("type").shortName("t").valueConverter(new ValueConverter() { + @Override + public PackageType convert(String value) { + if ("app-image".equals(value)) { + return AppImagePackageType.APP_IMAGE; + } else { + return StandardPackageType.fromCmdLineType(value); + } + } + + @Override + public Class valueType() { + return PackageType.class; + } + + })), + INPUT(build("input").shortName("i").ofDirectory(), APP_IMAGE), + DEST(build("dest").shortName("d").ofDirectory()), + DESCRIPTION("description"), + VENDOR("vendor"), + APPCLASS("main-class"), + NAME(build("input").shortName("i").ofString()), + VERBOSE(build("verbose").noValue()), + RESOURCE_DIR("resource-dir", OptionSpecBuilder::ofDirectory), + ARGUMENTS("arguments", OptionSpecBuilder::ofStringArray), + JLINK_OPTIONS("arguments", OptionSpecBuilder::ofStringArray), + ICON("icon", OptionSpecBuilder::ofPath), + COPYRIGHT("copyright"), + LICENSE_FILE("license-file", OptionSpecBuilder::ofPath), + VERSION("app-version"), + ABOUT_URL("about-url", OptionSpecBuilder::ofUrl), + JAVA_OPTIONS("java-options", OptionSpecBuilder::ofStringArray), + APP_CONTENT("app-content", OptionSpecBuilder::ofPathArray), + FILE_ASSOCIATIONS("file-associations", OptionSpecBuilder::ofPath), + ADD_LAUNCHER(build("add-launcher").valueConverter(new ValueConverter() { + @Override + public AdditionalLauncher convert(String value) { + var components = value.split("=", 2); + if (components.length == 1) { + components = new String[] { null, components[0] }; + } + return new AdditionalLauncher(components[0], + StandardValueConverter.PATH_CONV.convert(components[1])); + } + + @Override + public Class valueType() { + return AdditionalLauncher.class; + } + })), + TEMP_ROOT("temp", OptionSpecBuilder::ofDirectory), + INSTALL_DIR("install-dir", OptionSpecBuilder::ofPath), + PREDEFINED_APP_IMAGE("app-image", OptionSpecBuilder::ofDirectory, NATIVE_PACKAGE), + PREDEFINED_RUNTIME_IMAGE("runtime-image", OptionSpecBuilder::ofDirectory), + MAIN_JAR("main-jar", OptionSpecBuilder::ofPath), + MODULE(build("module").shortName("m").ofString()), + ADD_MODULES("add-modules", OptionSpecBuilder::ofStringArray), + MODULE_PATH(build("module-path").shortName("p").ofDirectoryArray()), + LAUNCHER_AS_SERVICE(build("launcher-as-service").noValue()), + // Linux-specific + LINUX_RELEASE("linux-app-release", NATIVE_PACKAGE), + LINUX_BUNDLE_NAME("linux-package-name", NATIVE_PACKAGE), + LINUX_DEB_MAINTAINER("linux-deb-maintainer", NATIVE_PACKAGE), + LINUX_CATEGORY("linux-app-category", NATIVE_PACKAGE), + LINUX_RPM_LICENSE_TYPE("linux-rpm-license-type", NATIVE_PACKAGE), + LINUX_PACKAGE_DEPENDENCIES("linux-package-deps", NATIVE_PACKAGE), + LINUX_SHORTCUT_HINT(build("linux-shortcut").noValue(), NATIVE_PACKAGE), + LINUX_MENU_GROUP("linux-package-deps", NATIVE_PACKAGE), + // MacOS-specific + DMG_CONTENT(build("mac-dmg-content").ofPathArray()), + MAC_SIGN(build("mac-sign").shortName("s").noValue()), + MAC_APP_STORE(build("mac-app-store").shortName("s").noValue(), NATIVE_PACKAGE), + MAC_CATEGORY("mac-app-category"), + MAC_BUNDLE_NAME("mac-package-name"), + MAC_BUNDLE_IDENTIFIER("mac-package-identifier"), + MAC_BUNDLE_SIGNING_PREFIX("mac-package-signing-prefix"), + MAC_SIGNING_KEY_NAME("mac-signing-key-user-name"), + MAC_APP_IMAGE_SIGN_IDENTITY("mac-app-image-sign-identity", APP_IMAGE), + MAC_INSTALLER_SIGN_IDENTITY("mac-installer-sign-identity", NATIVE_PACKAGE), + MAC_SIGNING_KEYCHAIN("mac-signing-keychain", OptionSpecBuilder::ofPath), + MAC_ENTITLEMENTS("mac-entitlements"), + // Windows-specific + WIN_HELP_URL("win-help-url", OptionSpecBuilder::ofUrl, NATIVE_PACKAGE), + WIN_UPDATE_URL("win-update-url", OptionSpecBuilder::ofUrl, NATIVE_PACKAGE), + WIN_MENU_HINT(build("win-menu").noValue(), NATIVE_PACKAGE), + WIN_MENU_GROUP("win-menu-group", NATIVE_PACKAGE), + WIN_SHORTCUT_HINT(build("win-shortcut").noValue(), NATIVE_PACKAGE), + WIN_SHORTCUT_PROMPT("win-shortcut-prompt", NATIVE_PACKAGE), + WIN_PER_USER_INSTALLATION(build("win-per-user-install").noValue(), NATIVE_PACKAGE), + WIN_DIR_CHOOSER(build("win-dir-chooser").noValue(), NATIVE_PACKAGE), + WIN_UPGRADE_UUID("win-upgrade-uuid", NATIVE_PACKAGE), + WIN_CONSOLE_HINT(build("win-console").noValue()), + ; + + StandardOption(OptionSpecBuilder builder) { + this(builder, ALL_PACKAGE_TYPES); + } + + StandardOption(OptionSpecBuilder builder, PackageTypeGroup packageTypeGroup) { + this.spec = createOptionSpec(builder, packageTypeGroup); + } + + StandardOption(String name) { + this(name, ALL_PACKAGE_TYPES); + } + + StandardOption(String name, PackageTypeGroup packageTypeGroup) { + this(name, OptionSpecBuilder::ofString, packageTypeGroup); + } + + StandardOption(String name, UnaryOperator conv) { + this(name, conv, ALL_PACKAGE_TYPES); + } + + StandardOption(String name, UnaryOperator conv, + PackageTypeGroup packageTypeGroup) { + this(conv.apply(build(name)), packageTypeGroup); + } + + @Override + public OptionSpec getSpec() { + return spec; + } + + public static List filterOptions(PackageType... packageTypes) { + return Stream.of(values()).filter(option -> { + return Stream.of(packageTypes).anyMatch( + option.spec.supportedPackageTypes()::contains); + }).toList(); + } + + private static OptionSpecBuilder build(String name) { + return new OptionSpecBuilder().name(name); + } + + private static OptionSpec createOptionSpec(OptionSpecBuilder builder, + PackageTypeGroup packageTypeGroup) { + Objects.requireNonNull(packageTypeGroup); + if (Optional.ofNullable(builder.getSupportedPackageTypes()).map( + Collection::isEmpty).orElse(false)) { + var name = builder.getName(); + if (name.startsWith("win-exe")) { + builder.supportedPackageTypes(WIN_EXE); + } else if (name.startsWith("win-msi")) { + builder.supportedPackageTypes(WIN_MSI); + } else if (name.startsWith("linux-deb")) { + builder.supportedPackageTypes(LINUX_DEB); + } else if (name.startsWith("linux-rpm")) { + builder.supportedPackageTypes(LINUX_RPM); + } else if (name.startsWith("mac-dmg")) { + builder.supportedPackageTypes(MAC_DMG); + } else if (name.startsWith("mac-pkg")) { + builder.supportedPackageTypes(MAC_PKG); + } else { + builder.supportedPackageTypes(packageTypeGroup.forOptionName(name)); + } + } + return builder.create(); + } + + private final OptionSpec spec; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java index 1d7421d1e1a73..2037baf87015c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java @@ -1,83 +1,83 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.cli; - -import java.io.File; -import java.nio.file.Path; -import java.util.Objects; -import java.util.stream.Stream; - - -final class StandardValueConverter { - final static ValueConverter IDENTITY_CONV = new ValueConverter<>() { - @Override - public String convert(String value) { - Objects.requireNonNull(value); - return value; - } - - @Override - public Class valueType() { - return String.class; - } - }; - - final static ValueConverter PATH_CONV = new ValueConverter<>() { - @Override - public Path convert(String value) { - return Path.of(value); - } - - @Override - public Class valueType() { - return Path.class; - } - }; - - final static ValueConverter STRING_ARRAY_CONV = new ValueConverter<>() { - @Override - public String[] convert(String value) { - return value.split("[,\\s]"); - } - - @Override - public Class valueType() { - return String[].class; - } - }; - - final static ValueConverter PATH_ARRAY_CONV = new ValueConverter<>() { - @Override - public Path[] convert(String value) { - return Stream.of(value.split(File.pathSeparator)).map(Path::of).toArray(Path[]::new); - } - - @Override - public Class valueType() { - return Path[].class; - } - }; -} +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.cli; + +import java.io.File; +import java.nio.file.Path; +import java.util.Objects; +import java.util.stream.Stream; + + +final class StandardValueConverter { + final static ValueConverter IDENTITY_CONV = new ValueConverter<>() { + @Override + public String convert(String value) { + Objects.requireNonNull(value); + return value; + } + + @Override + public Class valueType() { + return String.class; + } + }; + + final static ValueConverter PATH_CONV = new ValueConverter<>() { + @Override + public Path convert(String value) { + return Path.of(value); + } + + @Override + public Class valueType() { + return Path.class; + } + }; + + final static ValueConverter STRING_ARRAY_CONV = new ValueConverter<>() { + @Override + public String[] convert(String value) { + return value.split("[,\\s]"); + } + + @Override + public Class valueType() { + return String[].class; + } + }; + + final static ValueConverter PATH_ARRAY_CONV = new ValueConverter<>() { + @Override + public Path[] convert(String value) { + return Stream.of(value.split(File.pathSeparator)).map(Path::of).toArray(Path[]::new); + } + + @Override + public Class valueType() { + return Path[].class; + } + }; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueValidator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueValidator.java index e36127c2d5890..dbc0d79147e8f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueValidator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueValidator.java @@ -1,53 +1,53 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal.cli; - -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Path; - -final class StandardValueValidator { - - static void validateDirectory(Path path) { - if (!Files.isDirectory(path)) { - throw new IllegalArgumentException(); - } - } - - static void validateDirectoryArray(Path[] paths) { - for (var path : paths) { - validateDirectory(path); - } - } - - static void validateUrl(String str) { - try { - new URI(str); - } catch (URISyntaxException ex) { - throw new IllegalArgumentException(ex); - } - } -} +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.cli; + +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; + +final class StandardValueValidator { + + static void validateDirectory(Path path) { + if (!Files.isDirectory(path)) { + throw new IllegalArgumentException(); + } + } + + static void validateDirectoryArray(Path[] paths) { + for (var path : paths) { + validateDirectory(path); + } + } + + static void validateUrl(String str) { + try { + new URI(str); + } catch (URISyntaxException ex) { + throw new IllegalArgumentException(ex); + } + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java index 59dc8fc3a2b8e..88988f6f8f24d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java @@ -1,46 +1,46 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal.cli; - -public interface ValueConverter { - - /** - * Converts the given string value into a Java type. - * - * @param value the string to convert - * @return the converted value - * @throws ValueConversionException if a problem occurs while converting the - * value - */ - T convert(String value); - - /** - * Gives the class of the type of values this converter converts to. - * - * @return the target class for conversion - */ - Class valueType(); - -} +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.cli; + +public interface ValueConverter { + + /** + * Converts the given string value into a Java type. + * + * @param value the string to convert + * @return the converted value + * @throws ValueConversionException if a problem occurs while converting the + * value + */ + T convert(String value); + + /** + * Gives the class of the type of values this converter converts to. + * + * @return the target class for conversion + */ + Class valueType(); + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java index 47ea5c1936af8..b0b9532bef189 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java @@ -58,8 +58,8 @@ public AppImageLayout resolveAt(Path base) { public static PathGroup toPathGroup(AppImageLayout appImageLayout) { return new PathGroup(Stream.of(appImageLayout.getClass().getInterfaces()) - // For all interfaces (it should be one, but multiple is OK) - // extending AppImageLayout interface call all non-static methods + // For all interfaces (it should be one, but multiple is OK) + // extending AppImageLayout interface call all non-static methods // without parameters and with java.nio.file.Path return type. // Create a map from the names of methods called and return values. .filter(AppImageLayout.class::isAssignableFrom) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java index db20c4e41e439..780ae873d5640 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java @@ -28,8 +28,8 @@ public final class AppImagePackageType implements PackageType { private AppImagePackageType() { - + } - + public final static AppImagePackageType APP_IMAGE = new AppImagePackageType(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java index dbc55b7b914aa..b3d1193265bcc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java @@ -1,34 +1,34 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.model; - -import java.io.IOException; -import java.nio.file.Path; - - -public interface ApplicationWriter { - void write(Application app, Path dst) throws PackagerException, IOException; -} +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.model; + +import java.io.IOException; +import java.nio.file.Path; + + +public interface ApplicationWriter { + void write(Application app, Path dst) throws PackagerException, IOException; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java index def53071d8bef..1ef82286d5c16 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java @@ -34,11 +34,11 @@ public interface FileAssociation { String description(); Path icon(); - + default boolean hasIcon() { return Objects.nonNull(icon()); } - + default boolean hasNonEmptyDescription() { return Optional.ofNullable(description()).filter(Predicate.not(String::isEmpty)).isPresent(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java index 04ae424f392f0..26bb7be9cc4cc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java @@ -70,16 +70,16 @@ default Map extraAppImageFileData() { * other value for custom icon. */ Path icon(); - + default String defaultIconResourceName() { return null; } record Stub(String name, LauncherStartupInfo startupInfo, List fileAssociations, boolean isService, - String description, Path icon) implements Launcher { + String description, Path icon) implements Launcher { } - + class Proxy extends ProxyBase implements Launcher { public Proxy(T target) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java index e10ba7470a303..407171ae36c93 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java @@ -29,8 +29,8 @@ public interface LauncherJarStartupInfo extends LauncherStartupInfo { /** * Returns path to the main jar relative to app's main source directory. - * - * @see jdk.jpackage.internal.model.Application#srcDir() + * + * @see jdk.jpackage.internal.model.Application#srcDir() */ Path jarPath(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java index 7a7f5a8015897..dcd83ec6d47da 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java @@ -44,11 +44,11 @@ default String packageName() { List defaultParameters(); /** - * Returns list of paths to add to the classath. - * + * Returns list of paths to add to the classath. + * * Every path in the list is relative to app's main source directory. - * - * @see jdk.jpackage.internal.Application#mainSrcDir() + * + * @see jdk.jpackage.internal.Application#mainSrcDir() */ List classPath(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java index 6e9d3b854838a..d9af6a7163a95 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java @@ -145,7 +145,7 @@ record Stub(Application app, PackageType type, String packageName, String description, String version, String aboutURL, Path licenseFile, Path predefinedAppImage, Path relativeInstallDir) implements Package { } - + class Proxy extends ProxyBase implements Package { Proxy(T target) { @@ -197,7 +197,7 @@ final public Path relativeInstallDir() { return target.relativeInstallDir(); } } - + class Unsupported implements Package { @Override @@ -244,5 +244,5 @@ public Path predefinedAppImage() { public Path relativeInstallDir() { throw new UnsupportedOperationException(); } - } + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java index a0ed855ae21ce..8ecd8d5e6fa65 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java @@ -1,34 +1,34 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.model; - -import java.io.IOException; -import java.nio.file.Path; - - -public interface PackageWriter { - void write(Package pkg, Path dst) throws PackagerException, IOException; -} +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.model; + +import java.io.IOException; +import java.nio.file.Path; + + +public interface PackageWriter { + void write(Package pkg, Path dst) throws PackagerException, IOException; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayoutStub.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayoutStub.java index 69d12a21f43c3..1e54e56ca84af 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayoutStub.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayoutStub.java @@ -27,7 +27,7 @@ import java.nio.file.Path; final class RuntimeLayoutStub extends AppImageLayout.Proxy implements RuntimeLayout { - + RuntimeLayoutStub(AppImageLayout target) { super(target); } @@ -35,5 +35,5 @@ final class RuntimeLayoutStub extends AppImageLayout.Proxy imple @Override public RuntimeLayout resolveAt(Path root) { return new RuntimeLayoutStub(target.resolveAt(root)); - } + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java index d51041b278de5..eb026b408cfe7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java @@ -27,11 +27,11 @@ import java.util.stream.Stream; public enum StandardPackageType implements PackageType { - WIN_MSI(".msi"), - WIN_EXE(".exe"), - LINUX_DEB(".deb"), - LINUX_RPM(".rpm"), - MAC_PKG(".pkg"), + WIN_MSI(".msi"), + WIN_EXE(".exe"), + LINUX_DEB(".deb"), + LINUX_RPM(".rpm"), + MAC_PKG(".pkg"), MAC_DMG(".dmg"); StandardPackageType(String suffix) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java index 7329bb0cf6845..7358981e940b6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java @@ -1,155 +1,155 @@ -/* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal.util; - -import java.io.IOException; -import java.nio.file.CopyOption; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.List; -import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.util.function.ExceptionWrapper; -import jdk.jpackage.internal.util.function.ThrowingConsumer; - -public final class FileUtils { - - public static void deleteRecursive(Path directory) throws IOException { - if (!Files.exists(directory)) { - return; - } - - var callback = new RecursiveDeleter(); - - Files.walkFileTree(directory, callback); - - if (callback.ex != null) { - throw callback.ex; - } - } - - public static void copyRecursive(Path src, Path dest, CopyOption... options) - throws IOException { - copyRecursive(src, dest, List.of(), options); - } - - public static void copyRecursive(Path src, Path dest, - final List excludes, CopyOption... options) - throws IOException { - - List copyActions = new ArrayList<>(); - - Files.walkFileTree(src, new SimpleFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(final Path dir, - final BasicFileAttributes attrs) { - if (isPathMatch(dir, excludes)) { - return FileVisitResult.SKIP_SUBTREE; - } else { - copyActions.add(new CopyAction(null, dest.resolve(src. - relativize(dir)))); - return FileVisitResult.CONTINUE; - } - } - - @Override - public FileVisitResult visitFile(final Path file, - final BasicFileAttributes attrs) { - if (!isPathMatch(file, excludes)) { - copyActions.add(new CopyAction(file, dest.resolve(src. - relativize(file)))); - } - return FileVisitResult.CONTINUE; - } - }); - - for (var copyAction : copyActions) { - copyAction.apply(options); - } - } - - private static boolean isPathMatch(Path what, List paths) { - return paths.stream().anyMatch(what::endsWith); - } - - private static record CopyAction(Path src, Path dest) { - - void apply(CopyOption... options) throws IOException { - if (src == null) { - Files.createDirectories(dest); - } else { - Files.copy(src, dest, options); - } - } - } - - private static class RecursiveDeleter extends SimpleFileVisitor { - - @Override - public FileVisitResult visitFile(Path file, - BasicFileAttributes attr) throws IOException { - adjustAttributes(file); - runActionOnPath(Files::delete, file); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, - BasicFileAttributes attr) throws IOException { - adjustAttributes(dir); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException e) - throws IOException { - runActionOnPath(Files::delete, dir); - return FileVisitResult.CONTINUE; - } - - private static void adjustAttributes(Path path) throws IOException { - if (OperatingSystem.isWindows()) { - Files.setAttribute(path, "dos:readonly", false); - } - } - - private void runActionOnPath(ThrowingConsumer action, Path path) { - try { - action.accept(path); - } catch (IOException ex) { - if (this.ex == null) { - this.ex = ex; - } - } catch (Throwable t) { - throw ExceptionWrapper.rethrowUnchecked(t); - } - } - - private IOException ex; - } -} +/* + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.io.IOException; +import java.nio.file.CopyOption; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.List; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.util.function.ExceptionWrapper; +import jdk.jpackage.internal.util.function.ThrowingConsumer; + +public final class FileUtils { + + public static void deleteRecursive(Path directory) throws IOException { + if (!Files.exists(directory)) { + return; + } + + var callback = new RecursiveDeleter(); + + Files.walkFileTree(directory, callback); + + if (callback.ex != null) { + throw callback.ex; + } + } + + public static void copyRecursive(Path src, Path dest, CopyOption... options) + throws IOException { + copyRecursive(src, dest, List.of(), options); + } + + public static void copyRecursive(Path src, Path dest, + final List excludes, CopyOption... options) + throws IOException { + + List copyActions = new ArrayList<>(); + + Files.walkFileTree(src, new SimpleFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(final Path dir, + final BasicFileAttributes attrs) { + if (isPathMatch(dir, excludes)) { + return FileVisitResult.SKIP_SUBTREE; + } else { + copyActions.add(new CopyAction(null, dest.resolve(src. + relativize(dir)))); + return FileVisitResult.CONTINUE; + } + } + + @Override + public FileVisitResult visitFile(final Path file, + final BasicFileAttributes attrs) { + if (!isPathMatch(file, excludes)) { + copyActions.add(new CopyAction(file, dest.resolve(src. + relativize(file)))); + } + return FileVisitResult.CONTINUE; + } + }); + + for (var copyAction : copyActions) { + copyAction.apply(options); + } + } + + private static boolean isPathMatch(Path what, List paths) { + return paths.stream().anyMatch(what::endsWith); + } + + private static record CopyAction(Path src, Path dest) { + + void apply(CopyOption... options) throws IOException { + if (src == null) { + Files.createDirectories(dest); + } else { + Files.copy(src, dest, options); + } + } + } + + private static class RecursiveDeleter extends SimpleFileVisitor { + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attr) throws IOException { + adjustAttributes(file); + runActionOnPath(Files::delete, file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, + BasicFileAttributes attr) throws IOException { + adjustAttributes(dir); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException e) + throws IOException { + runActionOnPath(Files::delete, dir); + return FileVisitResult.CONTINUE; + } + + private static void adjustAttributes(Path path) throws IOException { + if (OperatingSystem.isWindows()) { + Files.setAttribute(path, "dos:readonly", false); + } + } + + private void runActionOnPath(ThrowingConsumer action, Path path) { + try { + action.accept(path); + } catch (IOException ex) { + if (this.ex == null) { + this.ex = ex; + } + } catch (Throwable t) { + throw ExceptionWrapper.rethrowUnchecked(t); + } + } + + private IOException ex; + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java index 8e73170f90041..d6a78ef8b4120 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java @@ -1,75 +1,75 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal.util; - -import java.util.ArrayList; -import java.util.List; -import java.util.ListResourceBundle; -import java.util.Map; -import java.util.Optional; -import java.util.ResourceBundle; -import static java.util.stream.Collectors.toMap; -import java.util.stream.Stream; -import jdk.internal.util.OperatingSystem; - -public final class MultiResourceBundle extends ListResourceBundle { - - public static ResourceBundle create(String sharedResourceBundleName, - Map> platformResourceBundleNames) { - List bundleNames = new ArrayList<>(); - Optional.ofNullable(sharedResourceBundleName).ifPresent(bundleNames::add); - Optional.ofNullable(platformResourceBundleNames.get(OperatingSystem.current())).ifPresent(bundleNames::addAll); - if (bundleNames.isEmpty()) { - throw new IllegalArgumentException("Empty resource bundle names list"); - } else { - var resourceBundles = bundleNames.stream().map(ResourceBundle::getBundle).toArray(ResourceBundle[]::new); - if (resourceBundles.length == 1) { - return resourceBundles[0]; - } else { - return new MultiResourceBundle(resourceBundles); - } - } - } - - private MultiResourceBundle(ResourceBundle... bundles) { - contents = Stream.of(bundles).map(bundle -> { - return bundle.keySet().stream().map(key -> { - return Map.entry(key, bundle.getObject(key)); - }); - }).flatMap(x -> x).collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (o, n) -> { - // Override old value with the new one - return n; - })).entrySet().stream().map(e -> { - return new Object[]{e.getKey(), e.getValue()}; - }).toArray(Object[][]::new); - } - - @Override - protected Object[][] getContents() { - return contents; - } - - private final Object[][] contents; -} +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListResourceBundle; +import java.util.Map; +import java.util.Optional; +import java.util.ResourceBundle; +import static java.util.stream.Collectors.toMap; +import java.util.stream.Stream; +import jdk.internal.util.OperatingSystem; + +public final class MultiResourceBundle extends ListResourceBundle { + + public static ResourceBundle create(String sharedResourceBundleName, + Map> platformResourceBundleNames) { + List bundleNames = new ArrayList<>(); + Optional.ofNullable(sharedResourceBundleName).ifPresent(bundleNames::add); + Optional.ofNullable(platformResourceBundleNames.get(OperatingSystem.current())).ifPresent(bundleNames::addAll); + if (bundleNames.isEmpty()) { + throw new IllegalArgumentException("Empty resource bundle names list"); + } else { + var resourceBundles = bundleNames.stream().map(ResourceBundle::getBundle).toArray(ResourceBundle[]::new); + if (resourceBundles.length == 1) { + return resourceBundles[0]; + } else { + return new MultiResourceBundle(resourceBundles); + } + } + } + + private MultiResourceBundle(ResourceBundle... bundles) { + contents = Stream.of(bundles).map(bundle -> { + return bundle.keySet().stream().map(key -> { + return Map.entry(key, bundle.getObject(key)); + }); + }).flatMap(x -> x).collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (o, n) -> { + // Override old value with the new one + return n; + })).entrySet().stream().map(e -> { + return new Object[]{e.getKey(), e.getValue()}; + }).toArray(Object[][]::new); + } + + @Override + protected Object[][] getContents() { + return contents; + } + + private final Object[][] contents; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java index 3024ed1378640..3f5db83d4a4b5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java @@ -1,34 +1,34 @@ -/* - * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license - * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template - */ -package jdk.jpackage.internal.util; - -import java.nio.file.Path; -import java.util.Optional; -import jdk.jpackage.internal.IOUtils; - -public final class PathUtils { - - public static String getSuffix(Path path) { - String filename = replaceSuffix(IOUtils.getFileName(path), null).toString(); - return IOUtils.getFileName(path).toString().substring(filename.length()); - } - - public static Path addSuffix(Path path, String suffix) { - Path parent = path.getParent(); - String filename = IOUtils.getFileName(path).toString() + suffix; - return parent != null ? parent.resolve(filename) : Path.of(filename); - } - - public static Path replaceSuffix(Path path, String suffix) { - Path parent = path.getParent(); - String filename = IOUtils.getFileName(path).toString().replaceAll("\\.[^.]*$", - "") + Optional.ofNullable(suffix).orElse(""); - return parent != null ? parent.resolve(filename) : Path.of(filename); - } - - public static Path resolveNullablePath(Path base, Path path) { - return Optional.ofNullable(path).map(base::resolve).orElse(null); - } -} +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package jdk.jpackage.internal.util; + +import java.nio.file.Path; +import java.util.Optional; +import jdk.jpackage.internal.IOUtils; + +public final class PathUtils { + + public static String getSuffix(Path path) { + String filename = replaceSuffix(IOUtils.getFileName(path), null).toString(); + return IOUtils.getFileName(path).toString().substring(filename.length()); + } + + public static Path addSuffix(Path path, String suffix) { + Path parent = path.getParent(); + String filename = IOUtils.getFileName(path).toString() + suffix; + return parent != null ? parent.resolve(filename) : Path.of(filename); + } + + public static Path replaceSuffix(Path path, String suffix) { + Path parent = path.getParent(); + String filename = IOUtils.getFileName(path).toString().replaceAll("\\.[^.]*$", + "") + Optional.ofNullable(suffix).orElse(""); + return parent != null ? parent.resolve(filename) : Path.of(filename); + } + + public static Path resolveNullablePath(Path base, Path path) { + return Optional.ofNullable(path).map(base::resolve).orElse(null); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java index 76b8d95a0c2cf..461302537d935 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java @@ -40,7 +40,7 @@ default String format(String key, Object ... args) { return str; } } - + public static StringBundle fromResourceBundle(ResourceBundle bundle) { return bundle::getString; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java index 89b8f8dc7ec62..0d0ad7537cf79 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java @@ -44,7 +44,7 @@ import jdk.jpackage.internal.util.xml.SkipDocumentHandler; public final class XmlUtils { - + @FunctionalInterface public interface XmlConsumer { @@ -107,5 +107,5 @@ public static DocumentBuilderFactory initDocumentBuilderFactory() { throw new IllegalStateException(ex); } return dbf; - } + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionWrapper.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionWrapper.java index ebd5df5b24a16..ea8afdc6133a8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionWrapper.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionWrapper.java @@ -25,7 +25,7 @@ import java.lang.reflect.InvocationTargetException; public class ExceptionWrapper extends RuntimeException { - + private static final long serialVersionUID = 1L; public static RuntimeException rethrowUnchecked(Throwable throwable) throws @@ -42,5 +42,5 @@ public static RuntimeException rethrowUnchecked(Throwable throwable) throws private ExceptionWrapper(Throwable throwable) { super(throwable); } - + } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/PrettyPrintHandler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/PrettyPrintHandler.java index b3fd3c0643a89..38d47d7e2a31a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/PrettyPrintHandler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/PrettyPrintHandler.java @@ -29,7 +29,7 @@ import javax.xml.stream.XMLStreamWriter; public class PrettyPrintHandler implements InvocationHandler { - + public PrettyPrintHandler(XMLStreamWriter target) { this.target = target; } @@ -85,5 +85,5 @@ private static String repeat(int d, String s) { private int depth = 0; private final Map hasChildElement = new HashMap<>(); private static final String INDENT = " "; - private static final String EOL = "\n"; + private static final String EOL = "\n"; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/SkipDocumentHandler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/SkipDocumentHandler.java index 79a927ff766b8..918387baf8f45 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/SkipDocumentHandler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/SkipDocumentHandler.java @@ -29,7 +29,7 @@ import javax.xml.stream.XMLStreamWriter; public class SkipDocumentHandler implements InvocationHandler { - + public SkipDocumentHandler(XMLStreamWriter target) { this.target = target; } @@ -43,6 +43,6 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl } return null; } - - private final XMLStreamWriter target; + + private final XMLStreamWriter target; } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java index eb248f2a06a40..b9fd81b4eb5d6 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java @@ -38,7 +38,7 @@ final class WinExePackageBuilder { } WinExePackage create() throws ConfigException { - LauncherBuilder.validateIcon(icon); + LauncherBuilder.validateIcon(icon); return new WinExePackage.Stub(pkg, icon); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java index 7f2bb44e73e9e..88ce7169da71e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ApplicationLayout.java @@ -1,126 +1,126 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.test; - -import java.nio.file.Path; -import java.util.Optional; - -public record ApplicationLayout(Path launchersDirectory, Path appDirectory, - Path runtimeDirectory, Path runtimeHomeDirectory, Path appModsDirectory, - Path destktopIntegrationDirectory, Path contentDirectory) { - - public ApplicationLayout resolveAt(Path root) { - return new ApplicationLayout( - resolve(root, launchersDirectory), - resolve(root, appDirectory), - resolve(root, runtimeDirectory), - resolve(root, runtimeHomeDirectory), - resolve(root, appModsDirectory), - resolve(root, destktopIntegrationDirectory), - resolve(root, contentDirectory)); - } - - public static ApplicationLayout linuxAppImage() { - return new ApplicationLayout( - Path.of("bin"), - Path.of("lib/app"), - Path.of("lib/runtime"), - Path.of("lib/runtime"), - Path.of("lib/app/mods"), - Path.of("lib"), - Path.of("lib") - ); - } - - public static ApplicationLayout windowsAppImage() { - return new ApplicationLayout( - Path.of(""), - Path.of("app"), - Path.of("runtime"), - Path.of("runtime"), - Path.of("app/mods"), - Path.of(""), - Path.of("") - ); - } - - public static ApplicationLayout macAppImage() { - return new ApplicationLayout( - Path.of("Contents/MacOS"), - Path.of("Contents/app"), - Path.of("Contents/runtime"), - Path.of("Contents/runtime/Contents/Home"), - Path.of("Contents/app/mods"), - Path.of("Contents/Resources"), - Path.of("Contents") - ); - } - - public static ApplicationLayout platformAppImage() { - if (TKit.isWindows()) { - return windowsAppImage(); - } - - if (TKit.isLinux()) { - return linuxAppImage(); - } - - if (TKit.isOSX()) { - return macAppImage(); - } - - throw new IllegalArgumentException("Unknown platform"); - } - - public static ApplicationLayout javaRuntime() { - return new ApplicationLayout( - null, - null, - Path.of(""), - null, - null, - null, - null - ); - } - - public static ApplicationLayout linuxUsrTreePackageImage(Path prefix, - String packageName) { - final Path lib = prefix.resolve(Path.of("lib", packageName)); - return new ApplicationLayout( - prefix.resolve("bin"), - lib.resolve("app"), - lib.resolve("runtime"), - lib.resolve("runtime"), - lib.resolve("app/mods"), - lib, - lib - ); - } - - private static Path resolve(Path base, Path path) { - return Optional.ofNullable(path).map(base::resolve).orElse(null); - } -} +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import java.nio.file.Path; +import java.util.Optional; + +public record ApplicationLayout(Path launchersDirectory, Path appDirectory, + Path runtimeDirectory, Path runtimeHomeDirectory, Path appModsDirectory, + Path destktopIntegrationDirectory, Path contentDirectory) { + + public ApplicationLayout resolveAt(Path root) { + return new ApplicationLayout( + resolve(root, launchersDirectory), + resolve(root, appDirectory), + resolve(root, runtimeDirectory), + resolve(root, runtimeHomeDirectory), + resolve(root, appModsDirectory), + resolve(root, destktopIntegrationDirectory), + resolve(root, contentDirectory)); + } + + public static ApplicationLayout linuxAppImage() { + return new ApplicationLayout( + Path.of("bin"), + Path.of("lib/app"), + Path.of("lib/runtime"), + Path.of("lib/runtime"), + Path.of("lib/app/mods"), + Path.of("lib"), + Path.of("lib") + ); + } + + public static ApplicationLayout windowsAppImage() { + return new ApplicationLayout( + Path.of(""), + Path.of("app"), + Path.of("runtime"), + Path.of("runtime"), + Path.of("app/mods"), + Path.of(""), + Path.of("") + ); + } + + public static ApplicationLayout macAppImage() { + return new ApplicationLayout( + Path.of("Contents/MacOS"), + Path.of("Contents/app"), + Path.of("Contents/runtime"), + Path.of("Contents/runtime/Contents/Home"), + Path.of("Contents/app/mods"), + Path.of("Contents/Resources"), + Path.of("Contents") + ); + } + + public static ApplicationLayout platformAppImage() { + if (TKit.isWindows()) { + return windowsAppImage(); + } + + if (TKit.isLinux()) { + return linuxAppImage(); + } + + if (TKit.isOSX()) { + return macAppImage(); + } + + throw new IllegalArgumentException("Unknown platform"); + } + + public static ApplicationLayout javaRuntime() { + return new ApplicationLayout( + null, + null, + Path.of(""), + null, + null, + null, + null + ); + } + + public static ApplicationLayout linuxUsrTreePackageImage(Path prefix, + String packageName) { + final Path lib = prefix.resolve(Path.of("lib", packageName)); + return new ApplicationLayout( + prefix.resolve("bin"), + lib.resolve("app"), + lib.resolve("runtime"), + lib.resolve("runtime"), + lib.resolve("app/mods"), + lib, + lib + ); + } + + private static Path resolve(Path base, Path path) { + return Optional.ofNullable(path).map(base::resolve).orElse(null); + } +} diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java index c149f3e293be9..2dd501502de4d 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java @@ -226,7 +226,7 @@ private Path createCustomFile(String publicName, List data) throws return customFile; } - + private static OverridableResource createOverridableResource(String defaultName) { return Optional.ofNullable(defaultName).map(name -> { return new OverridableResource(defaultName, ResourceLocator.class); diff --git a/test/jdk/tools/jpackage/share/PredefinedAppImageErrorTest.java b/test/jdk/tools/jpackage/share/PredefinedAppImageErrorTest.java index 3d2d8e0f65631..496586ea98a59 100644 --- a/test/jdk/tools/jpackage/share/PredefinedAppImageErrorTest.java +++ b/test/jdk/tools/jpackage/share/PredefinedAppImageErrorTest.java @@ -111,7 +111,7 @@ private void getDummyAppImage(JPackageCommand cmd) throws IOException { = dummyAppFolder.resolve("DummyAppFile").toAbsolutePath(); Files.createFile(dummyAppFile); - cmd.addArguments("--app-image", dummyAppFolder.toString()); + cmd.addArguments("--app-image", dummyAppFolder.toString()); new AppImageFile("PredefinedAppImageErrorTest", "Hello").save(dummyAppFolder); } } From 2baa08e0fefcbc116454bd157be072baaae60ef3 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 15 Nov 2024 21:54:54 -0500 Subject: [PATCH 0161/1101] run blessed-modifier-order.sh script --- .../helpers/jdk/jpackage/test/FileAssociations.java | 4 ++-- .../helpers/jdk/jpackage/test/LauncherIconVerifier.java | 2 +- .../jpackage/helpers/jdk/jpackage/test/LinuxHelper.java | 6 +++--- .../jdk/jpackage/internal/AppImageFileTest.java | 2 +- .../jdk/jpackage/internal/OverridableResourceTest.java | 4 ++-- .../jdk/jpackage/internal/PlatformVersionTest.java | 4 ++-- .../jdk/jpackage/internal/ToolValidatorTest.java | 4 ++-- .../jdk/jpackage/internal/util/PathGroupTest.java | 8 ++++---- test/jdk/tools/jpackage/share/AppContentTest.java | 2 +- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java index a3f5853f9e9d0..f54cf225e7af0 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java @@ -35,7 +35,7 @@ import jdk.jpackage.internal.util.PathUtils; -final public class FileAssociations { +public final class FileAssociations { public FileAssociations(String faSuffixName) { suffixName = faSuffixName; setFilename("fa"); @@ -243,7 +243,7 @@ public static enum InvocationType { } private Path file; - final private String suffixName; + private final String suffixName; private String description; private Path icon; private Collection testRuns; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java index abc9b89ffd50a..6e3b01ce996c4 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java @@ -267,7 +267,7 @@ private void setIcon(Path iconPath, Path launcherPath) { } } - final static WinIconVerifier instance = new WinIconVerifier(); + static final WinIconVerifier instance = new WinIconVerifier(); private final Class executableRebranderClass; private final Method lockResource; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index 5fa26c8f022c6..9cab939676d7b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -749,10 +749,10 @@ private static Method initGetServiceUnitFileName() { private static Map archs; - private final static Pattern XDG_CMD_ICON_SIZE_PATTERN = Pattern.compile("\\s--size\\s+(\\d+)\\b"); + private static final Pattern XDG_CMD_ICON_SIZE_PATTERN = Pattern.compile("\\s--size\\s+(\\d+)\\b"); // Values grabbed from https://linux.die.net/man/1/xdg-icon-resource - private final static Set XDG_CMD_VALID_ICON_SIZES = Set.of(16, 22, 32, 48, 64, 128); + private static final Set XDG_CMD_VALID_ICON_SIZES = Set.of(16, 22, 32, 48, 64, 128); - private final static Method getServiceUnitFileName = initGetServiceUnitFileName(); + private static final Method getServiceUnitFileName = initGetServiceUnitFileName(); } diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java index a72762a007c38..822eca5b1bdc1 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java @@ -250,7 +250,7 @@ private AppImageFile createFromXml(String... xmlData) throws IOException { return image; } - private final static String JPACKAGE_STATE_OPEN = String.format( + private static final String JPACKAGE_STATE_OPEN = String.format( "", AppImageFile.getPlatform(), AppImageFile.getVersion()); diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java index 2dd501502de4d..1be595548e27e 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java @@ -192,8 +192,8 @@ public void testNoDefault() throws IOException { assertFalse(dstFile.toFile().exists()); } - private final static String DEFAULT_NAME; - private final static Map SUBSTITUTION_DATA; + private static final String DEFAULT_NAME; + private static final Map SUBSTITUTION_DATA; static { if (OperatingSystem.isWindows()) { DEFAULT_NAME = "WinLauncher.template"; diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java index 00d2deccf4b86..728d8c9d5c2b7 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java @@ -109,9 +109,9 @@ public void testIt() { private final String version; private final boolean valid; - private final static Function MAC_CFBUNDLE_VERSION_PARSER = findParser( + private static final Function MAC_CFBUNDLE_VERSION_PARSER = findParser( "jdk.jpackage.internal.CFBundleVersion"); - private final static Function WIN_MSI_PRODUCT_VERSION_PARSER = findParser( + private static final Function WIN_MSI_PRODUCT_VERSION_PARSER = findParser( "jdk.jpackage.internal.MsiVersion"); private static Function findParser(String className) { diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java index a9329de98bed5..3a08b6ca91611 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java @@ -84,8 +84,8 @@ private static void assertValidationFailure(ConfigException v, } } - private final static String TOOL_JAVA; - private final static String TOOL_UNKNOWN = Path.of(System.getProperty( + private static final String TOOL_JAVA; + private static final String TOOL_UNKNOWN = Path.of(System.getProperty( "java.home"), "bin").toString(); static { diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java index c4d039d52e164..16b899708caf6 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java @@ -270,8 +270,8 @@ private static Path[] walkFiles(Path root) throws IOException { } } - private final static Path PATH_FOO = Path.of("foo"); - private final static Path PATH_BAR = Path.of("bar"); - private final static Path PATH_BAZ = Path.of("baz"); - private final static Path PATH_EMPTY = Path.of(""); + private static final Path PATH_FOO = Path.of("foo"); + private static final Path PATH_BAR = Path.of("bar"); + private static final Path PATH_BAZ = Path.of("baz"); + private static final Path PATH_EMPTY = Path.of(""); } diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java index fc728089b01a8..ac78aac57a511 100644 --- a/test/jdk/tools/jpackage/share/AppContentTest.java +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -65,7 +65,7 @@ public class AppContentTest { // In particular, random files should be placed in "Contents/Resources" folder // otherwise "codesign" will fail to sign. // Need to prepare arguments for `--app-content` accordingly. - private final static boolean copyInResources = TKit.isOSX(); + private static final boolean copyInResources = TKit.isOSX(); private final List testPathArgs; From 342adf81d544f475f324ab1c22d9226be875b2ec Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 15 Nov 2024 22:13:28 -0500 Subject: [PATCH 0162/1101] Copyright year updated --- .../linux/classes/jdk/jpackage/internal/PackageProperty.java | 2 +- .../macosx/classes/jdk/jpackage/internal/CFBundleVersion.java | 2 +- .../classes/jdk/jpackage/internal/MacPkgInstallerScripts.java | 2 +- .../share/classes/jdk/jpackage/internal/AbstractBundler.java | 2 +- .../share/classes/jdk/jpackage/internal/AppImageFile.java | 2 +- .../share/classes/jdk/jpackage/internal/Bundler.java | 2 +- .../share/classes/jdk/jpackage/internal/InstallableFile.java | 2 +- .../classes/jdk/jpackage/internal/OverridableResource.java | 2 +- .../classes/jdk/jpackage/internal/model/AppImageLayout.java | 2 +- .../jdk/jpackage/internal/model/ApplicationLaunchers.java | 2 +- .../classes/jdk/jpackage/internal/model/ApplicationLayout.java | 2 +- .../classes/jdk/jpackage/internal/model/RuntimeLayout.java | 2 +- .../unix/classes/jdk/jpackage/internal/PackageScripts.java | 2 +- .../unix/classes/jdk/jpackage/internal/ShellCustomAction.java | 2 +- .../unix/classes/jdk/jpackage/internal/ShellScriptResource.java | 2 +- .../classes/jdk/jpackage/internal/ExecutableRebrander.java | 2 +- .../classes/jdk/jpackage/internal/WixLauncherAsService.java | 2 +- .../windows/classes/jdk/jpackage/internal/model/MsiVersion.java | 2 +- .../jpackage/helpers/jdk/jpackage/test/FileAssociations.java | 2 +- test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java | 2 +- .../jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java | 2 +- .../jdk/jpackage/internal/OverridableResourceTest.java | 2 +- .../jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java | 2 +- .../jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java | 2 +- .../jdk/jpackage/internal/model/ApplicationLayoutTest.java | 2 +- .../jdk/jpackage/internal/model/InvalidDottedVersionTest.java | 2 +- .../jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java index 5f7b072171987..939f3f88ad97d 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java index 181f7aa1dc008..052c14f68642c 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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 diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java index a1e153dd7fe89..6877d4568dd10 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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 diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java index caa1b1bea4e8b..234b2c34047bc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, 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 diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index e05cf854b30f1..1c0c9b6900251 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java index a45f3de9077ce..ce3466bf85bdf 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, 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 diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java index 0cbbdcb427809..c43c92bfc86d2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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 diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java index c5f37d8ec356f..330acbd001a61 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java index b0b9532bef189..9740b302f66e5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java index 253e0282e7d28..01ec8aaf3a0f2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index b37ee37b5965f..4f133e696a713 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java index 7f17309af79f1..3a823ccbbdeda 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java index b5dd828227326..a0053d369bdc7 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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 diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java index 418007b163182..d0a654a2d04e4 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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 diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellScriptResource.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellScriptResource.java index c6303636c66f4..268c6d173aa0b 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellScriptResource.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellScriptResource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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 diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java index 68b82a90ab7fb..658e6b2b1d415 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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 diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java index 1cc37bf983d05..3d9c1e05aa8a4 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, 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 diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java index 5e3aa6dd4f2f2..7eb5ac4b08bf3 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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 diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java index f54cf225e7af0..091a2206b173b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java index 4c884c7fe08cf..94a0deaf04fe3 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java index 822eca5b1bdc1..74e1f17d54c6e 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java index 1be595548e27e..5e7496787c58a 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java index 728d8c9d5c2b7..1081e1b1df3a0 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java index 3a08b6ca91611..ee076326eb804 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java index 4642a3df8a233..871756295008d 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/InvalidDottedVersionTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/InvalidDottedVersionTest.java index 31e5f074a6099..dfb01c7689425 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/InvalidDottedVersionTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/InvalidDottedVersionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java index 16b899708caf6..454963cbb2311 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 From 10f10da7ff3bc75ead0aa4e48169c914993307c8 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 15 Nov 2024 22:21:58 -0500 Subject: [PATCH 0163/1101] Fix bad merge --- .../jdk/jpackage/internal/model/Launcher.java | 40 -------------- .../LauncherModularStartupInfoMixin.java | 12 ----- .../jdk/jpackage/internal/model/Package.java | 52 ------------------- 3 files changed, 104 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java index a8f44d9bc042e..3af830fc15a86 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java @@ -78,46 +78,6 @@ default String defaultIconResourceName() { record Stub(String name, LauncherStartupInfo startupInfo, List fileAssociations, boolean isService, String description, Path icon) implements Launcher { -<<<<<<< HEAD -======= - } - - class Proxy extends ProxyBase implements Launcher { - - public Proxy(T target) { - super(target); - } - - @Override - final public String name() { - return target.name(); - } - - @Override - final public LauncherStartupInfo startupInfo() { - return target.startupInfo(); - } - - @Override - final public List fileAssociations() { - return target.fileAssociations(); - } - - @Override - final public boolean isService() { - return target.isService(); - } - - @Override - final public String description() { - return target.description(); - } - - @Override - final public Path icon() { - return target.icon(); - } ->>>>>>> JDK-8333664 } class Unsupported implements Launcher { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java index ee71ec4723bca..03306f2c657b8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java @@ -27,7 +27,6 @@ import java.nio.file.Path; import java.util.List; -<<<<<<< HEAD:src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java public interface LauncherModularStartupInfoMixin { String moduleName(); @@ -36,16 +35,5 @@ public interface LauncherModularStartupInfoMixin { record Stub(String moduleName, List modulePath) implements LauncherModularStartupInfoMixin { } -======= -final class RuntimeLayoutStub extends AppImageLayout.Proxy implements RuntimeLayout { - RuntimeLayoutStub(AppImageLayout target) { - super(target); - } - - @Override - public RuntimeLayout resolveAt(Path root) { - return new RuntimeLayoutStub(target.resolveAt(root)); - } ->>>>>>> JDK-8333664:src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayoutStub.java } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java index d9af6a7163a95..d52d2758b350f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java @@ -146,58 +146,6 @@ record Stub(Application app, PackageType type, String packageName, Path predefinedAppImage, Path relativeInstallDir) implements Package { } - class Proxy extends ProxyBase implements Package { - - Proxy(T target) { - super(target); - } - - @Override - final public Application app() { - return target.app(); - } - - @Override - final public PackageType type() { - return target.type(); - } - - @Override - final public String packageName() { - return target.packageName(); - } - - @Override - final public String description() { - return target.description(); - } - - @Override - final public String version() { - return target.version(); - } - - @Override - final public String aboutURL() { - return target.aboutURL(); - } - - @Override - final public Path licenseFile() { - return target.licenseFile(); - } - - @Override - final public Path predefinedAppImage() { - return target.predefinedAppImage(); - } - - @Override - final public Path relativeInstallDir() { - return target.relativeInstallDir(); - } - } - class Unsupported implements Package { @Override From 2b2d4811e3590b9db982603a217f8550f7faa437 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 15 Nov 2024 22:34:00 -0500 Subject: [PATCH 0164/1101] Fix imports --- .../macosx/SigningPackageFromTwoStepAppImageTest.java | 2 +- test/jdk/tools/jpackage/macosx/SigningPackageTest.java | 2 +- .../tools/jpackage/macosx/SigningPackageTwoStepTest.java | 2 +- test/jdk/tools/jpackage/share/InOutPathTest.java | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java index 0f4f2e774764c..f6408d21eba4d 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java @@ -22,7 +22,7 @@ */ import java.nio.file.Path; -import jdk.jpackage.internal.ApplicationLayout; +import jdk.jpackage.test.ApplicationLayout; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.TKit; import jdk.jpackage.test.PackageTest; diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java index 621fac1cd19f9..46a3dad2af8c8 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java @@ -22,7 +22,7 @@ */ import java.nio.file.Path; -import jdk.jpackage.internal.ApplicationLayout; +import jdk.jpackage.test.ApplicationLayout; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java index 65211e8c29e2a..84af48f6efb26 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java @@ -22,7 +22,7 @@ */ import java.nio.file.Path; -import jdk.jpackage.internal.ApplicationLayout; +import jdk.jpackage.test.ApplicationLayout; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.TKit; import jdk.jpackage.test.PackageTest; diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java index 1d5bb39bde316..8266da22c35cb 100644 --- a/test/jdk/tools/jpackage/share/InOutPathTest.java +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -31,9 +31,9 @@ import java.util.function.Predicate; import static java.util.stream.Collectors.toSet; import java.util.stream.Stream; -import jdk.jpackage.internal.AppImageFile; -import jdk.jpackage.internal.ApplicationLayout; -import jdk.jpackage.internal.PackageFile; +import jdk.jpackage.test.AppImageFile; +import jdk.jpackage.test.ApplicationLayout; +import jdk.jpackage.test.PackageFile; import jdk.jpackage.test.Annotations; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.internal.util.function.ThrowingConsumer; From 8c3be92c41e95975ceac5dd9e670987ccf1607bf Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 15 Nov 2024 22:48:30 -0500 Subject: [PATCH 0165/1101] Clean dangling ends --- test/jdk/tools/jpackage/share/AppVersionTest.java | 11 ++--------- test/jdk/tools/jpackage/share/ModulePathTest3.java | 12 ++---------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/test/jdk/tools/jpackage/share/AppVersionTest.java b/test/jdk/tools/jpackage/share/AppVersionTest.java index efd025590d28a..3fdddf56e2eaa 100644 --- a/test/jdk/tools/jpackage/share/AppVersionTest.java +++ b/test/jdk/tools/jpackage/share/AppVersionTest.java @@ -26,17 +26,13 @@ import java.util.Collection; import java.util.ArrayList; import java.util.List; -import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.AppImageFile; +import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.TKit; -import jdk.jpackage.internal.AppImageFile; -import org.w3c.dom.Document; /* * @test @@ -116,10 +112,7 @@ public void test() throws XPathExpressionException, IOException { } cmd.executeAndAssertHelloAppImageCreated(); - Document xml = AppImageFile.readXml(cmd.outputBundle()); - String actualVersion = XPathFactory.newInstance().newXPath().evaluate( - "/jpackage-state/app-version/text()", xml, XPathConstants.STRING).toString(); - + String actualVersion = AppImageFile.load(cmd.outputBundle()).version(); TKit.assertEquals(expectedVersion, actualVersion, "Check application version"); } diff --git a/test/jdk/tools/jpackage/share/ModulePathTest3.java b/test/jdk/tools/jpackage/share/ModulePathTest3.java index b4b51e1adfcf5..118dc2e5ed01f 100644 --- a/test/jdk/tools/jpackage/share/ModulePathTest3.java +++ b/test/jdk/tools/jpackage/share/ModulePathTest3.java @@ -29,20 +29,16 @@ import java.util.Collection; import java.util.List; import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.AppImageFile; +import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.HelloApp; import jdk.jpackage.test.JavaAppDesc; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Executor; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JavaTool; import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; -import org.w3c.dom.Document; /* @@ -105,11 +101,7 @@ private void testIt(String mainAppDesc) throws XPathExpressionException, cmd.executeAndAssertHelloAppImageCreated(); if (appDesc.moduleVersion() != null) { - Document xml = AppImageFile.readXml(cmd.outputBundle()); - String actualVersion = XPathFactory.newInstance().newXPath().evaluate( - "/jpackage-state/app-version/text()", xml, - XPathConstants.STRING).toString(); - + String actualVersion = AppImageFile.load(cmd.outputBundle()).version(); TKit.assertEquals(appDesc.moduleVersion(), actualVersion, "Check application version"); } From c58b6587b3b4fb9c08afd27eacf139e0ed9afb83 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 16 Nov 2024 01:50:18 -0500 Subject: [PATCH 0166/1101] Get rid of FunctionalUtils.java --- .../jdk/jpackage/internal/util/FileUtils.java | 1 - .../util/function/FunctionalUtils.java | 56 ------------------- .../helpers/jdk/jpackage/test/HelloApp.java | 6 +- .../jdk/jpackage/test/JPackageCommand.java | 34 ++++------- .../jdk/jpackage/test/JavaAppDesc.java | 10 ++-- .../jdk/jpackage/test/PackageTest.java | 3 +- .../jdk/jpackage/test/PackageType.java | 1 - .../helpers/jdk/jpackage/test/TKit.java | 43 ++++++-------- .../jdk/jpackage/test/TestInstance.java | 42 +++++++------- .../tools/jpackage/share/InstallDirTest.java | 4 +- 10 files changed, 60 insertions(+), 140 deletions(-) delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/FunctionalUtils.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java index 4f0192c21f4b6..bb36cd5792dfc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java @@ -35,7 +35,6 @@ import java.util.List; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.util.function.ExceptionBox; -import jdk.jpackage.internal.util.function.FunctionalUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; public final class FileUtils { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/FunctionalUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/FunctionalUtils.java deleted file mode 100644 index ee2cd99b8977a..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/FunctionalUtils.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal.util.function; - -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.Supplier; - -public final class FunctionalUtils { - - public static Supplier identity(Supplier v) { - return v; - } - - public static Consumer identity(Consumer v) { - return v; - } - - public static BiConsumer identity(BiConsumer v) { - return v; - } - - public static Runnable identity(Runnable v) { - return v; - } - - public static Function identityFunction(Function v) { - return v; - } - - public static Predicate identityPredicate(Predicate v) { - return v; - } -} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java index cce373dd9c0d3..a57b0d957c83d 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java @@ -33,6 +33,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.regex.Matcher; @@ -40,7 +41,6 @@ import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import jdk.jpackage.internal.util.function.FunctionalUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.internal.util.function.ThrowingFunction; import jdk.jpackage.internal.util.function.ThrowingSupplier; @@ -88,11 +88,11 @@ private JarBuilder prepareSources(Path srcDir) throws IOException { AtomicBoolean classDeclared = new AtomicBoolean(); AtomicBoolean packageInserted = new AtomicBoolean(packageName == null); - var packageInserter = FunctionalUtils.identityFunction((line) -> { + Function packageInserter = line -> { packageInserted.setPlain(true); return String.format("package %s;%s%s", packageName, System.lineSeparator(), line); - }); + }; Files.write(srcFile, Files.readAllLines(appDesc.srcJavaPath()).stream().map(line -> { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index e6931ecf4b692..e632f33cd4d0c 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -30,7 +30,6 @@ import java.security.SecureRandom; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; @@ -44,12 +43,12 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import static java.util.stream.Collectors.toMap; import java.util.stream.Stream; import jdk.jpackage.internal.AppImageFile; import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.internal.PackageFile; import jdk.jpackage.internal.util.XmlUtils; -import jdk.jpackage.internal.util.function.FunctionalUtils; import static jdk.jpackage.test.AdditionalLauncher.forEachAdditionalLauncher; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.internal.util.function.ThrowingFunction; @@ -1190,27 +1189,16 @@ public void run() { private Set appLayoutAsserts = Set.of(AppLayoutAssert.values()); private static boolean defaultWithToolProvider; - private static final Map PACKAGE_TYPES = FunctionalUtils.identity( - () -> { - Map reply = new HashMap<>(); - for (PackageType type : PackageType.values()) { - reply.put(type.getName(), type); - } - return reply; - }).get(); - - public static final Path DEFAULT_RUNTIME_IMAGE = FunctionalUtils.identity(() -> { - // Set the property to the path of run-time image to speed up - // building app images and platform bundles by avoiding running jlink - // The value of the property will be automativcally appended to - // jpackage command line if the command line doesn't have - // `--runtime-image` parameter set. - String val = TKit.getConfigProperty("runtime-image"); - if (val != null) { - return Path.of(val); - } - return null; - }).get(); + private static final Map PACKAGE_TYPES = Stream.of( + PackageType.values()).collect(toMap(PackageType::getName, x -> x)); + + // Set the property to the path of run-time image to speed up + // building app images and platform bundles by avoiding running jlink + // The value of the property will be automativcally appended to + // jpackage command line if the command line doesn't have + // `--runtime-image` parameter set. + public static final Path DEFAULT_RUNTIME_IMAGE = Optional.ofNullable( + TKit.getConfigProperty("runtime-image")).map(Path::of).orElse(null); private static final String UNPACKED_PATH_ARGNAME = "jpt-unpacked-folder"; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java index e55136e093e5f..1651a36045d90 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java @@ -24,8 +24,8 @@ import java.nio.file.Path; import java.util.Objects; +import java.util.function.Supplier; import java.util.stream.Stream; -import jdk.jpackage.internal.util.function.FunctionalUtils; public final class JavaAppDesc { @@ -238,7 +238,7 @@ public static JavaAppDesc parse(final String javaAppDesc) { return desc; } - String srcJavaPathAndOther = FunctionalUtils.identity(() -> { + String srcJavaPathAndOther = ((Supplier)() -> { String[] components = javaAppDesc.split("\\*", 2); if (components.length == 2) { desc.setSrcJavaPath(Path.of(components[0])); @@ -246,7 +246,7 @@ public static JavaAppDesc parse(final String javaAppDesc) { return components[components.length - 1]; }).get(); - String moduleNameAndOther = FunctionalUtils.identity(() -> { + String moduleNameAndOther = ((Supplier)() -> { String[] components = srcJavaPathAndOther.split(":", 2); if (components.length == 2) { desc.setBundleFileName(components[0]); @@ -254,7 +254,7 @@ public static JavaAppDesc parse(final String javaAppDesc) { return components[components.length - 1]; }).get(); - String classNameAndOther = FunctionalUtils.identity(() -> { + String classNameAndOther = ((Supplier)() -> { String[] components = moduleNameAndOther.split("/", 2); if (components.length == 2) { desc.setModuleName(components[0]); @@ -262,7 +262,7 @@ public static JavaAppDesc parse(final String javaAppDesc) { return components[components.length - 1]; }).get(); - FunctionalUtils.identity(() -> { + ((Runnable)() -> { String[] components = classNameAndOther.split("@", 2); if (components[0].endsWith("!")) { components[0] = components[0].substring(0, diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index b025a3a0a7b97..2a7a0e34ad171 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -53,7 +53,6 @@ import jdk.jpackage.internal.util.function.ThrowingRunnable; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; -import jdk.jpackage.internal.util.function.FunctionalUtils; import static jdk.jpackage.test.PackageType.LINUX; import static jdk.jpackage.test.PackageType.LINUX_DEB; import static jdk.jpackage.test.PackageType.LINUX_RPM; @@ -533,7 +532,7 @@ private void handleAction(Action action, T handler, private Path unpackDir; private Action unhandledAction; private boolean terminated; - private final JPackageCommand cmd = FunctionalUtils.identity(() -> { + private final JPackageCommand cmd = ((Supplier)() -> { JPackageCommand result = new JPackageCommand(); result.setDefaultInputOutput().setDefaultAppName(); if (BUNDLE_OUTPUT_DIR != null && !ignoreBundleOutputDir) { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageType.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageType.java index 0dfc979397eb5..2ecda662698d3 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageType.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageType.java @@ -33,7 +33,6 @@ import java.util.stream.Stream; import jdk.jpackage.internal.Log; import static jdk.jpackage.internal.util.function.ExceptionWrapper.rethrowUnchecked; -import jdk.jpackage.internal.util.function.FunctionalUtils; /** * jpackage type traits. diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index a829d3e32c2c5..8aa54595d0c77 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -62,14 +62,13 @@ import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.util.function.ExceptionBox; -import jdk.jpackage.internal.util.function.FunctionalUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.internal.util.function.ThrowingRunnable; import jdk.jpackage.internal.util.function.ThrowingSupplier; public final class TKit { - public static final Path TEST_SRC_ROOT = FunctionalUtils.identity(() -> { + public static final Path TEST_SRC_ROOT = ((Supplier)() -> { Path root = Path.of(System.getProperty("test.src")); for (int i = 0; i != 10; ++i) { @@ -82,25 +81,22 @@ public final class TKit { throw new RuntimeException("Failed to locate apps directory"); }).get(); - public static final Path SRC_ROOT = FunctionalUtils.identity(() -> { - return TEST_SRC_ROOT.resolve("../../../../src/jdk.jpackage").normalize().toAbsolutePath(); - }).get(); - - public static final String ICON_SUFFIX = FunctionalUtils.identity(() -> { - if (isOSX()) { - return ".icns"; - } + public static final Path SRC_ROOT = TEST_SRC_ROOT.resolve( + "../../../../src/jdk.jpackage").normalize().toAbsolutePath(); - if (isLinux()) { - return ".png"; - } + public static final String ICON_SUFFIX; - if (isWindows()) { - return ".ico"; + static { + if (isOSX()) { + ICON_SUFFIX = ".icns"; + } else if (isLinux()) { + ICON_SUFFIX = ".png"; + } else if (isWindows()) { + ICON_SUFFIX = ".ico"; + } else { + throw throwUnknownPlatformError(); } - - throw throwUnknownPlatformError(); - }).get(); + } static void withExtraLogStream(ThrowingRunnable action) { if (extraLogStream != null) { @@ -870,7 +866,7 @@ public static void assertStringListEquals(List expected, traceAssert(concatMessages("assertStringListEquals()", msg)); - String idxFieldFormat = FunctionalUtils.identity(() -> { + String idxFieldFormat = ((Supplier)() -> { int listSize = expected.size(); int width = 0; while (listSize != 0) { @@ -1056,13 +1052,8 @@ static Set tokenizeConfigProperty(String propertyName) { return tokens.stream().collect(Collectors.toSet()); } - static final Path LOG_FILE = FunctionalUtils.identity(() -> { - String val = getConfigProperty("logfile"); - if (val == null) { - return null; - } - return Path.of(val); - }).get(); + static final Path LOG_FILE = Optional.ofNullable( + getConfigProperty("logfile")).map(Path::of).orElse(null); static { Set logOptions = tokenizeConfigProperty("suppress-logging"); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java index 1eb99fcfbb85c..7d437abecc481 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java @@ -38,7 +38,6 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.util.function.FunctionalUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.internal.util.function.ThrowingFunction; import jdk.jpackage.internal.util.function.ThrowingRunnable; @@ -333,28 +332,29 @@ public String toString() { private final boolean dryRun; private final Path workDir; - private static final Set KEEP_WORK_DIR = FunctionalUtils.identity( - () -> { - final String propertyName = "keep-work-dir"; - Set keepWorkDir = TKit.tokenizeConfigProperty( - propertyName); - if (keepWorkDir == null) { - return Set.of(Status.Failed); - } + private static final Set KEEP_WORK_DIR; - Predicate> isOneOf = options -> { - return !Collections.disjoint(keepWorkDir, options); - }; + static { + final String propertyName = "keep-work-dir"; + Set keepWorkDir = TKit.tokenizeConfigProperty( + propertyName); + if (keepWorkDir == null) { + KEEP_WORK_DIR = Set.of(Status.Failed); + } else { - Set result = new HashSet<>(); - if (isOneOf.test(Set.of("pass", "p"))) { - result.add(Status.Passed); - } - if (isOneOf.test(Set.of("fail", "f"))) { - result.add(Status.Failed); - } + Predicate> isOneOf = options -> { + return !Collections.disjoint(keepWorkDir, options); + }; - return Collections.unmodifiableSet(result); - }).get(); + Set result = new HashSet<>(); + if (isOneOf.test(Set.of("pass", "p"))) { + result.add(Status.Passed); + } + if (isOneOf.test(Set.of("fail", "f"))) { + result.add(Status.Failed); + } + KEEP_WORK_DIR = Collections.unmodifiableSet(result); + } + } } diff --git a/test/jdk/tools/jpackage/share/InstallDirTest.java b/test/jdk/tools/jpackage/share/InstallDirTest.java index a53a080c33023..00d4f96031a41 100644 --- a/test/jdk/tools/jpackage/share/InstallDirTest.java +++ b/test/jdk/tools/jpackage/share/InstallDirTest.java @@ -24,10 +24,10 @@ import java.nio.file.Path; import java.util.HashMap; import java.util.Map; +import java.util.function.Supplier; import jdk.jpackage.test.TKit; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; -import jdk.jpackage.internal.util.function.FunctionalUtils; import jdk.jpackage.test.Annotations.Parameter; /** @@ -77,7 +77,7 @@ public class InstallDirTest { public static void testCommon() { - final Map INSTALL_DIRS = FunctionalUtils.identity(() -> { + final Map INSTALL_DIRS = ((Supplier>)() -> { Map reply = new HashMap<>(); reply.put(PackageType.WIN_MSI, Path.of("TestVendor\\InstallDirTest1234")); reply.put(PackageType.WIN_EXE, reply.get(PackageType.WIN_MSI)); From 2b12b28f2a247d0c7b42c48cc386977ff4bfc304 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 16 Nov 2024 01:52:40 -0500 Subject: [PATCH 0167/1101] Fix bad merge --- .../jpackage/helpers/jdk/jpackage/test/JPackageCommand.java | 1 - 1 file changed, 1 deletion(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 34b7d8856d13b..978ef7448d847 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -45,7 +45,6 @@ import java.util.stream.Collectors; import static java.util.stream.Collectors.toMap; import java.util.stream.Stream; -import jdk.jpackage.internal.util.function.FunctionalUtils; import static jdk.jpackage.test.AdditionalLauncher.forEachAdditionalLauncher; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.internal.util.function.ThrowingFunction; From 04ecb462f1802f6ee793e5e61b87fd5da2414e63 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 09:08:46 -0500 Subject: [PATCH 0168/1101] Fix bad merge --- test/jdk/tools/jpackage/share/InOutPathTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java index 66045ccec2bc1..ebca634ab7b22 100644 --- a/test/jdk/tools/jpackage/share/InOutPathTest.java +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -31,7 +31,6 @@ import java.util.function.Predicate; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.AppImageFile; From 50d3e86e3d3bb26b5aca7642201229a583e10aa7 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 09:11:02 -0500 Subject: [PATCH 0169/1101] Proper use of `Objects.requireNonNull()` --- .../jdk/jpackage/internal/LinuxDebPackageBuilder.java | 3 +-- .../classes/jdk/jpackage/internal/LinuxPackageBuilder.java | 3 +-- .../jdk/jpackage/internal/LinuxRpmPackageBuilder.java | 3 +-- .../classes/jdk/jpackage/internal/BuildEnvBuilder.java | 3 +-- .../classes/jdk/jpackage/internal/OverridableResource.java | 6 ++---- .../share/classes/jdk/jpackage/internal/PackageBuilder.java | 6 ++---- .../share/classes/jdk/jpackage/internal/PackageFile.java | 3 +-- .../jdk/jpackage/internal/cli/StandardValueConverter.java | 3 +-- .../classes/jdk/jpackage/internal/WinExePackageBuilder.java | 3 +-- .../classes/jdk/jpackage/internal/WinMsiPackageBuilder.java | 3 +-- 10 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java index 899d8874d8c10..82acacc0e83f8 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java @@ -33,8 +33,7 @@ final class LinuxDebPackageBuilder { LinuxDebPackageBuilder(LinuxPackageBuilder pkgBuilder) { - Objects.requireNonNull(pkgBuilder); - this.pkgBuilder = pkgBuilder; + this.pkgBuilder = Objects.requireNonNull(pkgBuilder); } LinuxRpmPackage create() throws ConfigException { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index 2dd26c3660f52..216a514b9d98f 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -42,8 +42,7 @@ final class LinuxPackageBuilder { LinuxPackageBuilder(PackageBuilder pkgBuilder) { - Objects.requireNonNull(pkgBuilder); - this.pkgBuilder = pkgBuilder; + this.pkgBuilder = Objects.requireNonNull(pkgBuilder); } LinuxPackage create() throws ConfigException { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java index 3d713bc727f1e..21adeead52140 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java @@ -33,8 +33,7 @@ final class LinuxRpmPackageBuilder { LinuxRpmPackageBuilder(LinuxPackageBuilder pkgBuilder) { - Objects.requireNonNull(pkgBuilder); - this.pkgBuilder = pkgBuilder; + this.pkgBuilder = Objects.requireNonNull(pkgBuilder); } LinuxRpmPackage create() throws ConfigException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java index 9836126f3d46b..2aac5f001188d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java @@ -36,8 +36,7 @@ final class BuildEnvBuilder { BuildEnvBuilder(Path root) { - Objects.requireNonNull(root); - this.root = root; + this.root = Objects.requireNonNull(root); } BuildEnv create() throws ConfigException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java index 330acbd001a61..5331696c44635 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java @@ -78,10 +78,8 @@ final class OverridableResource { OverridableResource(String defaultName, Supplier defaultResourceSupplier) { - Objects.requireNonNull(defaultName); - Objects.requireNonNull(defaultResourceSupplier); - this.defaultName = defaultName; - this.defaultResourceSupplier = defaultResourceSupplier; + this.defaultName = Objects.requireNonNull(defaultName); + this.defaultResourceSupplier = Objects.requireNonNull(defaultResourceSupplier); setSourceOrder(Source.values()); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index f26f724c54e6d..ee7c9d7d51a48 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -44,10 +44,8 @@ final class PackageBuilder { PackageBuilder(Application app, PackageType type) { - Objects.requireNonNull(app); - Objects.requireNonNull(type); - this.app = app; - this.type = type; + this.app = Objects.requireNonNull(app); + this.type = Objects.requireNonNull(type); } Package create() throws ConfigException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java index e225305c6caee..75b54d92402b5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java @@ -42,8 +42,7 @@ static Path getPathInAppImage(ApplicationLayout appLayout) { } PackageFile(String packageName) { - Objects.requireNonNull(packageName); - this.packageName = packageName; + this.packageName = Objects.requireNonNull(packageName); } void save(ApplicationLayout appLayout) throws IOException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java index 2037baf87015c..836769fcfdb71 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java @@ -35,8 +35,7 @@ final class StandardValueConverter { final static ValueConverter IDENTITY_CONV = new ValueConverter<>() { @Override public String convert(String value) { - Objects.requireNonNull(value); - return value; + return Objects.requireNonNull(value); } @Override diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java index b3b3ec46de8b3..1d66d513f85ba 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java @@ -33,8 +33,7 @@ final class WinExePackageBuilder { WinExePackageBuilder(WinMsiPackage pkg) { - Objects.requireNonNull(pkg); - this.pkg = pkg; + this.pkg = Objects.requireNonNull(pkg); } WinExePackage create() throws ConfigException { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java index 0447711c955da..f4df2fcdba5bf 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java @@ -40,8 +40,7 @@ final class WinMsiPackageBuilder { WinMsiPackageBuilder(PackageBuilder pkgBuilder) { - Objects.requireNonNull(pkgBuilder); - this.pkgBuilder = pkgBuilder; + this.pkgBuilder = Objects.requireNonNull(pkgBuilder); } WinMsiPackage create() throws ConfigException { From fd402852726af1cf697c98d49ed189bc861a64c0 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 09:12:18 -0500 Subject: [PATCH 0170/1101] Added XmlUtils.XmlConsumerNoArg --- .../classes/jdk/jpackage/internal/util/XmlUtils.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java index 0d0ad7537cf79..0aa1429e72110 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java @@ -52,6 +52,17 @@ public interface XmlConsumer { } + @FunctionalInterface + public interface XmlConsumerNoArg { + + void accept() throws IOException, XMLStreamException; + + } + + public static XmlConsumer toXmlConsumer(XmlConsumerNoArg xmlConsumer) { + return xml -> xmlConsumer.accept(); + } + public static void createXml(Path dstFile, XmlConsumer xmlConsumer) throws IOException { XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance(); From 782d0c4fb58d79d0e3ae182a8ce2348b507c05cc Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 09:13:08 -0500 Subject: [PATCH 0171/1101] Added `Application.fileAssociations()` --- .../classes/jdk/jpackage/internal/model/Application.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index 1b7a3ce9e03e1..51a1a4c9ed0e8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Stream; public interface Application { @@ -84,6 +85,10 @@ default Map extraAppImageFileData() { return Map.of(); } + default Stream fileAssociations() { + return launchers().stream().map(Launcher::fileAssociations).flatMap(List::stream); + } + record Stub(String name, String description, String version, String vendor, String copyright, Path srcDir, List contentDirs, AppImageLayout imageLayout, RuntimeBuilder runtimeBuilder, From b1266278a520e5b8ee6db1b07e4b43004dc342ca Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 10:49:09 -0500 Subject: [PATCH 0172/1101] 8344550: Compilation error of jpackage test JPackageStringBundle.java source --- .../helpers/jdk/jpackage/test/JPackageStringBundle.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageStringBundle.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageStringBundle.java index 565822d4504c0..4757f54fdfd2c 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageStringBundle.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageStringBundle.java @@ -26,6 +26,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.MessageFormat; +import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; public enum JPackageStringBundle { @@ -39,7 +40,7 @@ public enum JPackageStringBundle { i18nClass_getString = i18nClass.getDeclaredMethod("getString", String.class); i18nClass_getString.setAccessible(true); } catch (ClassNotFoundException|NoSuchMethodException ex) { - throw Functional.rethrowUnchecked(ex); + throw rethrowUnchecked(ex); } } @@ -50,7 +51,7 @@ private String getString(String key) { try { return (String)i18nClass_getString.invoke(i18nClass, key); } catch (IllegalAccessException|InvocationTargetException ex) { - throw Functional.rethrowUnchecked(ex); + throw rethrowUnchecked(ex); } } From 57a2cd6bf47c6385377b823fb931ee2f4ab9888b Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 11:46:04 -0500 Subject: [PATCH 0173/1101] Fix bad merge --- .../jpackage/helpers/jdk/jpackage/test/PackageTest.java | 4 ---- .../jpackage/helpers/jdk/jpackage/test/TestBuilder.java | 9 --------- test/jdk/tools/jpackage/share/InOutPathTest.java | 3 ++- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index 90329d2bcbfb0..07e592de310c6 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -45,10 +45,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; -<<<<<<< HEAD -======= -import jdk.jpackage.internal.ApplicationLayout; ->>>>>>> master import jdk.jpackage.internal.util.function.ThrowingBiConsumer; import static jdk.jpackage.internal.util.function.ThrowingBiConsumer.toBiConsumer; import jdk.jpackage.internal.util.function.ThrowingConsumer; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java index 6f7a81253fe35..23fd5dd52a508 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java @@ -354,14 +354,5 @@ static void trace(String msg) { private String spaceSubstitute; private boolean dryRun; - private static final Map> conv = Map.of( - boolean.class, Boolean::valueOf, - Boolean.class, Boolean::valueOf, - int.class, Integer::valueOf, - Integer.class, Integer::valueOf, - long.class, Long::valueOf, - Long.class, Long::valueOf, - String.class, String::valueOf); - static final String CMDLINE_ARG_PREFIX = "--jpt-"; } diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java index 8e058e2177c17..6b1b0edaa9380 100644 --- a/test/jdk/tools/jpackage/share/InOutPathTest.java +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -30,11 +30,12 @@ import java.util.Set; import java.util.function.Predicate; import java.util.stream.Stream; +import jdk.internal.util.OperatingSystem; import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.ApplicationLayout; import jdk.jpackage.test.PackageFile; -import jdk.jpackage.test.Annotations; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageCommand.AppLayoutAssert; From aac1973db683aca73af90137365ba38305ddb413 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 17 Nov 2024 10:23:34 -0500 Subject: [PATCH 0174/1101] Revert "Get rid of FunctionalUtils.java". Brings back Functional.java to make the diff easier to digest. It will be replaced with redoing c58b6587b3b4fb9c08afd27eacf139e0ed9afb83 commit in the next PR. This reverts commit c58b6587b3b4fb9c08afd27eacf139e0ed9afb83. --- .../helpers/jdk/jpackage/test/HelloApp.java | 4 +- .../jdk/jpackage/test/JPackageCommand.java | 33 ++++++++++----- .../jdk/jpackage/test/JavaAppDesc.java | 9 ++-- .../jdk/jpackage/test/PackageTest.java | 2 +- .../helpers/jdk/jpackage/test/TKit.java | 42 +++++++++++-------- .../jdk/jpackage/test/TestInstance.java | 37 +++++++--------- 6 files changed, 68 insertions(+), 59 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java index a57b0d957c83d..2cbd6e7a546bb 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java @@ -88,11 +88,11 @@ private JarBuilder prepareSources(Path srcDir) throws IOException { AtomicBoolean classDeclared = new AtomicBoolean(); AtomicBoolean packageInserted = new AtomicBoolean(packageName == null); - Function packageInserter = line -> { + var packageInserter = Functional.identityFunction((line) -> { packageInserted.setPlain(true); return String.format("package %s;%s%s", packageName, System.lineSeparator(), line); - }; + }); Files.write(srcFile, Files.readAllLines(appDesc.srcJavaPath()).stream().map(line -> { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 2f33ced84f362..a149a996f1135 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -30,6 +30,7 @@ import java.security.SecureRandom; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; @@ -43,7 +44,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import static java.util.stream.Collectors.toMap; import java.util.stream.Stream; import static jdk.jpackage.test.AdditionalLauncher.forEachAdditionalLauncher; import jdk.jpackage.internal.util.function.ThrowingConsumer; @@ -1172,16 +1172,27 @@ public void run() { private Consumer> outputValidator; private static boolean defaultWithToolProvider; - private static final Map PACKAGE_TYPES = Stream.of( - PackageType.values()).collect(toMap(PackageType::getName, x -> x)); - - // Set the property to the path of run-time image to speed up - // building app images and platform bundles by avoiding running jlink - // The value of the property will be automativcally appended to - // jpackage command line if the command line doesn't have - // `--runtime-image` parameter set. - public static final Path DEFAULT_RUNTIME_IMAGE = Optional.ofNullable( - TKit.getConfigProperty("runtime-image")).map(Path::of).orElse(null); + private static final Map PACKAGE_TYPES = Functional.identity( + () -> { + Map reply = new HashMap<>(); + for (PackageType type : PackageType.values()) { + reply.put(type.getName(), type); + } + return reply; + }).get(); + + public static final Path DEFAULT_RUNTIME_IMAGE = Functional.identity(() -> { + // Set the property to the path of run-time image to speed up + // building app images and platform bundles by avoiding running jlink + // The value of the property will be automativcally appended to + // jpackage command line if the command line doesn't have + // `--runtime-image` parameter set. + String val = TKit.getConfigProperty("runtime-image"); + if (val != null) { + return Path.of(val); + } + return null; + }).get(); private static final String UNPACKED_PATH_ARGNAME = "jpt-unpacked-folder"; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java index 1651a36045d90..3cc2458ce2acc 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java @@ -24,7 +24,6 @@ import java.nio.file.Path; import java.util.Objects; -import java.util.function.Supplier; import java.util.stream.Stream; @@ -238,7 +237,7 @@ public static JavaAppDesc parse(final String javaAppDesc) { return desc; } - String srcJavaPathAndOther = ((Supplier)() -> { + String srcJavaPathAndOther = Functional.identity(() -> { String[] components = javaAppDesc.split("\\*", 2); if (components.length == 2) { desc.setSrcJavaPath(Path.of(components[0])); @@ -246,7 +245,7 @@ public static JavaAppDesc parse(final String javaAppDesc) { return components[components.length - 1]; }).get(); - String moduleNameAndOther = ((Supplier)() -> { + String moduleNameAndOther = Functional.identity(() -> { String[] components = srcJavaPathAndOther.split(":", 2); if (components.length == 2) { desc.setBundleFileName(components[0]); @@ -254,7 +253,7 @@ public static JavaAppDesc parse(final String javaAppDesc) { return components[components.length - 1]; }).get(); - String classNameAndOther = ((Supplier)() -> { + String classNameAndOther = Functional.identity(() -> { String[] components = moduleNameAndOther.split("/", 2); if (components.length == 2) { desc.setModuleName(components[0]); @@ -262,7 +261,7 @@ public static JavaAppDesc parse(final String javaAppDesc) { return components[components.length - 1]; }).get(); - ((Runnable)() -> { + Functional.identity(() -> { String[] components = classNameAndOther.split("@", 2); if (components[0].endsWith("!")) { components[0] = components[0].substring(0, diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index 07e592de310c6..fd6d5e2da6bc7 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -531,7 +531,7 @@ private void handleAction(Action action, T handler, private Path unpackDir; private Action unhandledAction; private boolean terminated; - private final JPackageCommand cmd = ((Supplier)() -> { + private final JPackageCommand cmd = Functional.identity(() -> { JPackageCommand result = new JPackageCommand(); result.setDefaultInputOutput().setDefaultAppName(); if (BUNDLE_OUTPUT_DIR != null && !ignoreBundleOutputDir) { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index 76f2d614a4000..b58595645682c 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -68,7 +68,7 @@ public final class TKit { - public static final Path TEST_SRC_ROOT = ((Supplier)() -> { + public static final Path TEST_SRC_ROOT = Functional.identity(() -> { Path root = Path.of(System.getProperty("test.src")); for (int i = 0; i != 10; ++i) { @@ -81,22 +81,25 @@ public final class TKit { throw new RuntimeException("Failed to locate apps directory"); }).get(); - public static final Path SRC_ROOT = TEST_SRC_ROOT.resolve( - "../../../../src/jdk.jpackage").normalize().toAbsolutePath(); - - public static final String ICON_SUFFIX; + public static final Path SRC_ROOT = Functional.identity(() -> { + return TEST_SRC_ROOT.resolve("../../../../src/jdk.jpackage").normalize().toAbsolutePath(); + }).get(); - static { + public static final String ICON_SUFFIX = Functional.identity(() -> { if (isOSX()) { - ICON_SUFFIX = ".icns"; - } else if (isLinux()) { - ICON_SUFFIX = ".png"; - } else if (isWindows()) { - ICON_SUFFIX = ".ico"; - } else { - throw throwUnknownPlatformError(); + return ".icns"; } - } + + if (isLinux()) { + return ".png"; + } + + if (isWindows()) { + return ".ico"; + } + + throw throwUnknownPlatformError(); + }).get(); static void withExtraLogStream(ThrowingRunnable action) { if (extraLogStream != null) { @@ -851,7 +854,7 @@ public static void assertStringListEquals(List expected, traceAssert(concatMessages("assertStringListEquals()", msg)); - String idxFieldFormat = ((Supplier)() -> { + String idxFieldFormat = Functional.identity(() -> { int listSize = expected.size(); int width = 0; while (listSize != 0) { @@ -1065,8 +1068,13 @@ static Set tokenizeConfigProperty(String propertyName) { return tokens.stream().collect(Collectors.toSet()); } - static final Path LOG_FILE = Optional.ofNullable( - getConfigProperty("logfile")).map(Path::of).orElse(null); + static final Path LOG_FILE = Functional.identity(() -> { + String val = getConfigProperty("logfile"); + if (val == null) { + return null; + } + return Path.of(val); + }).get(); static { Set logOptions = tokenizeConfigProperty("suppress-logging"); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java index 871ddc2427784..d27863dabcffc 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java @@ -32,10 +32,8 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -53,7 +51,7 @@ private TestDesc() { String testFullName() { StringBuilder sb = new StringBuilder(); - sb.append(clazz.getName()); + sb.append(clazz.getSimpleName()); if (instanceArgs != null) { sb.append('(').append(instanceArgs).append(')'); } @@ -81,12 +79,12 @@ Builder method(Method v) { } Builder ctorArgs(Object... v) { - ctorArgs = Arrays.asList(v); + ctorArgs = ofNullable(v); return this; } Builder methodArgs(Object... v) { - methodArgs = Arrays.asList(v); + methodArgs = ofNullable(v); return this; } @@ -110,18 +108,22 @@ private static String formatArgs(List values) { } return values.stream().map(v -> { if (v != null && v.getClass().isArray()) { - String asString; - if (v.getClass().getComponentType().isPrimitive()) { - asString = PRIMITIVE_ARRAY_FORMATTERS.get(v.getClass()).apply(v); - } else { - asString = Arrays.deepToString((Object[]) v); - } - return String.format("%s(length=%d)", asString, Array.getLength(v)); + return String.format("%s(length=%d)", + Arrays.deepToString((Object[]) v), + Array.getLength(v)); } return String.format("%s", v); }).collect(Collectors.joining(", ")); } + private static List ofNullable(Object... values) { + List result = new ArrayList(); + for (var v: values) { + result.add(v); + } + return result; + } + private List ctorArgs; private List methodArgs; private Method method; @@ -354,15 +356,4 @@ public String toString() { return Collections.unmodifiableSet(result); }).get(); - private static final Map, Function> PRIMITIVE_ARRAY_FORMATTERS = Map.of( - boolean[].class, v -> Arrays.toString((boolean[])v), - byte[].class, v -> Arrays.toString((byte[])v), - char[].class, v -> Arrays.toString((char[])v), - short[].class, v -> Arrays.toString((short[])v), - int[].class, v -> Arrays.toString((int[])v), - long[].class, v -> Arrays.toString((long[])v), - float[].class, v -> Arrays.toString((float[])v), - double[].class, v -> Arrays.toString((double[])v) - ); - } From 63454833c7a4edee67b808bd27a444c905d2b710 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 11:54:07 -0500 Subject: [PATCH 0175/1101] Make AppImageFile and PackageFile classes package-private --- .../share/classes/jdk/jpackage/internal/AppImageFile.java | 2 +- .../share/classes/jdk/jpackage/internal/PackageFile.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index 256d292350af4..a8032979bb2c9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -61,7 +61,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; import jdk.jpackage.internal.util.XmlUtils; -public final class AppImageFile { +final class AppImageFile { // These values will be loaded from AppImage xml file. private final String appVersion; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java index 87935a9287c39..e8bc0cb665538 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java @@ -31,7 +31,7 @@ import java.util.Objects; import java.util.Optional; -public final class PackageFile { +final class PackageFile { /** * Returns path to package file. From fa0ba3e1a2a1ef4062151f72c0636ea7cb9e7436 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 12:02:10 -0500 Subject: [PATCH 0176/1101] Bad merge fix --- .../helpers/jdk/jpackage/test/HelloApp.java | 1 - .../jdk/jpackage/test/TestInstance.java | 37 ++++++++++++------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java index 2cbd6e7a546bb..bc35912bcbb6c 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java @@ -33,7 +33,6 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.regex.Matcher; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java index d27863dabcffc..871ddc2427784 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java @@ -32,8 +32,10 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -51,7 +53,7 @@ private TestDesc() { String testFullName() { StringBuilder sb = new StringBuilder(); - sb.append(clazz.getSimpleName()); + sb.append(clazz.getName()); if (instanceArgs != null) { sb.append('(').append(instanceArgs).append(')'); } @@ -79,12 +81,12 @@ Builder method(Method v) { } Builder ctorArgs(Object... v) { - ctorArgs = ofNullable(v); + ctorArgs = Arrays.asList(v); return this; } Builder methodArgs(Object... v) { - methodArgs = ofNullable(v); + methodArgs = Arrays.asList(v); return this; } @@ -108,22 +110,18 @@ private static String formatArgs(List values) { } return values.stream().map(v -> { if (v != null && v.getClass().isArray()) { - return String.format("%s(length=%d)", - Arrays.deepToString((Object[]) v), - Array.getLength(v)); + String asString; + if (v.getClass().getComponentType().isPrimitive()) { + asString = PRIMITIVE_ARRAY_FORMATTERS.get(v.getClass()).apply(v); + } else { + asString = Arrays.deepToString((Object[]) v); + } + return String.format("%s(length=%d)", asString, Array.getLength(v)); } return String.format("%s", v); }).collect(Collectors.joining(", ")); } - private static List ofNullable(Object... values) { - List result = new ArrayList(); - for (var v: values) { - result.add(v); - } - return result; - } - private List ctorArgs; private List methodArgs; private Method method; @@ -356,4 +354,15 @@ public String toString() { return Collections.unmodifiableSet(result); }).get(); + private static final Map, Function> PRIMITIVE_ARRAY_FORMATTERS = Map.of( + boolean[].class, v -> Arrays.toString((boolean[])v), + byte[].class, v -> Arrays.toString((byte[])v), + char[].class, v -> Arrays.toString((char[])v), + short[].class, v -> Arrays.toString((short[])v), + int[].class, v -> Arrays.toString((int[])v), + long[].class, v -> Arrays.toString((long[])v), + float[].class, v -> Arrays.toString((float[])v), + double[].class, v -> Arrays.toString((double[])v) + ); + } From f91b850d12ab19fb461552f75846e91cfa66bbb7 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 12:05:45 -0500 Subject: [PATCH 0177/1101] Bad merge fix --- test/jdk/tools/jpackage/share/InOutPathTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java index 6b1b0edaa9380..46da5e9939b00 100644 --- a/test/jdk/tools/jpackage/share/InOutPathTest.java +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -34,8 +34,8 @@ import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.ApplicationLayout; import jdk.jpackage.test.PackageFile; -import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Annotations.Parameters; +import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageCommand.AppLayoutAssert; From 4cd607fab7ccafe4b69982104d450809c29d9059 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 12:27:37 -0500 Subject: [PATCH 0178/1101] ExceptionWrapper -> ExceptionBox to simplify merge with master --- .../share/classes/jdk/jpackage/internal/Arguments.java | 4 ++-- .../classes/jdk/jpackage/internal/LauncherBuilder.java | 6 +++--- .../classes/jdk/jpackage/internal/util/FileUtils.java | 4 ++-- .../{ExceptionWrapper.java => ExceptionBox.java} | 10 +++++----- .../internal/util/function/ThrowingBiConsumer.java | 2 +- .../internal/util/function/ThrowingBiFunction.java | 2 +- .../internal/util/function/ThrowingConsumer.java | 2 +- .../internal/util/function/ThrowingFunction.java | 2 +- .../internal/util/function/ThrowingRunnable.java | 2 +- .../internal/util/function/ThrowingSupplier.java | 2 +- .../internal/util/function/ThrowingUnaryOperator.java | 2 +- 11 files changed, 19 insertions(+), 19 deletions(-) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/{ExceptionWrapper.java => ExceptionBox.java} (85%) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java index e682f9c56e5bb..8347e70367234 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java @@ -44,7 +44,7 @@ import java.util.ResourceBundle; import java.util.regex.Matcher; import java.util.regex.Pattern; -import jdk.jpackage.internal.util.function.ExceptionWrapper; +import jdk.jpackage.internal.util.function.ExceptionBox; /** * Arguments @@ -719,7 +719,7 @@ private void generateBundle(Map params) Log.verbose(MessageFormat.format( I18N.getString("message.bundle-created"), bundler.getName())); - } catch (ExceptionWrapper ex) { + } catch (ExceptionBox ex) { if (ex.getCause() instanceof ConfigException cfgEx) { throw cfgEx; } else if (ex.getCause() instanceof PackagerException pkgEx) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java index 33adbab507d5b..701363f02f6ad 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java @@ -42,8 +42,8 @@ import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.Launcher.Stub; import jdk.jpackage.internal.model.LauncherStartupInfo; -import jdk.jpackage.internal.util.function.ExceptionWrapper; -import static jdk.jpackage.internal.util.function.ExceptionWrapper.rethrowUnchecked; +import jdk.jpackage.internal.util.function.ExceptionBox; +import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import static jdk.jpackage.internal.model.ConfigException.rethrowConfigException; @@ -139,7 +139,7 @@ private Stream createFileAssociations( } else { return Map.entry(entry.getKey(), faGroup); } - } catch (ExceptionWrapper ex) { + } catch (ExceptionBox ex) { if (ex.getCause() instanceof ConfigException cfgException) { throw rethrowUnchecked(buildConfigException() .cause(cfgException.getCause()) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java index 7358981e940b6..bb36cd5792dfc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java @@ -34,7 +34,7 @@ import java.util.ArrayList; import java.util.List; import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.util.function.ExceptionWrapper; +import jdk.jpackage.internal.util.function.ExceptionBox; import jdk.jpackage.internal.util.function.ThrowingConsumer; public final class FileUtils { @@ -146,7 +146,7 @@ private void runActionOnPath(ThrowingConsumer action, Path path) { this.ex = ex; } } catch (Throwable t) { - throw ExceptionWrapper.rethrowUnchecked(t); + throw ExceptionBox.rethrowUnchecked(t); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionWrapper.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionBox.java similarity index 85% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionWrapper.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionBox.java index ea8afdc6133a8..870e17ba99f39 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionWrapper.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionBox.java @@ -24,22 +24,22 @@ import java.lang.reflect.InvocationTargetException; -public class ExceptionWrapper extends RuntimeException { +public class ExceptionBox extends RuntimeException { private static final long serialVersionUID = 1L; public static RuntimeException rethrowUnchecked(Throwable throwable) throws - ExceptionWrapper { + ExceptionBox { if (throwable instanceof RuntimeException runtimeThrowable) { throw runtimeThrowable; } if (throwable instanceof InvocationTargetException) { - throw new ExceptionWrapper(throwable.getCause()); + throw new ExceptionBox(throwable.getCause()); } - throw new ExceptionWrapper(throwable); + throw new ExceptionBox(throwable); } - private ExceptionWrapper(Throwable throwable) { + private ExceptionBox(Throwable throwable) { super(throwable); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiConsumer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiConsumer.java index dd6e38faa2652..8be116e13afe3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiConsumer.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiConsumer.java @@ -35,7 +35,7 @@ public static BiConsumer toBiConsumer( try { v.accept(t, u); } catch (Throwable ex) { - throw ExceptionWrapper.rethrowUnchecked(ex); + throw ExceptionBox.rethrowUnchecked(ex); } }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java index 7517981268860..a8119f25bdb76 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java @@ -35,7 +35,7 @@ public static BiFunction toBiFunction( try { return v.apply(t, u); } catch (Throwable ex) { - throw ExceptionWrapper.rethrowUnchecked(ex); + throw ExceptionBox.rethrowUnchecked(ex); } }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java index 7efff50990159..5ca33c22d9232 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java @@ -34,7 +34,7 @@ public static Consumer toConsumer(ThrowingConsumer v) { try { v.accept(o); } catch (Throwable ex) { - throw ExceptionWrapper.rethrowUnchecked(ex); + throw ExceptionBox.rethrowUnchecked(ex); } }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java index d78f5df079011..22e43548f4df6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java @@ -34,7 +34,7 @@ public static Function toFunction(ThrowingFunction v) { try { return v.apply(t); } catch (Throwable ex) { - throw ExceptionWrapper.rethrowUnchecked(ex); + throw ExceptionBox.rethrowUnchecked(ex); } }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java index b58b351305e6a..7f3fcda536ced 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java @@ -32,7 +32,7 @@ public static Runnable toRunnable(ThrowingRunnable v) { try { v.run(); } catch (Throwable ex) { - throw ExceptionWrapper.rethrowUnchecked(ex); + throw ExceptionBox.rethrowUnchecked(ex); } }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java index f02fec3078a2a..2f5ef135875a9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java @@ -34,7 +34,7 @@ public static Supplier toSupplier(ThrowingSupplier v) { try { return v.get(); } catch (Throwable ex) { - throw ExceptionWrapper.rethrowUnchecked(ex); + throw ExceptionBox.rethrowUnchecked(ex); } }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java index 7a08722816240..27a3e2f30f5ab 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java @@ -35,7 +35,7 @@ public static UnaryOperator toUnaryOperator( try { return v.apply(t); } catch (Throwable ex) { - throw ExceptionWrapper.rethrowUnchecked(ex); + throw ExceptionBox.rethrowUnchecked(ex); } }; } From 090e62b5dfd1ae2e5dc8d4ba06a403e898912f22 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 12:38:58 -0500 Subject: [PATCH 0179/1101] Redundant Stream.map() call removed --- .../classes/jdk/jpackage/internal/FileAssociationGroup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java index 6eedeab6bed31..90f1ea899c880 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java @@ -79,7 +79,7 @@ FileAssociationGroup create() { if (extensions.isEmpty()) { faStream = forExtension.apply(null); } else { - faStream = extensions.stream().map(forExtension).flatMap(x -> x); + faStream = extensions.stream().flatMap(forExtension); } return new FileAssociationGroup(faStream.toList()); From ab7c57ca5656d71664170150bb5f0ec36aea4a18 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 12:58:52 -0500 Subject: [PATCH 0180/1101] Make AppImageBuilder more configurable and suitable for use on Mac --- .../internal/LinuxAppImageBuilder.java | 45 ++-- .../jpackage/internal/AppImageBuilder.java | 193 +++++++++++------- .../jpackage/internal/WinAppImageBuilder.java | 30 +-- 3 files changed, 154 insertions(+), 114 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index 1617f920adbe1..5c873f9c3c3d9 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -24,41 +24,42 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.Application; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import jdk.jpackage.internal.AppImageBuilder.AppImageItemGroup; +import static jdk.jpackage.internal.AppImageBuilder.createLauncherIconResource; +import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.resources.ResourceLocator; final class LinuxAppImageBuilder { static AppImageBuilder.Builder build() { - return new AppImageBuilder.Builder().launcherCallback(new LauncherCallbackImpl()); + return new AppImageBuilder.Builder() + .itemGroup(AppImageItemGroup.LAUNCHERS) + .addItem(LinuxAppImageBuilder::writeLauncherLib) + .addItem(LinuxAppImageBuilder::writeLauncherIcons); } - private final static class LauncherCallbackImpl implements AppImageBuilder.LauncherCallback { - - @Override - public void onLauncher(Application app, - AppImageBuilder.LauncherContext ctx) throws IOException, PackagerException { - if (ctx.launcher() == app.mainLauncher()) { - var launcherLib = ((LinuxApplicationLayout)ctx.resolvedAppLayout()).libAppLauncher(); - try (var in = ResourceLocator.class.getResourceAsStream("libjpackageapplauncheraux.so")) { - Files.createDirectories(launcherLib.getParent()); - Files.copy(in, launcherLib); - } - } - AppImageBuilder.LauncherCallback.super.onLauncher(app, ctx); + private static void writeLauncherLib(BuildEnv env, Application app, + ApplicationLayout appLayout) throws IOException { + var launcherLib = ((LinuxApplicationLayout)appLayout).libAppLauncher(); + try (var in = ResourceLocator.class.getResourceAsStream("libjpackageapplauncheraux.so")) { + Files.createDirectories(launcherLib.getParent()); + Files.copy(in, launcherLib); } + } - @Override - public void onLauncher(Application app, - AppImageBuilder.LauncherContext ctx, - OverridableResource launcherIcon) throws IOException, PackagerException { - String iconFileName = ctx.launcher().executableName() + ".png"; - Path iconTarget = ctx.resolvedAppLayout().destktopIntegrationDirectory().resolve(iconFileName); - launcherIcon.saveToFile(iconTarget); + private static void writeLauncherIcons(BuildEnv env, Application app, + ApplicationLayout appLayout) throws IOException { + for (var launcher : app.launchers()) { + var iconResource = createLauncherIconResource(app, launcher, env::createResource); + if (iconResource != null) { + String iconFileName = launcher.executableName() + ".png"; + Path iconTarget = appLayout.destktopIntegrationDirectory().resolve(iconFileName); + iconResource.saveToFile(iconTarget); + } } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java index 8fb2cfc484d1b..0e1c8ff055bfe 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -34,7 +34,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.function.Function; @@ -48,8 +50,19 @@ final class AppImageBuilder { static final class Builder { - Builder launcherCallback(LauncherCallback v) { - launcherCallback = v; + Builder addItem(AppImageItem v) { + Objects.requireNonNull(v); + Optional.ofNullable(customAppImageItemGroups.get(curGroup)).orElseGet(() -> { + List items = new ArrayList<>(); + customAppImageItemGroups.put(curGroup, items); + return items; + }).add(v); + return this; + } + + Builder itemGroup(AppImageItemGroup v) { + Objects.requireNonNull(v); + curGroup = v; return this; } @@ -64,43 +77,77 @@ Builder excludeDirFromCopying(Path path) { } AppImageBuilder create(Application app) { - return new AppImageBuilder(app, excludeCopyDirs, launcherCallback); + return new AppImageBuilder(app, excludeCopyDirs, customAppImageItemGroups); } AppImageBuilder create(Package pkg) { - return new AppImageBuilder(pkg, excludeCopyDirs, launcherCallback); + return new AppImageBuilder(pkg, excludeCopyDirs, customAppImageItemGroups); } private List excludeCopyDirs; - private LauncherCallback launcherCallback; + private AppImageItemGroup curGroup = AppImageItemGroup.END; + private Map> customAppImageItemGroups = new HashMap<>(); } static Builder build() { return new Builder(); } + enum AppImageItemGroup { + BEGIN, + RUNTIME, + CONTENT, + LAUNCHERS, + APP_IMAGE_FILE, + END + } + + @FunctionalInterface + interface AppImageItem { + void write(BuildEnv env, Application app, ApplicationLayout appLayout) throws IOException, PackagerException; + } + private AppImageBuilder(Application app, ApplicationLayout appLayout, - List excludeCopyDirs, LauncherCallback launcherCallback, - boolean withAppImageFile) { - Objects.requireNonNull(app); - Objects.requireNonNull(appLayout); - - this.app = app; - this.appLayout = appLayout; - this.withAppImageFile = withAppImageFile; - this.launcherCallback = launcherCallback; - this.excludeCopyDirs = Optional.ofNullable(excludeCopyDirs).orElseGet(List::of); + List excludeCopyDirs, boolean withAppImageFile, + Map> customAppImageItemGroups) { + this.app = Objects.requireNonNull(app); + this.appLayout = Objects.requireNonNull(appLayout); + + appImageItemGroups = new HashMap<>(); + appImageItemGroups.put(AppImageItemGroup.RUNTIME, List.of( + createRuntimeAppImageItem())); + appImageItemGroups.put(AppImageItemGroup.CONTENT, List.of( + createContentAppImageItem( + Optional.ofNullable(excludeCopyDirs).orElseGet(List::of)))); + appImageItemGroups.put(AppImageItemGroup.LAUNCHERS, List.of( + createLaunchersAppImageItem())); + if (withAppImageFile) { + appImageItemGroups.put(AppImageItemGroup.APP_IMAGE_FILE, List.of( + createAppImageFileAppImageItem())); + } + + for (var e : customAppImageItemGroups.entrySet()) { + var group = e.getKey(); + var mutableItems = Optional.ofNullable(appImageItemGroups.get(group)).map(items -> { + return new ArrayList<>(items); + }).orElseGet(() -> { + return new ArrayList<>(); + }); + mutableItems.addAll(e.getValue()); + appImageItemGroups.put(group, mutableItems); + } } private AppImageBuilder(Application app, List excludeCopyDirs, - LauncherCallback launcherCallback) { - this(app, app.asApplicationLayout(), excludeCopyDirs, launcherCallback, true); + Map> customAppImageItemGroups) { + this(app, app.asApplicationLayout(), excludeCopyDirs, true, + customAppImageItemGroups); } private AppImageBuilder(Package pkg, List excludeCopyDirs, - LauncherCallback launcherCallback) { - this(pkg.app(), pkg.asPackageApplicationLayout(), excludeCopyDirs, - launcherCallback, false); + Map> customAppImageItemGroups) { + this(pkg.app(), pkg.asPackageApplicationLayout(), excludeCopyDirs, false, + customAppImageItemGroups); } private static void copyRecursive(Path srcDir, Path dstDir, @@ -122,49 +169,10 @@ private static void copyRecursive(Path srcDir, Path dstDir, void execute(BuildEnv env) throws IOException, PackagerException { var resolvedAppLayout = appLayout.resolveAt(env.appImageDir()); - - app.runtimeBuilder().createRuntime(resolvedAppLayout); - if (app.isRuntime()) { - return; - } - - var excludeCandidates = Stream.concat( - excludeCopyDirs.stream(), - Stream.of(env.buildRoot(), env.appImageDir()) - ).map(Path::toAbsolutePath).toList(); - - if (app.srcDir() != null) { - copyRecursive(app.srcDir(), resolvedAppLayout.appDirectory(), excludeCandidates); - } - - for (var srcDir : Optional.ofNullable(app.contentDirs()).orElseGet(List::of)) { - copyRecursive(srcDir, - resolvedAppLayout.contentDirectory().resolve(srcDir.getFileName()), - excludeCandidates); - } - - if (withAppImageFile) { - new AppImageFile2(app).save(resolvedAppLayout); - } - - for (var launcher : app.launchers()) { - // Create corresponding .cfg file - new CfgFile(app, launcher).create(appLayout, resolvedAppLayout); - - // Copy executable to launchers folder - Path executableFile = resolvedAppLayout.launchersDirectory().resolve( - launcher.executableNameWithSuffix()); - try (var in = launcher.executableResource()) { - Files.createDirectories(executableFile.getParent()); - Files.copy(in, executableFile); + for (var group : AppImageItemGroup.values()) { + for (var appImageItem : Optional.ofNullable(appImageItemGroups.get(group)).orElseGet(List::of)) { + appImageItem.write(env, app, resolvedAppLayout); } - - if (launcherCallback != null) { - launcherCallback.onLauncher(app, new LauncherContext(launcher, - env, resolvedAppLayout, executableFile)); - } - - executableFile.toFile().setExecutable(true); } } @@ -200,23 +208,54 @@ static OverridableResource createLauncherIconResource(Application app, return resource; } - static interface LauncherCallback { - default public void onLauncher(Application app, LauncherContext ctx) - throws IOException, PackagerException { - var iconResource = createLauncherIconResource(app, ctx.launcher, - ctx.env::createResource); - if (iconResource != null) { - onLauncher(app, ctx, iconResource); + private static AppImageItem createRuntimeAppImageItem() { + return (env, app, appLayout) -> { + app.runtimeBuilder().createRuntime(appLayout); + }; + } + + private static AppImageItem createAppImageFileAppImageItem() { + return (env, app, appLayout) -> { + new AppImageFile2(app).save(appLayout); + }; + } + + private static AppImageItem createContentAppImageItem(List excludeCopyDirs) { + return (env, app, appLayout) -> { + var excludeCandidates = Stream.concat( + excludeCopyDirs.stream(), + Stream.of(env.buildRoot(), env.appImageDir()) + ).map(Path::toAbsolutePath).toList(); + + if (app.srcDir() != null) { + copyRecursive(app.srcDir(), appLayout.appDirectory(), excludeCandidates); } - } - default public void onLauncher(Application app, LauncherContext ctx, - OverridableResource launcherIcon) throws IOException, PackagerException { - } + for (var srcDir : Optional.ofNullable(app.contentDirs()).orElseGet(List::of)) { + copyRecursive(srcDir, + appLayout.contentDirectory().resolve(srcDir.getFileName()), + excludeCandidates); + } + }; } - static record LauncherContext(Launcher launcher, BuildEnv env, - ApplicationLayout resolvedAppLayout, Path launcherExecutable) { + private static AppImageItem createLaunchersAppImageItem() { + return (env, app, appLayout) -> { + for (var launcher : app.launchers()) { + // Create corresponding .cfg file + new CfgFile(app, launcher).create(appLayout, appLayout); + + // Copy executable to launchers folder + Path executableFile = appLayout.launchersDirectory().resolve( + launcher.executableNameWithSuffix()); + try (var in = launcher.executableResource()) { + Files.createDirectories(executableFile.getParent()); + Files.copy(in, executableFile); + } + + executableFile.toFile().setExecutable(true); + } + }; } private enum IconType { @@ -233,9 +272,7 @@ public static IconType getLauncherIconType(Path iconPath) { } } - private final boolean withAppImageFile; private final Application app; private final ApplicationLayout appLayout; - private final List excludeCopyDirs; - private final LauncherCallback launcherCallback; + private final Map> appImageItemGroups; } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java index 814820b61ed59..81992229a2b19 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java @@ -30,37 +30,39 @@ import jdk.jpackage.internal.model.WinApplication; import java.io.IOException; import java.nio.file.Path; +import jdk.jpackage.internal.AppImageBuilder.AppImageItemGroup; import static jdk.jpackage.internal.AppImageBuilder.createLauncherIconResource; import jdk.jpackage.internal.model.ApplicationLayout; final class WinAppImageBuilder { static AppImageBuilder.Builder build() { - return new AppImageBuilder.Builder().launcherCallback(new LauncherCallbackImpl()); + return new AppImageBuilder.Builder() + .itemGroup(AppImageItemGroup.LAUNCHERS) + .addItem(WinAppImageBuilder::rebrandLaunchers); } - private final static class LauncherCallbackImpl implements - AppImageBuilder.LauncherCallback { - - @Override - public void onLauncher(Application app, - AppImageBuilder.LauncherContext ctx) throws IOException, PackagerException { + private static void rebrandLaunchers(BuildEnv env, Application app, + ApplicationLayout appLayout) throws IOException, PackagerException { + for (var launcher : app.launchers()) { Path iconTarget = null; - var iconResource = createLauncherIconResource(app, ctx.launcher(), - name -> ctx.env().createResource(name)); + var iconResource = createLauncherIconResource(app, launcher, + name -> env.createResource(name)); if (iconResource != null) { - var iconDir = ctx.env().buildRoot().resolve("icons"); - iconTarget = iconDir.resolve(ctx.launcher().executableName() + ".ico"); + var iconDir = env.buildRoot().resolve("icons"); + iconTarget = iconDir.resolve(launcher.executableName() + ".ico"); if (null == iconResource.saveToFile(iconTarget)) { iconTarget = null; } } + var launcherExecutable = appLayout.launchersDirectory().resolve( + launcher.executableNameWithSuffix()); + // Update branding of launcher executable new ExecutableRebrander((WinApplication) app, - (WinLauncher) ctx.launcher(), - name -> ctx.env().createResource(name)).execute( - ctx.env(), ctx.launcherExecutable(), iconTarget); + (WinLauncher) launcher, name -> env.createResource(name)).execute( + env, launcherExecutable, iconTarget); } } From fb9bd870f90ac233294bf14a538a780dfa450c2a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 12:59:44 -0500 Subject: [PATCH 0181/1101] First iteration of Mac app image building and signing decoupled from "params" --- .../jdk/jpackage/internal/AppImageSigner.java | 167 +++++++++++++ .../jdk/jpackage/internal/Codesign.java | 151 ++++++++++++ .../internal/MacAppImageBuilder2.java | 230 ++++++++++++++++++ .../jdk/jpackage/internal/PListUtils.java | 109 +++++++++ .../jdk/jpackage/internal/SigningConfig.java | 99 ++++++++ .../internal/model/MacApplication.java | 22 +- .../internal/model/MacApplicationMixin.java | 50 ++++ .../internal/model/MacFileAssociation.java | 34 +++ .../model/MacFileAssociationMixin.java | 59 +++++ 9 files changed, 917 insertions(+), 4 deletions(-) create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Codesign.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/PListUtils.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfig.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociation.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociationMixin.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java new file mode 100644 index 0000000000000..534e9bc3aa88d --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermission; +import java.util.EnumSet; +import java.util.Set; +import java.util.function.Consumer; +import static java.util.stream.Collectors.toSet; +import jdk.jpackage.internal.Codesign.CodesignException; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.util.function.ExceptionBox; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; + + +final class AppImageSigner { + + static Consumer createSigner(Application app, SigningConfig signingCfg) { + return toConsumer(appImage -> { + try { + new AppImageSigner(app, signingCfg).accept(appImage); + } catch (CodesignException ex) { + throw Codesign.handleCodesignException(app, ex); + } catch (ExceptionBox ex) { + if (ex.getCause() instanceof CodesignException codesignEx) { + Codesign.handleCodesignException(app, codesignEx); + } + throw ex; + } + }); + } + + static Consumer createUnsigner(Application app) { + return toConsumer(new AppImageSigner(app)::accept); + } + + void accept(Path appImage) throws IOException, CodesignException { + var appLayout = ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT.resolveAt(appImage); + + try (var content = Files.walk(appImage)) { + var launchersDir = appLayout.launchersDirectory(); + content.filter(path -> { + return testDoSign(launchersDir, path); + }).forEachOrdered(toConsumer(path -> { + final var origPerms = ensureCanWrite(path); + try { + unsign(path); + sign(path); + } finally { + if (origPerms != null) { + Files.setPosixFilePermissions(path, origPerms); + } + } + })); + } + + codesignDir.accept(appLayout.runtimeDirectory()); + + var frameworkPath = appImage.resolve("Contents/Frameworks"); + if (Files.isDirectory(frameworkPath)) { + try (var content = Files.list(frameworkPath)) { + content.forEach(toConsumer(path -> { + codesignDir.accept(path); + })); + } + } + + // sign the app itself + codesignDir.accept(appImage); + } + + private static Set ensureCanWrite(Path path) throws IOException { + final var origPerms = Files.getPosixFilePermissions(path); + if (origPerms.contains(PosixFilePermission.OWNER_WRITE)) { + return null; + } else { + var pfp = EnumSet.copyOf(origPerms); + pfp.add(PosixFilePermission.OWNER_WRITE); + Files.setPosixFilePermissions(path, pfp); + return origPerms; + } + } + + private boolean testDoSign(Path launchersDir, Path path) { + if (!Files.isRegularFile(path)) { + return false; + } + + if (!Files.isExecutable(path) && !path.getFileName().toString().endsWith(".dylib")) { + return false; + } + + if (path.toString().contains("dylib.dSYM/Contents")) { + return false; + } + + if (path.getParent().equals(launchersDir) && launcherExecutables.contains(path.getFileName().toString())) { + // Don't sign launchers + return false; + } + + return true; + } + + private static void unsign(Path path) throws IOException { + // run quietly + Executor.of("/usr/bin/codesign", "--remove-signature", path.toString()) + .setQuiet(true) + .executeExpectSuccess(); + } + + private void sign(Path path) { + var codesign = Files.isExecutable(path) ? codesignExecutableFile : codesignOtherFile; + codesign.accept(path); + } + + private AppImageSigner(Application app) { + launcherExecutables = app.launchers().stream().map( + Launcher::executableNameWithSuffix).collect(toSet()); + Consumer nop = path -> {}; + codesignExecutableFile = nop; + codesignOtherFile = nop; + codesignDir = nop; + } + + private AppImageSigner(Application app, SigningConfig signingCfg) { + launcherExecutables = app.launchers().stream().map( + Launcher::executableNameWithSuffix).collect(toSet()); + + var signingCfgWithoutEntitlements = SigningConfig.build(signingCfg).entitlements(null).create(); + + codesignExecutableFile = Codesign.build(signingCfg).quiet(true).create().asConsumer(); + codesignOtherFile = Codesign.build(signingCfgWithoutEntitlements).quiet(true).create().asConsumer(); + codesignDir = Codesign.build(signingCfgWithoutEntitlements).force(true).create().asConsumer(); + } + + private final Set launcherExecutables; + private final Consumer codesignExecutableFile; + private final Consumer codesignOtherFile; + private final Consumer codesignDir; +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Codesign.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Codesign.java new file mode 100644 index 0000000000000..b585571b58d31 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Codesign.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; +import static java.util.stream.Collectors.joining; +import java.util.stream.Stream; +import jdk.jpackage.internal.model.Application; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; + + +final class Codesign { + + final static class CodesignException extends Exception { + + CodesignException(String[] output) { + this.output = output; + } + + String[] getOutput() { + return output; + } + + private final String[] output; + + private static final long serialVersionUID = 1L; + } + + final static class Builder { + + private Builder(SigningConfig signingCfg) { + this.signingCfg = Objects.requireNonNull(signingCfg); + } + + Codesign create() { + List cmdline = new ArrayList<>(); + cmdline.add("/usr/bin/codesign"); + cmdline.addAll(signingCfg.toCodesignArgs()); + if (force) { + cmdline.add("--force"); + } + + return new Codesign(cmdline, quiet ? exec -> { + exec.setQuiet(true); + } : null); + } + + Builder force(boolean v) { + force = v; + return this; + } + + Builder quiet(boolean v) { + quiet = v; + return this; + } + + private final SigningConfig signingCfg; + private boolean force; + private boolean quiet; + } + + static Builder build(SigningConfig signingCfg) { + return new Builder(signingCfg); + } + + void applyTo(Path path) throws IOException, CodesignException { + + var exec = Executor.of(Stream.concat( + cmdline.stream(), + Stream.of(path.toString())).toArray(String[]::new) + ).saveOutput(true); + configureExecutor.ifPresent(configure -> configure.accept(exec)); + + if (exec.execute() != 0) { + throw new CodesignException(exec.getOutput().toArray(String[]::new)); + } + } + + Consumer asConsumer() { + return toConsumer(this::applyTo); + } + + static CodesignException handleCodesignException(Application app, CodesignException ex) { + // Log output of "codesign" in case of error. It should help + // user to diagnose issues when using --mac-app-image-sign-identity. + // In addition add possible reason for failure. For example + // "--app-content" can fail "codesign". + + if (!Optional.ofNullable(app.contentDirs()).orElseGet(List::of).isEmpty()) { + Log.info(I18N.getString("message.codesign.failed.reason.app.content")); + } + + // Signing might not work without Xcode with command line + // developer tools. Show user if Xcode is missing as possible + // reason. + if (!isXcodeDevToolsInstalled()) { + Log.info(I18N.getString("message.codesign.failed.reason.xcode.tools")); + } + + // Log "codesign" output + Log.info(I18N.format("error.tool.failed.with.output", "codesign")); + Log.info(Stream.of(ex.getOutput()).collect(joining("\n")).strip()); + + return ex; + } + + private Codesign(List cmdline, Consumer configureExecutor) { + this.cmdline = Objects.requireNonNull(cmdline); + this.configureExecutor = Optional.ofNullable(configureExecutor); + } + + private static boolean isXcodeDevToolsInstalled() { + try { + return Executor.of("/usr/bin/xcrun", "--help").execute() == 0; + } catch (IOException ex) { + return false; + } + } + + private final List cmdline; + private final Optional> configureExecutor; +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java new file mode 100644 index 0000000000000..6a12184a7f788 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.io.IOException; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import jdk.jpackage.internal.AppImageBuilder.AppImageItem; +import jdk.jpackage.internal.AppImageBuilder.AppImageItemGroup; +import static jdk.jpackage.internal.PListUtils.writeArray; +import jdk.jpackage.internal.model.MacApplication; +import jdk.jpackage.internal.model.MacFileAssociation; +import static jdk.jpackage.internal.PListUtils.writeBoolean; +import static jdk.jpackage.internal.PListUtils.writeDict; +import static jdk.jpackage.internal.PListUtils.writeKey; +import static jdk.jpackage.internal.PListUtils.writeString; +import static jdk.jpackage.internal.PListUtils.writeStringArray; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.FileAssociation; +import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + +final class MacAppImageBuilder2 { + + static AppImageBuilder.Builder build() { + return new AppImageBuilder.Builder() + .itemGroup(AppImageItemGroup.RUNTIME) + .addItem(MacAppImageBuilder2::writeRuntimeInfoPlist) + .addItem(MacAppImageBuilder2::copyJliLib) + .itemGroup(AppImageItemGroup.BEGIN) + .addItem(new ApplicationIcon()) + .addItem(MacAppImageBuilder2::writePkgInfoFile) + .addItem(MacAppImageBuilder2::writeFileAssociationIcons) + .addItem(MacAppImageBuilder2::writeAppInfoPlist); + } + + private static void copyJliLib(BuildEnv env, Application app, + ApplicationLayout appLayout) throws IOException { + + final Path jliName = Path.of("libjli.dylib"); + try (var walk = Files.walk(appLayout.runtimeDirectory().resolve("Contents/Home/lib"))) { + final Path jli = walk + .filter(file -> file.getFileName().equals(jliName)) + .findFirst() + .get(); + Files.copy(jli, appLayout.launchersDirectory().resolve(jliName)); + } + } + + private static void writeRuntimeInfoPlist(BuildEnv env, Application app, + ApplicationLayout appLayout) throws IOException { + + final var macApp = ((MacApplication)app); + + Map data = new HashMap<>(); + data.put("CF_BUNDLE_IDENTIFIER", macApp.bundleIdentifier()); + data.put("CF_BUNDLE_NAME", macApp.bundleName()); + data.put("CF_BUNDLE_VERSION", macApp.version()); + data.put("CF_BUNDLE_SHORT_VERSION_STRING", macApp.shortVersion().toString()); + + env.createResource("Runtime-Info.plist.template") + .setPublicName("Runtime-Info.plist") + .setCategory(I18N.getString("resource.runtime-info-plist")) + .setSubstitutionData(data) + .saveToFile(appLayout.runtimeDirectory().resolve("Contents/Info.plist")); + } + + private static void writeAppInfoPlist(BuildEnv env, Application app, + ApplicationLayout appLayout) throws IOException { + + final var macApp = ((MacApplication)app); + + final String faXml = toSupplier(() -> { + var buf = new StringWriter(); + var xml = XMLOutputFactory.newInstance().createXMLStreamWriter(buf); + writeCFBundleDocumentTypes(xml, macApp); + writeUTExportedTypeDeclarations(xml, macApp); + xml.flush(); + xml.close(); + return buf.toString(); + }).get(); + + Map data = new HashMap<>(); + data.put("DEPLOY_ICON_FILE", ApplicationIcon.getPath(app, appLayout).getFileName().toString()); + data.put("DEPLOY_BUNDLE_COPYRIGHT", app.copyright()); + data.put("DEPLOY_LAUNCHER_NAME", app.mainLauncher().executableNameWithSuffix()); + data.put("DEPLOY_BUNDLE_SHORT_VERSION", macApp.shortVersion().toString()); + data.put("DEPLOY_BUNDLE_CFBUNDLE_VERSION", app.version()); + data.put("DEPLOY_BUNDLE_NAME", macApp.bundleName()); + data.put("DEPLOY_BUNDLE_IDENTIFIER", macApp.bundleIdentifier()); + data.put("DEPLOY_APP_CATEGORY", macApp.category()); + data.put("DEPLOY_FILE_ASSOCIATIONS", faXml); + + env.createResource("Info-lite.plist.template") + .setCategory(I18N.getString("resource.app-info-plist")) + .setSubstitutionData(data) + .setPublicName("Info.plist") + .saveToFile(appLayout.contentDirectory().resolve("Info.plist")); + } + + private static void writeCFBundleDocumentTypes(XMLStreamWriter xml, + MacApplication app) throws XMLStreamException, IOException { + writeKey(xml, "CFBundleDocumentTypes"); + for (var fa : app.fileAssociations().toList()) { + writeArray(xml, toXmlConsumer(() -> { + writeDict(xml, toXmlConsumer(() -> { + addFaToCFBundleDocumentTypes(xml, app, (MacFileAssociation) fa); + })); + })); + } + } + + private static void writeUTExportedTypeDeclarations(XMLStreamWriter xml, + MacApplication app) throws XMLStreamException, IOException { + writeKey(xml, "UTExportedTypeDeclarations"); + for (var fa : app.fileAssociations().toList()) { + writeArray(xml, toXmlConsumer(() -> { + writeDict(xml, toXmlConsumer(() -> { + addFaToUTExportedTypeDeclarations(xml, app, (MacFileAssociation) fa); + })); + })); + } + } + + private static String faContentType(MacApplication app, MacFileAssociation fa) { + return String.format("%s.%s", app.bundleIdentifier(), fa.extension()); + } + + private static void faWriteIcon(XMLStreamWriter xml, String key, FileAssociation fa) + throws XMLStreamException { + var icon = fa.icon(); + if (icon != null) { + writeString(xml, key, fa.icon().getFileName()); + } + } + + private static void addFaToCFBundleDocumentTypes(XMLStreamWriter xml, + MacApplication app, MacFileAssociation fa) throws XMLStreamException, IOException { + + writeStringArray(xml, "LSItemContentTypes", List.of(faContentType(app, fa))); + writeString(xml, "CFBundleTypeName", fa.description()); + writeString(xml, "LSHandlerRank", fa.lsHandlerRank()); + writeString(xml, "CFBundleTypeRole", fa.cfBundleTypeRole()); + writeString(xml, "NSPersistentStoreTypeKey", + fa.nsPersistentStoreTypeKey()); + writeString(xml, "NSDocumentClass", fa.nsDocumentClass()); + writeBoolean(xml, "LSIsAppleDefaultForType", true); + writeString(xml, "LSTypeIsPackage", fa.lsTypeIsPackage()); + writeBoolean(xml, "LSSupportsOpeningDocumentsInPlace", + fa.lsSupportsOpeningDocumentsInPlace()); + writeBoolean(xml, "UISupportsDocumentBrowser", + fa.uiSupportsDocumentBrowser()); + faWriteIcon(xml, "CFBundleTypeIconFile", fa); + } + + private static void addFaToUTExportedTypeDeclarations(XMLStreamWriter xml, + MacApplication app, MacFileAssociation fa) throws XMLStreamException, + IOException { + writeString(xml, "UTTypeIdentifier", List.of(faContentType(app, fa))); + writeString(xml, "UTTypeDescription", fa.description()); + writeStringArray(xml, "UTTypeConformsTo", fa.utTypeConformsTo()); + faWriteIcon(xml, "UTTypeIconFile", fa); + + writeKey(xml, "UTTypeTagSpecification"); + writeDict(xml, toXmlConsumer(() -> { + writeStringArray(xml, "public.filename-extension", List.of(fa.extension())); + writeStringArray(xml, "public.mime-type", List.of(fa.mimeType())); + writeStringArray(xml, "NSExportableTypes", fa.nsExportableTypes()); + })); + } + + private static class ApplicationIcon implements AppImageItem { + static Path getPath(Application app, ApplicationLayout appLayout) { + return appLayout.destktopIntegrationDirectory().resolve(app.name() + ".icns"); + } + + @Override + public void write(BuildEnv env, Application app, ApplicationLayout appLayout) + throws IOException { + env.createResource("JavaApp.icns") + .setCategory("icon") + .setExternal(((MacApplication)app).icon()) + .saveToFile(getPath(app, appLayout)); + } + } + + private static void writeFileAssociationIcons(BuildEnv env, Application app, + ApplicationLayout appLayout) throws IOException { + for (var faIcon : app.fileAssociations().filter(FileAssociation::hasIcon).map(FileAssociation::icon).toList()) { + Files.copy(faIcon, appLayout.destktopIntegrationDirectory().resolve(faIcon.getFileName())); + } + } + + private static void writePkgInfoFile(BuildEnv env, Application app, + ApplicationLayout appLayout) throws IOException { + Files.write(appLayout.contentDirectory().resolve("PkgInfo"), + "APPL????".getBytes(StandardCharsets.ISO_8859_1)); + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/PListUtils.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/PListUtils.java new file mode 100644 index 0000000000000..014c5f123b8ce --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/PListUtils.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.io.IOException; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import jdk.jpackage.internal.util.XmlUtils.XmlConsumer; +import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; + +final class PListUtils { + + static void writeBoolean(XMLStreamWriter xml, String key, boolean value) + throws XMLStreamException { + writeKey(xml, key); + xml.writeEmptyElement(Boolean.toString(value)); + } + + static void writeString(XMLStreamWriter xml, String key, Object value) + throws XMLStreamException { + writeKey(xml, key); + writeString(xml, value); + } + + static void writeStringArray(XMLStreamWriter xml, String key, Iterable values) + throws XMLStreamException, IOException { + writeKey(xml, key); + writeArray(xml, toXmlConsumer(() -> { + for (var v : values) { + writeString(xml, v); + } + })); + } + + static void writeStringArray(XMLStreamWriter xml, String key, Object... values) + throws XMLStreamException, IOException { + writeKey(xml, key); + writeArray(xml, toXmlConsumer(() -> { + for (var v : values) { + writeString(xml, v); + } + })); + } + + static void writeDict(XMLStreamWriter xml, XmlConsumer content) + throws XMLStreamException, IOException { + writeElement(xml, "dict", content); + } + + static void writeArray(XMLStreamWriter xml, XmlConsumer content) + throws XMLStreamException, IOException { + writeElement(xml, "array", content); + } + + static void writePList(XMLStreamWriter xml, XmlConsumer content) + throws XMLStreamException, IOException { + xml.writeDTD("plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"https://www.apple.com/DTDs/PropertyList-1.0.dtd\""); + xml.writeStartElement("plist"); + xml.writeAttribute("version", "1.0"); + content.accept(xml); + xml.writeEndElement(); + } + + static void writeKey(XMLStreamWriter xml, String key) + throws XMLStreamException { + writeElement(xml, "key", key); + } + + private static void writeString(XMLStreamWriter xml, Object value) + throws XMLStreamException { + writeElement(xml, "string", value.toString()); + } + + private static void writeElement(XMLStreamWriter xml, String name, String value) + throws XMLStreamException { + xml.writeStartElement(name); + xml.writeCharacters(value); + xml.writeEndElement(); + } + + private static void writeElement(XMLStreamWriter xml, String name, XmlConsumer content) + throws XMLStreamException, IOException { + xml.writeStartElement(name); + content.accept(xml); + xml.writeEndElement(); + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfig.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfig.java new file mode 100644 index 0000000000000..ca2a5cacd0213 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfig.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + + +record SigningConfig(String signingIdentity, String identifierPrefix, Path entitlements, String keyChain) { + + static final class Builder { + + private Builder(String signingIdentity) { + this.signingIdentity = Objects.requireNonNull(signingIdentity); + } + + SigningConfig create() { + return new SigningConfig(signingIdentity, identifierPrefix, entitlements, keyChain); + } + + Builder entitlements(Path v) { + entitlements = v; + return this; + } + + Builder identifierPrefix(String v) { + identifierPrefix = v; + return this; + } + + Builder keyChain(String v) { + keyChain = v; + return this; + } + + private final String signingIdentity; + private String identifierPrefix; + private Path entitlements; + private String keyChain; + } + + static Builder build(String signingIdentity) { + return new Builder(signingIdentity); + } + + static Builder build(SigningConfig signingCfg) { + return new Builder(signingCfg.signingIdentity) + .entitlements(signingCfg.entitlements) + .identifierPrefix(signingCfg.identifierPrefix) + .keyChain(signingCfg.keyChain); + } + + SigningConfig { + Objects.requireNonNull(signingIdentity); + } + + List toCodesignArgs() { + List args = new ArrayList<>(List.of("-s", signingIdentity, "-vvvv")); + + if (!signingIdentity.equals("-")) { + args.addAll(List.of("--timestamp", "--options", "runtime", + "--prefix", identifierPrefix)); + if (keyChain != null && !keyChain.isEmpty()) { + args.addAll(List.of("--keychain", keyChain)); + } + + if (entitlements != null) { + args.addAll(List.of("--entitlements", + entitlements.toString())); + } + } + + return args; + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java index 3e546706992e3..b9b67a6d6f318 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java @@ -25,16 +25,30 @@ package jdk.jpackage.internal.model; import java.util.Map; +import static java.util.stream.Collectors.joining; +import java.util.stream.IntStream; +import jdk.jpackage.internal.util.CompositeProxy; -public interface MacApplication extends Application { +public interface MacApplication extends Application, MacApplicationMixin { - boolean signed(); - - boolean appStore(); + default DottedVersion shortVersion() { + var verComponents = DottedVersion.lazy(version()).getComponents(); + return DottedVersion.greedy(IntStream.range(0, 3).mapToObj(idx -> { + if (idx < verComponents.length) { + return verComponents[idx].toString(); + } else { + return "0"; + } + }).collect(joining("."))); + } @Override default Map extraAppImageFileData() { return Map.of("signed", Boolean.toString(signed()), "app-store", Boolean.toString(appStore())); } + + public static MacApplication create(Application app, MacApplicationMixin mixin) { + return CompositeProxy.create(MacApplication.class, app, mixin); + } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java new file mode 100644 index 0000000000000..84eb90ed2ff4e --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.nio.file.Path; + +public interface MacApplicationMixin { + + Path icon(); + + String bundleName(); + + String bundleIdentifier(); + + String category(); + + boolean signed(); + + boolean appStore(); + + Path entitlements(); + + record Stub(Path icon, String bundleName, String bundleIdentifier, String category, + boolean signed, boolean appStore, Path entitlements) implements + MacApplicationMixin { + + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociation.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociation.java new file mode 100644 index 0000000000000..765e9c1cce44a --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociation.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import jdk.jpackage.internal.util.CompositeProxy; + +public interface MacFileAssociation extends FileAssociation, MacFileAssociationMixin { + + static public MacFileAssociation create(FileAssociation fa, MacFileAssociationMixin mixin) { + return CompositeProxy.create(MacFileAssociation.class, fa, mixin); + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociationMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociationMixin.java new file mode 100644 index 0000000000000..919140bb31aaa --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociationMixin.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.util.List; + +public interface MacFileAssociationMixin { + + String cfBundleTypeName(); + + String cfBundleTypeRole(); + + String lsHandlerRank(); + + String lsTypeIsPackage(); + + String nsDocumentClass(); + + String nsPersistentStoreTypeKey(); + + boolean lsSupportsOpeningDocumentsInPlace(); + + boolean uiSupportsDocumentBrowser(); + + List utTypeConformsTo(); + + List nsExportableTypes(); + + record Stub(String cfBundleTypeName, String cfBundleTypeRole, + String lsHandlerRank, String lsTypeIsPackage, String nsDocumentClass, + String nsPersistentStoreTypeKey, + boolean lsSupportsOpeningDocumentsInPlace, + boolean uiSupportsDocumentBrowser, List utTypeConformsTo, + List nsExportableTypes) implements MacFileAssociationMixin { + + } +} From f3531734f84185af1e1f3adf94fbe5564b4edca1 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 13:27:48 -0500 Subject: [PATCH 0182/1101] Move XmlUtils.XmlConsumer to outer level --- .../jdk/jpackage/internal/PListUtils.java | 2 +- .../jpackage/internal/util/XmlConsumer.java | 35 +++++++++++++++++++ .../jdk/jpackage/internal/util/XmlUtils.java | 7 ---- .../internal/WixAppImageFragmentBuilder.java | 2 +- .../jpackage/internal/WixFragmentBuilder.java | 2 +- .../internal/WixUiFragmentBuilder.java | 2 +- 6 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlConsumer.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/PListUtils.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/PListUtils.java index 014c5f123b8ce..2a4a4c654bea9 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/PListUtils.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/PListUtils.java @@ -27,7 +27,7 @@ import java.io.IOException; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import jdk.jpackage.internal.util.XmlUtils.XmlConsumer; +import jdk.jpackage.internal.util.XmlConsumer; import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; final class PListUtils { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlConsumer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlConsumer.java new file mode 100644 index 0000000000000..97f5f6c07e39b --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlConsumer.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.io.IOException; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + + +@FunctionalInterface +public interface XmlConsumer { + + void accept(XMLStreamWriter xml) throws IOException, XMLStreamException; + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java index 0aa1429e72110..097ca689a1dc6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java @@ -45,13 +45,6 @@ public final class XmlUtils { - @FunctionalInterface - public interface XmlConsumer { - - void accept(XMLStreamWriter xml) throws IOException, XMLStreamException; - - } - @FunctionalInterface public interface XmlConsumerNoArg { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index 3ac7ab0d5db68..30702a0541f9e 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -67,7 +67,7 @@ import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.XmlUtils; -import jdk.jpackage.internal.util.XmlUtils.XmlConsumer; +import jdk.jpackage.internal.util.XmlConsumer; import org.w3c.dom.NodeList; /** diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java index 0b086cf5503eb..87b87e44835d9 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java @@ -44,7 +44,7 @@ import jdk.jpackage.internal.WixSourceConverter.ResourceGroup; import jdk.jpackage.internal.WixToolset.WixToolsetType; import jdk.jpackage.internal.util.XmlUtils; -import jdk.jpackage.internal.util.XmlUtils.XmlConsumer; +import jdk.jpackage.internal.util.XmlConsumer; /** * Creates WiX fragment. diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java index 8a67df62e690e..9eda71925fa23 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java @@ -42,7 +42,7 @@ import jdk.jpackage.internal.WixAppImageFragmentBuilder.ShortcutsFolder; import jdk.jpackage.internal.WixToolset.WixToolsetType; import jdk.jpackage.internal.resources.ResourceLocator; -import jdk.jpackage.internal.util.XmlUtils.XmlConsumer; +import jdk.jpackage.internal.util.XmlConsumer; /** * Creates UI WiX fragment. From db5f640d30ea477ecb258877f39bed3c9b3bceed Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 13:30:24 -0500 Subject: [PATCH 0183/1101] Remove trailing whitespace --- .../classes/jdk/jpackage/internal/LinuxAppImageBuilder.java | 2 +- .../jdk/jpackage/internal/LinuxApplicationLayoutMixin.java | 4 ++-- .../classes/jdk/jpackage/internal/model/LinuxApplication.java | 4 ++-- .../classes/jdk/jpackage/internal/MacAppImageBuilder2.java | 2 +- .../jdk/jpackage/internal/model/MacApplicationMixin.java | 2 +- .../jpackage/internal/model/LauncherJarStartupInfoMixin.java | 4 ++-- .../share/classes/jdk/jpackage/internal/util/XmlConsumer.java | 2 +- .../classes/jdk/jpackage/internal/model/WinExePackage.java | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index 5c873f9c3c3d9..8d573b21489a0 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -49,7 +49,7 @@ private static void writeLauncherLib(BuildEnv env, Application app, Files.createDirectories(launcherLib.getParent()); Files.copy(in, launcherLib); } - } + } private static void writeLauncherIcons(BuildEnv env, Application app, ApplicationLayout appLayout) throws IOException { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java index effbb95606678..d5a669c964fdc 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java @@ -26,13 +26,13 @@ import java.nio.file.Path; -// Must be publc to allow access from AppImageLayout.toPathGroup() +// Must be publc to allow access from AppImageLayout.toPathGroup() public interface LinuxApplicationLayoutMixin { /** * Path to "libapplauncher.so". */ Path libAppLauncher(); - + record Stub(Path libAppLauncher) implements LinuxApplicationLayoutMixin {} } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java index 221788240f8ba..d2ead0a382836 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java @@ -28,8 +28,8 @@ import jdk.jpackage.internal.util.CompositeProxy; public interface LinuxApplication extends Application { - + public static LinuxApplication create(Application app) { return CompositeProxy.create(LinuxApplication.class, app); - } + } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java index 6a12184a7f788..33b7d2f255dc6 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java @@ -157,7 +157,7 @@ private static String faContentType(MacApplication app, MacFileAssociation fa) { return String.format("%s.%s", app.bundleIdentifier(), fa.extension()); } - private static void faWriteIcon(XMLStreamWriter xml, String key, FileAssociation fa) + private static void faWriteIcon(XMLStreamWriter xml, String key, FileAssociation fa) throws XMLStreamException { var icon = fa.icon(); if (icon != null) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java index 84eb90ed2ff4e..6e2dd40570f9e 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java @@ -29,7 +29,7 @@ public interface MacApplicationMixin { Path icon(); - + String bundleName(); String bundleIdentifier(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java index f75971b6d7b69..baaff758496ff 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java @@ -29,8 +29,8 @@ public interface LauncherJarStartupInfoMixin { /** * Returns path to the main jar relative to app's main source directory. - * - * @see jdk.jpackage.internal.model.Application#srcDir() + * + * @see jdk.jpackage.internal.model.Application#srcDir() */ Path jarPath(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlConsumer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlConsumer.java index 97f5f6c07e39b..ec184d445e51e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlConsumer.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlConsumer.java @@ -31,5 +31,5 @@ public interface XmlConsumer { void accept(XMLStreamWriter xml) throws IOException, XMLStreamException; - + } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java index ef20268a4f34b..08e25377c7697 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java @@ -34,7 +34,7 @@ public static WinExePackage create(WinMsiPackage msiPackage, Path icon) { return CompositeProxy.create(WinExePackage.class, createExePackage( msiPackage), new WinExePackageMixin.Stub(msiPackage, icon)); } - + private static Package createExePackage(WinMsiPackage pkg) { return new Package.Stub( pkg.app(), From 30da5218f117cad0058272738b07cd62e0d22989 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 13:58:22 -0500 Subject: [PATCH 0184/1101] Bad merge fix --- .../internal/MacLaunchersAsServices.java | 6 -- .../jdk/jpackage/internal/util/XmlUtils.java | 9 ++ .../internal/util/xml/PrettyPrintHandler.java | 89 ------------------- .../util/xml/SkipDocumentHandler.java | 48 ---------- .../internal/WixLauncherAsService.java | 4 - 5 files changed, 9 insertions(+), 147 deletions(-) delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/PrettyPrintHandler.java delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/SkipDocumentHandler.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index 32e80933b444e..fd642ac3203c4 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -32,12 +32,6 @@ import java.util.Map; import java.util.Optional; import java.util.function.Predicate; -<<<<<<< HEAD -======= -import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; -import static jdk.jpackage.internal.OverridableResource.createResource; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; ->>>>>>> SplitIOUtils.DecoupleAppImageFile import jdk.jpackage.internal.util.PathUtils; /** diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java index 8012384b67901..bdfeae8b5db2a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java @@ -44,6 +44,15 @@ public final class XmlUtils { + @FunctionalInterface + public interface XmlConsumerNoArg { + void accept() throws IOException, XMLStreamException; + } + + public static XmlConsumer toXmlConsumer(XmlConsumerNoArg xmlConsumer) { + return xml -> xmlConsumer.accept(); + } + public static void createXml(Path dstFile, XmlConsumer xmlConsumer) throws IOException { XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/PrettyPrintHandler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/PrettyPrintHandler.java deleted file mode 100644 index 38d47d7e2a31a..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/PrettyPrintHandler.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal.util.xml; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; -import javax.xml.stream.XMLStreamWriter; - -public class PrettyPrintHandler implements InvocationHandler { - - public PrettyPrintHandler(XMLStreamWriter target) { - this.target = target; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - switch (method.getName()) { - case "writeStartElement": - // update state of parent node - if (depth > 0) { - hasChildElement.put(depth - 1, true); - } - // reset state of current node - hasChildElement.put(depth, false); - // indent for current depth - target.writeCharacters(EOL); - target.writeCharacters(repeat(depth, INDENT)); - depth++; - break; - case "writeEndElement": - depth--; - if (hasChildElement.get(depth) == true) { - target.writeCharacters(EOL); - target.writeCharacters(repeat(depth, INDENT)); - } - break; - case "writeProcessingInstruction": - case "writeEmptyElement": - // update state of parent node - if (depth > 0) { - hasChildElement.put(depth - 1, true); - } - // indent for current depth - target.writeCharacters(EOL); - target.writeCharacters(repeat(depth, INDENT)); - break; - default: - break; - } - method.invoke(target, args); - return null; - } - - private static String repeat(int d, String s) { - StringBuilder sb = new StringBuilder(); - while (d-- > 0) { - sb.append(s); - } - return sb.toString(); - } - - private final XMLStreamWriter target; - private int depth = 0; - private final Map hasChildElement = new HashMap<>(); - private static final String INDENT = " "; - private static final String EOL = "\n"; -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/SkipDocumentHandler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/SkipDocumentHandler.java deleted file mode 100644 index 918387baf8f45..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/xml/SkipDocumentHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal.util.xml; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import javax.xml.stream.XMLStreamWriter; - -public class SkipDocumentHandler implements InvocationHandler { - - public SkipDocumentHandler(XMLStreamWriter target) { - this.target = target; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - switch (method.getName()) { - case "writeStartDocument", "writeEndDocument" -> { - } - default -> method.invoke(target, args); - } - return null; - } - - private final XMLStreamWriter target; -} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java index ce72c32a2b260..3d9c1e05aa8a4 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixLauncherAsService.java @@ -39,10 +39,6 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -<<<<<<< HEAD -======= -import static jdk.jpackage.internal.OverridableResource.createResource; ->>>>>>> SplitIOUtils.DecoupleAppImageFile import jdk.jpackage.internal.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Node; From 6dcb09d4348401aa767cffd270802930256c683c Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 14:18:23 -0500 Subject: [PATCH 0185/1101] Undo pointless changes to reduce the diff --- .../jdk/jpackage/test/LinuxHelper.java | 2 +- .../helpers/jdk/jpackage/test/Main.java | 19 ++++++++++++++++--- .../internal/model/DottedVersionTest.java | 1 - .../tools/jpackage/share/EmptyFolderTest.java | 2 +- .../share/PredefinedAppImageErrorTest.java | 2 +- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index 9be74418fb0e1..ddbbee4aa6075 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -437,7 +437,7 @@ private static void verifyDesktopFile(JPackageCommand cmd, Path desktopFile) "Check value of [%s] key", key)); } - // Verify the value of `Exec` key in is escaped if required + // Verify the value of `Exec` key is escaped if required String launcherPath = data.get("Exec"); if (Pattern.compile("\\s").matcher(launcherPath).find()) { TKit.assertTrue(launcherPath.startsWith("\"") diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java index 3a93a01876c63..5919d8361c432 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java @@ -54,9 +54,22 @@ public static void main(String args[]) throws Throwable { if (arg.startsWith("@")) { // Command file - var newArgs = Files.readAllLines(Path.of(arg.substring(1))).stream().map(line -> { - return Stream.of(line.split("\\s+")); - }).flatMap(x -> x).collect(toCollection(ArrayDeque::new)); + // @=args will read arguments from the "args" file, one argument per line + // @args will read arguments from the "args" file, splitting lines into arguments at whitespaces + arg = arg.substring(1); + var oneArgPerLine = arg.startsWith("="); + if (oneArgPerLine) { + arg = arg.substring(1); + } + + var newArgsStream = Files.readAllLines(Path.of(arg)).stream(); + if (!oneArgPerLine) { + newArgsStream.map(line -> { + return Stream.of(line.split("\\s+")); + }).flatMap(x -> x); + } + + var newArgs = newArgsStream.collect(toCollection(ArrayDeque::new)); newArgs.addAll(argsAsList); argsAsList = newArgs; continue; diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java index d3a87d2749b51..a16ee650b7c8a 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java @@ -22,7 +22,6 @@ */ package jdk.jpackage.internal.model; -import jdk.jpackage.internal.model.DottedVersion; import java.util.Collections; import java.util.List; import java.util.function.Function; diff --git a/test/jdk/tools/jpackage/share/EmptyFolderTest.java b/test/jdk/tools/jpackage/share/EmptyFolderTest.java index 402b6eb7fd599..40a4db03d6f69 100644 --- a/test/jdk/tools/jpackage/share/EmptyFolderTest.java +++ b/test/jdk/tools/jpackage/share/EmptyFolderTest.java @@ -25,8 +25,8 @@ import java.nio.file.Files; import java.nio.file.Path; import jdk.jpackage.test.PackageTest; -import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; diff --git a/test/jdk/tools/jpackage/share/PredefinedAppImageErrorTest.java b/test/jdk/tools/jpackage/share/PredefinedAppImageErrorTest.java index 5a64413c9203b..0e1d358dae46b 100644 --- a/test/jdk/tools/jpackage/share/PredefinedAppImageErrorTest.java +++ b/test/jdk/tools/jpackage/share/PredefinedAppImageErrorTest.java @@ -31,7 +31,6 @@ import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.AppImageFile; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.TKit; @@ -115,4 +114,5 @@ private void getDummyAppImage(JPackageCommand cmd) throws IOException { cmd.addArguments("--app-image", dummyAppFolder.toString()); new AppImageFile("PredefinedAppImageErrorTest", "Hello").save(dummyAppFolder); } + } From 345ccbfd2d699575f600684e4ac81f3ca9662a3d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 14:28:11 -0500 Subject: [PATCH 0186/1101] Merge CompositeProxy and CompositeProxySpec classes --- .../internal/util/CompositeProxy.java | 65 +++++++++++- .../internal/util/CompositeProxySpec.java | 100 ------------------ 2 files changed, 61 insertions(+), 104 deletions(-) delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxySpec.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java index 2e2c5dee0e0f0..f62e443149833 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java @@ -26,9 +26,13 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.function.BinaryOperator; import java.util.function.Predicate; import static java.util.stream.Collectors.toMap; @@ -74,8 +78,18 @@ private static T createCompositeProxy(Class interfaceType, BinaryOperator conflictResolver, InvokeTunnel invokeTunnel, Object... slices) { - final Map, Object> interfaceDispatch = CompositeProxySpec.create( - interfaceType, slices).getInterfaceDispatch(); + validateTypeIsInterface(interfaceType); + + final var interfaces = interfaceType.getInterfaces(); + List.of(interfaces).forEach(CompositeProxy::validateTypeIsInterface); + + if (interfaces.length != slices.length) { + throw new IllegalArgumentException(String.format( + "type %s must extend %d interfaces", interfaceType.getName(), + slices.length)); + } + + final Map, Object> interfaceDispatch = createInterfaceDispatch(interfaces, slices); final Map methodDispatch = getProxyableMethods(interfaceType).map(method -> { var handler = createHandler(interfaceType, method, interfaceDispatch, @@ -90,11 +104,54 @@ private static T createCompositeProxy(Class interfaceType, @SuppressWarnings("unchecked") T proxy = (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), new Class[]{interfaceType}, - new DynamicProxyInvocationHandler(methodDispatch)); + new CompositeProxyInvocationHandler(methodDispatch)); return proxy; } + private static Map, Object> createInterfaceDispatch( + Class[] interfaces, Object[] slices) { + + final Map, Object> interfaceDispatch = Stream.of(interfaces).collect(toMap(x -> x, iface -> { + return Stream.of(slices).filter(obj -> { + return Set.of(obj.getClass().getInterfaces()).contains(iface); + }).reduce((a, b) -> { + throw new IllegalArgumentException(String.format( + "both [%s] and [%s] slices implement %s", a, b, iface)); + }).orElseThrow(() -> createInterfaceNotImplementedException(List.of(iface))); + })); + + if (interfaceDispatch.size() != interfaces.length) { + final List> missingInterfaces = new ArrayList<>(Set.of(interfaces)); + missingInterfaces.removeAll(interfaceDispatch.entrySet()); + throw createInterfaceNotImplementedException(missingInterfaces); + } + + return Stream.of(interfaces).flatMap(iface -> { + return unfoldInterface(iface).map(unfoldedIface -> { + return Map.entry(unfoldedIface, interfaceDispatch.get(iface)); + }); + }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + private static Stream> unfoldInterface(Class interfaceType) { + return Stream.concat(Stream.of(interfaceType), Stream.of( + interfaceType.getInterfaces()).flatMap(CompositeProxy::unfoldInterface)); + } + + private static IllegalArgumentException createInterfaceNotImplementedException( + Collection> missingInterfaces) { + return new IllegalArgumentException(String.format( + "none of the slices implement %s", missingInterfaces)); + } + + private static void validateTypeIsInterface(Class type) { + if (!type.isInterface()) { + throw new IllegalArgumentException(String.format( + "type %s must be an interface", type.getName())); + } + } + private static Handler createHandler(Class interfaceType, Method method, Map, Object> interfaceDispatch, BinaryOperator conflictResolver, @@ -170,7 +227,7 @@ private static boolean signatureEquals(Method a, Method b) { return Objects.equals(a.getReturnType(), b.getReturnType()); } - private record DynamicProxyInvocationHandler(Map dispatch) implements InvocationHandler { + private record CompositeProxyInvocationHandler(Map dispatch) implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxySpec.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxySpec.java deleted file mode 100644 index a6ba46c7e2b59..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxySpec.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal.util; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import static java.util.stream.Collectors.toMap; -import java.util.stream.Stream; - -final class CompositeProxySpec { - - Map, Object> getInterfaceDispatch() { - return interfaceDispatch; - } - - static CompositeProxySpec create(Class interfaceType, Object... slices) { - validateTypeIsInterface(interfaceType); - return new CompositeProxySpec(interfaceType, interfaceType.getInterfaces(), slices); - } - - private CompositeProxySpec(Class interfaceType, Class[] interfaces, Object[] slices) { - List.of(interfaces).forEach(CompositeProxySpec::validateTypeIsInterface); - - if (interfaces.length != slices.length) { - throw new IllegalArgumentException(String.format( - "type %s must extend %d interfaces", interfaceType.getName(), - slices.length)); - } - - this.interfaceDispatch = createInterfaceDispatch(interfaces, slices); - } - - private static Map, Object> createInterfaceDispatch( - Class[] interfaces, Object[] slices) { - - final Map, Object> interfaceDispatch = Stream.of(interfaces).collect(toMap(x -> x, iface -> { - return Stream.of(slices).filter(obj -> { - return Set.of(obj.getClass().getInterfaces()).contains(iface); - }).reduce((a, b) -> { - throw new IllegalArgumentException(String.format( - "both [%s] and [%s] slices implement %s", a, b, iface)); - }).orElseThrow(() -> createInterfaceNotImplementedException(List.of(iface))); - })); - - if (interfaceDispatch.size() != interfaces.length) { - final List> missingInterfaces = new ArrayList<>(Set.of(interfaces)); - missingInterfaces.removeAll(interfaceDispatch.entrySet()); - throw createInterfaceNotImplementedException(missingInterfaces); - } - - return Stream.of(interfaces).flatMap(iface -> { - return unfoldInterface(iface).map(unfoldedIface -> { - return Map.entry(unfoldedIface, interfaceDispatch.get(iface)); - }); - }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); - } - - private static Stream> unfoldInterface(Class interfaceType) { - return Stream.concat(Stream.of(interfaceType), Stream.of( - interfaceType.getInterfaces()).flatMap(CompositeProxySpec::unfoldInterface)); - } - - private static IllegalArgumentException createInterfaceNotImplementedException( - Collection> missingInterfaces) { - return new IllegalArgumentException(String.format( - "none of the slices implement %s", missingInterfaces)); - } - - private static void validateTypeIsInterface(Class type) { - if (!type.isInterface()) { - throw new IllegalArgumentException(String.format( - "type %s must be an interface", type.getName())); - } - } - - final Map, Object> interfaceDispatch; -} From b7f4de7f660a972b510bc6e47050b8a0bd6441db Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 14:55:12 -0500 Subject: [PATCH 0187/1101] Bugfix & cleanup --- .../jpackage/helpers/jdk/jpackage/test/Functional.java | 1 - .../jpackage/helpers/jdk/jpackage/test/JPackageCommand.java | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Functional.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Functional.java index a974670b8e4ce..28b3574268142 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Functional.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Functional.java @@ -22,7 +22,6 @@ */ package jdk.jpackage.test; -import java.lang.reflect.InvocationTargetException; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index a149a996f1135..ba96309effabb 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -153,8 +153,10 @@ public String getArgumentValue(String argName, public T getArgumentValue(String argName, Supplier defaultValueSupplier, Function stringConverter) { - return getArgumentValue(argName, (unused) -> defaultValueSupplier.get(), - stringConverter); + return getArgumentValue(argName, + Optional.ofNullable(defaultValueSupplier).map(supplier -> { + return (Function)unused -> supplier.get(); + }).orElse(null), stringConverter); } public String getArgumentValue(String argName, From a0b9595ebaec7577c019b90e82fc0a38ef7c0a6f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 16:15:01 -0500 Subject: [PATCH 0188/1101] Make IOUtils class package-private --- .../share/classes/jdk/jpackage/internal/IOUtils.java | 2 +- .../classes/jdk/jpackage/internal/util/PathUtils.java | 9 ++++----- .../classes/jdk/jpackage/internal/util/XmlUtils.java | 3 +-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java index 534786ada13c9..cb8ef22790153 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java @@ -40,7 +40,7 @@ * * A collection of static utility methods. */ -public class IOUtils { +final class IOUtils { public static void copyFile(Path sourceFile, Path destFile) throws IOException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java index 267062a2031b6..26d4951929175 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java @@ -26,24 +26,23 @@ import java.nio.file.Path; import java.util.Optional; -import jdk.jpackage.internal.IOUtils; public final class PathUtils { public static String getSuffix(Path path) { - String filename = replaceSuffix(IOUtils.getFileName(path), null).toString(); - return IOUtils.getFileName(path).toString().substring(filename.length()); + String filename = replaceSuffix(path.getFileName(), null).toString(); + return path.getFileName().toString().substring(filename.length()); } public static Path addSuffix(Path path, String suffix) { Path parent = path.getParent(); - String filename = IOUtils.getFileName(path).toString() + suffix; + String filename = path.getFileName().toString() + suffix; return parent != null ? parent.resolve(filename) : Path.of(filename); } public static Path replaceSuffix(Path path, String suffix) { Path parent = path.getParent(); - String filename = IOUtils.getFileName(path).toString().replaceAll("\\.[^.]*$", + String filename = path.getFileName().toString().replaceAll("\\.[^.]*$", "") + Optional.ofNullable(suffix).orElse(""); return parent != null ? parent.resolve(filename) : Path.of(filename); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java index 8012384b67901..ff4168e5d0c00 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java @@ -39,7 +39,6 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stax.StAXResult; -import jdk.jpackage.internal.IOUtils; public final class XmlUtils { @@ -47,7 +46,7 @@ public final class XmlUtils { public static void createXml(Path dstFile, XmlConsumer xmlConsumer) throws IOException { XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance(); - Files.createDirectories(IOUtils.getParent(dstFile)); + Files.createDirectories(dstFile.getParent()); try (Writer w = Files.newBufferedWriter(dstFile)) { // Wrap with pretty print proxy XMLStreamWriter xml = (XMLStreamWriter) Proxy.newProxyInstance(XMLStreamWriter.class.getClassLoader(), From 9d1f097d8dd0a9d0d7b00b0d57666cbbd2bc18da Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 17:37:40 -0500 Subject: [PATCH 0189/1101] Minor improvements --- .../helpers/jdk/jpackage/test/AppImageFile.java | 10 +++------- .../helpers/jdk/jpackage/test/PackageFile.java | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java index 690da93b74926..2381aecec2ea1 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java @@ -28,12 +28,11 @@ import java.util.Map; import java.util.Optional; import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.util.XmlUtils; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; import org.w3c.dom.Document; -import org.xml.sax.SAXException; public record AppImageFile(String mainLauncherName, String mainLauncherClassName, String version, boolean macSigned, boolean macAppStore) { @@ -78,7 +77,7 @@ public void save(Path appImageDir) throws IOException { } public static AppImageFile load(Path appImageDir) { - try { + return toSupplier(() -> { Document doc = XmlUtils.initDocumentBuilder().parse( Files.newInputStream(getPathInAppImage(appImageDir))); @@ -103,10 +102,7 @@ public static AppImageFile load(Path appImageDir) { return new AppImageFile(mainLauncherName, mainLauncherClassName, version, macSigned, macAppStore); - } catch (XPathExpressionException | SAXException | IOException ex) { - // This should never happen as XPath expressions should be correct - throw new RuntimeException(ex); - } + }).get(); } private static String getVersion() { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageFile.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageFile.java index a0285201174f4..6307ccabda553 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageFile.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageFile.java @@ -24,7 +24,7 @@ import java.nio.file.Path; -public class PackageFile { +public final class PackageFile { public static Path getPathInAppImage(Path appImageDir) { return ApplicationLayout.platformAppImage() From 8a0bc9426c8a0c02591c7bc7ffe0be22629aa2e8 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 19 Nov 2024 18:22:51 -0500 Subject: [PATCH 0190/1101] Added AppImageFile2.getExtra() --- .../share/classes/jdk/jpackage/internal/AppImageFile2.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index 3eb4abd82cbee..31c239f9a616d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -114,6 +114,13 @@ String getMainClass() { return mainClass; } + /** + * Returns additional properties. Never returns null. + */ + Map getExtra() { + return extra; + } + /** * Saves file with application image info in application image using values * from this instance. From 7af6579fce08d200cca4c9b5861e7ae214bc2d04 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 21 Nov 2024 20:40:07 -0500 Subject: [PATCH 0191/1101] Fix bad merge --- .../internal/ExecutableRebrander.java | 32 ++++++++----------- .../jdk/jpackage/internal/WinMsiBundler.java | 21 +++++------- 2 files changed, 21 insertions(+), 32 deletions(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java index 871f4a5886dbd..236a9aeff7eeb 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java @@ -43,16 +43,8 @@ import java.util.Optional; import java.util.Properties; import java.util.ResourceBundle; -import java.util.function.Supplier; -import static jdk.jpackage.internal.OverridableResource.createResource; -import static jdk.jpackage.internal.ShortPathUtils.adjustPath; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.COPYRIGHT; -import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; -import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; -import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.WindowsAppImageBuilder.ICON_ICO; +import java.util.function.Function; +import java.util.stream.Stream; @SuppressWarnings("restricted") final class ExecutableRebrander { @@ -102,8 +94,10 @@ void execute(BuildEnv env, Path target, Path icon) throws IOException { } }; - var absIcon = Optional.ofNullable(icon).map(Path::toAbsolutePath).orElse( - null); + final var absIcon = Optional.ofNullable(icon) + .map(Path::toAbsolutePath) + .map(ShortPathUtils::adjustPath) + .orElse(null); if (absIcon == null) { rebrandExecutable(env, target, versionSwapper); } else { @@ -118,7 +112,7 @@ void execute(BuildEnv env, Path target, Path icon) throws IOException { } private static void rebrandExecutable(BuildEnv env, - final Path target, UpdateResourceAction action) throws IOException { + final Path target, UpdateResourceAction ... actions) throws IOException { try { String tempDirectory = env.buildRoot().toAbsolutePath().toString(); if (WindowsDefender.isThereAPotentialWindowsDefenderIssue( @@ -200,12 +194,12 @@ private static String[] toStringArray( } } - private static void iconSwapWrapper(long resourceLock, - String iconTarget) { - iconTarget = adjustPath(iconTarget); - if (iconSwap(resourceLock, iconTarget) != 0) { - throw new RuntimeException(MessageFormat.format(I18N.getString( - "error.icon-swap"), iconTarget)); + private static void validateValueAndPut(Map target, + Map.Entry e, String label) { + if (e.getValue().contains("\r") || e.getValue().contains("\n")) { + Log.error("Configuration parameter " + label + + " contains multiple lines of text, ignore it"); + e = Map.entry(e.getKey(), ""); } target.put(e.getKey(), e.getValue()); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index d094c536708f4..d19bbd2ce37ab 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -344,17 +344,12 @@ private Path buildMSI(BuildEnv env, WinMsiPackage pkg, Log.verbose(I18N.format("message.preparing-msi-config", msiOut.toAbsolutePath())); - Log.verbose(MessageFormat.format(I18N.getString( - "message.preparing-msi-config"), msiOut.toAbsolutePath() - .toString())); + final var wixObjDir = env.buildRoot().resolve("wixobj"); - var wixObjDir = TEMP_ROOT.fetchFrom(params).resolve("wixobj"); - - var wixPipeline = WixPipeline.build() + final var wixPipeline = WixPipeline.build() .setWixObjDir(wixObjDir) - .setWorkDir(WIN_APP_IMAGE.fetchFrom(params)) - .addSource(CONFIG_ROOT.fetchFrom(params).resolve("main.wxs"), - wixVars); + .setWorkDir(env.appImageDir()) + .addSource(env.configDir().resolve("main.wxs"), wixVars); for (var wixFragment : wixFragments) { wixFragment.configureWixPipeline(wixPipeline); @@ -495,16 +490,16 @@ private static String getCultureFromWxlFile(Path wxlPath) throws IOException { NodeList nodes = (NodeList) xPath.evaluate( "//WixLocalization/@Culture", doc, XPathConstants.NODESET); if (nodes.getLength() != 1) { - throw new IOException(MessageFormat.format(I18N.getString( - "error.extract-culture-from-wix-l10n-file"), + throw new IOException(I18N.format( + "error.extract-culture-from-wix-l10n-file", wxlPath.toAbsolutePath().normalize())); } return nodes.item(0).getNodeValue(); } catch (XPathExpressionException | ParserConfigurationException | SAXException ex) { - throw new IOException(MessageFormat.format(I18N.getString( - "error.read-wix-l10n-file"), wxlPath.toAbsolutePath().normalize()), ex); + throw new IOException(I18N.format("error.read-wix-l10n-file", + wxlPath.toAbsolutePath().normalize()), ex); } } From 88d2f9bd02f3183a0dcb5dbb267c036fc7cc4865 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 23 Dec 2024 16:07:55 -0500 Subject: [PATCH 0192/1101] Minor --- .../jdk/jpackage/internal/model/LauncherStartupInfo.java | 2 +- .../jdk/jpackage/internal/model/StandardPackageType.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java index acd7257f29066..312e3d20e6994 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java @@ -44,7 +44,7 @@ default String packageName() { List defaultParameters(); /** - * Returns list of paths to add to the classath. + * Returns list of paths to add to the classpath. * * Every path in the list is relative to app's main source directory. * diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java index eb026b408cfe7..590d3d502b2ff 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java @@ -47,6 +47,7 @@ public static StandardPackageType fromCmdLineType(String type) { return pt.suffix().substring(1).equals(type); }).findAny().get(); } - final String suffix; + + private final String suffix; } From 302c9aece6e4c08a02217bba5bb6bdb32365e3b2 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 23 Dec 2024 17:24:18 -0500 Subject: [PATCH 0193/1101] Convert to JUnit5 format --- .../internal/model/ApplicationLayoutTest.java | 29 +++++++++---------- .../internal/util/CompositeProxyTest.java | 5 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java index 871756295008d..fc1275d0ace7a 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java @@ -25,22 +25,20 @@ import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; import java.util.stream.Stream; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; public class ApplicationLayoutTest { - @Rule - public final TemporaryFolder tempFolder = new TemporaryFolder(); - - public void test(boolean move) throws IOException { - final var srcAppImageRoot = tempFolder.newFolder("src").toPath(); + public void test(boolean move, Path tempDir) throws IOException { + final var srcAppImageRoot = tempDir.resolve("src"); + Files.createDirectories(srcAppImageRoot); final var appImageCopyFiles = List.of("bin/Foo", "lib/app/Foo.cfg", "lib/app/hello.jar", "runtime/bin/java"); final var appImageCopyDirs = List.of("lib/app/hello"); @@ -63,7 +61,8 @@ public void test(boolean move) throws IOException { .runtimeDirectory("runtime") .create(); - final var dstAppImageRoot = tempFolder.newFolder("dst").toPath(); + final var dstAppImageRoot = tempDir.resolve("dst"); + Files.createDirectories(dstAppImageRoot); final var srcPathGroup = AppImageLayout.toPathGroup(layout.resolveAt(srcAppImageRoot)); final var dstPathGroup = AppImageLayout.toPathGroup(layout.resolveAt(dstAppImageRoot)); @@ -99,12 +98,12 @@ public void test(boolean move) throws IOException { } @Test - public void testMove() throws IOException { - test(true); + public void testMove(@TempDir Path tempDir) throws IOException { + test(true, tempDir); } @Test - public void testCopy() throws IOException { - test(false); + public void testCopy(@TempDir Path tempDir) throws IOException { + test(false, tempDir); } } diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java index 7154895cce427..17ff0b5b18c6f 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java @@ -22,8 +22,9 @@ */ package jdk.jpackage.internal.util; -import static org.junit.Assert.assertEquals; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; + public class CompositeProxyTest { From 4a43eb21334a250d6eee97d647c668cd51c00b5c Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 23 Dec 2024 17:25:09 -0500 Subject: [PATCH 0194/1101] Fix unit tests after merge with the master --- .../jpackage/internal/AppImageFileTest.java | 2 +- .../internal/ApplicationLayoutTest.java | 103 ------------------ .../jpackage/internal/DeployParamsTest.java | 1 + .../internal/OverridableResourceTest.java | 16 +-- .../internal/PlatformVersionTest.java | 1 + .../jpackage/internal/ToolValidatorTest.java | 8 +- .../internal/model/DottedVersionTest.java | 2 +- 7 files changed, 17 insertions(+), 116 deletions(-) delete mode 100644 test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ApplicationLayoutTest.java diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java index 64acd24040e8f..875e71593f336 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java @@ -80,7 +80,7 @@ public void testInvalidCommandLine() throws IOException { public void testInavlidXml(String[] xmlData) throws IOException { Exception ex = assertThrowsExactly(RuntimeException.class, () -> createFromXml(xmlData)); assertTrue(ex.getMessage().contains("generated by another jpackage version or malformed")); - assertTrue(ex.getMessage().endsWith(".jpackage.xml\"")); + assertTrue(ex.getMessage().endsWith(".jpackage.xml\" file")); } private static Stream testInavlidXml() { diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ApplicationLayoutTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ApplicationLayoutTest.java deleted file mode 100644 index 58bf733c85514..0000000000000 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ApplicationLayoutTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; -import static org.junit.jupiter.api.Assertions.assertTrue; - - -public class ApplicationLayoutTest { - - private Path newFolder(Path folderName, String ... extraFolderNames) throws IOException { - var path = tempFolder.resolve(folderName); - Files.createDirectories(path); - for (var extraFolderName : extraFolderNames) { - path = path.resolve(extraFolderName); - Files.createDirectories(path); - } - return path; - } - - private Path newFile(Path fileName) throws IOException { - var path = tempFolder.resolve(fileName); - Files.createDirectories(path.getParent()); - Files.createFile(path); - return path; - } - - private void fillLinuxAppImage() throws IOException { - appImage = newFolder(Path.of("Foo")); - - Path base = appImage.getFileName(); - - newFolder(base, "bin"); - newFolder(base, "lib", "app", "mods"); - newFolder(base, "lib", "runtime", "bin"); - newFile(base.resolve("bin/Foo")); - newFile(base.resolve("lib/app/Foo.cfg")); - newFile(base.resolve("lib/app/hello.jar")); - newFile(base.resolve("lib/Foo.png")); - newFile(base.resolve("lib/libapplauncher.so")); - newFile(base.resolve("lib/runtime/bin/java")); - } - - @Test - public void testLinux() throws IOException { - fillLinuxAppImage(); - testApplicationLayout(ApplicationLayout.linuxAppImage()); - } - - private void testApplicationLayout(ApplicationLayout layout) throws IOException { - ApplicationLayout srcLayout = layout.resolveAt(appImage); - assertApplicationLayout(srcLayout); - - ApplicationLayout dstLayout = layout.resolveAt( - appImage.getParent().resolve( - "Copy" + appImage.getFileName().toString())); - srcLayout.move(dstLayout); - Files.deleteIfExists(appImage); - assertApplicationLayout(dstLayout); - - dstLayout.copy(srcLayout); - assertApplicationLayout(srcLayout); - assertApplicationLayout(dstLayout); - } - - private void assertApplicationLayout(ApplicationLayout layout) throws IOException { - assertTrue(Files.isRegularFile(layout.appDirectory().resolve("Foo.cfg"))); - assertTrue(Files.isRegularFile(layout.appDirectory().resolve("hello.jar"))); - assertTrue(Files.isDirectory(layout.appModsDirectory())); - assertTrue(Files.isRegularFile(layout.launchersDirectory().resolve("Foo"))); - assertTrue(Files.isRegularFile(layout.destktopIntegrationDirectory().resolve("Foo.png"))); - assertTrue(Files.isRegularFile(layout.runtimeDirectory().resolve("bin/java"))); - } - - @TempDir - private Path tempFolder; - private Path appImage; -} diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java index e4db8f5c0a5da..5cd96e373bea0 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java @@ -22,6 +22,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.PackagerException; import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java index a45d6e8c5a36b..6a84c8ea354f8 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java @@ -97,7 +97,7 @@ private static List data() { public void testDefault(Path dstPath, boolean dstFileOverwrite, @TempDir Path tempFolder) throws IOException { final String[] content = saveResource( - new OverridableResource(DEFAULT_NAME), tempFolder.resolve( + new OverridableResource(DEFAULT_NAME, ResourceLocator.class), tempFolder.resolve( dstPath), dstFileOverwrite); try (var resource = ResourceLocator.class.getResourceAsStream(DEFAULT_NAME); @@ -117,7 +117,7 @@ public void testDefaultWithSubstitution(Path dstPath, boolean dstFileOverwrite, "Substitution map should contain only a single entry"); } - OverridableResource resource = new OverridableResource(DEFAULT_NAME); + OverridableResource resource = new OverridableResource(DEFAULT_NAME, ResourceLocator.class); var linesBeforeSubstitution = List.of(saveResource(resource, tempFolder.resolve(dstPath), dstFileOverwrite)); @@ -170,7 +170,7 @@ public void testResourceDir(ResourceName defaultName, Path dstPath, Files.write(customFile, expectedResourceData); final var actualResourceData = saveResource(buildResourceWriter( - new OverridableResource(defaultName.value) + new OverridableResource(defaultName.value, ResourceLocator.class) .setPublicName(customFile.getFileName()) .setResourceDir(customFile.getParent()) ).dstFileOverwrite(dstFileOverwrite).expectedSource(ResourceDir), @@ -199,7 +199,7 @@ public void testResourceDirWithSubstitution(ResourceName defaultName, Path dstPa "Bar", "Bar", "Goodbye", "JJ"); final var actualResourceData = saveResource(buildResourceWriter( - new OverridableResource(defaultName.value) + new OverridableResource(defaultName.value, ResourceLocator.class) .setSubstitutionData(substitutionData) .setPublicName(customFile.getFileName()) .setResourceDir(customFile.getParent()) @@ -221,7 +221,7 @@ public void testPublicNameNotSet(boolean namesMatch, @TempDir Path tempFolder) t final Path outputDir = tempFolder.resolve("output"); var resourceWriter = buildResourceWriter( - new OverridableResource(null).setResourceDir(customFile.getParent())); + new OverridableResource().setResourceDir(customFile.getParent())); if (namesMatch) { final var actualResourceData = resourceWriter @@ -244,7 +244,7 @@ public void testSubstitutionDataCopied(@TempDir Path tempFolder) throws IOExcept final Map substitutionData = new HashMap<>(Map.of("Hello", "Goodbye")); - var resource = new OverridableResource(null) + var resource = new OverridableResource() .setSubstitutionData(substitutionData) .setPublicName(customFile.getFileName()) .setResourceDir(customFile.getParent()); @@ -265,7 +265,7 @@ public void testSubstitutionDataCopied(@TempDir Path tempFolder) throws IOExcept @Test public void testNoDefault(@TempDir Path tempFolder) throws IOException { - var resourceWriter = buildResourceWriter(new OverridableResource(null)).expectedSource(null); + var resourceWriter = buildResourceWriter(new OverridableResource()).expectedSource(null); assertEquals(null, resourceWriter.saveInDir(tempFolder)); var dstDir = tempFolder.resolve("foo"); @@ -275,7 +275,7 @@ public void testNoDefault(@TempDir Path tempFolder) throws IOException { enum ResourceName { DEFAULT_NAME(OverridableResourceTest.DEFAULT_NAME), - NULL_NAME(null); + NO_NAME(""); ResourceName(String value) { this.value = value; diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java index 21aea35220b85..b5cd1f60f353a 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java @@ -22,6 +22,7 @@ */ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.DottedVersion; import java.lang.reflect.InvocationTargetException; import java.util.function.Function; import java.lang.reflect.Method; diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java index 9731deafe0217..51e51579adbfd 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java @@ -23,6 +23,8 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.DottedVersion; +import jdk.jpackage.internal.model.ConfigException; import java.nio.file.Path; import jdk.internal.util.OperatingSystem; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -52,11 +54,11 @@ public void testVersionParserUsage() { // Minimal version is 1, actual is 10. Should be OK. assertNull(new ToolValidator(TOOL_JAVA).setMinimalVersion( - new DottedVersion("1")).setVersionParser(unused -> "10").validate()); + DottedVersion.greedy("1")).setVersionParser(unused -> "10").validate()); // Minimal version is 5, actual is 4.99.37. Error expected. assertValidationFailure(new ToolValidator(TOOL_JAVA).setMinimalVersion( - new DottedVersion("5")).setVersionParser(unused -> "4.99.37").validate(), + DottedVersion.greedy("5")).setVersionParser(unused -> "4.99.37").validate(), false); // Minimal version is 8, actual is 10, lexicographical comparison is used. Error expected. @@ -65,7 +67,7 @@ public void testVersionParserUsage() { // Minimal version is 8, actual is 10, Use DottedVersion class for comparison. Should be OK. assertNull(new ToolValidator(TOOL_JAVA).setMinimalVersion( - new DottedVersion("8")).setVersionParser(unused -> "10").validate()); + DottedVersion.greedy("8")).setVersionParser(unused -> "10").validate()); } private static void assertValidationFailure(ConfigException v, boolean withCause) { diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java index 6f3d709a964ef..b8536c5b13332 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java @@ -115,7 +115,7 @@ private static List testValid() { @ParameterizedTest @MethodSource public void testInvalid(String str) { - assertThrowsExactly(IllegalArgumentException.class, () -> new DottedVersion(str)); + assertThrowsExactly(IllegalArgumentException.class, () -> DottedVersion.greedy(str)); } private static Stream testInvalid() { From f7f85412a08f83722f8ba42e46d1a27e3fde03ef Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 30 Dec 2024 13:56:34 -0500 Subject: [PATCH 0195/1101] Fix WinResourceTest to make it work with WiX v4.0+ --- test/jdk/tools/jpackage/windows/WinResourceTest.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/jdk/tools/jpackage/windows/WinResourceTest.java b/test/jdk/tools/jpackage/windows/WinResourceTest.java index 72e805d0a48b5..5b35a469d2d5b 100644 --- a/test/jdk/tools/jpackage/windows/WinResourceTest.java +++ b/test/jdk/tools/jpackage/windows/WinResourceTest.java @@ -30,6 +30,8 @@ import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Annotations.Parameters; import java.util.List; +import static jdk.jpackage.test.WindowsHelper.WixType.WIX3; +import static jdk.jpackage.test.WindowsHelper.getWixTypeFromVerboseJPackageOutput; /** * Test --resource-dir option. The test should set --resource-dir to point to @@ -83,11 +85,18 @@ public void test() throws IOException { .addBundleVerifier((cmd, result) -> { // Assert jpackage picked custom main.wxs and failed as expected by // examining its output + final String expectedWixErrorMsg; + if (getWixTypeFromVerboseJPackageOutput(result) == WIX3) { + expectedWixErrorMsg = "error CNDL0104 : Not a valid source file"; + } else { + expectedWixErrorMsg = "error WIX0104: Not a valid source file"; + } + TKit.assertTextStream(expectedLogMessage) .predicate(String::startsWith) .apply(JPackageCommand.stripTimestamps( result.getOutput().stream())); - TKit.assertTextStream("error CNDL0104 : Not a valid source file") + TKit.assertTextStream(expectedWixErrorMsg) .apply(result.getOutput().stream()); }) .setExpectedExitCode(1) From fdce348040cfaa70a415d1297c47435586379cbd Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 30 Dec 2024 13:58:51 -0500 Subject: [PATCH 0196/1101] Shorten names of variants of packages created by the WinInstallerUiTest test to avoid test failures when the test output directory is long enough that some paths exceed 260 characters. --- test/jdk/tools/jpackage/windows/WinInstallerUiTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/jdk/tools/jpackage/windows/WinInstallerUiTest.java b/test/jdk/tools/jpackage/windows/WinInstallerUiTest.java index c6489ab68cf4c..b005aa82e5fc5 100644 --- a/test/jdk/tools/jpackage/windows/WinInstallerUiTest.java +++ b/test/jdk/tools/jpackage/windows/WinInstallerUiTest.java @@ -122,13 +122,13 @@ private void setPackageName(JPackageCommand cmd) { StringBuilder sb = new StringBuilder(cmd.name()); sb.append("With"); if (withDirChooser) { - sb.append("DirChooser"); + sb.append("Dc"); // DirChooser } if (withShortcutPrompt) { - sb.append("ShortcutPrompt"); + sb.append("Sp"); // ShortcutPrompt } if (withLicense) { - sb.append("License"); + sb.append("L"); // License } cmd.setArgumentValue("--name", sb.toString()); } From f5548614ec4f6cd5ad2893c598abb5807a386e1b Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 30 Dec 2024 14:03:16 -0500 Subject: [PATCH 0197/1101] Skip the RuntimeImageSymbolicLinksTest test on Windows when it is executed outside of jtreg. This is shared test and applies to multiple platforms but Windows. --- .../tools/jpackage/share/RuntimeImageSymbolicLinksTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java b/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java index db74e3456c4ee..2ab3eecca76c4 100644 --- a/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java +++ b/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java @@ -23,6 +23,7 @@ import java.nio.file.Files; import java.nio.file.Path; +import static jdk.internal.util.OperatingSystem.WINDOWS; import jdk.jpackage.test.ApplicationLayout; import jdk.jpackage.test.TKit; import jdk.jpackage.test.Annotations.Test; @@ -49,7 +50,7 @@ public class RuntimeImageSymbolicLinksTest { - @Test + @Test(ifNotOS = WINDOWS) public static void test() throws Exception { final Path jmods = Path.of(System.getProperty("java.home"), "jmods"); final Path workDir = TKit.createTempDirectory("runtime").resolve("data"); From 8ca4d3f7b1d5133e36722e1e79022810704b9e30 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 30 Dec 2024 14:07:59 -0500 Subject: [PATCH 0198/1101] Fix JPackageCommand.ignoreFakeRuntime() to test externally supplied runtime instead of the runtime configured for the current jpackage command line. --- .../helpers/jdk/jpackage/test/JPackageCommand.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index f4f782e395a9c..aac88d790c0a2 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -593,7 +593,7 @@ public Path appLauncherCfgPath(String launcherName) { } public boolean isFakeRuntime(String msg) { - if (isFakeRuntime()) { + if (isFakeRuntime(appRuntimeDirectory())) { // Fake runtime Path runtimeDir = appRuntimeDirectory(); TKit.trace(String.format( @@ -604,7 +604,7 @@ public boolean isFakeRuntime(String msg) { return false; } - private boolean isFakeRuntime() { + private static boolean isFakeRuntime(Path runtimeDir) { final Collection criticalRuntimeFiles; if (TKit.isWindows()) { criticalRuntimeFiles = WindowsHelper.CRITICAL_RUNTIME_FILES; @@ -616,7 +616,6 @@ private boolean isFakeRuntime() { throw TKit.throwUnknownPlatformError(); } - Path runtimeDir = appRuntimeDirectory(); return !criticalRuntimeFiles.stream().map(runtimeDir::resolve).allMatch( Files::exists); } @@ -690,10 +689,8 @@ public JPackageCommand ignoreDefaultRuntime(boolean v) { } public JPackageCommand ignoreFakeRuntime() { - if (isFakeRuntime()) { - ignoreDefaultRuntime(true); - } - return this; + return ignoreDefaultRuntime(Optional.ofNullable(DEFAULT_RUNTIME_IMAGE) + .map(JPackageCommand::isFakeRuntime).orElse(false)); } public JPackageCommand ignoreDefaultVerbose(boolean v) { From 2f6dae40913ec0906370df1e3154fc69ff121e64 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 30 Dec 2024 14:28:32 -0500 Subject: [PATCH 0199/1101] - Don't exclude the "PATH" var from the environment when running app launchers in jpackage tests. Removal of the "PATH" var was a part of the JDK-8254920 fix. But this removal is redundant as JDK-8254920 was fixed by making jpackage app launcher not to look up for dll-s in the PATH. There are a few jpackage tests running app launchers without removing the PATH var from the environment - WinChildProcessTest, AppLauncherEnvTest. They proves that removal of the "PATH" var from the environment when testing app launchers is redundant. - Add support to remove any var from the environment in Executor class. - Add support for boolean property 'jpackage.test.clear-app-launcher-java-env-vars'. If set to true, "JAVA_TOOL_OPTIONS" and "_JAVA_OPTIONS" will be removed from the environment when running app launchers. This is needed to support local jpackage test configurations when JRE used to run jpackage tests relies on these variables, but they should not be applied to runtimes of app launchers. --- .../helpers/jdk/jpackage/test/Executor.java | 17 +++++++++-------- .../helpers/jdk/jpackage/test/HelloApp.java | 19 +++++++++++++++---- .../jpackage/share/AppLauncherEnvTest.java | 4 +++- .../jpackage/windows/WinChildProcessTest.java | 6 ++++-- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index 7a0878d826b43..d3240a301bc9f 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -53,7 +53,6 @@ public static Executor of(String... cmdline) { public Executor() { saveOutputType = new HashSet<>(Set.of(SaveOutputType.NONE)); - removePathEnvVar = false; winEnglishOutput = false; } @@ -86,8 +85,8 @@ public Executor setExecutable(JavaTool v) { return setExecutable(v.getPath()); } - public Executor setRemovePathEnvVar(boolean value) { - removePathEnvVar = value; + public Executor removeEnvVar(String envVarName) { + removeEnvVars.add(Objects.requireNonNull(envVarName)); return this; } @@ -372,10 +371,12 @@ private Result runExecutable() throws IOException, InterruptedException { builder.directory(directory.toFile()); sb.append(String.format("; in directory [%s]", directory)); } - if (removePathEnvVar) { - // run this with cleared Path in Environment - TKit.trace("Clearing PATH in environment"); - builder.environment().remove("PATH"); + if (!removeEnvVars.isEmpty()) { + final var envComm = Comm.compare(builder.environment().keySet(), removeEnvVars); + builder.environment().keySet().removeAll(envComm.common()); + envComm.common().forEach(envVar -> { + TKit.trace(String.format("Clearing %s in environment", envVar)); + }); } trace("Execute " + sb.toString() + "..."); @@ -504,7 +505,7 @@ private static void trace(String msg) { private Path executable; private Set saveOutputType; private Path directory; - private boolean removePathEnvVar; + private Set removeEnvVars = new HashSet<>(); private boolean winEnglishOutput; private String winTmpDir = null; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java index 0c7476e863dc4..359a6c2fb6ce3 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java @@ -472,14 +472,14 @@ private Executor getExecutor(String...args) { } } - final List launcherArgs = List.of(args); - return new Executor() + final var executor = new Executor() .setDirectory(outputFile.getParent()) .saveOutput(saveOutput) .dumpOutput() - .setRemovePathEnvVar(removePathEnvVar) .setExecutable(executablePath) - .addArguments(launcherArgs); + .addArguments(List.of(args)); + + return configureEnvironment(executor); } private boolean launcherNoExit; @@ -496,6 +496,14 @@ public static AppOutputVerifier assertApp(Path helloAppLauncher) { return new AppOutputVerifier(helloAppLauncher); } + public static Executor configureEnvironment(Executor executor) { + if (CLEAR_JAVA_ENV_VARS) { + executor.removeEnvVar("JAVA_TOOL_OPTIONS"); + executor.removeEnvVar("_JAVA_OPTIONS"); + } + return executor; + } + static final String OUTPUT_FILENAME = "appOutput.txt"; private final JavaAppDesc appDesc; @@ -505,4 +513,7 @@ public static AppOutputVerifier assertApp(Path helloAppLauncher) { private static final String CLASS_NAME = HELLO_JAVA.getFileName().toString().split( "\\.", 2)[0]; + + private static final boolean CLEAR_JAVA_ENV_VARS = Optional.ofNullable( + TKit.getConfigProperty("clear-app-launcher-java-env-vars")).map(Boolean::parseBoolean).orElse(false); } diff --git a/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java b/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java index a16ff9c18f96d..61ed679c29149 100644 --- a/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java +++ b/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java @@ -30,6 +30,7 @@ import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Executor; +import static jdk.jpackage.test.HelloApp.configureEnvironment; import jdk.jpackage.test.TKit; /** @@ -53,6 +54,7 @@ public static void test() throws Exception { JPackageCommand cmd = JPackageCommand .helloAppImage(TEST_APP_JAVA + "*Hello") + .ignoreFakeRuntime() .addArguments("--java-options", "-D" + testAddDirProp + "=$APPDIR"); @@ -62,7 +64,7 @@ public static void test() throws Exception { final int attempts = 3; final int waitBetweenAttemptsSeconds = 5; - List output = new Executor() + List output = configureEnvironment(new Executor()) .saveOutput() .setExecutable(cmd.appLauncherPath().toAbsolutePath()) .addArguments("--print-env-var=" + envVarName) diff --git a/test/jdk/tools/jpackage/windows/WinChildProcessTest.java b/test/jdk/tools/jpackage/windows/WinChildProcessTest.java index 5565d3dc50352..b46f84f8c48bb 100644 --- a/test/jdk/tools/jpackage/windows/WinChildProcessTest.java +++ b/test/jdk/tools/jpackage/windows/WinChildProcessTest.java @@ -40,6 +40,7 @@ import java.nio.file.Path; import jdk.jpackage.test.JPackageCommand; +import static jdk.jpackage.test.HelloApp.configureEnvironment; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Executor; import jdk.jpackage.test.TKit; @@ -54,14 +55,15 @@ public static void test() { long childPid = 0; try { JPackageCommand cmd = JPackageCommand - .helloAppImage(TEST_APP_JAVA + "*Hello"); + .helloAppImage(TEST_APP_JAVA + "*Hello") + .ignoreFakeRuntime(); // Create the image of the third party application launcher cmd.executeAndAssertImageCreated(); // Start the third party application launcher and dump and save the // output of the application - List output = new Executor().saveOutput().dumpOutput() + List output = configureEnvironment(new Executor()).saveOutput().dumpOutput() .setExecutable(cmd.appLauncherPath().toAbsolutePath()) .execute(0).getOutput(); String pidStr = output.get(0); From 4000f5a6f37f5d5ab82b4701f0ac7664c2ec4386 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 31 Dec 2024 10:09:33 -0500 Subject: [PATCH 0200/1101] Remove redundant IOException from the "throws" list --- .../classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java index febe0b9126d80..885d367b7d759 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java @@ -62,7 +62,7 @@ private JLinkRuntimeBuilder(List jlinkCmdLine) { } @Override - public void createRuntime(AppImageLayout appImageLayout) throws PackagerException, IOException { + public void createRuntime(AppImageLayout appImageLayout) throws PackagerException { var args = new ArrayList(); args.add("--output"); args.add(appImageLayout.runtimeDirectory().toString()); From 74adf7d30c5a4eca0beba5c938971ab2c5e0cb65 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 31 Dec 2024 10:11:55 -0500 Subject: [PATCH 0201/1101] Convert IOException into UncheckedIOException --- .../internal/RuntimeBuilderBuilder.java | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java index 60384ed7476cd..5f91c73fa9244 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal; +import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; @@ -110,21 +112,25 @@ private static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, } return appImageLayout -> { - // copy whole runtime, need to skip jmods and src.zip - final List excludes = List.of(Path.of("jmods"), Path.of("src.zip")); - FileUtils.copyRecursive(runtimeDir, - appImageLayout.runtimeDirectory(), - excludes, - LinkOption.NOFOLLOW_LINKS); - - // if module-path given - copy modules to appDir/mods - List defaultModulePath = getDefaultModulePath(); - Path dest = ((ApplicationLayout)appImageLayout).appModsDirectory(); - - for (Path mp : modulePath) { - if (!defaultModulePath.contains(mp.toAbsolutePath())) { - FileUtils.copyRecursive(mp, dest); + try { + // copy whole runtime, need to skip jmods and src.zip + final List excludes = List.of(Path.of("jmods"), Path.of("src.zip")); + FileUtils.copyRecursive(runtimeDir, + appImageLayout.runtimeDirectory(), + excludes, + LinkOption.NOFOLLOW_LINKS); + + // if module-path given - copy modules to appDir/mods + List defaultModulePath = getDefaultModulePath(); + Path dest = ((ApplicationLayout)appImageLayout).appModsDirectory(); + + for (Path mp : modulePath) { + if (!defaultModulePath.contains(mp.toAbsolutePath())) { + FileUtils.copyRecursive(mp, dest); + } } + } catch (IOException ex) { + throw new UncheckedIOException(ex); } }; } From c1b03610206bc2bd5809bda87a409e2452e1b72f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 31 Dec 2024 10:12:23 -0500 Subject: [PATCH 0202/1101] Comment fixed --- .../classes/jdk/jpackage/internal/model/AppImageLayout.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java index 9740b302f66e5..203ac04109613 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java @@ -42,7 +42,7 @@ public interface AppImageLayout { /** - * Path to Java run-time directory. + * Path to Java runtime directory. */ Path runtimeDirectory(); From bc280940b81578ad15d849c24a982ac4c73d38e8 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 31 Dec 2024 10:12:44 -0500 Subject: [PATCH 0203/1101] Code reformatted --- .../jdk/jpackage/internal/model/AppImagePackageType.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java index 780ae873d5640..87ec04bf84f26 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java @@ -22,13 +22,11 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.jpackage.internal.model; - public final class AppImagePackageType implements PackageType { - private AppImagePackageType() { + private AppImagePackageType() { } public final static AppImagePackageType APP_IMAGE = new AppImagePackageType(); From 991cc3d8aae18d227bff2672a058ede7b17cb820 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 31 Dec 2024 10:41:30 -0500 Subject: [PATCH 0204/1101] Remove IOException from the "throws" list of RuntimeBuilder.createRuntime() --- .../classes/jdk/jpackage/internal/model/RuntimeBuilder.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java index f4cf57b515716..6de783f72c571 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java @@ -24,13 +24,12 @@ */ package jdk.jpackage.internal.model; -import java.io.IOException; import java.nio.file.Path; import java.util.List; public interface RuntimeBuilder { - public void createRuntime(AppImageLayout appImageLayout) throws PackagerException, IOException; + void createRuntime(AppImageLayout appImageLayout) throws PackagerException; public static List getDefaultModulePath() { return List.of( From 24e4afdd3f201a9559c3bfadbbb47266fb99e203 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 31 Dec 2024 10:43:09 -0500 Subject: [PATCH 0205/1101] Added Objects.requireNonNull() to StandardPackageType.fromCmdLineType() --- .../jdk/jpackage/internal/model/StandardPackageType.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java index 590d3d502b2ff..bdf20b4e44e63 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal.model; +import java.util.Objects; import java.util.stream.Stream; public enum StandardPackageType implements PackageType { @@ -43,6 +44,7 @@ public String suffix() { } public static StandardPackageType fromCmdLineType(String type) { + Objects.requireNonNull(type); return Stream.of(values()).filter(pt -> { return pt.suffix().substring(1).equals(type); }).findAny().get(); From 81f4e42c891e2eea3701e8509722f705cbbe7e4a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 3 Jan 2025 13:35:17 -0500 Subject: [PATCH 0206/1101] Add annotations to test cases in LicenseTest --- .../jdk/tools/jpackage/share/LicenseTest.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/test/jdk/tools/jpackage/share/LicenseTest.java b/test/jdk/tools/jpackage/share/LicenseTest.java index b0eef94fa7c57..e0de3f85deede 100644 --- a/test/jdk/tools/jpackage/share/LicenseTest.java +++ b/test/jdk/tools/jpackage/share/LicenseTest.java @@ -29,6 +29,8 @@ import java.util.Arrays; import java.util.function.Function; import java.util.stream.Collectors; +import static jdk.internal.util.OperatingSystem.LINUX; +import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.PackageType; import jdk.jpackage.test.PackageTest; @@ -67,6 +69,7 @@ * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @compile LicenseTest.java + * @requires (jpackage.test.SQETest != null) * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main * --jpt-run=LicenseTest.testCommon */ @@ -78,18 +81,14 @@ * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @compile LicenseTest.java - * @requires (os.family == "linux") * @requires (jpackage.test.SQETest == null) * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main - * --jpt-run=LicenseTest.testCustomDebianCopyright - * --jpt-run=LicenseTest.testCustomDebianCopyrightSubst - * --jpt-run=LicenseTest.testLinuxLicenseInUsrTree - * --jpt-run=LicenseTest.testLinuxLicenseInUsrTree2 - * --jpt-run=LicenseTest.testLinuxLicenseInUsrTree3 - * --jpt-run=LicenseTest.testLinuxLicenseInUsrTree4 + * --jpt-run=LicenseTest */ public class LicenseTest { + + @Test public static void testCommon() { PackageTest test = new PackageTest().configureHelloApp() .addInitializer(cmd -> { @@ -102,26 +101,32 @@ public static void testCommon() { test.run(); } + @Test(ifOS = LINUX) public static void testLinuxLicenseInUsrTree() { testLinuxLicenseInUsrTree("/usr"); } + @Test(ifOS = LINUX) public static void testLinuxLicenseInUsrTree2() { testLinuxLicenseInUsrTree("/usr/local"); } + @Test(ifOS = LINUX) public static void testLinuxLicenseInUsrTree3() { testLinuxLicenseInUsrTree("/usr/foo"); } + @Test(ifOS = LINUX) public static void testLinuxLicenseInUsrTree4() { testLinuxLicenseInUsrTree("/usrbuz"); } + @Test(ifOS = LINUX) public static void testCustomDebianCopyright() { new CustomDebianCopyrightTest().run(); } + @Test(ifOS = LINUX) public static void testCustomDebianCopyrightSubst() { new CustomDebianCopyrightTest().withSubstitution(true).run(); } From 541d9f10eb2ce4cd0a489d2f3fc85bc8833e2420 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 3 Jan 2025 13:36:14 -0500 Subject: [PATCH 0207/1101] Use java.util.Optional in model interfaces. Use UncheckedIOException where appropriate. --- .../jpackage/internal/DesktopIntegration.java | 90 +++++++++---------- .../internal/LinuxAppImageBuilder.java | 12 ++- .../jpackage/internal/LinuxDebBundler.java | 4 +- .../internal/LinuxLaunchersAsServices.java | 5 +- .../internal/LinuxPackageBuilder.java | 11 ++- .../internal/LinuxPackageBundler.java | 11 ++- .../jpackage/internal/LinuxRpmBundler.java | 4 +- .../internal/model/LinuxLauncher.java | 5 -- .../jpackage/internal/model/LinuxPackage.java | 25 +++--- .../internal/model/LinuxPackageMixin.java | 6 +- .../internal/MacAppImageBuilder2.java | 16 ++-- .../internal/MacLaunchersAsServices.java | 3 +- .../internal/AbstractAppImageBuilder.java | 3 +- .../jpackage/internal/AppImageBuilder.java | 73 +++++++-------- .../jdk/jpackage/internal/AppImageFile2.java | 17 ++-- .../jpackage/internal/ApplicationBuilder.java | 3 +- .../jdk/jpackage/internal/BuildEnv.java | 14 +-- .../jpackage/internal/BuildEnvBuilder.java | 4 +- .../jdk/jpackage/internal/CfgFile.java | 2 +- .../internal/FileAssociationGroup.java | 13 ++- .../jdk/jpackage/internal/FromParams.java | 4 +- .../jpackage/internal/LauncherBuilder.java | 35 +++++--- .../jpackage/internal/LauncherFromParams.java | 38 +++++++- .../jdk/jpackage/internal/PackageBuilder.java | 6 +- .../jpackage/internal/model/Application.java | 25 +++--- .../internal/model/ApplicationLaunchers.java | 21 ++--- .../internal/model/ApplicationLayout.java | 9 ++ .../internal/model/CustomLauncherIcon.java | 50 +++++++++++ .../internal/model/DefaultLauncherIcon.java | 40 +++++++++ .../internal/model/FileAssociation.java | 13 ++- .../jdk/jpackage/internal/model/Launcher.java | 43 +++++---- .../jpackage/internal/model/LauncherIcon.java | 28 ++++++ .../jdk/jpackage/internal/model/Package.java | 67 +++++++------- .../internal/ExecutableRebrander.java | 43 +++++---- .../jpackage/internal/WinAppImageBuilder.java | 20 +++-- .../internal/WinExePackageBuilder.java | 7 +- .../jdk/jpackage/internal/WinMsiBundler.java | 52 ++++++----- .../internal/WinMsiPackageBuilder.java | 6 +- .../internal/WixAppImageFragmentBuilder.java | 16 ++-- .../internal/WixUiFragmentBuilder.java | 5 +- .../internal/model/WinExePackage.java | 3 +- .../internal/model/WinExePackageMixin.java | 5 +- .../jpackage/internal/model/WinLauncher.java | 9 +- .../internal/model/WinMsiPackageMixin.java | 11 +-- 44 files changed, 548 insertions(+), 329 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/CustomLauncherIcon.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DefaultLauncherIcon.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 55e16e84e165b..11b8185d9925b 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -81,13 +81,13 @@ private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launche var curIconResource = createLauncherIconResource(pkg.app(), launcher, env::createResource); - if (curIconResource == null) { + + if (curIconResource.isEmpty()) { // This is additional launcher with explicit `no icon` configuration. withDesktopFile = false; } else { final Path nullPath = null; - if (curIconResource.saveToFile(nullPath) - != OverridableResource.Source.DefaultResource) { + if (curIconResource.get().saveToFile(nullPath) != OverridableResource.Source.DefaultResource) { // This launcher has custom icon configured. withDesktopFile = true; } @@ -110,23 +110,23 @@ private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launche mimeInfoFile = createDesktopFile(mimeInfoFileName); if (withDesktopFile) { - desktopFile = createDesktopFile(desktopFileName); - iconFile = createDesktopFile(escapedAppFileName + ".png"); + desktopFile = Optional.of(createDesktopFile(desktopFileName)); + iconFile = Optional.of(createDesktopFile(escapedAppFileName + ".png")); - if (curIconResource == null) { + if (curIconResource.isEmpty()) { // Create default icon. - curIconResource = createLauncherIconResource(pkg.app(), pkg.app().mainLauncher(), env::createResource); + curIconResource = createLauncherIconResource(pkg.app(), pkg.app().mainLauncher().orElseThrow(), env::createResource); } } else { - desktopFile = null; - iconFile = null; + desktopFile = Optional.empty(); + iconFile = Optional.empty(); } iconResource = curIconResource; desktopFileData = createDataForDesktopFile(); - if (launcher != pkg.app().mainLauncher()) { + if (launcher != pkg.app().mainLauncher().orElseThrow()) { nestedIntegrations = List.of(); } else { nestedIntegrations = pkg.app().additionalLaunchers().stream().map(v -> { @@ -144,7 +144,7 @@ static ShellCustomAction create(BuildEnv env, Package pkg) throws IOException { return ShellCustomAction.nop(REPLACEMENT_STRING_IDS); } return new DesktopIntegration(env, (LinuxPackage) pkg, - (LinuxLauncher) pkg.app().mainLauncher()); + (LinuxLauncher) pkg.app().mainLauncher().orElseThrow()); } @Override @@ -161,15 +161,15 @@ protected List replacementStringIds() { @Override protected Map createImpl() throws IOException { - if (iconFile != null) { + if (iconFile.isPresent()) { // Create application icon file. - iconResource.saveToFile(iconFile.srcPath()); + iconResource.orElseThrow().saveToFile(iconFile.orElseThrow().srcPath()); } Map data = new HashMap<>(desktopFileData); final ShellCommands shellCommands; - if (desktopFile != null) { + if (desktopFile.isPresent()) { // Create application desktop description file. saveDesktopFile(data); @@ -221,21 +221,18 @@ protected Map createImpl() throws IOException { } private List requiredPackagesSelf() { - if (desktopFile != null) { - return List.of("xdg-utils"); - } - return Collections.emptyList(); + return desktopFile.map(file -> List.of("xdg-utils")).orElseGet(Collections::emptyList); } private Map createDataForDesktopFile() { Map data = new HashMap<>(); data.put("APPLICATION_NAME", launcher.name()); data.put("APPLICATION_DESCRIPTION", launcher.description()); - data.put("APPLICATION_ICON", Optional.ofNullable(iconFile).map( + data.put("APPLICATION_ICON", iconFile.map( f -> f.installPath().toString()).orElse(null)); - data.put("DEPLOY_BUNDLE_CATEGORY", pkg.category()); + data.put("DEPLOY_BUNDLE_CATEGORY", pkg.menuGroupName()); data.put("APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo( - pkg.asInstalledPackageApplicationLayout().launchersDirectory().resolve( + pkg.asInstalledPackageApplicationLayout().orElseThrow().launchersDirectory().resolve( launcher.executableNameWithSuffix()).toString())); return data; @@ -250,12 +247,13 @@ private class ShellCommands { registerIconCmds = new ArrayList<>(); unregisterIconCmds = new ArrayList<>(); - registerDesktopFileCmd = String.join(" ", "xdg-desktop-menu", - "install", desktopFile.installPath().toString()); + final var desktopFileInstallPath = desktopFile.orElseThrow().installPath().toString(); + + registerDesktopFileCmd = String.join(" ", + "xdg-desktop-menu", "install", desktopFileInstallPath); unregisterDesktopFileCmd = String.join(" ", - "do_if_file_belongs_to_single_package", desktopFile. - installPath().toString(), "xdg-desktop-menu", - "uninstall", desktopFile.installPath().toString()); + "do_if_file_belongs_to_single_package", desktopFileInstallPath, + "xdg-desktop-menu", "uninstall", desktopFileInstallPath); } void setFileAssociations() { @@ -267,6 +265,8 @@ void setFileAssociations() { installPath().toString(), "xdg-mime", "uninstall", mimeInfoFile.installPath().toString()); + final var desktopFileInstallPath = desktopFile.orElseThrow().installPath(); + // // Add manual cleanup of system files to get rid of // the default mime type handlers. @@ -281,11 +281,9 @@ void setFileAssociations() { // of non-existing desktop file. // String cleanUpCommand = String.join(" ", - "do_if_file_belongs_to_single_package", desktopFile. - installPath().toString(), - "desktop_uninstall_default_mime_handler", desktopFile. - installPath().getFileName().toString(), String.join( - " ", getMimeTypeNamesFromFileAssociations())); + "do_if_file_belongs_to_single_package", desktopFileInstallPath.toString(), + "desktop_uninstall_default_mime_handler", desktopFileInstallPath.getFileName().toString(), + String.join(" ", getMimeTypeNamesFromFileAssociations())); unregisterFileAssociationsCmd = stringifyShellCommands( unregisterFileAssociationsCmd, cleanUpCommand); @@ -336,10 +334,8 @@ void applyTo(Map data) { * - installPath(): path where it should be installed by package manager; */ private InstallableFile createDesktopFile(String fileName) { - var srcPath = pkg.asPackageApplicationLayout().resolveAt(env.appImageDir()).destktopIntegrationDirectory().resolve( - fileName); - var installPath = pkg.asInstalledPackageApplicationLayout().destktopIntegrationDirectory().resolve( - fileName); + var srcPath = pkg.asPackageApplicationLayout().orElseThrow().resolveAt(env.appImageDir()).destktopIntegrationDirectory().resolve(fileName); + var installPath = pkg.asInstalledPackageApplicationLayout().orElseThrow().destktopIntegrationDirectory().resolve(fileName); return new InstallableFile(srcPath, installPath); } @@ -349,9 +345,10 @@ private void appendFileAssociation(XMLStreamWriter xml, xml.writeStartElement("mime-type"); xml.writeAttribute("type", fa.mimeType()); - if (fa.hasNonEmptyDescription()) { + final var description = fa.nonEmptyDescription().orElse(null); + if (description != null) { xml.writeStartElement("comment"); - xml.writeCharacters(fa.description()); + xml.writeCharacters(description); xml.writeEndElement(); } @@ -392,11 +389,13 @@ private void addFileAssociationIconFiles(ShellCommands shellCommands) processedMimeTypes.add(mimeType); + final var faIcon = fa.icon().orElseThrow(); + // Create icon name for mime type from mime type. var faIconFile = createDesktopFile(mimeType.replace(File.separatorChar, - '-') + PathUtils.getSuffix(fa.icon())); + '-') + PathUtils.getSuffix(faIcon)); - IOUtils.copyFile(fa.icon(), faIconFile.srcPath()); + IOUtils.copyFile(faIcon, faIconFile.srcPath()); shellCommands.addIcon(mimeType, faIconFile.installPath(), fa.iconSize()); } @@ -409,7 +408,7 @@ private void saveDesktopFile(Map data) throws IOException { // prepare desktop shortcut desktopFileResource .setSubstitutionData(data) - .saveToFile(desktopFile.srcPath()); + .saveToFile(desktopFile.orElseThrow().srcPath()); } private List getMimeTypeNamesFromFileAssociations() { @@ -463,7 +462,7 @@ static LinuxFileAssociation create(FileAssociation fa) { var iconSize = getIconSize(fa); if (iconSize <= 0) { // nullify the icon - fa = new FileAssociation.Stub(fa.description(), null, + fa = new FileAssociation.Stub(fa.description(), Optional.empty(), fa.mimeType(), fa.extension()); } return CompositeProxy.build() @@ -474,8 +473,7 @@ static LinuxFileAssociation create(FileAssociation fa) { private static int getIconSize(FileAssociation fa) { return Optional.of(fa) - .filter(FileAssociation::hasIcon) - .map(FileAssociation::icon) + .flatMap(FileAssociation::icon) .map(DesktopIntegration::getSquareSizeOfImage) .orElse(-1); } @@ -487,12 +485,12 @@ private static int getIconSize(FileAssociation fa) { private final List associations; - private final OverridableResource iconResource; + private final Optional iconResource; private final OverridableResource desktopFileResource; private final InstallableFile mimeInfoFile; - private final InstallableFile desktopFile; - private final InstallableFile iconFile; + private final Optional desktopFile; + private final Optional iconFile; private final List nestedIntegrations; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index 8d573b21489a0..d7f6bb0db3eee 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -26,6 +26,7 @@ import jdk.jpackage.internal.model.Application; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import jdk.jpackage.internal.AppImageBuilder.AppImageItemGroup; @@ -54,12 +55,15 @@ private static void writeLauncherLib(BuildEnv env, Application app, private static void writeLauncherIcons(BuildEnv env, Application app, ApplicationLayout appLayout) throws IOException { for (var launcher : app.launchers()) { - var iconResource = createLauncherIconResource(app, launcher, env::createResource); - if (iconResource != null) { + createLauncherIconResource(app, launcher, env::createResource).ifPresent(iconResource -> { String iconFileName = launcher.executableName() + ".png"; Path iconTarget = appLayout.destktopIntegrationDirectory().resolve(iconFileName); - iconResource.saveToFile(iconTarget); - } + try { + iconResource.saveToFile(iconTarget); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index 77f45a8ed4075..6fe1fe6df8a3f 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -340,7 +340,7 @@ private void prepareProjectConfig(Map data, BuildEnv env, LinuxP protected Map createReplacementData(BuildEnv env, LinuxPackage pkg) throws IOException { Map data = new HashMap<>(); - String licenseText = Optional.ofNullable(pkg.licenseFile()).map(toFunction(Files::readString)).orElse("Unknown"); + String licenseText = pkg.licenseFile().map(toFunction(Files::readString)).orElse("Unknown"); data.put("APPLICATION_MAINTAINER", ((LinuxDebPackage) pkg).maintainer()); data.put("APPLICATION_SECTION", pkg.category()); @@ -350,7 +350,7 @@ protected Map createReplacementData(BuildEnv env, LinuxPackage p data.put("APPLICATION_INSTALLED_SIZE", Long.toString( AppImageLayout.toPathGroup(pkg.packageLayout().resolveAt( env.appImageDir())).sizeInBytes() >> 10)); - data.put("APPLICATION_HOMEPAGE", Optional.ofNullable(pkg.aboutURL()).map( + data.put("APPLICATION_HOMEPAGE", pkg.aboutURL().map( value -> "Homepage: " + value).orElse("")); data.put("APPLICATION_VERSION_WITH_RELEASE", ((LinuxDebPackage) pkg).versionWithRelease()); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java index c3bbef5a5dc4a..e7b03552e60bd 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java @@ -82,9 +82,8 @@ private static class LauncherImpl extends UnixLauncherAsService { getResource().setPublicName(unitFilename).addSubstitutionDataEntry( "APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo( - pkg.asInstalledPackageApplicationLayout().resolveAt( - env.appImageDir()).launchersDirectory().resolve( - getName()).toString())); + pkg.asInstalledPackageApplicationLayout().orElseThrow().resolveAt( + env.appImageDir()).launchersDirectory().resolve(getName()).toString())); } @Override diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index 216a514b9d98f..7f5f1a116e644 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -53,9 +53,12 @@ LinuxPackage create() throws ConfigException { pkgBuilder.name(pkgBuilder.create().packageName().toLowerCase().replaceAll("[ _]", "-")); } - var pkg = pkgBuilder.create(); + final var pkg = pkgBuilder.create(); - validatePackageName(pkg.packageName(), pkg.asStandardPackageType()); + final var stdPkgType = pkg.asStandardPackageType(); + if (stdPkgType.isPresent()) { + validatePackageName(pkg.packageName(), stdPkgType.orElseThrow()); + } var reply = create(pkg, pkg.packageLayout()); if (reply.isInstallDirInUsrTree()) { @@ -70,9 +73,9 @@ private LinuxPackage create(Package pkg, AppImageLayout pkgLayout) throws Config pkgLayout, Optional.ofNullable(menuGroupName).orElseGet(DEFAULTS::menuGroupName), Optional.ofNullable(category).orElseGet(DEFAULTS::category), - additionalDependencies, + Optional.ofNullable(additionalDependencies), Optional.ofNullable(release).orElseGet(DEFAULTS::release), - LinuxPackageArch.getValue(pkg.asStandardPackageType()))); + pkg.asStandardPackageType().map(LinuxPackageArch::getValue).orElseThrow())); } LinuxPackageBuilder directName(String v) { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index fa92bd3d16b32..64cb04ae82198 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -111,23 +111,22 @@ public final Path execute(Map params, try { // We either have an application image or need to build one. - if (pkg.app().runtimeBuilder() != null) { + if (pkg.app().runtimeBuilder().isPresent()) { // Runtime builder is present, build app image. LinuxAppImageBuilder.build() .excludeDirFromCopying(outputParentDir) .create(pkg).execute(pkgEnv); } else { - Path srcAppImageDir = pkg.predefinedAppImage(); - if (srcAppImageDir == null) { + Path srcAppImageDir = pkg.predefinedAppImage().orElseGet(() -> { // No predefined app image and no runtime builder. // This should be runtime packaging. if (pkg.isRuntimeInstaller()) { - srcAppImageDir = env.appImageDir(); + return env.appImageDir(); } else { // Can't create app image without runtime builder. throw new UnsupportedOperationException(); } - } + }); var srcLayout = pkg.appImageLayout().resolveAt(srcAppImageDir); var srcLayoutPathGroup = AppImageLayout.toPathGroup(srcLayout); @@ -207,7 +206,7 @@ private Map createDefaultReplacementData(BuildEnv env, LinuxPack data.put("APPLICATION_DESCRIPTION", pkg.description()); String defaultDeps = String.join(", ", getListOfNeededPackages(env)); - String customDeps = Optional.ofNullable(pkg.additionalDependencies()).orElse(""); + String customDeps = pkg.additionalDependencies().orElse(""); if (!customDeps.isEmpty() && !defaultDeps.isEmpty()) { customDeps = ", " + customDeps; } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index ae3ac0b5219ba..2031f527a03bb 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -125,13 +125,13 @@ protected Map createReplacementData(BuildEnv env, LinuxPackage p data.put("APPLICATION_SUMMARY", pkg.packageName()); data.put("APPLICATION_LICENSE_TYPE", ((LinuxRpmPackage)pkg).licenseType()); - String licenseFile = Optional.ofNullable(pkg.licenseFile()).map(v -> { + String licenseFile = pkg.licenseFile().map(v -> { return v.toAbsolutePath().normalize().toString(); }).orElse(null); data.put("APPLICATION_LICENSE_FILE", licenseFile); data.put("APPLICATION_GROUP", pkg.category()); - data.put("APPLICATION_URL", Optional.ofNullable(pkg.aboutURL()).orElse("")); + data.put("APPLICATION_URL", pkg.aboutURL().orElse("")); return data; } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java index 3ac1b9d0df53a..7647e559c0d48 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java @@ -36,11 +36,6 @@ default Map extraAppImageFileData() { }).orElseGet(Map::of); } - @Override - default String defaultIconResourceName() { - return "JavaApp.png"; - } - public static LinuxLauncher create(Launcher launcher, LinuxLauncherMixin mixin) { return CompositeProxy.create(LinuxLauncher.class, launcher, mixin); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java index 9e3154052137c..742303f296ef3 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java @@ -25,6 +25,8 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; import jdk.jpackage.internal.util.CompositeProxy; public interface LinuxPackage extends Package, LinuxPackageMixin { @@ -34,18 +36,19 @@ public interface LinuxPackage extends Package, LinuxPackageMixin { @Override default String packageFileName() { - String packageFileNameTemlate; - switch (asStandardPackageType()) { - case LINUX_DEB -> { - packageFileNameTemlate = "%s_%s-%s_%s"; + String packageFileNameTemlate = asStandardPackageType().map(stdType -> { + switch (stdType) { + case LINUX_DEB -> { + return "%s_%s-%s_%s"; + } + case LINUX_RPM -> { + return "%s-%s-%s.%s"; + } + default -> { + throw new IllegalStateException(); + } } - case LINUX_RPM -> { - packageFileNameTemlate = "%s-%s-%s.%s"; - } - default -> { - throw new UnsupportedOperationException(); - } - } + }).orElseThrow(UnsupportedOperationException::new); return String.format(packageFileNameTemlate, packageName(), version(), release(), arch()); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java index d263d670f91af..918c00c1bec73 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal.model; +import java.util.Optional; + public interface LinuxPackageMixin { AppImageLayout packageLayout(); @@ -32,14 +34,14 @@ public interface LinuxPackageMixin { String category(); - String additionalDependencies(); + Optional additionalDependencies(); String release(); String arch(); record Stub(AppImageLayout packageLayout, String menuGroupName, - String category, String additionalDependencies, String release, + String category, Optional additionalDependencies, String release, String arch) implements LinuxPackageMixin { } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java index 33b7d2f255dc6..e1a67e5a4a65f 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java @@ -32,6 +32,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; @@ -49,6 +50,7 @@ import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.FileAssociation; import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; +import jdk.jpackage.internal.util.function.ThrowingConsumer; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; final class MacAppImageBuilder2 { @@ -114,7 +116,7 @@ private static void writeAppInfoPlist(BuildEnv env, Application app, Map data = new HashMap<>(); data.put("DEPLOY_ICON_FILE", ApplicationIcon.getPath(app, appLayout).getFileName().toString()); data.put("DEPLOY_BUNDLE_COPYRIGHT", app.copyright()); - data.put("DEPLOY_LAUNCHER_NAME", app.mainLauncher().executableNameWithSuffix()); + data.put("DEPLOY_LAUNCHER_NAME", app.mainLauncher().orElseThrow().executableNameWithSuffix()); data.put("DEPLOY_BUNDLE_SHORT_VERSION", macApp.shortVersion().toString()); data.put("DEPLOY_BUNDLE_CFBUNDLE_VERSION", app.version()); data.put("DEPLOY_BUNDLE_NAME", macApp.bundleName()); @@ -159,10 +161,9 @@ private static String faContentType(MacApplication app, MacFileAssociation fa) { private static void faWriteIcon(XMLStreamWriter xml, String key, FileAssociation fa) throws XMLStreamException { - var icon = fa.icon(); - if (icon != null) { - writeString(xml, key, fa.icon().getFileName()); - } + fa.icon().ifPresent(ThrowingConsumer.toConsumer(icon -> { + writeString(xml, key, icon.getFileName()); + })); } private static void addFaToCFBundleDocumentTypes(XMLStreamWriter xml, @@ -217,7 +218,10 @@ public void write(BuildEnv env, Application app, ApplicationLayout appLayout) private static void writeFileAssociationIcons(BuildEnv env, Application app, ApplicationLayout appLayout) throws IOException { - for (var faIcon : app.fileAssociations().filter(FileAssociation::hasIcon).map(FileAssociation::icon).toList()) { + for (var faIcon : app.fileAssociations() + .filter(FileAssociation::hasIcon) + .map(FileAssociation::icon) + .map(Optional::get).toList()) { Files.copy(faIcon, appLayout.destktopIntegrationDirectory().resolve(faIcon.getFileName())); } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index fd642ac3203c4..1dfc6f81d7464 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -81,8 +81,7 @@ private static class MacLauncherAsService extends UnixLauncherAsService { .setPublicName(plistFilename) .addSubstitutionDataEntry("LABEL", label) .addSubstitutionDataEntry("APPLICATION_LAUNCHER", - pkg.asInstalledPackageApplicationLayout().launchersDirectory().resolve( - getName()).toString()); + pkg.asInstalledPackageApplicationLayout().orElseThrow().launchersDirectory().resolve(getName()).toString()); } @Override diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java index 04c5af8b35406..bafbdfce8d3cc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java @@ -36,6 +36,7 @@ import java.util.ArrayList; import java.util.Map; import java.util.List; +import java.util.Optional; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.SOURCE_DIR; import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; @@ -78,7 +79,7 @@ public String version() { } }, new Launcher.Unsupported() { @Override - public LauncherStartupInfo startupInfo() { + public Optional startupInfo() { return toSupplier(() -> new LauncherFromParams().create(params).startupInfo()).get(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java index 0e1c8ff055bfe..6c2b50763d7c9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -41,8 +41,11 @@ import java.util.Optional; import java.util.function.Function; import java.util.stream.Stream; +import jdk.jpackage.internal.model.CustomLauncherIcon; import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.PathUtils; +import jdk.jpackage.internal.util.function.ExceptionBox; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; @@ -140,18 +143,15 @@ private AppImageBuilder(Application app, ApplicationLayout appLayout, private AppImageBuilder(Application app, List excludeCopyDirs, Map> customAppImageItemGroups) { - this(app, app.asApplicationLayout(), excludeCopyDirs, true, - customAppImageItemGroups); + this(app, app.asApplicationLayout().orElseThrow(), excludeCopyDirs, true, customAppImageItemGroups); } private AppImageBuilder(Package pkg, List excludeCopyDirs, Map> customAppImageItemGroups) { - this(pkg.app(), pkg.asPackageApplicationLayout(), excludeCopyDirs, false, - customAppImageItemGroups); + this(pkg.app(), pkg.asPackageApplicationLayout().orElseThrow(), excludeCopyDirs, false, customAppImageItemGroups); } - private static void copyRecursive(Path srcDir, Path dstDir, - List excludeDirs) throws IOException { + private static void copyRecursive(Path srcDir, Path dstDir, List excludeDirs) throws IOException { srcDir = srcDir.toAbsolutePath(); List excludes = new ArrayList<>(); @@ -169,48 +169,55 @@ private static void copyRecursive(Path srcDir, Path dstDir, void execute(BuildEnv env) throws IOException, PackagerException { var resolvedAppLayout = appLayout.resolveAt(env.appImageDir()); - for (var group : AppImageItemGroup.values()) { - for (var appImageItem : Optional.ofNullable(appImageItemGroups.get(group)).orElseGet(List::of)) { - appImageItem.write(env, app, resolvedAppLayout); - } + try { + Stream.of(AppImageItemGroup.values()) + .map(appImageItemGroups::get) + .filter(Objects::nonNull) + .flatMap(List::stream) + .forEachOrdered(toConsumer(appImageItem -> { + appImageItem.write(env, app, resolvedAppLayout); + })); + } catch (ExceptionBox ex) { + throw ExceptionBox.rethrowUnchecked(ex); } } - static OverridableResource createLauncherIconResource(Application app, + static Optional createLauncherIconResource(Application app, Launcher launcher, Function resourceSupplier) { final String defaultIconName = launcher.defaultIconResourceName(); - final String resourcePublicName = launcher.executableName() + PathUtils.getSuffix(Path.of( - defaultIconName)); + final String resourcePublicName = launcher.executableName() + PathUtils.getSuffix(Path.of(defaultIconName)); - var iconType = IconType.getLauncherIconType(launcher.icon()); - if (iconType == IconType.NO_ICON) { - return null; + if (!launcher.hasIcon()) { + return Optional.empty(); } OverridableResource resource = resourceSupplier.apply(defaultIconName) .setCategory("icon") - .setExternal(launcher.icon()) .setPublicName(resourcePublicName); - if (iconType == IconType.DEFAULT_OR_RESOURCEDIR_ICON && app.mainLauncher() != launcher) { + launcher.icon().flatMap(CustomLauncherIcon::fromLauncherIcon).map(CustomLauncherIcon::path).ifPresent(resource::setExternal); + + if (launcher.hasDefaultIcon() && app.mainLauncher().orElseThrow() != launcher) { // No icon explicitly configured for this launcher. // Dry-run resource creation to figure out its source. final Path nullPath = null; if (toSupplier(() -> resource.saveToFile(nullPath)).get() != OverridableResource.Source.ResourceDir) { // No icon in resource dir for this launcher, inherit icon // configured for the main launcher. - return createLauncherIconResource(app, app.mainLauncher(), - resourceSupplier).setLogPublicName(resourcePublicName); + return createLauncherIconResource( + app, app.mainLauncher().orElseThrow(), + resourceSupplier + ).map(r -> r.setLogPublicName(resourcePublicName)); } } - return resource; + return Optional.of(resource); } private static AppImageItem createRuntimeAppImageItem() { return (env, app, appLayout) -> { - app.runtimeBuilder().createRuntime(appLayout); + app.runtimeBuilder().ifPresent(toConsumer(runtimeBuilder -> runtimeBuilder.createRuntime(appLayout))); }; } @@ -227,11 +234,11 @@ private static AppImageItem createContentAppImageItem(List excludeCopyDirs Stream.of(env.buildRoot(), env.appImageDir()) ).map(Path::toAbsolutePath).toList(); - if (app.srcDir() != null) { - copyRecursive(app.srcDir(), appLayout.appDirectory(), excludeCandidates); - } + app.srcDir().ifPresent(toConsumer(srcDir -> { + copyRecursive(srcDir, appLayout.appDirectory(), excludeCandidates); + })); - for (var srcDir : Optional.ofNullable(app.contentDirs()).orElseGet(List::of)) { + for (var srcDir : app.contentDirs()) { copyRecursive(srcDir, appLayout.contentDirectory().resolve(srcDir.getFileName()), excludeCandidates); @@ -258,20 +265,6 @@ private static AppImageItem createLaunchersAppImageItem() { }; } - private enum IconType { - DEFAULT_OR_RESOURCEDIR_ICON, CUSTOM_ICON, NO_ICON; - - public static IconType getLauncherIconType(Path iconPath) { - if (iconPath == null) { - return DEFAULT_OR_RESOURCEDIR_ICON; - } - if (iconPath.toFile().getName().isEmpty()) { - return NO_ICON; - } - return CUSTOM_ICON; - } - } - private final Application app; private final ApplicationLayout appLayout; private final Map> appImageItemGroups; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index 31c239f9a616d..8fa6d43aea820 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -59,9 +59,12 @@ final class AppImageFile2 { AppImageFile2(Application app) { + + final var mainLauncher = app.mainLauncher().orElseThrow(); + appVersion = app.version(); - launcherName = app.mainLauncher().name(); - mainClass = app.mainLauncher().startupInfo().qualifiedClassName(); + launcherName = mainLauncher.name(); + mainClass = mainLauncher.startupInfo().orElseThrow().qualifiedClassName(); extra = app.extraAppImageFileData(); creatorVersion = getVersion(); creatorPlatform = getPlatform(); @@ -202,16 +205,16 @@ public String name() { } @Override - public LauncherStartupInfo startupInfo() { + public Optional startupInfo() { return startupInfo; } - private final LauncherStartupInfo startupInfo = new LauncherStartupInfo.Unsupported() { + private final Optional startupInfo = Optional.of(new LauncherStartupInfo.Unsupported() { @Override public String qualifiedClassName() { return props.get("main-class"); } - }; + }); }; List additionalLaunchers = AppImageProperties.launchers(doc, xPath).stream().map(launcherProps -> { @@ -337,10 +340,6 @@ record LauncherInfo(String name, boolean service, Map extra) { throw new InavlidAppImageFileException(); } } - - Launcher asLauncher() { - return new Launcher.Stub(name, null, null, service, null, null); - } } private static class InavlidAppImageFileException extends RuntimeException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 47c34f67c3625..8a65e6fe0c6a9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -72,7 +72,8 @@ Application create() throws ConfigException { Optional.ofNullable(version).orElseGet(DEFAULTS::version), Optional.ofNullable(vendor).orElseGet(DEFAULTS::vendor), Optional.ofNullable(copyright).orElseGet(DEFAULTS::copyright), - srcDir, contentDirs, appImageLayout, runtimeBuilder, launchersAsList); + Optional.ofNullable(srcDir), + contentDirs, appImageLayout, Optional.ofNullable(runtimeBuilder), launchersAsList); } ApplicationBuilder runtimeBuilder(RuntimeBuilder v) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java index bba0813ca33ee..1297595ec7104 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java @@ -25,12 +25,14 @@ package jdk.jpackage.internal; import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; interface BuildEnv { Path buildRoot(); - Path resourceDir(); + Optional resourceDir(); /** * Returns path to application image directory. @@ -57,7 +59,7 @@ public Path appImageDir() { }; } - static BuildEnv create(Path buildRoot, Path resourceDir, Class resourceLocator) { + static BuildEnv create(Path buildRoot, Optional resourceDir, Class resourceLocator) { return new BuildEnv() { @Override public Path buildRoot() { @@ -65,7 +67,7 @@ public Path buildRoot() { } @Override - public Path resourceDir() { + public Optional resourceDir() { return resourceDir; } @@ -77,7 +79,7 @@ public OverridableResource createResource(String defaultName) { } else { resource = new OverridableResource(); } - return resource.setResourceDir(resourceDir); + return resource.setResourceDir(resourceDir.orElse(null)); } }; } @@ -85,7 +87,7 @@ public OverridableResource createResource(String defaultName) { static class Proxy implements BuildEnv { Proxy(BuildEnv target) { - this.target = target; + this.target = Objects.requireNonNull(target); } @Override @@ -94,7 +96,7 @@ final public Path buildRoot() { } @Override - final public Path resourceDir() { + final public Optional resourceDir() { return target.resourceDir(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java index 2aac5f001188d..3362b88313d96 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java @@ -29,6 +29,7 @@ import jdk.jpackage.internal.model.ConfigException; import java.nio.file.Path; import java.util.Objects; +import java.util.Optional; import static jdk.jpackage.internal.I18N.buildConfigException; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.resources.ResourceLocator; @@ -56,8 +57,7 @@ BuildEnv create() throws ConfigException { } } - return BuildEnv.withAppImageDir(BuildEnv.create(root, resourceDir, - ResourceLocator.class), appImageDir); + return BuildEnv.withAppImageDir(BuildEnv.create(root, Optional.ofNullable(resourceDir), ResourceLocator.class), appImageDir); } BuildEnvBuilder resourceDir(Path v) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java index 41166e0cd5a27..212862f196672 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java @@ -45,7 +45,7 @@ */ final class CfgFile { CfgFile(Application app, Launcher launcher) { - startupInfo = launcher.startupInfo(); + startupInfo = launcher.startupInfo().orElseThrow(); outputFileName = launcher.executableName() + ".cfg"; version = app.version(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java index 90f1ea899c880..c4ea9e0d028a9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java @@ -38,6 +38,10 @@ import jdk.jpackage.internal.model.FileAssociation; final record FileAssociationGroup(List items) { + FileAssociationGroup { + Objects.requireNonNull(items); + } + boolean isEmpty() { return items.isEmpty(); } @@ -67,10 +71,10 @@ static final class Builder { FileAssociationGroup create() { Function> forExtension = ext -> { if (mimeTypes.isEmpty()) { - return Stream.of((FileAssociation)new FileAssociation.Stub(description, icon, null, ext)); + return Stream.of(createFileAssociation(Optional.empty(), ext)); } else { return mimeTypes.stream().map(faMimeType -> { - return (FileAssociation)new FileAssociation.Stub(description, icon, faMimeType, ext); + return createFileAssociation(Optional.of(faMimeType), ext); }); } }; @@ -110,6 +114,11 @@ private static Set conv(Collection col) { Stream::of).collect(toSet()); } + private FileAssociation createFileAssociation(Optional mimeType, String ext) { + Objects.requireNonNull(ext); + return new FileAssociation.Stub(Optional.ofNullable(description), Optional.ofNullable(icon), mimeType.orElse(null), ext); + } + private Path icon; private String description; private Set mimeTypes; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java index 6ebd912942c02..0796dd74a0224 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -105,7 +105,9 @@ static ApplicationBuilder createApplicationBuilder(Map p if (predefinedRuntimeImage != null) { runtimeBuilderBuilder.forRuntime(predefinedRuntimeImage); } else { - var startupInfos = launchers.asList().stream().map(Launcher::startupInfo).toList(); + var startupInfos = launchers.asList().stream() + .map(Launcher::startupInfo) + .map(Optional::orElseThrow).toList(); runtimeBuilderBuilder.forNewRuntime(startupInfos) .addModules(ADD_MODULES.fetchFrom(params)) .limitModules(LIMIT_MODULES.fetchFrom(params)) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java index 701363f02f6ad..1f4912cecf5a6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java @@ -45,15 +45,28 @@ import jdk.jpackage.internal.util.function.ExceptionBox; import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; -import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import static jdk.jpackage.internal.model.ConfigException.rethrowConfigException; +import jdk.jpackage.internal.model.CustomLauncherIcon; +import jdk.jpackage.internal.model.LauncherIcon; final class LauncherBuilder { Launcher create() throws ConfigException { - validateIcon(icon); - var fa = toFunction(this::createFileAssociations).apply(faSources.stream()).toList(); - return new Stub(name, startupInfo, fa, isService, description, icon); + try { + CustomLauncherIcon.fromLauncherIcon(icon) + .map(CustomLauncherIcon::path) + .ifPresent(toConsumer(LauncherBuilder::validateIcon)); + + var fa = createFileAssociations(faSources.stream()).toList(); + + Objects.requireNonNull(name); + Objects.requireNonNull(description); + Objects.requireNonNull(defaultIconResourceName); + + return new Stub(name, Optional.ofNullable(startupInfo), fa, isService, description, Optional.ofNullable(icon), defaultIconResourceName); + } catch (RuntimeException ex) { + throw ConfigException.rethrowConfigException(ex); + } } LauncherBuilder name(String v) { @@ -86,11 +99,16 @@ LauncherBuilder description(String v) { return this; } - LauncherBuilder icon(Path v) { + LauncherBuilder icon(LauncherIcon v) { icon = v; return this; } + LauncherBuilder defaultIconResourceName(String v) { + defaultIconResourceName = v; + return this; + } + static boolean isFileAssociationValid(FileAssociation src) { toConsumer(LauncherBuilder::verifyFileAssociation).accept(src); @@ -98,10 +116,6 @@ static boolean isFileAssociationValid(FileAssociation src) { } static void validateIcon(Path icon) throws ConfigException { - if (icon == null || icon.toString().isEmpty()) { - return; - } - switch (OperatingSystem.current()) { case WINDOWS -> { if (!icon.getFileName().toString().toLowerCase().endsWith(".ico")) { @@ -185,5 +199,6 @@ private static void verifyFileAssociation(FileAssociation src) throws ConfigExce private Predicate faPrediacate = LauncherBuilder::isFileAssociationValid; private boolean isService; private String description; - private Path icon; + private LauncherIcon icon; + private String defaultIconResourceName; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java index 0b3e8df571eac..3ac98eb9a190d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java @@ -24,12 +24,17 @@ */ package jdk.jpackage.internal; +import java.nio.file.Path; import java.util.List; import jdk.jpackage.internal.model.Launcher; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.function.Predicate; +import jdk.internal.util.OperatingSystem; +import static jdk.internal.util.OperatingSystem.LINUX; +import static jdk.internal.util.OperatingSystem.MACOS; +import static jdk.internal.util.OperatingSystem.WINDOWS; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.ARGUMENTS; import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; @@ -43,7 +48,10 @@ import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.JAVA_OPTIONS; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.CustomLauncherIcon; +import jdk.jpackage.internal.model.DefaultLauncherIcon; import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.model.LauncherIcon; record LauncherFromParams(Predicate faPredicate) { @@ -58,9 +66,10 @@ record LauncherFromParams(Predicate faPredicate) { Launcher create(Map params) throws ConfigException { var builder = new LauncherBuilder() .description(DESCRIPTION.fetchFrom(params)) - .icon(ICON.fetchFrom(params)) + .icon(toLauncherIcon(ICON.fetchFrom(params))) .isService(LAUNCHER_AS_SERVICE.fetchFrom(params)) .name(APP_NAME.fetchFrom(params)) + .defaultIconResourceName(defaultIconResourceName()) .faPrediacate(faPredicate); if (PREDEFINED_APP_IMAGE.fetchFrom(params) == null) { @@ -83,4 +92,31 @@ Launcher create(Map params) throws ConfigException { return builder.faSources(faSources).create(); } + + private static LauncherIcon toLauncherIcon(Path launcherIconPath) { + if (launcherIconPath == null) { + return DefaultLauncherIcon.INSTANCE; + } else if (launcherIconPath.toString().isEmpty()) { + return null; + } else { + return CustomLauncherIcon.create(launcherIconPath); + } + } + + private static String defaultIconResourceName() { + switch (OperatingSystem.current()) { + case WINDOWS -> { + return "JavaApp.ico"; + } + case LINUX -> { + return "JavaApp.png"; + } + case MACOS -> { + return "JavaApp.icns"; + } + default -> { + throw new UnsupportedOperationException(); + } + } + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index ee7c9d7d51a48..a1b446bcf7dc7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -91,9 +91,9 @@ Package create() throws ConfigException { effectiveName, Optional.ofNullable(description).orElseGet(app::description), version = Optional.ofNullable(version).orElseGet(app::version), - aboutURL, - licenseFile, - predefinedAppImage, + Optional.ofNullable(aboutURL), + Optional.ofNullable(licenseFile), + Optional.ofNullable(predefinedAppImage), relativeInstallDir); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index 51a1a4c9ed0e8..e5fce735e4754 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; @@ -42,21 +43,21 @@ public interface Application { String copyright(); - Path srcDir(); + Optional srcDir(); List contentDirs(); AppImageLayout imageLayout(); - default ApplicationLayout asApplicationLayout() { + default Optional asApplicationLayout() { if (imageLayout() instanceof ApplicationLayout layout) { - return layout; + return Optional.of(layout); } else { - throw new UnsupportedOperationException(); + return Optional.empty(); } } - RuntimeBuilder runtimeBuilder(); + Optional runtimeBuilder(); default Path appImageDirName() { return Path.of(name()); @@ -64,12 +65,12 @@ default Path appImageDirName() { List launchers(); - default Launcher mainLauncher() { - return ApplicationLaunchers.fromList(launchers()).mainLauncher(); + default Optional mainLauncher() { + return ApplicationLaunchers.fromList(launchers()).map(ApplicationLaunchers::mainLauncher); } default List additionalLaunchers() { - return ApplicationLaunchers.fromList(launchers()).additionalLaunchers(); + return ApplicationLaunchers.fromList(launchers()).map(ApplicationLaunchers::additionalLaunchers).orElseGet(Collections::emptyList); } default boolean isRuntime() { @@ -90,8 +91,8 @@ default Stream fileAssociations() { } record Stub(String name, String description, String version, String vendor, - String copyright, Path srcDir, List contentDirs, - AppImageLayout imageLayout, RuntimeBuilder runtimeBuilder, + String copyright, Optional srcDir, List contentDirs, + AppImageLayout imageLayout, Optional runtimeBuilder, List launchers) implements Application { } @@ -123,7 +124,7 @@ public String copyright() { } @Override - public Path srcDir() { + public Optional srcDir() { throw new UnsupportedOperationException(); } @@ -138,7 +139,7 @@ public AppImageLayout imageLayout() { } @Override - public RuntimeBuilder runtimeBuilder() { + public Optional runtimeBuilder() { throw new UnsupportedOperationException(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java index 01ec8aaf3a0f2..fe72c721c89b1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java @@ -25,20 +25,15 @@ package jdk.jpackage.internal.model; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.stream.Stream; -public record ApplicationLaunchers(Launcher mainLauncher, - List additionalLaunchers) { +public record ApplicationLaunchers(Launcher mainLauncher, List additionalLaunchers) { public ApplicationLaunchers { - if (mainLauncher == null && additionalLaunchers != null) { - throw new IllegalArgumentException(); - } - } - - public ApplicationLaunchers() { - this(null, null); + Objects.requireNonNull(mainLauncher); + Objects.requireNonNull(additionalLaunchers); } public ApplicationLaunchers(Launcher mainLauncher) { @@ -51,12 +46,12 @@ public List asList() { }).orElseGet(List::of); } - public static ApplicationLaunchers fromList(List launchers) { + public static Optional fromList(List launchers) { if (launchers == null || launchers.isEmpty()) { - return new ApplicationLaunchers(); + return Optional.empty(); } else { - return new ApplicationLaunchers(launchers.getFirst(), - launchers.subList(1, launchers.size())); + return Optional.of(new ApplicationLaunchers(launchers.getFirst(), + launchers.subList(1, launchers.size()))); } } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index 139a6adb60f69..566fb090d0f1f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import java.util.Objects; import jdk.jpackage.internal.util.CompositeProxy; import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; @@ -64,6 +65,14 @@ private Builder(ApplicationLayout appLayout) { } public ApplicationLayout create() { + + Objects.requireNonNull(runtimeDirectory); + Objects.requireNonNull(launchersDirectory); + Objects.requireNonNull(appDirectory); + Objects.requireNonNull(appModsDirectory); + Objects.requireNonNull(destktopIntegrationDirectory); + Objects.requireNonNull(contentDirectory); + return ApplicationLayout.create(new AppImageLayout.Stub( runtimeDirectory), new ApplicationLayoutMixin.Stub( launchersDirectory, appDirectory, appModsDirectory, diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/CustomLauncherIcon.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/CustomLauncherIcon.java new file mode 100644 index 0000000000000..8fdac1dc5013d --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/CustomLauncherIcon.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; + +public interface CustomLauncherIcon extends LauncherIcon { + + Path path(); + + public static Optional fromLauncherIcon(LauncherIcon icon) { + if (icon instanceof CustomLauncherIcon customIcon) { + return Optional.of(customIcon); + } else { + return Optional.empty(); + } + } + + public static CustomLauncherIcon create(Path path) { + Objects.requireNonNull(path); + return new Stub(path); + } + + record Stub(Path path) implements CustomLauncherIcon { + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DefaultLauncherIcon.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DefaultLauncherIcon.java new file mode 100644 index 0000000000000..7462cf6b74852 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DefaultLauncherIcon.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.util.Optional; + +public interface DefaultLauncherIcon extends LauncherIcon { + + public static Optional fromLauncherIcon(LauncherIcon icon) { + if (icon instanceof DefaultLauncherIcon defaultIcon) { + return Optional.of(defaultIcon); + } else { + return Optional.empty(); + } + } + + public static DefaultLauncherIcon INSTANCE = new DefaultLauncherIcon() {}; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java index 3feb6384f0f39..3f630e9fb706e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java @@ -25,28 +25,27 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; -import java.util.Objects; import java.util.Optional; import java.util.function.Predicate; public interface FileAssociation { - String description(); + Optional description(); - Path icon(); + Optional icon(); default boolean hasIcon() { - return Objects.nonNull(icon()); + return icon().isPresent(); } - default boolean hasNonEmptyDescription() { - return Optional.ofNullable(description()).filter(Predicate.not(String::isEmpty)).isPresent(); + default Optional nonEmptyDescription() { + return description().filter(Predicate.not(String::isEmpty)); } String mimeType(); String extension(); - record Stub(String description, Path icon, String mimeType, String extension) implements FileAssociation { + record Stub(Optional description, Optional icon, String mimeType, String extension) implements FileAssociation { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java index 3af830fc15a86..86519e8dc119b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal.model; import java.io.InputStream; -import java.nio.file.Path; import java.util.List; import java.util.Map; import java.util.Optional; @@ -39,15 +38,15 @@ default String executableName() { return name(); } - default String executableSuffix() { - return null; + default Optional executableSuffix() { + return Optional.empty(); } default String executableNameWithSuffix() { - return executableName() + Optional.ofNullable(executableSuffix()).orElse(""); + return executableName() + executableSuffix().orElse(""); } - LauncherStartupInfo startupInfo(); + Optional startupInfo(); List fileAssociations(); @@ -64,20 +63,28 @@ default Map extraAppImageFileData() { } /** - * Returns path to icon to assign for the launcher. - * - * Null for the default or resource directory icon, empty path for no icon, - * other value for custom icon. + * Icon for the launcher. */ - Path icon(); + Optional icon(); - default String defaultIconResourceName() { - return null; + default boolean hasIcon() { + return icon().isPresent(); } - record Stub(String name, LauncherStartupInfo startupInfo, + default boolean hasDefaultIcon() { + return icon().flatMap(DefaultLauncherIcon::fromLauncherIcon).isPresent(); + } + + default boolean hasCustomIcon() { + return icon().flatMap(CustomLauncherIcon::fromLauncherIcon).isPresent(); + } + + String defaultIconResourceName(); + + record Stub(String name, Optional startupInfo, List fileAssociations, boolean isService, - String description, Path icon) implements Launcher { + String description, Optional icon, + String defaultIconResourceName) implements Launcher { } class Unsupported implements Launcher { @@ -88,7 +95,7 @@ public String name() { } @Override - public LauncherStartupInfo startupInfo() { + public Optional startupInfo() { throw new UnsupportedOperationException(); } @@ -108,9 +115,13 @@ public String description() { } @Override - public Path icon() { + public Optional icon() { throw new UnsupportedOperationException(); } + @Override + public String defaultIconResourceName() { + throw new UnsupportedOperationException(); + } } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java new file mode 100644 index 0000000000000..41beeaa86cdcf --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +public interface LauncherIcon { +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java index d52d2758b350f..bf6da84a1da10 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java @@ -33,11 +33,11 @@ public interface Package { PackageType type(); - default StandardPackageType asStandardPackageType() { + default Optional asStandardPackageType() { if (type() instanceof StandardPackageType stdType) { - return stdType; + return Optional.of(stdType); } else { - return null; + return Optional.empty(); } } @@ -53,11 +53,11 @@ default StandardPackageType asStandardPackageType() { String version(); - String aboutURL(); + Optional aboutURL(); - Path licenseFile(); + Optional licenseFile(); - Path predefinedAppImage(); + Optional predefinedAppImage(); /** * Returns source app image layout. @@ -66,7 +66,7 @@ default AppImageLayout appImageLayout() { return app().imageLayout(); } - default ApplicationLayout asApplicationLayout() { + default Optional asApplicationLayout() { return app().asApplicationLayout(); } @@ -77,37 +77,41 @@ default AppImageLayout packageLayout() { return appImageLayout().resolveAt(relativeInstallDir()); } - default ApplicationLayout asPackageApplicationLayout() { + default Optional asPackageApplicationLayout() { if (packageLayout() instanceof ApplicationLayout layout) { - return layout; + return Optional.of(layout); } else { - throw new UnsupportedOperationException(); + return Optional.empty(); } } /** * Returns app image layout of the installed package. */ - default AppImageLayout installedPackageLayout() { - if (type() instanceof StandardPackageType type) { - switch (type) { + default Optional installedPackageLayout() { + return asStandardPackageType().map(stdType -> { + switch (stdType) { case LINUX_DEB, LINUX_RPM, MAC_DMG, MAC_PKG -> { return packageLayout().resolveAt(Path.of("/")); } case WIN_EXE, WIN_MSI -> { return packageLayout(); } + default -> { + throw new UnsupportedOperationException(); + } } - } - throw new UnsupportedOperationException(); + }); } - default ApplicationLayout asInstalledPackageApplicationLayout() { - if (installedPackageLayout() instanceof ApplicationLayout layout) { - return layout; - } else { - throw new UnsupportedOperationException(); - } + default Optional asInstalledPackageApplicationLayout() { + return installedPackageLayout().map(layout -> { + if (layout instanceof ApplicationLayout appLayout) { + return appLayout; + } else { + return (ApplicationLayout)null; + } + }); } /** @@ -117,16 +121,12 @@ default String packageFileName() { return String.format("%s-%s", packageName(), version()); } - default String packageFileSuffix() { - if (type() instanceof StandardPackageType type) { - return type.suffix(); - } else { - throw new UnsupportedOperationException(); - } + default Optional packageFileSuffix() { + return asStandardPackageType().map(StandardPackageType::suffix); } default String packageFileNameWithSuffix() { - return packageFileName() + Optional.ofNullable(packageFileSuffix()).orElse(""); + return packageFileName() + packageFileSuffix().orElse(""); } default boolean isRuntimeInstaller() { @@ -142,8 +142,9 @@ default boolean isRuntimeInstaller() { Path relativeInstallDir(); record Stub(Application app, PackageType type, String packageName, - String description, String version, String aboutURL, Path licenseFile, - Path predefinedAppImage, Path relativeInstallDir) implements Package { + String description, String version, Optional aboutURL, + Optional licenseFile, Optional predefinedAppImage, + Path relativeInstallDir) implements Package { } class Unsupported implements Package { @@ -174,17 +175,17 @@ public String version() { } @Override - public String aboutURL() { + public Optional aboutURL() { throw new UnsupportedOperationException(); } @Override - public Path licenseFile() { + public Optional licenseFile() { throw new UnsupportedOperationException(); } @Override - public Path predefinedAppImage() { + public Optional predefinedAppImage() { throw new UnsupportedOperationException(); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java index 236a9aeff7eeb..5422047aa5765 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java @@ -33,6 +33,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; +import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -84,7 +85,7 @@ private ExecutableRebrander(ExecutableProperties props, this.props.put("ORIGINAL_FILENAME", props.executableName); } - void execute(BuildEnv env, Path target, Path icon) throws IOException { + void execute(BuildEnv env, Path target, Optional icon) { String[] propsArray = toStringArray(propertiesFileResource, props); UpdateResourceAction versionSwapper = resourceLock -> { @@ -94,20 +95,26 @@ void execute(BuildEnv env, Path target, Path icon) throws IOException { } }; - final var absIcon = Optional.ofNullable(icon) + Optional updateIcon = icon .map(Path::toAbsolutePath) .map(ShortPathUtils::adjustPath) - .orElse(null); - if (absIcon == null) { - rebrandExecutable(env, target, versionSwapper); - } else { - rebrandExecutable(env, target, versionSwapper, - resourceLock -> { + .map(absIcon -> { + return resourceLock -> { if (iconSwap(resourceLock, absIcon.toString()) != 0) { throw new RuntimeException(MessageFormat.format( I18N.getString("error.icon-swap"), absIcon)); } - }); + }; + }); + + try { + if (updateIcon.isEmpty()) { + rebrandExecutable(env, target, versionSwapper); + } else { + rebrandExecutable(env, target, versionSwapper, updateIcon.orElseThrow()); + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); } } @@ -176,13 +183,17 @@ private static String toFixedFileVersion(DottedVersion value) { private static String[] toStringArray( OverridableResource propertiesFileResource, - Map props) throws IOException { + Map props) { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - propertiesFileResource - .setSubstitutionData(props) - .setCategory(I18N.getString( - "resource.executable-properties-template")) - .saveToStream(buffer); + try { + propertiesFileResource + .setSubstitutionData(props) + .setCategory(I18N.getString( + "resource.executable-properties-template")) + .saveToStream(buffer); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } try (Reader reader = new InputStreamReader(new ByteArrayInputStream( buffer.toByteArray()), StandardCharsets.UTF_8)) { @@ -191,6 +202,8 @@ private static String[] toStringArray( return configProp.entrySet().stream().flatMap(e -> Stream.of( e.getKey().toString(), e.getValue().toString())).toArray( String[]::new); + } catch (IOException ex) { + throw new UncheckedIOException(ex); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java index 81992229a2b19..bf4c88784ff4b 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java @@ -29,7 +29,7 @@ import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.WinApplication; import java.io.IOException; -import java.nio.file.Path; +import java.io.UncheckedIOException; import jdk.jpackage.internal.AppImageBuilder.AppImageItemGroup; import static jdk.jpackage.internal.AppImageBuilder.createLauncherIconResource; import jdk.jpackage.internal.model.ApplicationLayout; @@ -45,16 +45,18 @@ static AppImageBuilder.Builder build() { private static void rebrandLaunchers(BuildEnv env, Application app, ApplicationLayout appLayout) throws IOException, PackagerException { for (var launcher : app.launchers()) { - Path iconTarget = null; - var iconResource = createLauncherIconResource(app, launcher, - name -> env.createResource(name)); - if (iconResource != null) { + final var iconTarget = createLauncherIconResource(app, launcher, name -> env.createResource(name)).map(iconResource -> { var iconDir = env.buildRoot().resolve("icons"); - iconTarget = iconDir.resolve(launcher.executableName() + ".ico"); - if (null == iconResource.saveToFile(iconTarget)) { - iconTarget = null; + var theIconTarget = iconDir.resolve(launcher.executableName() + ".ico"); + try { + if (null == iconResource.saveToFile(theIconTarget)) { + theIconTarget = null; + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); } - } + return theIconTarget; + }); var launcherExecutable = appLayout.launchersDirectory().resolve( launcher.executableNameWithSuffix()); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java index 1d66d513f85ba..6d5159d631722 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java @@ -26,6 +26,7 @@ import java.nio.file.Path; import java.util.Objects; +import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.WinExePackage; import jdk.jpackage.internal.model.WinMsiPackage; @@ -37,8 +38,10 @@ final class WinExePackageBuilder { } WinExePackage create() throws ConfigException { - LauncherBuilder.validateIcon(icon); - return WinExePackage.create(pkg, icon); + if (icon != null) { + LauncherBuilder.validateIcon(icon); + } + return WinExePackage.create(pkg, Optional.ofNullable(icon)); } WinExePackageBuilder icon(Path v) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index d19bbd2ce37ab..309ea0d4ee225 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -30,6 +30,7 @@ import jdk.jpackage.internal.model.WinMsiPackage; import java.io.IOException; import java.io.InputStream; +import java.io.UncheckedIOException; import java.io.Writer; import java.nio.charset.Charset; import java.nio.file.FileSystems; @@ -42,7 +43,6 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -56,7 +56,6 @@ import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.RuntimeLayout; -import jdk.jpackage.internal.util.FileUtils; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; @@ -209,24 +208,23 @@ private void prepareProto(WinMsiPackage pkg, BuildEnv env, Path msiOutputDir) th AppImageLayout appImageLayout; // we either have an application image or need to build one - if (pkg.app().runtimeBuilder() != null) { + if (pkg.app().runtimeBuilder().isPresent()) { // Runtime builder is present, build app image. WinAppImageBuilder.build() .excludeDirFromCopying(msiOutputDir) .create(pkg.app()).execute(env); appImageLayout = pkg.appImageLayout().resolveAt(env.appImageDir()); } else { - Path srcAppImageDir = pkg.predefinedAppImage(); - if (srcAppImageDir == null) { + Path srcAppImageDir = pkg.predefinedAppImage().orElseGet(() -> { // No predefined app image and no runtime builder. // This should be runtime packaging. if (pkg.isRuntimeInstaller()) { - srcAppImageDir = env.appImageDir(); + return env.appImageDir(); } else { // Can't create app image without runtime builder. throw new UnsupportedOperationException(); } - } + }); appImageLayout = pkg.appImageLayout().resolveAt(srcAppImageDir); } @@ -240,20 +238,23 @@ private void prepareProto(WinMsiPackage pkg, BuildEnv env, Path msiOutputDir) th installerIcon = runtimeLayout.runtimeDirectory().resolve(Path.of("bin", "java.exe")); } else if (appImageLayout instanceof ApplicationLayout appLayout) { installerIcon = appLayout.launchersDirectory().resolve( - pkg.app().mainLauncher().executableNameWithSuffix()); + pkg.app().mainLauncher().orElseThrow().executableNameWithSuffix()); } installerIcon = installerIcon.toAbsolutePath(); - Path licenseFile = pkg.licenseFile(); - if (licenseFile != null) { + pkg.licenseFile().ifPresent(licenseFile -> { // need to copy license file to the working directory // and convert to rtf if needed Path destFile = env.configDir().resolve(licenseFile.getFileName()); - IOUtils.copyFile(licenseFile, destFile); + try { + IOUtils.copyFile(licenseFile, destFile); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } destFile.toFile().setWritable(true); ensureByMutationFileIsRTF(destFile); - } + }); } @Override @@ -312,15 +313,15 @@ private Map prepareMainProjectFile(BuildEnv env, WinMsiPackage p data.put("JpIcon", installerIcon.toString()); } - Optional.ofNullable(pkg.helpURL()).ifPresent(value -> { + pkg.helpURL().ifPresent(value -> { data.put("JpHelpURL", value); }); - Optional.ofNullable(pkg.updateURL()).ifPresent(value -> { + pkg.updateURL().ifPresent(value -> { data.put("JpUpdateURL", value); }); - Optional.ofNullable(pkg.aboutURL()).ifPresent(value -> { + pkg.aboutURL().ifPresent(value -> { data.put("JpAboutURL", value); }); @@ -397,7 +398,10 @@ private Path buildMSI(BuildEnv env, WinMsiPackage pkg, // Filter out custom l10n files that were already used to // override primary l10n files. Ignore case filename comparison, // both lists are expected to be short. - List customWxlFiles = getWxlFilesFromDir(env.resourceDir()).stream() + List customWxlFiles = env.resourceDir() + .map(WinMsiBundler::getWxlFilesFromDir) + .orElseGet(Collections::emptyList) + .stream() .filter(custom -> primaryWxlFiles.stream().noneMatch(primary -> primary.getFileName().toString().equalsIgnoreCase( custom.getFileName().toString()))) @@ -460,11 +464,7 @@ private Path buildMSI(BuildEnv env, WinMsiPackage pkg, return msiOut; } - private static List getWxlFilesFromDir(Path dir) throws IOException { - if (dir == null) { - return Collections.emptyList(); - } - + private static List getWxlFilesFromDir(Path dir) { final String glob = "glob:**/*.wxl"; final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher( glob); @@ -475,10 +475,12 @@ private static List getWxlFilesFromDir(Path dir) throws IOException { .filter(pathMatcher::matches) .sorted((a, b) -> a.getFileName().toString().compareToIgnoreCase(b.getFileName().toString())) .toList(); + } catch (IOException ex) { + throw new UncheckedIOException(ex); } } - private static String getCultureFromWxlFile(Path wxlPath) throws IOException { + private static String getCultureFromWxlFile(Path wxlPath) { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(false); @@ -498,8 +500,10 @@ private static String getCultureFromWxlFile(Path wxlPath) throws IOException { return nodes.item(0).getNodeValue(); } catch (XPathExpressionException | ParserConfigurationException | SAXException ex) { - throw new IOException(I18N.format("error.read-wix-l10n-file", - wxlPath.toAbsolutePath().normalize()), ex); + throw new UncheckedIOException(new IOException( + I18N.format("error.read-wix-l10n-file", wxlPath.toAbsolutePath().normalize()), ex)); + } catch (IOException ex) { + throw new UncheckedIOException(ex); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java index f4df2fcdba5bf..9fe992930e3d3 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java @@ -64,13 +64,13 @@ WinMsiPackage create() throws ConfigException { return WinMsiPackage.create(pkg, new WinMsiPackageMixin.Stub( withInstallDirChooser, withShortcutPrompt, - helpURL, - updateURL, + Optional.ofNullable(helpURL), + Optional.ofNullable(updateURL), startMenuGroupName, isSystemWideInstall, Optional.ofNullable(upgradeCode).orElseGet(() -> upgradeCode(pkg.app())), productCode(pkg.app(), pkg.version()), - serviceInstaller)); + Optional.ofNullable(serviceInstaller))); } private static UUID upgradeCode(Application app) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index 30702a0541f9e..cef4a317b9f72 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -68,6 +68,7 @@ import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.XmlUtils; import jdk.jpackage.internal.util.XmlConsumer; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; import org.w3c.dom.NodeList; /** @@ -113,10 +114,11 @@ void initFromParams(BuildEnv env, WinMsiPackage pkg) { if (!launchersAsServices.isEmpty()) { // Service installer tool will be installed in launchers directory + final var serviceInstallerPath = pkg.serviceInstaller().orElseThrow(); serviceInstaller = new InstallableFile( - pkg.serviceInstaller().toAbsolutePath().normalize(), + serviceInstallerPath.toAbsolutePath().normalize(), installedAppImage.launchersDirectory().resolve( - pkg.serviceInstaller().getFileName())); + serviceInstallerPath.getFileName())); } programMenuFolderName = pkg.startMenuGroupName(); @@ -181,10 +183,10 @@ private void initFileAssociations() { Launcher::executableNameWithSuffix, WinLauncher::fileAssociations)); - associations.values().stream().flatMap(List::stream).filter(FileAssociation::hasIcon).forEach(fa -> { + associations.values().stream().flatMap(List::stream).filter(FileAssociation::hasIcon).toList().forEach(fa -> { // Need to add fa icon in the image. Object key = new Object(); - appImagePathGroup.setPath(key, fa.icon().toAbsolutePath().normalize()); + appImagePathGroup.setPath(key, fa.icon().orElseThrow().toAbsolutePath().normalize()); installedAppImagePathGroup.setPath(key, getInstalledFaIcoPath(fa)); }); } @@ -523,9 +525,9 @@ private String addFaComponent(XMLStreamWriter xml, Path path = INSTALLDIR.resolve(String.format("%s_%s", fa.extension(), launcherExe)); return addComponent(xml, path, Component.ProgId, unused -> { - if (fa.hasNonEmptyDescription()) { - xml.writeAttribute("Description", fa.description()); - } + fa.nonEmptyDescription().ifPresent(toConsumer(description -> { + xml.writeAttribute("Description", description); + })); if (fa.hasIcon()) { xml.writeAttribute("Icon", Id.File.of(getInstalledFaIcoPath(fa))); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java index bf183fc337ac6..b7c03c00d1b3d 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java @@ -53,10 +53,9 @@ final class WixUiFragmentBuilder extends WixFragmentBuilder { void initFromParams(BuildEnv env, WinMsiPackage pkg) { super.initFromParams(env, pkg); - Path licenseFile = pkg.licenseFile(); - withLicenseDlg = licenseFile != null; + withLicenseDlg = pkg.licenseFile().isPresent(); if (withLicenseDlg) { - Path licenseFileName = IOUtils.getFileName(licenseFile); + Path licenseFileName = pkg.licenseFile().orElseThrow().getFileName(); Path destFile = getConfigRoot().resolve(licenseFileName); setWixVariable("JpLicenseRtf", destFile.toAbsolutePath().toString()); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java index 08e25377c7697..4509a20c3777e 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java @@ -25,12 +25,13 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import java.util.Optional; import static jdk.jpackage.internal.model.StandardPackageType.WIN_EXE; import jdk.jpackage.internal.util.CompositeProxy; public interface WinExePackage extends Package, WinExePackageMixin { - public static WinExePackage create(WinMsiPackage msiPackage, Path icon) { + public static WinExePackage create(WinMsiPackage msiPackage, Optional icon) { return CompositeProxy.create(WinExePackage.class, createExePackage( msiPackage), new WinExePackageMixin.Stub(msiPackage, icon)); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackageMixin.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackageMixin.java index c24af4dd30693..11d1f4a08f001 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackageMixin.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackageMixin.java @@ -25,12 +25,13 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import java.util.Optional; public interface WinExePackageMixin { WinMsiPackage msiPackage(); - Path icon(); + Optional icon(); - record Stub(WinMsiPackage msiPackage, Path icon) implements WinExePackageMixin {} + record Stub(WinMsiPackage msiPackage, Optional icon) implements WinExePackageMixin {} } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java index ee1955fe75ac9..b6c7f1d103d43 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java @@ -35,8 +35,8 @@ public interface WinLauncher extends Launcher, WinLauncherMixin { @Override - default String executableSuffix() { - return ".exe"; + default Optional executableSuffix() { + return Optional.of(".exe"); } @Override @@ -51,11 +51,6 @@ default Map extraAppImageFileData() { toMap(WinShortcut::name, v -> Boolean.toString(true))); } - @Override - default String defaultIconResourceName() { - return "JavaApp.ico"; - } - public static WinLauncher create(Launcher launcher, WinLauncherMixin mixin) { return CompositeProxy.create(WinLauncher.class, launcher, mixin); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java index f2a26b081de6f..48b2677fd7ea9 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import java.util.Optional; import java.util.UUID; public interface WinMsiPackageMixin { @@ -33,9 +34,9 @@ public interface WinMsiPackageMixin { boolean withShortcutPrompt(); - String helpURL(); + Optional helpURL(); - String updateURL(); + Optional updateURL(); String startMenuGroupName(); @@ -45,10 +46,10 @@ public interface WinMsiPackageMixin { UUID productCode(); - Path serviceInstaller(); + Optional serviceInstaller(); record Stub(boolean withInstallDirChooser, boolean withShortcutPrompt, - String helpURL, String updateURL, String startMenuGroupName, + Optional helpURL, Optional updateURL, String startMenuGroupName, boolean isSystemWideInstall, UUID upgradeCode, UUID productCode, - Path serviceInstaller) implements WinMsiPackageMixin {} + Optional serviceInstaller) implements WinMsiPackageMixin {} } From 88bfc7019255ad562219eefcc5f7f06c7a2b1d1d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 3 Jan 2025 21:27:03 -0500 Subject: [PATCH 0208/1101] Fix NPE --- .../jdk/jpackage/internal/model/ApplicationLayoutTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java index fc1275d0ace7a..b1ec4c0c2e40e 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java @@ -59,6 +59,9 @@ public void test(boolean move, Path tempDir) throws IOException { .launchersDirectory("bin") .appDirectory("lib/app") .runtimeDirectory("runtime") + .appModsDirectory("mods") + .contentDirectory("content") + .destktopIntegrationDirectory("lib/apps") .create(); final var dstAppImageRoot = tempDir.resolve("dst"); From a4b2c315e49448ed1cec0d055924b2ad5c7fe3db Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 7 Jan 2025 00:01:36 -0500 Subject: [PATCH 0209/1101] javadoc added --- .../internal/model/AppImageLayout.java | 25 +++- .../internal/model/AppImagePackageType.java | 8 ++ .../jpackage/internal/model/Application.java | 134 ++++++++++++++++++ .../internal/model/ApplicationLaunchers.java | 13 +- .../internal/model/ApplicationLayout.java | 12 +- .../model/ApplicationLayoutMixin.java | 5 +- .../internal/model/LauncherStartupInfo.java | 2 +- .../internal/model/RuntimeLayout.java | 2 +- 8 files changed, 194 insertions(+), 7 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java index 203ac04109613..ea972c54419cc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java @@ -37,17 +37,26 @@ /** - * App image directory layout. + * Generic app image directory layout. */ public interface AppImageLayout { /** - * Path to Java runtime directory. + * A path to Java runtime directory. + * @return Java runtime sub-directory within this app image */ Path runtimeDirectory(); + /** + * Creates a copy of this app image resolved at the given root directory. + * @param root path to a directory at which to resolve the layout + * @return a copy of this app image resolved at the given root directory + */ AppImageLayout resolveAt(Path root); + /** + * Default implementation of {@link AppImageLayout} interface. + */ record Stub(Path runtimeDirectory) implements AppImageLayout { @Override @@ -56,6 +65,18 @@ public AppImageLayout resolveAt(Path base) { } } + /** + * Creates {@link PathGroup} object from the given {@link AppImageLayout} instance. + * + * It will call every non-static accessible method without parameters and with + * {@link Path} return type of the given {@link AppImageLayout} instance. + *

+ * For every call, it will save the return value in the output {@link PathGroup} + * object under the key equals the name of a function used in the call. + * + * @param appImageLayout source layout object + * @return {@link PathGroup} object constructed from the given source layout object + */ public static PathGroup toPathGroup(AppImageLayout appImageLayout) { return new PathGroup(Stream.of(appImageLayout.getClass().getInterfaces()) // For all interfaces (it should be one, but multiple is OK) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java index 87ec04bf84f26..21733fe141559 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java @@ -24,10 +24,18 @@ */ package jdk.jpackage.internal.model; +/** + * App image packaging type. + * + * @see StandardPackageType + */ public final class AppImagePackageType implements PackageType { private AppImagePackageType() { } + /** + * Singleton + */ public final static AppImagePackageType APP_IMAGE = new AppImagePackageType(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index e5fce735e4754..d5b82bc9127de 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -31,24 +31,81 @@ import java.util.Optional; import java.util.stream.Stream; +/** + * A generic application for packaging. + * + * @apiNote All methods return non-null values. + * + * @see Package + */ public interface Application { + /** + * Returns application's name. + * @return application name + */ String name(); + /** + * Returns application's description. + * @return application description + */ String description(); + /** + * Returns the application's version. + * @return application name + */ String version(); + /** + * Returns application's vendor. + * @return application vendor + */ String vendor(); + /** + * Returns application's copyright. + * @return application copyright + */ String copyright(); + /** + * Returns the application's source directory if available or an empty {@link Optional} instance. + *

+ * Source directory is a directory with the applications's classes and other resources. + * + * @return application source directory + */ Optional srcDir(); + /** + * Returns the application's input content directories. + *

+ * Contents of the content directories will be copied as-is into the dedicated location of the application image. + * + * @see ApplicationLayout#contentDirectory + * + * @return application content directories + */ List contentDirs(); + /** + * Returns app image layout. + * @return app image layout + */ AppImageLayout imageLayout(); + /** + * Returns app image layout as {@link ApplicationLayout} type or an empty {@link Optional} instance + * if the return value of {@link #imageLayout()} call is not instance of {@link ApplicationLayout}. + *

+ * Returns an empty {@link Optional} instance if {@link #isRuntime()} returns true. + * + * @see #isRuntime + * + * @return app image as {@link ApplicationLayout} + */ default Optional asApplicationLayout() { if (imageLayout() instanceof ApplicationLayout layout) { return Optional.of(layout); @@ -57,45 +114,122 @@ default Optional asApplicationLayout() { } } + /** + * Returns runtime builder if available or an empty {@link Optional} instance. + * @return runtime builder + */ Optional runtimeBuilder(); + /** + * Returns the name of the root app image directory. + * @return name of the root app image directory. + */ default Path appImageDirName() { return Path.of(name()); } + /** + * Returns application launchers. + *

+ * If the returned list is not empty, the first element in the list is the main launcher. + *

+ * Returns an empty list if {@link #isRuntime()} returns true. + * + * @see #mainLauncher() + * @see #additionalLaunchers() + * @see #isRuntime() + * + * @return application launchers + */ List launchers(); + /** + * Returns the main application launcher or an empty {@link Optional} instance if the application doesn't have launchers. + *

+ * Returns an empty {@link Optional} instance if {@link #isRuntime()} returns true. + * + * @see #launchers() + * @see #additionalLaunchers() + * @see #isRuntime() + * + * @return main application launcher + */ default Optional mainLauncher() { return ApplicationLaunchers.fromList(launchers()).map(ApplicationLaunchers::mainLauncher); } + /** + * Returns additional application launchers. + *

+ * Returns an empty list if there are no additional application launchers. + *

+ * Returns an empty list if {@link #isRuntime()} returns true. + * + * @see #launchers() + * @see #mainLauncher() + * @see #isRuntime() + * + * @return additional application launchers + */ default List additionalLaunchers() { return ApplicationLaunchers.fromList(launchers()).map(ApplicationLaunchers::additionalLaunchers).orElseGet(Collections::emptyList); } + /** + * Returns true if the application for packaging is Java runtime. + * @return true if the application for packaging is Java runtime. + */ default boolean isRuntime() { return imageLayout() instanceof RuntimeLayout; } + /** + * Returns true if any of application launchers are configured as services. + * + * @see Launcher#isService + * + * @return true if any of application launchers are configured as services + */ default boolean isService() { return Optional.ofNullable(launchers()).orElseGet(List::of).stream().filter( Launcher::isService).findAny().isPresent(); } + /** + * Returns additional properties for application launcher entries in the app image (".jpackage") file. + * + * @see Launcher#isService + * + * @return additional properties for application launcher entries in ".jpackage" file + */ default Map extraAppImageFileData() { return Map.of(); } + /** + * Returns file associations of all application launchers. + * + * @return file associations of all application launchers + * + * @see Launcher#fileAssociations + */ default Stream fileAssociations() { return launchers().stream().map(Launcher::fileAssociations).flatMap(List::stream); } + /** + * Default implementation of {@link Application} interface. + */ record Stub(String name, String description, String version, String vendor, String copyright, Optional srcDir, List contentDirs, AppImageLayout imageLayout, Optional runtimeBuilder, List launchers) implements Application { } + /** + * Implementation of {@link Application} interface in which every method + * throws {@link UnsupportedOperationException} exception. + */ class Unsupported implements Application { @Override diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java index fe72c721c89b1..94503ddd570e6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java @@ -29,9 +29,20 @@ import java.util.Optional; import java.util.stream.Stream; +/** + * Utility class to manage application launchers. + *

+ * Use {@link #asList} to get application launchers as a list. + *

+ * Use {@link #mainLauncher()} to get the main application launcher. + *

+ * Use {@link #additionalLaunchers()} to get additional application launchers. + *

+ * Use {@link #fromList} to convert the list of application launchers into {@link ApplicationLaunchers} instance. + */ public record ApplicationLaunchers(Launcher mainLauncher, List additionalLaunchers) { - public ApplicationLaunchers { + public ApplicationLaunchers { Objects.requireNonNull(mainLauncher); Objects.requireNonNull(additionalLaunchers); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index 566fb090d0f1f..7da5c9a84e770 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -30,7 +30,9 @@ import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; /** - * Application directory layout. + * Application app image layout. + * + * Application is comprised from application files and Java runtime. */ public interface ApplicationLayout extends AppImageLayout, ApplicationLayoutMixin { @@ -39,6 +41,14 @@ default ApplicationLayout resolveAt(Path root) { return buildFrom(this).resolveAt(root).create(); } + /** + * Creates an object implementing {@link ApplicationLayout} interface from + * {@link AppImageLayout} and {@link ApplicationLayoutMixin} instances. + * + * @param appImage app image layout object + * @param mixin application layout mixin for the app image layout + * @return new object implementing {@link ApplicationLayout} interface + */ static ApplicationLayout create(AppImageLayout appImage, ApplicationLayoutMixin mixin) { return CompositeProxy.create(ApplicationLayout.class, appImage, mixin); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java index 590f61fc0c1cc..2fc4871a57a1e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java @@ -42,7 +42,7 @@ public interface ApplicationLayoutMixin { Path appDirectory(); /** - * Path to application mods directory. + * Path to directory with application's Java modules. */ Path appModsDirectory(); @@ -56,6 +56,9 @@ public interface ApplicationLayoutMixin { */ Path contentDirectory(); + /** + * Default implementation of {@link ApplicationLayoutMixin} interface. + */ record Stub(Path launchersDirectory, Path appDirectory, Path appModsDirectory, Path destktopIntegrationDirectory, Path contentDirectory) implements ApplicationLayoutMixin { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java index 312e3d20e6994..c6a31e70657ab 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java @@ -48,7 +48,7 @@ default String packageName() { * * Every path in the list is relative to app's main source directory. * - * @see jdk.jpackage.internal.Application#mainSrcDir() + * @see Application#srcDir() */ List classPath(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java index da7e9238651bc..f9329c17557f7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java @@ -30,7 +30,7 @@ /** - * Runtime app image layout. + * Java runtime app image layout. Returns the root app image directory. */ public interface RuntimeLayout extends AppImageLayout { From 939327fd1ef652dbbb68c17733e808f6e2045915 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 7 Jan 2025 00:40:29 -0500 Subject: [PATCH 0210/1101] More javadoc --- .../internal/model/ApplicationLayout.java | 8 ++++- .../internal/model/ApplicationWriter.java | 12 +++++++ .../internal/model/ConfigException.java | 34 ++++++++++++++++++- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index 7da5c9a84e770..a97850b04aa09 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -31,8 +31,11 @@ /** * Application app image layout. - * + *

* Application is comprised from application files and Java runtime. + *

+ * Use {@link #build()} or {@link #buildFrom(ApplicationLayout)} methods to + * configure and construct instances of this interface. */ public interface ApplicationLayout extends AppImageLayout, ApplicationLayoutMixin { @@ -61,6 +64,9 @@ public static Builder buildFrom(ApplicationLayout appLayout) { return new Builder(appLayout); } + /** + * Builds {@link ApplicationLayout} instances. + */ final class Builder { private Builder() { } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java index b3d1193265bcc..b4b7c1ade6aa2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java @@ -29,6 +29,18 @@ import java.nio.file.Path; +/** + * Packages the given {@link Application} and saves it at the given location. + */ +@FunctionalInterface public interface ApplicationWriter { + /** + * Packages the given {@link Application} and saves it at the given location. + * + * @param app an application to package + * @param dst destination where to save the packaged application + * @throws PackagerException + * @throws IOException + */ void write(Application app, Path dst) throws PackagerException, IOException; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java index 44e8d1ff0ad26..741c891f636f4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java @@ -28,9 +28,27 @@ import jdk.jpackage.internal.util.LocalizedExceptionBuilder; import jdk.jpackage.internal.util.StringBundle; +/** + * Signals that error has occurred at configuration phase. + *

+ * It contains an error message and an optional advice message on how to correct the error. + *

+ * The preferred way to construct instances of this class is to use + * {@link #build(StringBundle)}, or {@link #build(StringBundle, Throwable)}, + * or {@link #build(StringBundle, String, Object...)} methods. + * + * {@snippet : + * StringBundle i18n = getStringBundle(); // Some way to obtain a string bundle with localized messages + * + * throw ConfigException.build(i18n) + * .message("error.no.name") + * .advice("error.no.name.advice") + * .create() + * } + */ public class ConfigException extends Exception { private static final long serialVersionUID = 1L; - final String advice; + private final String advice; public ConfigException(String msg, String advice) { super(msg); @@ -63,6 +81,9 @@ public static Builder build(StringBundle i18n, Throwable t) { return build(i18n).causeAndMessage(t); } + /** + * Builds {@link ConfigException} instances. + */ public static class Builder extends LocalizedExceptionBuilder { public Builder advice(String adviceId, Object ... args) { @@ -85,6 +106,17 @@ private ConfigException create(String msg, Throwable cause) { private String advice; } + /** + * Throws the cause of the given {@link RuntimeException} exception + * as {@link ConfigException} if the cause is of this type or re-throws the given + * {@link RuntimeException} exception as-is otherwise. + *

+ * Never return a value. It always throws some exception object. + * + * @param ex exception to re-throw + * @return doesn't return value + * @throws ConfigException + */ public static RuntimeException rethrowConfigException(RuntimeException ex) throws ConfigException { if (ex.getCause() instanceof ConfigException configEx) { throw configEx; From 11e7769d5acbaeaf291de1aa239752f05b9bc31d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 7 Jan 2025 00:59:12 -0500 Subject: [PATCH 0211/1101] More javadoc added --- .../internal/model/CustomLauncherIcon.java | 24 +++++++++++++++++++ .../internal/model/DefaultLauncherIcon.java | 17 +++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/CustomLauncherIcon.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/CustomLauncherIcon.java index 8fdac1dc5013d..fc270ecd03ec9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/CustomLauncherIcon.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/CustomLauncherIcon.java @@ -28,10 +28,26 @@ import java.util.Objects; import java.util.Optional; +/** + * Custom application launcher icon. + *

+ * Use {@link #create(Path)} method to create an instance of this type. + */ public interface CustomLauncherIcon extends LauncherIcon { + /** + * Returns path to icon file. + * @return path to icon file + */ Path path(); + /** + * Returns the given icon as {@link CustomLauncherIcon} type or an empty {@link Optional} instance + * if the given icon object is not an instance of {@link CustomLauncherIcon} type. + * + * @param icon application launcher icon object or null + * @return the given icon as {@link CustomLauncherIcon} type or an empty {@link Optional} instance + */ public static Optional fromLauncherIcon(LauncherIcon icon) { if (icon instanceof CustomLauncherIcon customIcon) { return Optional.of(customIcon); @@ -40,11 +56,19 @@ public static Optional fromLauncherIcon(LauncherIcon icon) { } } + /** + * Creates object of type {@link CustomLauncherIcon} from the path to icon file. + * @param path path to icon file + * @return {@link CustomLauncherIcon} instance + */ public static CustomLauncherIcon create(Path path) { Objects.requireNonNull(path); return new Stub(path); } + /** + * Default implementation of {@link CustomLauncherIcon} type. + */ record Stub(Path path) implements CustomLauncherIcon { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DefaultLauncherIcon.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DefaultLauncherIcon.java index 7462cf6b74852..b9ee8c6defb55 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DefaultLauncherIcon.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DefaultLauncherIcon.java @@ -26,8 +26,22 @@ import java.util.Optional; +/** + * Default application launcher icon. + *

+ * Default icon is either loaded from the resources of {@link jdk.jpackage/} module or picked from the resource directory. + *

+ * Use {@link #INSTANCE} field to get an instance of this type. + */ public interface DefaultLauncherIcon extends LauncherIcon { + /** + * Returns the given icon as {@link DefaultLauncherIcon} type or an empty {@link Optional} instance + * if the given icon object is not an instance of {@link DefaultLauncherIcon} type. + * + * @param icon application launcher icon object or null + * @return the given icon as {@link DefaultLauncherIcon} type or an empty {@link Optional} instance + */ public static Optional fromLauncherIcon(LauncherIcon icon) { if (icon instanceof DefaultLauncherIcon defaultIcon) { return Optional.of(defaultIcon); @@ -36,5 +50,8 @@ public static Optional fromLauncherIcon(LauncherIcon icon) } } + /** + * Singleton. + */ public static DefaultLauncherIcon INSTANCE = new DefaultLauncherIcon() {}; } From 7635496a4334ded8c10ea09e518e8c7d343219c7 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 7 Jan 2025 12:11:25 -0500 Subject: [PATCH 0212/1101] More javadoc --- .../jpackage/internal/model/Application.java | 6 +- .../internal/model/FileAssociation.java | 34 +++++++ .../jdk/jpackage/internal/model/Launcher.java | 91 ++++++++++++++++++- .../jpackage/internal/model/PackageType.java | 5 + .../internal/model/StandardPackageType.java | 16 ++-- .../jpackage/internal/util/StringBundle.java | 31 +++++++ 6 files changed, 170 insertions(+), 13 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index d5b82bc9127de..8cf04c9b086bd 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -196,11 +196,9 @@ default boolean isService() { } /** - * Returns additional properties for application launcher entries in the app image (".jpackage") file. + * Gets the additional properties for the application entry in the app image (".jpackage") file. * - * @see Launcher#isService - * - * @return additional properties for application launcher entries in ".jpackage" file + * @return the additional properties for the application entry in ".jpackage" file */ default Map extraAppImageFileData() { return Map.of(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java index 3f630e9fb706e..74162a6137c85 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java @@ -28,24 +28,58 @@ import java.util.Optional; import java.util.function.Predicate; +/** + * File association. + */ public interface FileAssociation { + /** + * Returns file association description if available or an empty {@link Optional} instance. + * @see {@link #nonEmptyDescription()} + * @return file association description + */ Optional description(); + /** + * Returns file association icon if available or an empty {@link Optional} instance. + * @see {@link #hasIcon()} + * @return file association icon + */ Optional icon(); + /** + * Returns true if the file association has an icon. + * @see {@link #icon()} + * @return true if the file association has an icon + */ default boolean hasIcon() { return icon().isPresent(); } + /** + * Returns a non-empty description of this file association if available or an empty {@link Optional} instance. + * @see {@link #description()} + * @return non-empty file association description + */ default Optional nonEmptyDescription() { return description().filter(Predicate.not(String::isEmpty)); } + /** + * Returns file association MIME type. E.g.: application/foo, text/plain. + * @return file association MIME type + */ String mimeType(); + /** + * Returns file association extension. E.g.: .txt + * @return file association extension + */ String extension(); + /** + * Default implementation of {@link FileAssociation} interface + */ record Stub(Optional description, Optional icon, String mimeType, String extension) implements FileAssociation { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java index 86519e8dc119b..539726c872dff 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java @@ -30,63 +30,152 @@ import java.util.Optional; import jdk.jpackage.internal.resources.ResourceLocator; +/** + * Application launcher. + * + * @apiNote All methods return non-null values. + * + * @see Application#launchers() + */ public interface Launcher { + /** + * Gets name of this launcher. + * @return the name of this launcher + */ String name(); + /** + * Gets name of the executable file of this launcher without file extension. + * @return the name of the executable file of this launcher + */ default String executableName() { return name(); } + /** + * Gets extension of the executable file of this launcher if available or an empty {@link Optional} instance. + * @return the extension of the executable file of this launcher + */ default Optional executableSuffix() { return Optional.empty(); } + /** + * Gets full name of the executable file of this launcher. The full name consists of the name and the extension. + * @return the full name of the executable file of this launcher + */ default String executableNameWithSuffix() { return executableName() + executableSuffix().orElse(""); } + /** + * Gets startup information of this launcher if available or an empty {@link Optional} instance. + * @apiNote + * Launchers from an external application image may not have startup information. + * @return the startup information of this launcher + */ Optional startupInfo(); + /** + * Gets file associations of this launcher. + * @return the file associations of this launcher + */ List fileAssociations(); + /** + * Returns true if this launcher should be installed as a service. + * @return true if this launcher should be installed as a service + */ boolean isService(); + /** + * Gets description of this launcher. + * @return the description of this launcher + */ String description(); + /** + * Opens a stream with the template executable file for this launcher. + * Caller is responsible for close the stream. + * @return a stream with the template executable file for this launcher + */ default InputStream executableResource() { return ResourceLocator.class.getResourceAsStream("jpackageapplauncher"); } + /** + * Gets the additional properties for application launcher entries in the app image (".jpackage") file. + * + * @return the additional properties for application launcher entries in ".jpackage" file + */ default Map extraAppImageFileData() { return Map.of(); } /** - * Icon for the launcher. + * Gets the icon for this launcher or an empty {@link Optional} instance if the launcher is requested to have no icon. + * @return the icon for this launcher + * @see #hasIcon() + * @see #hasDefaultIcon() + * @see #hasCustomIcon() */ Optional icon(); + /** + * Returns true if this launcher is requested to have an icon. + * @return true if this launcher is requested to have an icon + * @see #icon() + * @see #hasDefaultIcon() + * @see #hasCustomIcon() + */ default boolean hasIcon() { return icon().isPresent(); } + /** + * Returns true if this launcher has a default icon. + * @return true if this launcher has a default icon + * @see DefaultLauncherIcon + * @see #icon() + * @see #hasIcon() + * @see #hasCustomIcon() + */ default boolean hasDefaultIcon() { return icon().flatMap(DefaultLauncherIcon::fromLauncherIcon).isPresent(); } + /** + * Returns true if this launcher has a custom icon. + * @return true if this launcher has a custom icon + * @see CustomLauncherIcon + * @see #icon() + * @see #hasDefaultIcon() + * @see #hasIcon() + */ default boolean hasCustomIcon() { return icon().flatMap(CustomLauncherIcon::fromLauncherIcon).isPresent(); } + /** + * Gets key in the resource bundle of {@link jdk.jpackage/} module referring to the default launcher icon. + * @return the key in the resource bundle referring to the default launcher icon + */ String defaultIconResourceName(); + /** + * Default implementation of {@link Launcher} interface. + */ record Stub(String name, Optional startupInfo, List fileAssociations, boolean isService, String description, Optional icon, String defaultIconResourceName) implements Launcher { } + /** + * Implementation of {@link Launcher} interface in which every method + * throws {@link UnsupportedOperationException} exception. + */ class Unsupported implements Launcher { @Override diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java index 7dfbf505c6fa8..bd02d30e9ec04 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java @@ -26,4 +26,9 @@ package jdk.jpackage.internal.model; +/** + * Generic package type. E.g.: application image, rpm, msi are all package types. + * + * @see jdk.jpackage.internal.model.Package + */ public interface PackageType {} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java index bdf20b4e44e63..13e23e3d27eaa 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java @@ -27,6 +27,9 @@ import java.util.Objects; import java.util.stream.Stream; +/** + * Standard native package types. + */ public enum StandardPackageType implements PackageType { WIN_MSI(".msi"), WIN_EXE(".exe"), @@ -39,17 +42,14 @@ public enum StandardPackageType implements PackageType { this.suffix = suffix; } + /** + * Gets file extension of this package type. + * E.g.: .msi, .dmg, .deb. + * @return file extension of this package type + */ public String suffix() { return suffix; } - public static StandardPackageType fromCmdLineType(String type) { - Objects.requireNonNull(type); - return Stream.of(values()).filter(pt -> { - return pt.suffix().substring(1).equals(type); - }).findAny().get(); - } - - private final String suffix; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java index 461302537d935..d97e73ddf12fd 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java @@ -28,10 +28,36 @@ import java.util.ResourceBundle; +/** + * String bundle contains locale-specific strings. + * It can be viewed a specialized variant of {@link ResourceBundle}. + *

+ * Use {@link #fromResourceBundle(ResourceBundle)} to obtain {@link StringBundle} + * instance from {@link ResourceBundle} object. + */ @FunctionalInterface public interface StringBundle { + + /** + * Gets a string for the given key from this string bundle. + * @param key the key for the desired string + * @return the string for the given key + * + * @see ResourceBundle#getString(String) + */ String getString(String key); + /** + * Gets a formatted message built from the pattern string matching + * the given key in this string bundle and the given arguments. + *

+ * If non-empty list of arguments provided the function calls {@link MessageFormat#format(String, Object...)}. + * Otherwise, it returns the result of {@link #getString(String)} method call. + * + * @param key the key for the desired pattern + * @param args the array of arguments for formatting or an empty array for no formatting + * @return the formatted message + */ default String format(String key, Object ... args) { var str = getString(key); if (args.length != 0) { @@ -41,6 +67,11 @@ default String format(String key, Object ... args) { } } + /** + * Gets {@link StringBundle} instance from the given {@link ResourceBundle} object. + * @param bundle the resource bundle + * @return the string bundle + */ public static StringBundle fromResourceBundle(ResourceBundle bundle) { return bundle::getString; } From 7cf9ba17dc6934b5c087ccb88c614ea896d39e50 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 7 Jan 2025 12:12:48 -0500 Subject: [PATCH 0213/1101] Fix javadoc --- .../share/classes/jdk/jpackage/internal/cli/ValueConverter.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java index 88988f6f8f24d..d505a72e6f299 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java @@ -31,8 +31,6 @@ public interface ValueConverter { * * @param value the string to convert * @return the converted value - * @throws ValueConversionException if a problem occurs while converting the - * value */ T convert(String value); From ec5d98e212cfaf77e8392d76a03aaf929378e358 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 7 Jan 2025 12:13:17 -0500 Subject: [PATCH 0214/1101] Remove redundant imports --- .../jdk/jpackage/internal/model/StandardPackageType.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java index 13e23e3d27eaa..0938fa6bf7db3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java @@ -24,9 +24,6 @@ */ package jdk.jpackage.internal.model; -import java.util.Objects; -import java.util.stream.Stream; - /** * Standard native package types. */ From f3094ada8ea396549567c56b0e21c3c8301ccbaf Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 7 Jan 2025 12:14:04 -0500 Subject: [PATCH 0215/1101] Move StandardPackageType.fromCmdLineType() to jdk.jpackage.internal.cli.StandardOption --- .../classes/jdk/jpackage/internal/cli/StandardOption.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index 5599ad3922660..c1676a39aa955 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -50,7 +50,7 @@ public PackageType convert(String value) { if ("app-image".equals(value)) { return AppImagePackageType.APP_IMAGE; } else { - return StandardPackageType.fromCmdLineType(value); + return fromCmdLineType(value); } } @@ -59,6 +59,12 @@ public Class valueType() { return PackageType.class; } + private static StandardPackageType fromCmdLineType(String type) { + Objects.requireNonNull(type); + return Stream.of(StandardPackageType.values()).filter(pt -> { + return pt.suffix().substring(1).equals(type); + }).findAny().get(); + } })), INPUT(build("input").shortName("i").ofDirectory(), APP_IMAGE), DEST(build("dest").shortName("d").ofDirectory()), From 08e64de0517576db6e0d20c4ca92121cce2a0ed6 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 7 Jan 2025 13:30:07 -0500 Subject: [PATCH 0216/1101] More javadoc --- .../jpackage/internal/model/Application.java | 4 +- .../jpackage/internal/model/LauncherIcon.java | 3 ++ .../model/LauncherJarStartupInfo.java | 14 +++++- .../model/LauncherJarStartupInfoMixin.java | 20 ++++++-- .../model/LauncherModularStartupInfo.java | 14 +++++- .../LauncherModularStartupInfoMixin.java | 14 ++++++ .../internal/model/LauncherStartupInfo.java | 46 +++++++++++++++---- .../jpackage/internal/model/package-info.java | 34 ++++++++++++++ 8 files changed, 129 insertions(+), 20 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/package-info.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index 8cf04c9b086bd..b6ae55dc0e9ff 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -34,7 +34,9 @@ /** * A generic application for packaging. * - * @apiNote All methods return non-null values. + * @apiNote + * All paths of startup configurations of application launchers returned + * by {@link #launchers()} call must be relative to the path returned by {@link #srcDir()} call. * * @see Package */ diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java index 41beeaa86cdcf..61add162a4e47 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java @@ -24,5 +24,8 @@ */ package jdk.jpackage.internal.model; +/** + * Launcher icon + */ public interface LauncherIcon { } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java index 486b7e64e7508..46791b6702adb 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java @@ -26,12 +26,22 @@ import jdk.jpackage.internal.util.CompositeProxy; +/** + * Application launcher startup configuration using non-modular jar file. + */ public interface LauncherJarStartupInfo extends LauncherStartupInfo, LauncherJarStartupInfoMixin { + /** + * Constructs {@link LauncherJarStartupInfo} instance from the given + * {@link LauncherJarStartupInfo} and {@link LauncherJarStartupInfoMixin} instances. + * + * @param info the generic launcher startup information + * @param mixin the supplementary launcher startup information + * @return the proxy dispatching calls to the given objects + */ public static LauncherJarStartupInfo create(LauncherStartupInfo info, LauncherJarStartupInfoMixin mixin) { - return CompositeProxy.create(LauncherJarStartupInfo.class, - info, mixin); + return CompositeProxy.create(LauncherJarStartupInfo.class, info, mixin); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java index baaff758496ff..9164c9cdfbbac 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java @@ -26,15 +26,25 @@ import java.nio.file.Path; +/** + * Application launcher startup configuration from a non-modular jar file. + */ public interface LauncherJarStartupInfoMixin { + /** - * Returns path to the main jar relative to app's main source directory. - * - * @see jdk.jpackage.internal.model.Application#srcDir() + * Gets the path to the input jar file. + * @return the path to the input jar file */ Path jarPath(); - boolean isClassNameFromMainJar(); + /** + * Returns true if the input jar file has Main-Class entry in the manifest. + * @return true if the input jar file has Main-Class entry in the manifest + */ + boolean isJarWithMainClass(); - record Stub(Path jarPath, boolean isClassNameFromMainJar) implements LauncherJarStartupInfoMixin {} + /** + * Default implementation of {@link LauncherJarStartupInfoMixin} interface. + */ + record Stub(Path jarPath, boolean isJarWithMainClass) implements LauncherJarStartupInfoMixin {} } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java index 8d2abe1baf2af..068daf4b9bf28 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java @@ -26,12 +26,22 @@ import jdk.jpackage.internal.util.CompositeProxy; +/** + * Application launcher startup configuration using Java module. + */ public interface LauncherModularStartupInfo extends LauncherStartupInfo, LauncherModularStartupInfoMixin { + /** + * Constructs {@link LauncherModularStartupInfo} instance from the given + * {@link LauncherJarStartupInfo} and {@link LauncherModularStartupInfoMixin} instances. + * + * @param info the generic launcher startup information + * @param mixin the supplementary launcher startup information + * @return the proxy dispatching calls to the given objects + */ public static LauncherModularStartupInfo create(LauncherStartupInfo info, LauncherModularStartupInfoMixin mixin) { - return CompositeProxy.create( - LauncherModularStartupInfo.class, info, mixin); + return CompositeProxy.create(LauncherModularStartupInfo.class, info, mixin); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java index 03306f2c657b8..774648bf599cf 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java @@ -27,12 +27,26 @@ import java.nio.file.Path; import java.util.List; +/** + * Application launcher startup configuration from Java module. + */ public interface LauncherModularStartupInfoMixin { + /** + * Gets the main module name. + * @return the main module name + */ String moduleName(); + /** + * Gets the path to the input module location. + * @return the path to the input module location + */ List modulePath(); + /** + * Default implementation of {@link LauncherModularStartupInfoMixin} interface. + */ record Stub(String moduleName, List modulePath) implements LauncherModularStartupInfoMixin { } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java index c6a31e70657ab..d707fd75cc090 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java @@ -24,40 +24,66 @@ */ package jdk.jpackage.internal.model; +import java.lang.constant.ClassDesc; import java.nio.file.Path; import java.util.List; +/** + * Generic startup configuration of an application launcher. + * + * @see Launcher#startupInfo() + */ public interface LauncherStartupInfo { + /** + * Gets the qualified name of the main class of this launcher startup configuration. + * @return the qualified name of the main class of this launcher startup configuration + */ String qualifiedClassName(); + /** + * Gets the package name of the main class of this launcher startup configuration. + * @return the package name of the main class of this launcher startup configuration + */ default String packageName() { - int sepIdx = qualifiedClassName().lastIndexOf('.'); - if (sepIdx < 0) { - return ""; - } - return qualifiedClassName().substring(sepIdx + 1); + return ClassDesc.of(qualifiedClassName()).packageName(); } + /** + * Gets JVM options of this launcher startup configuration. + * @return the JVM options of this launcher startup configuration + */ List javaOptions(); + /** + * Gets the default parameters for the main(String[] args) + * method of the main class of this launcher startup configuration. + * + * @return the default parameters for the main(String[] args) + * method of the main class of this launcher startup configuration + */ List defaultParameters(); /** - * Returns list of paths to add to the classpath. - * - * Every path in the list is relative to app's main source directory. - * - * @see Application#srcDir() + * Gets the files and directories that should be put on a classpath for + * an application launcher this launcher startup configuration applies to. + * @return the classpath of this launcher startup configuration */ List classPath(); + /** + * Default implementation of {@link LauncherStartupInfo} interface. + */ record Stub(String qualifiedClassName, List javaOptions, List defaultParameters, List classPath) implements LauncherStartupInfo { } + /** + * Implementation of {@link LauncherStartupInfo} interface in which every method + * throws {@link UnsupportedOperationException} exception. + */ class Unsupported implements LauncherStartupInfo { @Override diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/package-info.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/package-info.java new file mode 100644 index 0000000000000..7044fcfb2169f --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/package-info.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Classes and interfaces of the internal application packaging model. + * + * Primary entities are: {@link Application}, {@link jdk.jpackage.internal.model.Package}, and {@link Launcher}. + * + * @apiNote + * All methods of all interfaces and classes in this package return non-null values unless stated otherwise. + */ +package jdk.jpackage.internal.model; \ No newline at end of file From 1b16976a70e0b88aa98aa097202260abfaa3289e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 7 Jan 2025 18:10:36 -0500 Subject: [PATCH 0217/1101] More javadoc --- .../internal/model/AppImageLayout.java | 14 +- .../jpackage/internal/model/Application.java | 133 ++++++---- .../internal/model/ApplicationWriter.java | 11 +- .../jdk/jpackage/internal/model/Launcher.java | 62 +++-- .../jpackage/internal/model/LauncherIcon.java | 2 +- .../jdk/jpackage/internal/model/Package.java | 232 ++++++++++++++++-- .../internal/model/PackageWriter.java | 13 + .../internal/model/RuntimeLayout.java | 14 +- 8 files changed, 373 insertions(+), 108 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java index ea972c54419cc..58c5a926b2d50 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java @@ -38,17 +38,25 @@ /** * Generic app image directory layout. + * + * App image layout is a collection of files and directories with specific roles + * (executables, configuration files, etc.) sharing the same root directory. + * + * The layout is "unresolved" if the root directory is an empty string and + * "resolved" otherwise. */ public interface AppImageLayout { /** * A path to Java runtime directory. + * * @return Java runtime sub-directory within this app image */ Path runtimeDirectory(); /** * Creates a copy of this app image resolved at the given root directory. + * * @param root path to a directory at which to resolve the layout * @return a copy of this app image resolved at the given root directory */ @@ -66,7 +74,8 @@ public AppImageLayout resolveAt(Path base) { } /** - * Creates {@link PathGroup} object from the given {@link AppImageLayout} instance. + * Creates {@link PathGroup} object from the given {@link AppImageLayout} + * instance. * * It will call every non-static accessible method without parameters and with * {@link Path} return type of the given {@link AppImageLayout} instance. @@ -75,7 +84,8 @@ public AppImageLayout resolveAt(Path base) { * object under the key equals the name of a function used in the call. * * @param appImageLayout source layout object - * @return {@link PathGroup} object constructed from the given source layout object + * @return {@link PathGroup} object constructed from the given source layout + * object */ public static PathGroup toPathGroup(AppImageLayout appImageLayout) { return new PathGroup(Stream.of(appImageLayout.getClass().getInterfaces()) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index b6ae55dc0e9ff..a27b2d42c437e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -34,79 +34,92 @@ /** * A generic application for packaging. * - * @apiNote - * All paths of startup configurations of application launchers returned - * by {@link #launchers()} call must be relative to the path returned by {@link #srcDir()} call. + * @apiNote All paths of startup configurations of application launchers + * returned by {@link #launchers()} call must be relative to the path + * returned by {@link #srcDir()} call. * * @see Package */ public interface Application { /** - * Returns application's name. - * @return application name + * Gets the name of this application. + * + * @return the name of this application */ String name(); /** - * Returns application's description. - * @return application description + * Gets the description of this application. + * + * @return the description of this application */ String description(); /** - * Returns the application's version. - * @return application name + * Gets the version of this application. + * + * @return the version of this application */ String version(); /** - * Returns application's vendor. - * @return application vendor + * Gets the vendor of this application. + * + * @return the vendor of this application */ String vendor(); /** - * Returns application's copyright. - * @return application copyright + * Gets the copyright of this application. + * + * @return the copyright of this application */ String copyright(); /** - * Returns the application's source directory if available or an empty {@link Optional} instance. + * Gets the source directory of this application if available or an empty + * {@link Optional} instance. *

- * Source directory is a directory with the applications's classes and other resources. + * Source directory is a directory with the applications's classes and other + * resources. * - * @return application source directory + * @return the source directory of this application */ Optional srcDir(); /** - * Returns the application's input content directories. + * Gets the input content directories of this application. *

- * Contents of the content directories will be copied as-is into the dedicated location of the application image. + * Contents of the content directories will be copied as-is into the dedicated + * location of the application image. * * @see ApplicationLayout#contentDirectory * - * @return application content directories + * @return the input content directories of this application */ List contentDirs(); /** - * Returns app image layout. - * @return app image layout + * Gets the unresolved app image layout of this application. + * + * @return the unresolved app image layout of this application */ AppImageLayout imageLayout(); /** - * Returns app image layout as {@link ApplicationLayout} type or an empty {@link Optional} instance - * if the return value of {@link #imageLayout()} call is not instance of {@link ApplicationLayout}. + * Gets the unresolved app image layout of this application as + * {@link ApplicationLayout} type or an empty {@link Optional} instance if the + * return value of {@link #imageLayout()} call is not an instance of + * {@link ApplicationLayout} type. *

- * Returns an empty {@link Optional} instance if {@link #isRuntime()} returns true. + * Returns an empty {@link Optional} instance if {@link #isRuntime()} returns + * true. * * @see #isRuntime * - * @return app image as {@link ApplicationLayout} + * @return the unresolved app image layout of this application as + * {@link ApplicationLayout} */ default Optional asApplicationLayout() { if (imageLayout() instanceof ApplicationLayout layout) { @@ -117,23 +130,27 @@ default Optional asApplicationLayout() { } /** - * Returns runtime builder if available or an empty {@link Optional} instance. - * @return runtime builder + * Gets the runtime builder of this application if available or an empty + * {@link Optional} instance. + * + * @return the runtime builder of this application */ Optional runtimeBuilder(); /** - * Returns the name of the root app image directory. - * @return name of the root app image directory. + * Gets the name of the root app image directory of this application. + * + * @return the name of the root app image directory of this application */ default Path appImageDirName() { return Path.of(name()); } /** - * Returns application launchers. + * Gets the application launchers of this application. *

- * If the returned list is not empty, the first element in the list is the main launcher. + * If the returned list is not empty, the first element in the list is the main + * launcher. *

* Returns an empty list if {@link #isRuntime()} returns true. * @@ -141,29 +158,31 @@ default Path appImageDirName() { * @see #additionalLaunchers() * @see #isRuntime() * - * @return application launchers + * @return the application launchers of this application */ List launchers(); /** - * Returns the main application launcher or an empty {@link Optional} instance if the application doesn't have launchers. + * Returns the main application launcher of this application or an empty + * {@link Optional} instance if the application doesn't have launchers. *

- * Returns an empty {@link Optional} instance if {@link #isRuntime()} returns true. + * Returns an empty {@link Optional} instance if {@link #isRuntime()} returns + * true. * * @see #launchers() * @see #additionalLaunchers() * @see #isRuntime() * - * @return main application launcher + * @return the main application launcher of this application */ default Optional mainLauncher() { return ApplicationLaunchers.fromList(launchers()).map(ApplicationLaunchers::mainLauncher); } /** - * Returns additional application launchers. + * Gets the additional application launchers of this application. *

- * Returns an empty list if there are no additional application launchers. + * Returns an empty list if this application doesn't have additional launchers. *

* Returns an empty list if {@link #isRuntime()} returns true. * @@ -171,45 +190,52 @@ default Optional mainLauncher() { * @see #mainLauncher() * @see #isRuntime() * - * @return additional application launchers + * @return the additional application launchers of this application */ default List additionalLaunchers() { - return ApplicationLaunchers.fromList(launchers()).map(ApplicationLaunchers::additionalLaunchers).orElseGet(Collections::emptyList); + return ApplicationLaunchers.fromList(launchers()).map(ApplicationLaunchers::additionalLaunchers) + .orElseGet(Collections::emptyList); } /** - * Returns true if the application for packaging is Java runtime. - * @return true if the application for packaging is Java runtime. + * Returns true if this application is Java runtime. + * + * @return true if this application is Java runtime */ default boolean isRuntime() { return imageLayout() instanceof RuntimeLayout; } /** - * Returns true if any of application launchers are configured as services. + * Returns true if any of application launchers of this application + * are configured as services. * * @see Launcher#isService * - * @return true if any of application launchers are configured as services + * @return true if any of application launchers of this application + * are configured as services */ default boolean isService() { - return Optional.ofNullable(launchers()).orElseGet(List::of).stream().filter( - Launcher::isService).findAny().isPresent(); + return Optional.ofNullable(launchers()).orElseGet(List::of).stream() + .filter(Launcher::isService).findAny().isPresent(); } /** - * Gets the additional properties for the application entry in the app image (".jpackage") file. + * Gets the additional properties of this application for the application entry + * in the app image (".jpackage") file. * - * @return the additional properties for the application entry in ".jpackage" file + * @return the additional properties of this application for the application + * entry in ".jpackage" file */ default Map extraAppImageFileData() { return Map.of(); } /** - * Returns file associations of all application launchers. + * Gets the file associations of all application launchers of this application. * - * @return file associations of all application launchers + * @return the file associations of all application launchers of this + * application * * @see Launcher#fileAssociations */ @@ -220,15 +246,14 @@ default Stream fileAssociations() { /** * Default implementation of {@link Application} interface. */ - record Stub(String name, String description, String version, String vendor, - String copyright, Optional srcDir, List contentDirs, - AppImageLayout imageLayout, Optional runtimeBuilder, + record Stub(String name, String description, String version, String vendor, String copyright, Optional srcDir, + List contentDirs, AppImageLayout imageLayout, Optional runtimeBuilder, List launchers) implements Application { } /** - * Implementation of {@link Application} interface in which every method - * throws {@link UnsupportedOperationException} exception. + * Implementation of {@link Application} interface in which every method throws + * {@link UnsupportedOperationException} exception. */ class Unsupported implements Application { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java index b4b7c1ade6aa2..9cc64cb542742 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java @@ -30,15 +30,18 @@ /** - * Packages the given {@link Application} and saves it at the given location. + * Creates app image directory from the given {@link Application} object. + * + * @ see PackageWriter */ @FunctionalInterface public interface ApplicationWriter { + /** - * Packages the given {@link Application} and saves it at the given location. + * Creates app image directory from the given {@link Application} object in the given directory. * - * @param app an application to package - * @param dst destination where to save the packaged application + * @param app the source application + * @param dst the directory where to create app image of the source application * @throws PackagerException * @throws IOException */ diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java index 539726c872dff..dbb68cdfe0b1e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java @@ -40,13 +40,15 @@ public interface Launcher { /** - * Gets name of this launcher. + * Gets the name of this launcher. + * * @return the name of this launcher */ String name(); /** - * Gets name of the executable file of this launcher without file extension. + * Gets the name of the executable file of this launcher without file extension. + * * @return the name of the executable file of this launcher */ default String executableName() { @@ -54,7 +56,9 @@ default String executableName() { } /** - * Gets extension of the executable file of this launcher if available or an empty {@link Optional} instance. + * Gets extension of the executable file of this launcher if available or an + * empty {@link Optional} instance otherwise. + * * @return the extension of the executable file of this launcher */ default Optional executableSuffix() { @@ -62,7 +66,9 @@ default Optional executableSuffix() { } /** - * Gets full name of the executable file of this launcher. The full name consists of the name and the extension. + * Gets the full name of the executable file of this launcher. The full name + * consists of the name and the extension. + * * @return the full name of the executable file of this launcher */ default String executableNameWithSuffix() { @@ -70,34 +76,40 @@ default String executableNameWithSuffix() { } /** - * Gets startup information of this launcher if available or an empty {@link Optional} instance. - * @apiNote - * Launchers from an external application image may not have startup information. + * Gets the startup information of this launcher if available or an empty + * {@link Optional} instance otherwise. + * + * @apiNote Launchers from an external application image may not have startup + * information. * @return the startup information of this launcher */ Optional startupInfo(); /** - * Gets file associations of this launcher. + * Gets the file associations of this launcher. + * * @return the file associations of this launcher */ List fileAssociations(); /** * Returns true if this launcher should be installed as a service. + * * @return true if this launcher should be installed as a service */ boolean isService(); /** - * Gets description of this launcher. + * Gets the description of this launcher. + * * @return the description of this launcher */ String description(); /** - * Opens a stream with the template executable file for this launcher. - * Caller is responsible for close the stream. + * Opens a stream with the template executable file for this launcher. Caller is + * responsible for close the stream. + * * @return a stream with the template executable file for this launcher */ default InputStream executableResource() { @@ -105,16 +117,20 @@ default InputStream executableResource() { } /** - * Gets the additional properties for application launcher entries in the app image (".jpackage") file. + * Gets the additional properties for application launcher entries in the app + * image (".jpackage") file. * - * @return the additional properties for application launcher entries in ".jpackage" file + * @return the additional properties for application launcher entries in + * ".jpackage" file */ default Map extraAppImageFileData() { return Map.of(); } /** - * Gets the icon for this launcher or an empty {@link Optional} instance if the launcher is requested to have no icon. + * Gets the icon for this launcher or an empty {@link Optional} instance if the + * launcher is requested to have no icon. + * * @return the icon for this launcher * @see #hasIcon() * @see #hasDefaultIcon() @@ -124,6 +140,7 @@ default Map extraAppImageFileData() { /** * Returns true if this launcher is requested to have an icon. + * * @return true if this launcher is requested to have an icon * @see #icon() * @see #hasDefaultIcon() @@ -135,6 +152,7 @@ default boolean hasIcon() { /** * Returns true if this launcher has a default icon. + * * @return true if this launcher has a default icon * @see DefaultLauncherIcon * @see #icon() @@ -147,6 +165,7 @@ default boolean hasDefaultIcon() { /** * Returns true if this launcher has a custom icon. + * * @return true if this launcher has a custom icon * @see CustomLauncherIcon * @see #icon() @@ -158,7 +177,9 @@ default boolean hasCustomIcon() { } /** - * Gets key in the resource bundle of {@link jdk.jpackage/} module referring to the default launcher icon. + * Gets key in the resource bundle of {@link jdk.jpackage/} module referring to + * the default launcher icon. + * * @return the key in the resource bundle referring to the default launcher icon */ String defaultIconResourceName(); @@ -166,15 +187,14 @@ default boolean hasCustomIcon() { /** * Default implementation of {@link Launcher} interface. */ - record Stub(String name, Optional startupInfo, - List fileAssociations, boolean isService, - String description, Optional icon, - String defaultIconResourceName) implements Launcher { + record Stub(String name, Optional startupInfo, List fileAssociations, + boolean isService, String description, Optional icon, String defaultIconResourceName) + implements Launcher { } /** - * Implementation of {@link Launcher} interface in which every method - * throws {@link UnsupportedOperationException} exception. + * Implementation of {@link Launcher} interface in which every method throws + * {@link UnsupportedOperationException} exception. */ class Unsupported implements Launcher { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java index 61add162a4e47..69e719a490408 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java @@ -25,7 +25,7 @@ package jdk.jpackage.internal.model; /** - * Launcher icon + * Application launcher icon. */ public interface LauncherIcon { } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java index bf6da84a1da10..0905ebf1d64a1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java @@ -27,12 +27,80 @@ import java.nio.file.Path; import java.util.Optional; +/** + * Native application package. + * + * The interface specifies the source app image layout with two transformations: + * package app image layout and installed app image layout. + *

+ * Use {@link #appImageLayout()} or {@link #asApplicationLayout()} to get the + * unresolved source app image layout. + *

+ * Package app image layout is the source app image layout resolved at the + * relative installation directory of the package. Additionally, to resolve the + * source layout, some packages may transform the source layout. + *

+ * Use {@link #packageLayout()} or {@link #asPackageApplicationLayout()} to get + * the package app image layout. + *

+ * Installed app image layout is the layout of the installed app image. + *

+ * Use {@link #installedPackageLayout()} or + * {@link #asInstalledPackageApplicationLayout()} to get the installed app image + * layout. + *

+ * The following table shows app image layouts of the application named "Duke" + * on different platforms: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Source app image layoutPackage app image layoutInstalled app image layout
Windowsbin/foo.exe app/foo.jarDuke/bin/foo.exe Duke/app/foo.jarDuke/bin/foo.exe Duke/app/foo.jar
Linuxbin/foo app/foo.jaropt/duke/bin/foo opt/duke/app/foo.jar/opt/duke/bin/foo /opt/duke/app/foo.jar
OSXbin/foo app/foo.jarApplications/duke/bin/foo Applications/duke/app/foo.jar/Applications/duke/bin/foo /Applications/duke/app/foo.jar
+ */ public interface Package { + /** + * Gets the application of this package. + * + * @return the application of this package + */ Application app(); + /** + * Gets the type of this package. + * + * @return the type of this package + */ PackageType type(); + /** + * Gets the type of this package as {@link StandardPackageType} type or an empty + * {@link Optional} instance if the return value of {@link #type()} call is not + * an instance of {@link StandardPackageType} type. + * + * @return the type of this package as {@link StandardPackageType} type + */ default Optional asStandardPackageType() { if (type() instanceof StandardPackageType stdType) { return Optional.of(stdType); @@ -42,41 +110,111 @@ default Optional asStandardPackageType() { } /** - * Returns platform-specific package name. - * - * The value should be valid file system name as it will be used to create + * Gets the name of the native package of this package. + *

+ * The value is a valid file system name and can be safely used to name * files/directories in the file system. + * + * @return the name of the native package of this package */ String packageName(); + /** + * Gets the description of this package. + * @return the description of this package + */ String description(); + /** + * Gets the version of this package. + * @return the version of this package + */ String version(); + /** + * Gets the "About" URL of this package if available or an empty + * {@link Optional} instance otherwise. + * + * @return the "About" URL of this package + */ Optional aboutURL(); + /** + * Gets the path to a license file of this package if available or an empty + * {@link Optional} instance otherwise. + * + * @return the path to a license file of this package + */ Optional licenseFile(); + /** + * Gets the path to a directory with the application app image of this package + * if available or an empty {@link Optional} instance otherwise. + * + * @return the path to a directory with the application app image of this + * package + */ Optional predefinedAppImage(); /** - * Returns source app image layout. + * Gets the unresolved source app image layout of the application of this package. + * + * @return the unresolved app image layout of the application of this package + * + * @see #packageLayout + * @see #installedPackageLayout */ default AppImageLayout appImageLayout() { return app().imageLayout(); } + /** + * Returns the unresolved source app image layout of the application of this + * package as {@link ApplicationLayout} type or an empty {@link Optional} + * instance if the layout object is of incompatible type. + *

+ * Returns an empty {@link Optional} instance if {@link #isRuntimeInstaller()} + * returns true. + * + * @return the unresolved source app image layout of the application of this + * package as {@link ApplicationLayout} type + * + * @see #appImageLayout + */ default Optional asApplicationLayout() { return app().asApplicationLayout(); } /** - * Returns app image layout inside of the package. + * Gets the layout of the installed app image of the application resolved at the + * relative installation directory of this package. + * + * @return the layout of the installed app image of the application resolved at + * the relative installation directory of this package + * + * @see #relativeInstallDir + * @see #appImageLayout + * @see #installedPackageLayout */ default AppImageLayout packageLayout() { return appImageLayout().resolveAt(relativeInstallDir()); } + /** + * Returns the layout of the installed app image of the application resolved at + * the relative installation directory of this package as + * {@link ApplicationLayout} type or an empty {@link Optional} instance if the + * layout object is of incompatible type. + *

+ * Returns an empty {@link Optional} instance if {@link #isRuntimeInstaller()} + * returns true. + * + * @return the layout of the installed app image of the application resolved at + * the relative installation directory of this package as + * {@link ApplicationLayout} type + * + * @see #packageLayout + */ default Optional asPackageApplicationLayout() { if (packageLayout() instanceof ApplicationLayout layout) { return Optional.of(layout); @@ -86,9 +224,14 @@ default Optional asPackageApplicationLayout() { } /** - * Returns app image layout of the installed package. + * Gets the layout of the installed app image of this package. + * + * @return the layout of the installed app image of this package + * + * @see #appImageLayout + * @see #packageLayout */ - default Optional installedPackageLayout() { + default AppImageLayout installedPackageLayout() { return asStandardPackageType().map(stdType -> { switch (stdType) { case LINUX_DEB, LINUX_RPM, MAC_DMG, MAC_PKG -> { @@ -98,55 +241,98 @@ default Optional installedPackageLayout() { return packageLayout(); } default -> { - throw new UnsupportedOperationException(); + // Should never get here + throw new IllegalStateException(); } } - }); + }).orElseThrow(UnsupportedOperationException::new); } + /** + * Returns the layout of the installed app image of this package as + * {@link ApplicationLayout} type or an empty {@link Optional} instance if the + * layout object is of incompatible type. + *

+ * Returns an empty {@link Optional} instance if {@link #isRuntimeInstaller()} + * returns true. + * + * @return the layout of the installed app image of this package as + * {@link ApplicationLayout} type + * + * @see #installedPackageLayout + */ default Optional asInstalledPackageApplicationLayout() { - return installedPackageLayout().map(layout -> { - if (layout instanceof ApplicationLayout appLayout) { - return appLayout; - } else { - return (ApplicationLayout)null; - } - }); + if (installedPackageLayout() instanceof ApplicationLayout layout) { + return Optional.of(layout); + } else { + return Optional.empty(); + } } /** - * Returns package file name. + * Get the name without an extension of the package file of this package. + * + * @return the name without an extension of the package file of this package */ default String packageFileName() { return String.format("%s-%s", packageName(), version()); } + /** + * Gets the extension of the package file of this package if available or an + * empty {@link Optional} instance otherwise. + * + * @return the extension of the package file of this package + */ default Optional packageFileSuffix() { return asStandardPackageType().map(StandardPackageType::suffix); } + /** + * Gets the full name of the package file of this package. The full name + * consists of the name and the extension. + * + * @return the full name of the package file of this package + */ default String packageFileNameWithSuffix() { return packageFileName() + packageFileSuffix().orElse(""); } + /** + * Returns true if the application of this package is Java runtime. + * + * @return true if the application of this package is Java runtime + * + * @see Application#isRuntime() + */ default boolean isRuntimeInstaller() { return app().isRuntime(); } /** - * Returns relative path to the package installation directory. + * Gets the relative path to the package installation directory of this package. + * + * On Windows it is relative to the program files directory + * ("%ProgramFiles%") and to the system root ("/") on + * other platforms. * - * On Windows it should be relative to %ProgramFiles% and relative - * to the system root ('/') on other platforms. + * @return the relative path to the package installation directory of this + * package */ Path relativeInstallDir(); - record Stub(Application app, PackageType type, String packageName, - String description, String version, Optional aboutURL, - Optional licenseFile, Optional predefinedAppImage, + /** + * Default implementation of {@link Package} interface. + */ + record Stub(Application app, PackageType type, String packageName, String description, String version, + Optional aboutURL, Optional licenseFile, Optional predefinedAppImage, Path relativeInstallDir) implements Package { } + /** + * Implementation of {@link Package} interface in which every method + * throws {@link UnsupportedOperationException} exception. + */ class Unsupported implements Package { @Override diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java index 8ecd8d5e6fa65..aa594c8ab6d6d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java @@ -29,6 +29,19 @@ import java.nio.file.Path; +/** + * Creates native package from the given {@link jdk.jpackage.internal.model.Package} object. + * + * @ see ApplicationWriter + */ +@FunctionalInterface public interface PackageWriter { + /** + * Creates native package from the given {@link jdk.jpackage.internal.model.Package} object in the given directory. + * @param pkg the source package + * @param dst the directory where to create a native package + * @throws PackagerException + * @throws IOException + */ void write(Package pkg, Path dst) throws PackagerException, IOException; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java index f9329c17557f7..d1bc9968ee7b7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java @@ -28,9 +28,10 @@ import jdk.jpackage.internal.util.CompositeProxy; import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; - /** - * Java runtime app image layout. Returns the root app image directory. + * Java runtime app image layout. + *

+ * Use {@link #DEFAULT} to get the instance of {@link RuntimeLayout} type. */ public interface RuntimeLayout extends AppImageLayout { @@ -39,9 +40,16 @@ default RuntimeLayout resolveAt(Path root) { return create(new AppImageLayout.Stub(resolveNullablePath(root, runtimeDirectory()))); } - static RuntimeLayout create(AppImageLayout layout) { + private static RuntimeLayout create(AppImageLayout layout) { return CompositeProxy.create(RuntimeLayout.class, layout); } + /** + * Singleton. + *

+ * {@link #runtimeDirectory()} of the singleton returns empty string (""), i.e. + * the runtime directory is the same as the directory at which the layout is + * resolved. + */ static final RuntimeLayout DEFAULT = create(new AppImageLayout.Stub(Path.of(""))); } From 96cb9b7cfc2ceeb6bc36619574135cfb958243b0 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 7 Jan 2025 18:19:31 -0500 Subject: [PATCH 0218/1101] Rename l18n -> i18n --- .../internal/util/LocalizedExceptionBuilder.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java index 39864beb8aef2..45697f5334f6c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java @@ -28,15 +28,15 @@ public class LocalizedExceptionBuilder> { - protected LocalizedExceptionBuilder(StringBundle l18n) { - this.l18n = l18n; + protected LocalizedExceptionBuilder(StringBundle i18n) { + this.i18n = i18n; } - public static > R buildLocalizedException(StringBundle l18n) { - return new LocalizedExceptionBuilder(l18n).thiz(); + public static > R buildLocalizedException(StringBundle i18n) { + return new LocalizedExceptionBuilder(i18n).thiz(); } - final public T create(BiFunction exceptionCtor) { + final public U create(BiFunction exceptionCtor) { return exceptionCtor.apply(msg, cause); } @@ -66,7 +66,7 @@ final public T causeAndMessage(Throwable t) { final protected String formatString(String keyId, Object... args) { if (!noFormat) { - return l18n.format(keyId, args); + return i18n.format(keyId, args); } else if (args.length == 0) { return keyId; } else { @@ -83,5 +83,5 @@ private T thiz() { private String msg; private Throwable cause; - private final StringBundle l18n; + private final StringBundle i18n; } From 8a60ca7b7bf87d7b422d359624c8793e49d85b46 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 8 Jan 2025 00:47:53 -0500 Subject: [PATCH 0219/1101] More javadoc --- .../internal/model/ConfigException.java | 2 +- .../util/LocalizedExceptionBuilder.java | 68 ++++++- .../jdk/jpackage/internal/util/PathGroup.java | 175 ++++++++++++++---- 3 files changed, 207 insertions(+), 38 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java index 741c891f636f4..a709273a40023 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java @@ -43,7 +43,7 @@ * throw ConfigException.build(i18n) * .message("error.no.name") * .advice("error.no.name.advice") - * .create() + * .create(); * } */ public class ConfigException extends Exception { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java index 45697f5334f6c..d7b3404395cc6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java @@ -26,39 +26,103 @@ import java.util.function.BiFunction; +/** + * Builder of exceptions with localized messages. + * @param Subclass extending {@link LocalizedExceptionBuilder} class. + */ public class LocalizedExceptionBuilder> { protected LocalizedExceptionBuilder(StringBundle i18n) { this.i18n = i18n; } - public static > R buildLocalizedException(StringBundle i18n) { - return new LocalizedExceptionBuilder(i18n).thiz(); + /** + * Creates an exception builder with the given source of error messages. + * + * @param i18n the source of error messages + * @return the exception builder + */ + public static LocalizedExceptionBuilder buildLocalizedException(StringBundle i18n) { + return new LocalizedExceptionBuilder<>(i18n); } + /** + * Creates an instance of type extending {@link Exception} class from the + * configured message and cause. + *

+ * Use {@link #message(String, Object...)}, {@link #causeAndMessage(Throwable)}, + * and {@link #cause(Throwable)} methods to initialize message and/or cause. + * + * @param the exception class + * @param exceptionCtor the exception constructor + * @return the exception + */ final public U create(BiFunction exceptionCtor) { return exceptionCtor.apply(msg, cause); } + /** + * Configures this builder if strings from the associated string bundle should + * be used as patterns for message formatting or not. + * + * Affects the behavior of the subsequent {@link #message(String, Object...)} + * calls. + * + * @param v true if strings from the associated string bundle + * should be used as patterns for message formatting by this builder or + * false otherwise + * @return this + * + * @see #noformat() + */ final public T format(boolean v) { noFormat = !v; return thiz(); } + /** + * A shortcut for format(false) call. + * + * @return this + * + * @see #format(boolean) + */ final public T noformat() { return format(false); } + /** + * Sets the message. + * + * @param msgId key of the string in the associated string bundle for the + * formatting pattern + * @param args the arguments for formatting message + * @return this + */ final public T message(String msgId, Object... args) { msg = formatString(msgId, args); return thiz(); } + /** + * Sets the cause. + * + * @param v the cause. A null value is permitted, and indicates that the cause + * is nonexistent or unknown. + * @return this + */ final public T cause(Throwable v) { cause = v; return thiz(); } + /** + * Sets the cause and the message. The message is copied from the given + * {@link Throwable} object as is. + * + * @param t the cause. Must not be null. + * @return this + */ final public T causeAndMessage(Throwable t) { boolean oldNoFormat = noFormat; return noformat().message(t.getMessage()).cause(t).format(oldNoFormat); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java index 776b1f10d0586..457db6abb28bd 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java @@ -39,24 +39,45 @@ import java.util.stream.Stream; import jdk.jpackage.internal.util.FileUtils; - /** - * Group of paths. - * Each path in the group is assigned a unique id. + * Group of paths. Each path in the group is assigned a unique id. */ public final class PathGroup { + + /** + * Creates path group with the initial paths. + * + * @param paths the initial paths + */ public PathGroup(Map paths) { entries = new HashMap<>(paths); } + /** + * Returns a path associated with the given identifier in this path group. + * + * @param id the identifier + * @return the path corresponding to the given identifier in this path group or + * null if there is no such path + */ public Path getPath(Object id) { - if (id == null) { - throw new NullPointerException(); - } + Objects.requireNonNull(id); return entries.get(id); } + /** + * Assigns the specified path value to the given identifier in this path group. + * If the given identifier doesn't exist in this path group, it is added, + * otherwise, the current value associated with the identifier is replaced with + * the given path value. If the path value is null the given + * identifier is removed from this path group if it existed; otherwise, no + * action is taken. + * + * @param id the identifier + * @param path the path to associate with the identifier or null + */ public void setPath(Object id, Path path) { + Objects.requireNonNull(id); if (path != null) { entries.put(id, path); } else { @@ -64,32 +85,54 @@ public void setPath(Object id, Path path) { } } + /** + * Adds a path associated with the new unique identifier to this path group. + * + * @param path the path to associate the new unique identifier in this path + * group + */ public void ghostPath(Path path) { Objects.requireNonNull(path); setPath(new Object(), path); } /** - * All configured IDs. + * Gets all identifiers of this path group. + *

+ * The order of identifiers in the returned list is undefined. + * + * @return all identifiers of this path group */ public Set keys() { return entries.keySet(); } /** - * All configured entries. + * Gets paths associated with all identifiers in this path group. + *

+ * The order of paths in the returned list is undefined. + * + * @return paths associated with all identifiers in this path group */ public List paths() { return entries.values().stream().toList(); } /** - * Root entries. + * Gets root paths in this path group. + *

+ * If multiple identifiers are associated with the same path value in the group, + * the path value is added to the returned list only once. Paths that are + * descendants of other paths in the group are not added to the returned list. + *

+ * The order of paths in the returned list is undefined. + * + * @return unique root paths in this path group */ public List roots() { // Sort by the number of path components in ascending order. - List> sorted = normalizedPaths().stream().sorted( - (a, b) -> a.getKey().getNameCount() - b.getKey().getNameCount()).toList(); + List> sorted = normalizedPaths().stream() + .sorted((a, b) -> a.getKey().getNameCount() - b.getKey().getNameCount()).toList(); // Returns `true` if `a` is a parent of `b` BiFunction, Map.Entry, Boolean> isParentOrSelf = (a, b) -> { @@ -97,57 +140,121 @@ public List roots() { }; return sorted.stream().filter( - v -> v == sorted.stream().sequential().filter( - v2 -> isParentOrSelf.apply(v2, v)).findFirst().get()).map( - v -> v.getValue()).toList(); + v -> v == sorted.stream().sequential().filter(v2 -> isParentOrSelf.apply(v2, v)).findFirst().get()) + .map(v -> v.getValue()).toList(); } + /** + * Gets the number of bytes in root paths of this path group. The method sums + * the size of all root path entries in the group. If the path entry is a + * directory it calculates the total size of the files in the directory. If the + * path entry is a file, it takes its size. + * + * @return the total number of bytes in root paths of this path group + * @throws IOException If an I/O error occurs + */ public long sizeInBytes() throws IOException { long reply = 0; - for (Path dir : roots().stream().filter(f -> Files.isDirectory(f)).collect( - Collectors.toList())) { + for (Path dir : roots().stream().filter(f -> Files.isDirectory(f)).collect(Collectors.toList())) { try (Stream stream = Files.walk(dir)) { - reply += stream.filter(p -> Files.isRegularFile(p)).mapToLong( - f -> f.toFile().length()).sum(); + reply += stream.filter(p -> Files.isRegularFile(p)).mapToLong(f -> f.toFile().length()).sum(); } } return reply; } + /** + * Creates a copy of this path group with all paths resolved against the given + * root. Taken action is equivalent to creating a copy of this path group and + * calling root.resolve() on every path in the copy. + * + * @param root the root against which to resolve paths + * + * @return a new path group resolved against the given root path + */ public PathGroup resolveAt(Path root) { - return new PathGroup(entries.entrySet().stream().collect( - Collectors.toMap(e -> e.getKey(), - e -> root.resolve(e.getValue())))); + Objects.requireNonNull(root); + return new PathGroup(entries.entrySet().stream() + .collect(Collectors.toMap(e -> e.getKey(), e -> root.resolve(e.getValue())))); } + /** + * Copies files/directories from the locations in the path group into the + * locations of the given path group. For every identifier found in this and the + * given group, copy the associated file or directory from the location + * specified by the path value associated with the identifier in this group into + * the location associated with the identifier in the given group. + * + * @param dst the destination path group + * @throws IOException If an I/O error occurs + */ public void copy(PathGroup dst) throws IOException { copy(this, dst, null, false); } + /** + * Similar to {@link #copy(PathGroup)} but moves files/directories instead of + * copying. + * + * @param dst the destination path group + * @throws IOException If an I/O error occurs + */ public void move(PathGroup dst) throws IOException { copy(this, dst, null, true); } + /** + * Similar to {@link #copy(PathGroup)} but uses the given handler to transform + * paths instead of coping. + * + * @param dst the destination path group + * @param handler the path transformation handler + * @throws IOException If an I/O error occurs + */ public void transform(PathGroup dst, TransformHandler handler) throws IOException { + Objects.requireNonNull(handler); copy(this, dst, handler, false); } + /** + * Handler of file copying and directory creating. + * + * @see #transform + */ public static interface TransformHandler { + + /** + * Request to copy a file from the given source location into the given + * destination location. + * + * @implNote Default implementation takes no action + * + * @param src the source file location + * @param dst the destination file location + * @throws IOException If an I/O error occurs + */ default void copyFile(Path src, Path dst) throws IOException { } + /** + * Request to create a directory at the given location. + * + * @implNote Default implementation takes no action + * + * @param dir the path where the directory is requested to be created + * @throws IOException + */ default void createDirectory(Path dir) throws IOException { } } - private static void copy(PathGroup src, PathGroup dst, - TransformHandler handler, boolean move) throws IOException { + private static void copy(PathGroup src, PathGroup dst, TransformHandler handler, boolean move) throws IOException { List> copyItems = new ArrayList<>(); List excludeItems = new ArrayList<>(); - for (var id: src.entries.keySet()) { + for (var id : src.entries.keySet()) { Path srcPath = src.entries.get(id); if (dst.entries.containsKey(id)) { copyItems.add(Map.entry(srcPath, dst.entries.get(id))); @@ -159,9 +266,8 @@ private static void copy(PathGroup src, PathGroup dst, copy(move, copyItems, excludeItems, handler); } - private static void copy(boolean move, List> entries, - List excludePaths, TransformHandler handler) throws - IOException { + private static void copy(boolean move, List> entries, List excludePaths, + TransformHandler handler) throws IOException { if (handler == null) { handler = new TransformHandler() { @@ -184,14 +290,14 @@ public void createDirectory(Path dir) throws IOException { // destination -> source file mapping Map actions = new HashMap<>(); - for (var action: entries) { + for (var action : entries) { Path src = action.getKey(); Path dst = action.getValue(); if (Files.isDirectory(src)) { - try (Stream stream = Files.walk(src)) { - stream.sequential().forEach(path -> actions.put(dst.resolve( - src.relativize(path)).normalize(), path)); - } + try (Stream stream = Files.walk(src)) { + stream.sequential() + .forEach(path -> actions.put(dst.resolve(src.relativize(path)).normalize(), path)); + } } else { actions.put(dst.normalize(), src); } @@ -218,7 +324,7 @@ public void createDirectory(Path dir) throws IOException { if (move) { // Delete source dirs. - for (var entry: entries) { + for (var entry : entries) { Path srcFile = entry.getKey(); if (Files.isDirectory(srcFile)) { FileUtils.deleteRecursive(srcFile); @@ -239,8 +345,7 @@ private static Map.Entry normalizedPath(Path v) { } private List> normalizedPaths() { - return entries.values().stream().map(PathGroup::normalizedPath).collect( - Collectors.toList()); + return entries.values().stream().map(PathGroup::normalizedPath).collect(Collectors.toList()); } private final Map entries; From 513b39439ac7e28766a8adf0e6e229b6a8125d49 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 8 Jan 2025 14:20:33 -0500 Subject: [PATCH 0220/1101] Change signature of LinuxDebPackage.relativeCopyrightFilePath() to return Optional. LinuxDebPackage documented --- .../jpackage/internal/LinuxDebBundler.java | 5 +- .../internal/model/LinuxDebPackage.java | 46 +++++++++++++++++-- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index 6fe1fe6df8a3f..491dc6f109971 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -43,7 +43,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.regex.Matcher; @@ -69,7 +68,7 @@ public LinuxDebBundler() { protected void doValidate(BuildEnv env, LinuxPackage pkg) throws ConfigException { // Show warning if license file is missing - if (pkg.licenseFile() == null) { + if (pkg.licenseFile().isEmpty()) { Log.verbose(I18N.getString("message.debs-like-licenses")); } } @@ -326,7 +325,7 @@ private void prepareProjectConfig(Map data, BuildEnv env, LinuxP configDir.resolve("postrm"), "resource.deb-postrm-script").setExecutable()); - Optional.ofNullable(((LinuxDebPackage)pkg).relativeCopyrightFilePath()).ifPresent(copyrightFile -> { + ((LinuxDebPackage)pkg).relativeCopyrightFilePath().ifPresent(copyrightFile -> { debianFiles.add(new DebianFile(Path.of("/").resolve(copyrightFile), "resource.copyright-file")); }); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java index 9d0d1a2273516..96563c5681099 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java @@ -25,29 +25,67 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import java.util.Optional; + import jdk.jpackage.internal.util.CompositeProxy; +/** + * Linux DEB package. + *

+ * Use {@link #create} method to create objects implementing this interface. + * + * @see https://www.debian.org/doc/debian-policy/ch-binary.html# + * @see https://linux.die.net/man/5/deb-control + */ public interface LinuxDebPackage extends LinuxPackage, LinuxDebPackageMixin { + /** + * Gets the value of the maintainer property of this DEB package. + * + * @see https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-maintainer + * @return the maintainer property of this DEB package + */ default String maintainer() { return String.format("%s <%s>", app().vendor(), maintainerEmail()); } + /** + * Gets the version with the release number of this DEB package. + * + * @see https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-version + * @return the version with the release number of this DEB package + */ default String versionWithRelease() { return String.format("%s-%s", version(), release()); } - default Path relativeCopyrightFilePath() { + /** + * Gets the relative path to this DEB package's copyright file. Returns empty + * {@link Optional} instance if this DEB package has no copyright file. + * + * @return the relative path to the copyright file of this DEB package + */ + default Optional relativeCopyrightFilePath() { if (isRuntimeInstaller()) { - return null; + return Optional.empty(); } else if (isInstallDirInUsrTree() || Path.of("/").resolve(relativeInstallDir()).startsWith( "/usr/")) { - return Path.of("/usr/share/doc/", packageName(), "copyright"); + return Optional.of(Path.of("/usr/share/doc/", packageName(), "copyright")); } else { - return relativeInstallDir().resolve("share/doc/copyright"); + return Optional.of(relativeInstallDir().resolve("share/doc/copyright")); } } + /** + * Constructs {@link LinuxDebPackage} instance from the given + * {@link LinuxPackage} and {@link LinuxDebPackageMixin} instances. + * + * @param pkg the Linux package + * @param mixin DEB-specific details supplementing the Linux package + * @return the proxy dispatching calls to the given objects + */ public static LinuxDebPackage create(LinuxPackage pkg, LinuxDebPackageMixin mixin) { return CompositeProxy.create(LinuxDebPackage.class, pkg, mixin); } From f24600dc254cb76c6a21b9d02d8a93b31f267651 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 8 Jan 2025 14:21:16 -0500 Subject: [PATCH 0221/1101] More javadoc --- .../internal/model/LinuxApplication.java | 12 + .../internal/model/LinuxDebPackageMixin.java | 11 + .../internal/model/LinuxLauncher.java | 13 + .../internal/model/LinuxLauncherMixin.java | 20 ++ .../jpackage/internal/model/LinuxPackage.java | 21 +- .../internal/model/LinuxPackageMixin.java | 40 +++ .../internal/model/LinuxRpmPackage.java | 11 + .../internal/model/LinuxRpmPackageMixin.java | 10 + .../internal/model/ApplicationWriter.java | 4 +- .../jdk/jpackage/internal/model/Launcher.java | 2 - .../model/LauncherJarStartupInfo.java | 2 + .../model/LauncherJarStartupInfoMixin.java | 2 +- .../model/LauncherModularStartupInfo.java | 2 + .../LauncherModularStartupInfoMixin.java | 2 +- .../internal/model/PackageWriter.java | 4 +- .../internal/model/RuntimeBuilder.java | 19 ++ .../internal/model/RuntimeLayout.java | 2 +- .../internal/util/CollectionUtils.java | 12 + .../internal/util/CompositeProxy.java | 260 ++++++++++++++---- 19 files changed, 391 insertions(+), 58 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java index d2ead0a382836..2a1dbc89bbc45 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java @@ -27,8 +27,20 @@ import jdk.jpackage.internal.util.CompositeProxy; +/** + * Linux application. + *

+ * Use {@link #create} method to create objects implementing this interface. + */ public interface LinuxApplication extends Application { + /** + * Creates {@link LinuxApplication} instance from the given {@link Application} + * instance. + * + * @param app the generic application + * @return the proxy dispatching calls to the given {@link Application} instance + */ public static LinuxApplication create(Application app) { return CompositeProxy.create(LinuxApplication.class, app); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java index b4065407763e2..eb7cbbdb26dda 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java @@ -24,10 +24,21 @@ */ package jdk.jpackage.internal.model; +/** + * Details of Linux DEB package. + */ public interface LinuxDebPackageMixin { + /** + * Gets the email of the maintainer of this DEB package. + * + * @return the email of the maintainer of this DEB package + */ String maintainerEmail(); + /** + * Default implementation of {@link LinuxDebPackageMixin} interface. + */ record Stub(String maintainerEmail) { } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java index 7647e559c0d48..b4ad887b1d053 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java @@ -27,6 +27,11 @@ import java.util.Map; import jdk.jpackage.internal.util.CompositeProxy; +/** + * Linux application launcher. + *

+ * Use {@link #create} method to create objects implementing this interface. + */ public interface LinuxLauncher extends Launcher, LinuxLauncherMixin { @Override @@ -36,6 +41,14 @@ default Map extraAppImageFileData() { }).orElseGet(Map::of); } + /** + * Constructs {@link LinuxLauncher} instance from the given + * {@link Launcher} and {@link LinuxLauncherMixin} instances. + * + * @param launcher the generic application launcher + * @param mixin Linux-specific details supplementing the generic application launcher + * @return the proxy dispatching calls to the given objects + */ public static LinuxLauncher create(Launcher launcher, LinuxLauncherMixin mixin) { return CompositeProxy.create(LinuxLauncher.class, launcher, mixin); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java index abf2c43eb00d2..8ee7963068bea 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java @@ -26,10 +26,30 @@ import java.util.Optional; +/** + * Details of Linux application launcher. + */ public interface LinuxLauncherMixin { + /** + * Gets the start menu shortcut setting of this application launcher. + *

+ * Returns true if this application launcher was requested to have + * the start menu shortcut. + *

+ * Returns false if this application launcher was requested not to + * have the start menu shortcut. + *

+ * Returns an empty {@link Optional} instance if there was no request about the + * start menu shortcut for this application launcher. + * + * @return the start menu shortcut setting of this application launcher + */ Optional shortcut(); + /** + * Default implementation of {@link LinuxLauncherMixin} interface. + */ record Stub(Optional shortcut) implements LinuxLauncherMixin { } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java index 742303f296ef3..4a92c50fdf341 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java @@ -25,10 +25,14 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; + import jdk.jpackage.internal.util.CompositeProxy; +/** + * Linux package. + *

+ * Use {@link #create} method to create objects implementing this interface. + */ public interface LinuxPackage extends Package, LinuxPackageMixin { @Override @@ -53,10 +57,23 @@ default String packageFileName() { return String.format(packageFileNameTemlate, packageName(), version(), release(), arch()); } + /** + * Returns true in this Linux package installs in "/usr" tree. + * + * @return true in this Linux package installs in "/usr" tree + */ default boolean isInstallDirInUsrTree() { return !relativeInstallDir().getFileName().equals(Path.of(packageName())); } + /** + * Constructs {@link LinuxPackage} instance from the given + * {@link Package} and {@link LinuxPackageMixin} instances. + * + * @param pkg the generic package + * @param mixin Linux-specific details supplementing the Linux package + * @return the proxy dispatching calls to the given objects + */ public static LinuxPackage create(Package pkg, LinuxPackageMixin mixin) { return CompositeProxy.create(LinuxPackage.class, pkg, mixin); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java index 918c00c1bec73..cc0b19926c4a3 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java @@ -26,20 +26,60 @@ import java.util.Optional; +/** + * Details of Linux package. + */ public interface LinuxPackageMixin { + /** + * Overrides {@link Package#packageLayout()}. + */ AppImageLayout packageLayout(); + /** + * Gets the name of the start menu group where to create shortcuts for + * application launchers of this package. + * + * @return the name of the start menu group where to create shortcuts for + * application launchers of this package + * + * @see LinuxLauncherMixin#shortcut() + */ String menuGroupName(); + /** + * Gets the category of this package. + * + * @return the category of this package + */ String category(); + /** + * Gets a string with the additional dependencies of this package. Returns an + * empty {@link Optional} instance if this package has no additional + * dependencies. + * + * @return a string with the additional dependencies of this package + */ Optional additionalDependencies(); + /** + * Gets the release of this package. + * + * @return the release of this package + */ String release(); + /** + * Gets the platform architecture of this package. + * + * @return the platform architecture of this package + */ String arch(); + /** + * Default implementation of {@link LinuxPackageMixin} interface. + */ record Stub(AppImageLayout packageLayout, String menuGroupName, String category, Optional additionalDependencies, String release, String arch) implements LinuxPackageMixin { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java index 90ecc0b9e8453..dabf60fced80b 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java @@ -26,8 +26,19 @@ import jdk.jpackage.internal.util.CompositeProxy; +/** + * Linux RPM package. + */ public interface LinuxRpmPackage extends LinuxPackage, LinuxRpmPackageMixin { + /** + * Constructs {@link LinuxRpmPackage} instance from the given + * {@link LinuxPackage} and {@link LinuxRpmPackageMixin} instances. + * + * @param pkg the Linux package + * @param mixin RPM-specific details supplementing the generic package + * @return the proxy dispatching calls to the given objects + */ public static LinuxRpmPackage create(LinuxPackage pkg, LinuxRpmPackageMixin mixin) { return CompositeProxy.create(LinuxRpmPackage.class, pkg, mixin); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackageMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackageMixin.java index e599fe42390fc..5874980177417 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackageMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackageMixin.java @@ -24,10 +24,20 @@ */ package jdk.jpackage.internal.model; +/** + * Details of Linux RPM package. + */ public interface LinuxRpmPackageMixin { + /** + * Gets type of the license of this RPM package. + * @return type of the license of this RPM package + */ String licenseType(); + /** + * Default implementation of {@link LinuxRpmPackageMixin} interface. + */ record Stub(String licenseType) implements LinuxRpmPackageMixin { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java index 9cc64cb542742..be0bd04a0933a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java @@ -42,8 +42,8 @@ public interface ApplicationWriter { * * @param app the source application * @param dst the directory where to create app image of the source application - * @throws PackagerException - * @throws IOException + * @throws PackagerException if packaging error occurs + * @throws IOException if an I/O error occurs */ void write(Application app, Path dst) throws PackagerException, IOException; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java index dbb68cdfe0b1e..4cb52243c8341 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java @@ -33,8 +33,6 @@ /** * Application launcher. * - * @apiNote All methods return non-null values. - * * @see Application#launchers() */ public interface Launcher { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java index 46791b6702adb..24b6d4b66edea 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java @@ -28,6 +28,8 @@ /** * Application launcher startup configuration using non-modular jar file. + *

+ * Use {@link #create} method to create objects implementing this interface. */ public interface LauncherJarStartupInfo extends LauncherStartupInfo, LauncherJarStartupInfoMixin { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java index 9164c9cdfbbac..812280e133627 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java @@ -27,7 +27,7 @@ import java.nio.file.Path; /** - * Application launcher startup configuration from a non-modular jar file. + * Details of Linux application launcher startup configuration using non-modular jar file. */ public interface LauncherJarStartupInfoMixin { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java index 068daf4b9bf28..9a17d61d844ea 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java @@ -28,6 +28,8 @@ /** * Application launcher startup configuration using Java module. + *

+ * Use {@link #create} method to create objects implementing this interface. */ public interface LauncherModularStartupInfo extends LauncherStartupInfo, LauncherModularStartupInfoMixin { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java index 774648bf599cf..7744aac2cf670 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java @@ -28,7 +28,7 @@ import java.util.List; /** - * Application launcher startup configuration from Java module. + * Details of application launcher startup configuration using Java module. */ public interface LauncherModularStartupInfoMixin { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java index aa594c8ab6d6d..8f05bc98b18fc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java @@ -40,8 +40,8 @@ public interface PackageWriter { * Creates native package from the given {@link jdk.jpackage.internal.model.Package} object in the given directory. * @param pkg the source package * @param dst the directory where to create a native package - * @throws PackagerException - * @throws IOException + * @throws PackagerException if packaging error occurs + * @throws IOException if an I/O error occurs */ void write(Package pkg, Path dst) throws PackagerException, IOException; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java index 6de783f72c571..4e439a29d053e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java @@ -27,10 +27,29 @@ import java.nio.file.Path; import java.util.List; +/** + * Creates Java runtime. + */ +@FunctionalInterface public interface RuntimeBuilder { + /** + * Creates Java runtime in the given app image. + * + * @implNote Java runtime should be created in the directory returned by + * {@link AppImageLayout#runtimeDirectory()} method called on the + * given app image layout object. + * + * @param appImageLayout the app image where to create Java runtime. + * @throws PackagerException if packaging error occurs + */ void createRuntime(AppImageLayout appImageLayout) throws PackagerException; + /** + * Gets the default set of paths where to find Java modules. + * + * @return the default set of paths where to find Java modules + */ public static List getDefaultModulePath() { return List.of( Path.of(System.getProperty("java.home"), "jmods").toAbsolutePath()); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java index d1bc9968ee7b7..23a250136ccbe 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java @@ -31,7 +31,7 @@ /** * Java runtime app image layout. *

- * Use {@link #DEFAULT} to get the instance of {@link RuntimeLayout} type. + * Use {@link #DEFAULT} to get the object implementing this interface. */ public interface RuntimeLayout extends AppImageLayout { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java index 97595eda5bad3..0b6988058fab9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java @@ -24,8 +24,20 @@ import java.util.Collection; +/** + * This class consists exclusively of static methods that operate on or return collections. + */ public final class CollectionUtils { + /** + * Casts the given collection to the requested type. + * + * @param the type of elements in this output collection + * @param the type of elements in this input collection + * @param the input collection type + * @param v the input collection. Null is permitted. + * @return the input collection cast to the requested type + */ @SuppressWarnings("unchecked") public static > C toCollection(Collection v) { Collection tmp = v; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java index f62e443149833..56602eb096bfa 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java @@ -22,6 +22,8 @@ */ package jdk.jpackage.internal.util; +import static java.util.stream.Collectors.toMap; + import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -35,48 +37,230 @@ import java.util.Set; import java.util.function.BinaryOperator; import java.util.function.Predicate; -import static java.util.stream.Collectors.toMap; import java.util.stream.Stream; +/** + * Dynamic proxy dispatching method calls to multiple objects. It is aimed at + * creating objects from mixins. The class provides functionality similar to + * that of net.sf.cglib.proxy.Mixin class from the cglib library. + * + * Sample usage: + * {@snippet : + * interface Sailboat { + * default void trimSails() { + * } + * } + * + * interface WithMain { + * void trimMain(); + * } + * + * interface WithJib { + * void trimJib(); + * } + * + * interface Sloop extends Sailboat, WithMain, WithJib { + * @Override + * public default void trimSails() { + * System.out.println("On the sloop:"); + * trimMain(); + * trimJib(); + * } + * } + * + * interface Catboat extends Sailboat, WithMain { + * @Override + * public default void trimSails() { + * System.out.println("On the catboat:"); + * trimMain(); + * } + * } + * + * final var withMain = new WithMain() { + * @Override + * public void trimMain() { + * System.out.println(" trim the main"); + * } + * }; + * + * final var withJib = new WithJib() { + * @Override + * public void trimJib() { + * System.out.println(" trim the jib"); + * } + * }; + * + * Sloop sloop = CompositeProxy.create(Sloop.class, new Sailboat() { + * }, withMain, withJib); + * + * Catboat catboat = CompositeProxy.create(Catboat.class, new Sailboat() { + * }, withMain); + * + * sloop.trimSails(); + * catboat.trimSails(); + * } + * + * Output: + * + *

+ * On the sloop:
+ *   trim the main
+ *   trim the jib
+ * On the cat:
+ *   trim the main
+ * 
+ * + * @see Proxy + */ public final class CompositeProxy { + /** + * Builder of {@link CompositeProxy} instances. + */ public final static class Builder { + /** + * Returns a proxy instance for the specified interface that dispatches method + * invocations to the specified handlers. Uses previously configured invocation + * tunnel and conflict resolver objects with the created proxy object. + * + * @param the interface type + * @param interfaceType the interface class composite proxy instance should + * implement + * @param slices handlers for the method calls of the interface + * @return a new instance of {@link Proxy} implementing the given interface and + * dispatching the interface method invocations to the given handlers + */ public T create(Class interfaceType, Object... slices) { - return CompositeProxy.createCompositeProxy(interfaceType, conflictResolver, - invokeTunnel, slices); + return CompositeProxy.createCompositeProxy(interfaceType, conflictResolver, invokeTunnel, slices); } + /** + * Sets the method dispatch conflict resolver for this builder. The conflict + * resolver is used by composite proxy to select a method call handler from + * multiple candidates. + * + * @param v the conflict resolver for this builder or null if the + * default conflict resolver should be used + * @return this + */ public Builder conflictResolver(BinaryOperator v) { conflictResolver = v; return this; } + /** + * Sets the invocation tunnel for this builder. + * + * @param v the invocation tunnel for this builder or null if no + * invocation tunnel should be used + * @return this + */ public Builder invokeTunnel(InvokeTunnel v) { invokeTunnel = v; return this; } + private Builder() {} + private BinaryOperator conflictResolver = STANDARD_CONFLICT_RESOLVER; private InvokeTunnel invokeTunnel; } + /** + * Invocation tunnel. Must be used when building a composite proxy from objects + * that implement package-private interfaces to prevent + * {@link IllegalAccessException} exceptions being thrown by {@link Proxy} + * instances. Must be implemented by classes from packages with package-private + * interfaces used with {@link CompositeProxy} class. + * + * Assumed implementation: + * {@snippet : + * + * package org.foo; + * + * import java.lang.reflect.InvocationHandler; + * import java.lang.reflect.Method; + * import jdk.jpackage.internal.util.CompositeProxy; + * + * final class CompositeProxyTunnel implements CompositeProxy.InvokeTunnel { + * + * @Override + * public Object invoke(Object obj, Method method, Object[] args) throws Throwable { + * return method.invoke(obj, args); + * } + * + * @Override + * public Object invokeDefault(Object proxy, Method method, Object[] args) throws Throwable { + * return InvocationHandler.invokeDefault(proxy, method, args); + * } + * + * static final CompositeProxyTunnel INSTANCE = new CompositeProxyTunnel(); + * } + * } + */ public interface InvokeTunnel { + /** + * Processes a method invocation on an object of composite proxy and returns the result. + * + * @implNote Implementation should call the given method on the given object + * with the given arguments and return the result of the call. + * @param obj the object on which to invoke the method + * @param method the method to invoke + * @param args the arguments to use in the method call + * @return the result of the method call + * @throws Throwable if the method throws + */ Object invoke(Object obj, Method method, Object[] args) throws Throwable; + + /** + * Processes a default interface method invocation on a composite proxy and + * returns the result. + * + * @implNote Implementation should call + * {@link InvocationHandler#invokeDefault(Object, Method, Object...)} + * method on the given proxy object with the given arguments and + * return the result of the call. + * @param proxy the proxy parameter for + * {@link InvocationHandler#invokeDefault(Object, Method, Object...)} + * call + * @param method the method parameter for + * {@link InvocationHandler#invokeDefault(Object, Method, Object...)} + * call + * @param args the args parameter for + * {@link InvocationHandler#invokeDefault(Object, Method, Object...)} + * call + * @return the result of the + * {@link InvocationHandler#invokeDefault(Object, Method, Object...)} + * call + * @throws Throwable if the {@link InvocationHandler#invokeDefault(Object, Method, Object...)} call throws + */ Object invokeDefault(Object proxy, Method method, Object[] args) throws Throwable; } + /** + * Creates a new proxy builder. + * @return a new proxy builder + */ public static Builder build() { return new Builder(); } + /** + * Shortcut for + * CompositeProxy.build().create(interfaceType, slices). + * + * @see Builder#create(Class, Object...) + */ public static T create(Class interfaceType, Object... slices) { return build().create(interfaceType, slices); } - private static T createCompositeProxy(Class interfaceType, - BinaryOperator conflictResolver, InvokeTunnel invokeTunnel, - Object... slices) { + private CompositeProxy() { + } + + private static T createCompositeProxy(Class interfaceType, BinaryOperator conflictResolver, + InvokeTunnel invokeTunnel, Object... slices) { validateTypeIsInterface(interfaceType); @@ -84,16 +268,14 @@ private static T createCompositeProxy(Class interfaceType, List.of(interfaces).forEach(CompositeProxy::validateTypeIsInterface); if (interfaces.length != slices.length) { - throw new IllegalArgumentException(String.format( - "type %s must extend %d interfaces", interfaceType.getName(), - slices.length)); + throw new IllegalArgumentException( + String.format("type %s must extend %d interfaces", interfaceType.getName(), slices.length)); } final Map, Object> interfaceDispatch = createInterfaceDispatch(interfaces, slices); final Map methodDispatch = getProxyableMethods(interfaceType).map(method -> { - var handler = createHandler(interfaceType, method, interfaceDispatch, - conflictResolver, invokeTunnel); + var handler = createHandler(interfaceType, method, interfaceDispatch, conflictResolver, invokeTunnel); if (handler != null) { return Map.entry(method, handler); } else { @@ -102,22 +284,20 @@ private static T createCompositeProxy(Class interfaceType, }).filter(Objects::nonNull).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); @SuppressWarnings("unchecked") - T proxy = (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), - new Class[]{interfaceType}, + T proxy = (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), new Class[] { interfaceType }, new CompositeProxyInvocationHandler(methodDispatch)); return proxy; } - private static Map, Object> createInterfaceDispatch( - Class[] interfaces, Object[] slices) { + private static Map, Object> createInterfaceDispatch(Class[] interfaces, Object[] slices) { final Map, Object> interfaceDispatch = Stream.of(interfaces).collect(toMap(x -> x, iface -> { return Stream.of(slices).filter(obj -> { return Set.of(obj.getClass().getInterfaces()).contains(iface); }).reduce((a, b) -> { - throw new IllegalArgumentException(String.format( - "both [%s] and [%s] slices implement %s", a, b, iface)); + throw new IllegalArgumentException( + String.format("both [%s] and [%s] slices implement %s", a, b, iface)); }).orElseThrow(() -> createInterfaceNotImplementedException(List.of(iface))); })); @@ -135,27 +315,23 @@ private static Map, Object> createInterfaceDispatch( } private static Stream> unfoldInterface(Class interfaceType) { - return Stream.concat(Stream.of(interfaceType), Stream.of( - interfaceType.getInterfaces()).flatMap(CompositeProxy::unfoldInterface)); + return Stream.concat(Stream.of(interfaceType), + Stream.of(interfaceType.getInterfaces()).flatMap(CompositeProxy::unfoldInterface)); } private static IllegalArgumentException createInterfaceNotImplementedException( Collection> missingInterfaces) { - return new IllegalArgumentException(String.format( - "none of the slices implement %s", missingInterfaces)); + return new IllegalArgumentException(String.format("none of the slices implement %s", missingInterfaces)); } private static void validateTypeIsInterface(Class type) { if (!type.isInterface()) { - throw new IllegalArgumentException(String.format( - "type %s must be an interface", type.getName())); + throw new IllegalArgumentException(String.format("type %s must be an interface", type.getName())); } } - private static Handler createHandler(Class interfaceType, Method method, - Map, Object> interfaceDispatch, - BinaryOperator conflictResolver, - InvokeTunnel invokeTunnel) { + private static Handler createHandler(Class interfaceType, Method method, Map, Object> interfaceDispatch, + BinaryOperator conflictResolver, InvokeTunnel invokeTunnel) { final var methodDeclaringClass = method.getDeclaringClass(); @@ -176,15 +352,13 @@ private static Handler createHandler(Class interfaceType, Method method, try { Class iface = e.getKey(); Object slice = e.getValue(); - return createHandlerForMethod(slice, iface.getMethod( - method.getName(), method.getParameterTypes()), + return createHandlerForMethod(slice, iface.getMethod(method.getName(), method.getParameterTypes()), invokeTunnel); } catch (NoSuchMethodException ex) { return null; } }).filter(Objects::nonNull).reduce(new ConflictResolverAdapter(conflictResolver)).orElseThrow(() -> { - return new IllegalArgumentException(String.format( - "none of the slices can handle %s", method)); + return new IllegalArgumentException(String.format("none of the slices can handle %s", method)); }); return handler; @@ -192,8 +366,7 @@ private static Handler createHandler(Class interfaceType, Method method, } private static Stream getProxyableMethods(Class interfaceType) { - return Stream.of(interfaceType.getMethods()).filter( - method -> !Modifier.isStatic(method.getModifiers())); + return Stream.of(interfaceType.getMethods()).filter(method -> !Modifier.isStatic(method.getModifiers())); } private static boolean isInvokeDefault(Method method, Object slice) { @@ -202,13 +375,12 @@ private static boolean isInvokeDefault(Method method, Object slice) { } // The "method" is default. - // See if is overriden by any non-abstract method in the "slice". + // See if is overridden by any non-abstract method in the "slice". // If it is, InvocationHandler.invokeDefault() should not be used to call it. final var sliceClass = slice.getClass(); - final var methodOverriden = Stream.of(sliceClass.getMethods()) - .filter(Predicate.not(Predicate.isEqual(method))) + final var methodOverriden = Stream.of(sliceClass.getMethods()).filter(Predicate.not(Predicate.isEqual(method))) .filter(sliceMethod -> !Modifier.isAbstract(sliceMethod.getModifiers())) .anyMatch(sliceMethod -> signatureEquals(sliceMethod, method)); @@ -216,11 +388,7 @@ private static boolean isInvokeDefault(Method method, Object slice) { } private static boolean signatureEquals(Method a, Method b) { - if (!Objects.equals(a.getName(), b.getName())) { - return false; - } - - if (!Arrays.equals(a.getParameterTypes(), b.getParameterTypes())) { + if (!Objects.equals(a.getName(), b.getName()) || !Arrays.equals(a.getParameterTypes(), b.getParameterTypes())) { return false; } @@ -234,7 +402,7 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl var handler = dispatch.get(method); if (handler != null) { return handler.invoke(proxy, args); - } else if(method.isDefault()) { + } else if (method.isDefault()) { return InvocationHandler.invokeDefault(proxy, method, args); } else { throw new UnsupportedOperationException(String.format("No handler for %s", method)); @@ -287,9 +455,8 @@ private abstract static class HandlerOfMethod implements Handler { protected final Method method; } - private record ConflictResolverAdapter( - BinaryOperator conflictResolver) implements - BinaryOperator { + private record ConflictResolverAdapter(BinaryOperator conflictResolver) + implements BinaryOperator { @Override public HandlerOfMethod apply(HandlerOfMethod a, HandlerOfMethod b) { @@ -306,8 +473,7 @@ public HandlerOfMethod apply(HandlerOfMethod a, HandlerOfMethod b) { private static final BinaryOperator STANDARD_CONFLICT_RESOLVER = (a, b) -> { if (a.isDefault() == b.isDefault()) { - throw new IllegalArgumentException(String.format( - "ambiguous choice between %s and %s", a, b)); + throw new IllegalArgumentException(String.format("ambiguous choice between %s and %s", a, b)); } else if (!a.isDefault()) { return a; } else { From 369c3502e1051c1919ab7cf611feff9ae4a503ab Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 8 Jan 2025 14:22:06 -0500 Subject: [PATCH 0222/1101] Added a test for the sample used in javadoc of CompositeProxy class --- .../internal/util/CompositeProxyTest.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java index 17ff0b5b18c6f..72c036340d93a 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java @@ -23,6 +23,7 @@ package jdk.jpackage.internal.util; import static org.junit.jupiter.api.Assertions.assertEquals; + import org.junit.jupiter.api.Test; @@ -255,4 +256,57 @@ public String sayBye() { assertEquals("ciao,bye", proxy.talk()); } + + @Test + public void testJavadocExample() { + interface Sailboat { + default void trimSails() {} + } + + interface WithMain { + void trimMain(); + } + + interface WithJib { + void trimJib(); + } + + interface Sloop extends Sailboat, WithMain, WithJib { + @Override + public default void trimSails() { + System.out.println("On the sloop:"); + trimMain(); + trimJib(); + } + } + + interface Catboat extends Sailboat, WithMain { + @Override + public default void trimSails() { + System.out.println("On the catboat:"); + trimMain(); + } + } + + final var withMain = new WithMain() { + @Override + public void trimMain() { + System.out.println(" trim the main"); + } + }; + + final var withJib = new WithJib() { + @Override + public void trimJib() { + System.out.println(" trim the jib"); + } + }; + + Sloop sloop = CompositeProxy.create(Sloop.class, new Sailboat() {}, withMain, withJib); + + Catboat catboat = CompositeProxy.create(Catboat.class, new Sailboat() {}, withMain); + + sloop.trimSails(); + catboat.trimSails(); + } } From 043b96df69695f6e539a852a2de4fde06fbdd5b0 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 8 Jan 2025 14:59:19 -0500 Subject: [PATCH 0223/1101] Remove redundant Optional.ofNullable() call. --- .../jdk/jpackage/internal/WixAppImageFragmentBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index cef4a317b9f72..c125868d29f71 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -97,7 +97,7 @@ void initFromParams(BuildEnv env, WinMsiPackage pkg) { // different current directory. initAppImageLayouts(pkg.appImageLayout(), appImageRoot.toAbsolutePath().normalize()); - launchers = toCollection(Optional.ofNullable(pkg.app().launchers()).orElseGet(List::of)); + launchers = toCollection(pkg.app().launchers()); shortcutFolders = ShortcutsFolder.getForPackage(pkg); From 1872695a1218573ef22c89c899d6df7dcd91b533 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 8 Jan 2025 17:07:48 -0500 Subject: [PATCH 0224/1101] Part of the previous refactoring commit --- .../share/classes/jdk/jpackage/internal/CfgFile.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java index 212862f196672..528eb8d5abca7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java @@ -63,13 +63,13 @@ void create(ApplicationLayout unresolvedAppLayout, ApplicationLayout appLayout) } else if (startupInfo instanceof LauncherJarStartupInfo jarStartupInfo) { Path mainJarPath = appCfgLayout.appDirectory().resolve(jarStartupInfo.jarPath()); - if (jarStartupInfo.isClassNameFromMainJar()) { + if (jarStartupInfo.isJarWithMainClass()) { content.add(Map.entry("app.mainjar", mainJarPath)); } else { content.add(Map.entry("app.classpath", mainJarPath)); } - if (!jarStartupInfo.isClassNameFromMainJar()) { + if (!jarStartupInfo.isJarWithMainClass()) { content.add(Map.entry("app.mainclass", startupInfo.qualifiedClassName())); } } else { From 39046a72e12f65883c28e57b3f12f7384ceeed42 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 8 Jan 2025 17:08:31 -0500 Subject: [PATCH 0225/1101] Add javadoc to PackagerException but it is misleading because of its current implementation --- .../internal/model/PackagerException.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java index d2595112b3b09..60f747e570fa1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java @@ -24,6 +24,20 @@ */ package jdk.jpackage.internal.model; +import jdk.jpackage.internal.util.StringBundle; + +/** + * Signals that error has occurred at packaging phase. + *

+ * The preferred way to construct instances of this class is to use + * {@link jdk.jpackage.internal.util.LocalizedExceptionBuilder#buildLocalizedException(StringBundle)} methods + * + * {@snippet : + * StringBundle i18n = getStringBundle(); // Some way to obtain a string bundle with localized messages + * + * throw buildLocalizedException(i18n).message("error.no.name").create(); + * } + */ public class PackagerException extends Exception { private static final long serialVersionUID = 1L; @@ -48,6 +62,17 @@ public PackagerException(Throwable cause, String key, Object... arguments) { super(I18N.format(key, arguments), cause); } + /** + * Throws the cause of the given {@link RuntimeException} exception + * as {@link PackagerException} if the cause is of this type or re-throws the given + * {@link RuntimeException} exception as-is otherwise. + *

+ * Never return a value. It always throws some exception object. + * + * @param ex exception to re-throw + * @return doesn't return value + * @throws PackagerException + */ public static RuntimeException rethrowPackagerException(RuntimeException ex) throws PackagerException { if (ex.getCause() instanceof PackagerException pkgEx) { throw pkgEx; From 25deb50bc97dc6b0e3a26876d988c4d19dda4cd8 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 15 Jan 2025 13:18:59 -0500 Subject: [PATCH 0226/1101] Use Optional in cli interfaces --- .../classes/jdk/jpackage/internal/cli/OptionSpec.java | 7 +++++-- .../jdk/jpackage/internal/cli/OptionSpecBuilder.java | 11 +++++++---- .../jdk/jpackage/internal/cli/ParsedOptions.java | 9 ++++++++- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java index 519b8537a1d84..960a236182bfa 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java @@ -26,12 +26,15 @@ package jdk.jpackage.internal.cli; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import jdk.jpackage.internal.model.PackageType; -public record OptionSpec(String name, ValueConverter valueConverter, String shortName, Set supportedPackageTypes, Consumer valueValidator) { +public record OptionSpec(String name, Optional> valueConverter, + Optional shortName, Set supportedPackageTypes, Optional> valueValidator) { + public OptionSpec { Objects.requireNonNull(name); if (supportedPackageTypes.isEmpty()) { @@ -40,6 +43,6 @@ public record OptionSpec(String name, ValueConverter valueConverter, String s } public boolean withValue() { - return valueConverter != null; + return valueConverter.isPresent(); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java index 22501666d4b85..e1c48784666a3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java @@ -24,17 +24,20 @@ */ package jdk.jpackage.internal.cli; -import java.util.Set; -import java.util.function.Consumer; -import jdk.jpackage.internal.model.PackageType; import static jdk.jpackage.internal.cli.StandardValueConverter.IDENTITY_CONV; import static jdk.jpackage.internal.cli.StandardValueConverter.PATH_ARRAY_CONV; import static jdk.jpackage.internal.cli.StandardValueConverter.PATH_CONV; import static jdk.jpackage.internal.cli.StandardValueConverter.STRING_ARRAY_CONV; +import java.util.Optional; +import java.util.Set; +import java.util.function.Consumer; +import jdk.jpackage.internal.model.PackageType; + final class OptionSpecBuilder { OptionSpec create() { - return new OptionSpec(name, valueConverter, shortName, supportedPackageTypes, valueValidator); + return new OptionSpec(name, Optional.ofNullable(valueConverter), Optional.ofNullable(shortName), + supportedPackageTypes, Optional.ofNullable(valueValidator)); } OptionSpecBuilder ofString() { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ParsedOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ParsedOptions.java index 8d40d1bb6a79d..37c571aad9c9e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ParsedOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ParsedOptions.java @@ -26,8 +26,15 @@ package jdk.jpackage.internal.cli; import java.util.Optional; +import java.util.function.Consumer; public interface ParsedOptions { - public Optional get(Option id); + + Optional find(Option id); + + default void copy(Option id, Consumer consumer) { + final Optional opt = find(id); + opt.ifPresent(consumer); + } } From f31f5a5dfe5c609fb10e6231450ffffad59b54a6 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 15 Jan 2025 13:20:26 -0500 Subject: [PATCH 0227/1101] Add I10N.buildException() --- .../share/classes/jdk/jpackage/internal/I18N.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java index ab572784531bb..785e4f05691a4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java @@ -28,6 +28,7 @@ import java.util.Map; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.util.LocalizedExceptionBuilder; import jdk.jpackage.internal.util.MultiResourceBundle; import jdk.jpackage.internal.util.StringBundle; @@ -41,6 +42,10 @@ static String format(String key, Object ... args) { return BUNDLE.format(key, args); } + static LocalizedExceptionBuilder buildException() { + return LocalizedExceptionBuilder.buildLocalizedException(BUNDLE); + } + static ConfigException.Builder buildConfigException() { return ConfigException.build(BUNDLE); } From 5ca14adc8209fcc744077a76de890c172fdca93f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 15 Jan 2025 13:22:22 -0500 Subject: [PATCH 0228/1101] Add BundlerParamInfo.findIn(), BundlerParamInfo.copyInto(), BundlerParamInfo.createBooleanBundlerParam(), and BundlerParamInfo.createPathBundlerParam() --- .../jpackage/internal/BundlerParamInfo.java | 50 +++++++++++++++++-- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java index a9c11e75cfe37..11b461f2f2cbe 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,11 +24,14 @@ */ package jdk.jpackage.internal; +import java.nio.file.Path; 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 jdk.jpackage.internal.util.function.ThrowingFunction; -import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; /** * BundlerParamInfo @@ -48,14 +51,39 @@ record BundlerParamInfo(String id, Class valueType, Function, T> defaultValueFunction, BiFunction, T> stringConverter) { + BundlerParamInfo { + Objects.requireNonNull(id); + Objects.requireNonNull(valueType); + } + static BundlerParamInfo createStringBundlerParam(String id) { return new BundlerParamInfo<>(id, String.class, null, null); } + static BundlerParamInfo createBooleanBundlerParam(String id) { + return new BundlerParamInfo<>(id, Boolean.class, null, BundlerParamInfo::toBoolean); + } + + static BundlerParamInfo createPathBundlerParam(String id) { + return new BundlerParamInfo<>(id, Path.class, null, BundlerParamInfo::toPath); + } + @SuppressWarnings({"unchecked", "rawtypes"}) - static BundlerParamInfo createBundlerParam(String id, - ThrowingFunction, T2> valueFunc) { - return new BundlerParamInfo(id, Object.class, toFunction(valueFunc), null); + static BundlerParamInfo createBundlerParam(String id, Class valueType, + ThrowingFunction, U> valueCtor) { + return new BundlerParamInfo(id, valueType, ThrowingFunction.toFunction(valueCtor), null); + } + + static boolean toBoolean(String value, Map params) { + if (value == null || "null".equalsIgnoreCase(value)) { + return false; + } else { + return Boolean.valueOf(value); + } + } + + static Path toPath(String value, Map params) { + return Path.of(value); } String getID() { @@ -131,4 +159,16 @@ final T fetchFrom(Map params, // ultimate fallback return null; } + + Optional findIn(Map params) { + if (params.containsKey(getID())) { + return Optional.of(fetchFrom(params, true)); + } else { + return Optional.empty(); + } + } + + void copyInto(Map params, Consumer consumer) { + findIn(params).ifPresent(consumer); + } } From 99faa97240c60b6b1bf5a0f9b93f07ef62423d90 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 15 Jan 2025 13:40:11 -0500 Subject: [PATCH 0229/1101] Add LauncherStartupInfo.simpleClassName() --- .../jdk/jpackage/internal/model/LauncherStartupInfo.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java index d707fd75cc090..d6af4bd430dec 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java @@ -41,6 +41,14 @@ public interface LauncherStartupInfo { */ String qualifiedClassName(); + /** + * Returns the simple name of the main class of this launcher startup configuration as given in the source code. + * @return the simple name of the main class of this launcher startup configuration as given in the source code + */ + default String simpleClassName() { + return ClassDesc.of(qualifiedClassName()).displayName(); + } + /** * Gets the package name of the main class of this launcher startup configuration. * @return the package name of the main class of this launcher startup configuration From 8134d3bb302133a6b6fa5efe3ef8666160743335 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 15 Jan 2025 14:22:18 -0500 Subject: [PATCH 0230/1101] Minor --- .../classes/jdk/jpackage/internal/LinuxAppImageBuilder.java | 2 +- .../classes/jdk/jpackage/internal/LinuxApplicationLayout.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index d7f6bb0db3eee..fd19434b8055c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -37,7 +37,7 @@ final class LinuxAppImageBuilder { static AppImageBuilder.Builder build() { - return new AppImageBuilder.Builder() + return AppImageBuilder.build() .itemGroup(AppImageItemGroup.LAUNCHERS) .addItem(LinuxAppImageBuilder::writeLauncherLib) .addItem(LinuxAppImageBuilder::writeLauncherIcons); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java index 9072504e0d800..aab7fc27ebe14 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java @@ -24,10 +24,11 @@ */ package jdk.jpackage.internal; +import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; + import java.nio.file.Path; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.util.CompositeProxy; -import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; interface LinuxApplicationLayout extends ApplicationLayout, LinuxApplicationLayoutMixin { From 79db29defc06d6ae330cf53441ca638c7b13f161 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 15 Jan 2025 15:00:49 -0500 Subject: [PATCH 0231/1101] Macosx bugfix --- .../classes/jdk/jpackage/internal/ApplicationLayoutUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java index 3c43d4d8d65b2..c822a46637310 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java @@ -43,7 +43,7 @@ final class ApplicationLayoutUtils { private final static ApplicationLayout MAC_APPLICATION_LAYOUT = ApplicationLayout.build() .launchersDirectory("Contents/MacOS") .appDirectory("Contents/app") - .runtimeDirectory("Contents/runtime") + .runtimeDirectory("Contents/runtime/Contents/Home") .destktopIntegrationDirectory("Contents/Resources") .appModsDirectory("Contents/app/mods") .contentDirectory("Contents") From 5d69f108053512e71189954eb2568befdf1111c9 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 15 Jan 2025 15:02:58 -0500 Subject: [PATCH 0232/1101] Use the proper reference to application layout in AbstractAppImageBuilder --- .../classes/jdk/jpackage/internal/AbstractAppImageBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java index bafbdfce8d3cc..5a7995760f9b0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java @@ -87,7 +87,7 @@ public Optional startupInfo() { public String name() { return APP_NAME.fetchFrom(params); } - }).create(ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT, appLayout); + }).create(appLayout, appLayout); } protected void copyApplication(Map params) From dc57afd8043a39537648001ebff5f5cc3c55320b Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 15 Jan 2025 15:08:49 -0500 Subject: [PATCH 0233/1101] Add clarification comment to AppImageLayout.runtimeDirectory(). Better handle defaults in builders. --- .../jdk/jpackage/internal/AppImageBuilder.java | 3 +++ .../jdk/jpackage/internal/ApplicationBuilder.java | 14 ++++++++------ .../jpackage/internal/model/AppImageLayout.java | 1 + .../jdk/jpackage/internal/WinAppImageBuilder.java | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java index 6c2b50763d7c9..7fd7a4b16f325 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -53,6 +53,9 @@ final class AppImageBuilder { static final class Builder { + private Builder() { + } + Builder addItem(AppImageItem v) { Objects.requireNonNull(v); Optional.ofNullable(customAppImageItemGroups.get(curGroup)).orElseGet(() -> { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 8a65e6fe0c6a9..07616d5d671a3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal; +import static jdk.jpackage.internal.I18N.buildConfigException; + import java.nio.file.Path; import java.util.Date; import java.util.List; @@ -31,7 +33,6 @@ import java.util.Objects; import java.util.Optional; import java.util.function.Function; -import static jdk.jpackage.internal.I18N.buildConfigException; import jdk.jpackage.internal.AppImageFile2.LauncherInfo; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; @@ -60,12 +61,12 @@ Application create() throws ConfigException { } else if (!launchersAsList.isEmpty()) { effectiveName = launchers.mainLauncher().name(); } else { - throw buildConfigException() - .message("error.no.name") - .advice("error.no.name.advice") - .create(); + throw buildConfigException().message("error.no.name").advice("error.no.name.advice").create(); } + Objects.requireNonNull(launchersAsList); + Objects.requireNonNull(appImageLayout); + return new Application.Stub( effectiveName, Optional.ofNullable(description).orElseGet(DEFAULTS::description), @@ -73,7 +74,8 @@ Application create() throws ConfigException { Optional.ofNullable(vendor).orElseGet(DEFAULTS::vendor), Optional.ofNullable(copyright).orElseGet(DEFAULTS::copyright), Optional.ofNullable(srcDir), - contentDirs, appImageLayout, Optional.ofNullable(runtimeBuilder), launchersAsList); + Optional.ofNullable(contentDirs).orElseGet(List::of), + appImageLayout, Optional.ofNullable(runtimeBuilder), launchersAsList); } ApplicationBuilder runtimeBuilder(RuntimeBuilder v) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java index 58c5a926b2d50..0de3b6526ef12 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java @@ -49,6 +49,7 @@ public interface AppImageLayout { /** * A path to Java runtime directory. + * The directory should have standard JDK subdirectories like "bin", "lib", etc. * * @return Java runtime sub-directory within this app image */ diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java index bf4c88784ff4b..e6933daece06f 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java @@ -37,7 +37,7 @@ final class WinAppImageBuilder { static AppImageBuilder.Builder build() { - return new AppImageBuilder.Builder() + return AppImageBuilder.build() .itemGroup(AppImageItemGroup.LAUNCHERS) .addItem(WinAppImageBuilder::rebrandLaunchers); } From b88713e7107cd109a82b88be2281ad913770840d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 21 Jan 2025 13:36:00 -0500 Subject: [PATCH 0234/1101] Reworked AppImageFile2 to get rid of Launcher.Unsupported, Application.Unsupported, and LauncherStartupInfo..Unsupported classes. Bugfixes in AppImageFile2. --- .../jdk/jpackage/internal/AppImageFile2.java | 282 ++++++++++-------- .../jpackage/internal/model/Application.java | 64 +--- .../jdk/jpackage/internal/model/Launcher.java | 64 +--- .../internal/model/LauncherStartupInfo.java | 27 -- .../jdk/jpackage/internal/util/XmlUtils.java | 38 ++- 5 files changed, 202 insertions(+), 273 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index 8fa6d43aea820..62ef3a2d96a9f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,60 +24,52 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.LauncherStartupInfo; -import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.ApplicationLayout; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.toSet; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; + import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.NoSuchFileException; +import java.nio.file.Path; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; -import static java.util.stream.Collectors.toMap; -import java.util.stream.IntStream; import java.util.stream.Stream; import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; - import jdk.internal.util.OperatingSystem; -import static jdk.jpackage.internal.I18N.buildConfigException; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.util.XmlUtils; import org.w3c.dom.Document; -import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Element; import org.w3c.dom.Node; -import org.w3c.dom.NodeList; import org.xml.sax.SAXException; final class AppImageFile2 { AppImageFile2(Application app) { + this(new ApplicationData(app)); + } - final var mainLauncher = app.mainLauncher().orElseThrow(); + private AppImageFile2(ApplicationData app) { appVersion = app.version(); - launcherName = mainLauncher.name(); - mainClass = mainLauncher.startupInfo().orElseThrow().qualifiedClassName(); - extra = app.extraAppImageFileData(); + launcherName = app.mainLauncherName(); + mainClass = app.mainLauncherMainClassName(); + extra = app.extra; creatorVersion = getVersion(); creatorPlatform = getPlatform(); - addLauncherInfos = app.additionalLaunchers().stream().map(launcher -> { - return new LauncherInfo(launcher.name(), launcher.isService(), - launcher.extraAppImageFileData()); - }).toList(); - - for (var str : List.of(appVersion, launcherName, mainClass)) { - if (str == null || str.isBlank()) { - throw new InavlidAppImageFileException(); - } - } + addLauncherInfos = app.additionalLaunchers; } /** @@ -143,7 +135,7 @@ void save(ApplicationLayout appLayout) throws IOException { xml.writeEndElement(); xml.writeStartElement("main-class"); - xml.writeCharacters(launcherName); + xml.writeCharacters(mainClass); xml.writeEndElement(); for (var extraKey : extra.keySet().stream().sorted().toList()) { @@ -182,77 +174,41 @@ static Path getPathInAppImage(ApplicationLayout appLayout) { static AppImageFile2 load(Path appImageDir, ApplicationLayout appLayout) throws ConfigException, IOException { var srcFilePath = getPathInAppImage(appLayout.resolveAt(appImageDir)); try { - Document doc = XmlUtils.initDocumentBuilder().parse(Files.newInputStream(srcFilePath)); - - XPath xPath = XPathFactory.newInstance().newXPath(); + final Document doc = XmlUtils.initDocumentBuilder().parse(Files.newInputStream(srcFilePath)); - String platform = queryNodes(doc, xPath, "/jpackage-state/@platform").findFirst().map( - Node::getNodeValue).orElse(null); + final XPath xPath = XPathFactory.newInstance().newXPath(); - String version = queryNodes(doc, xPath, "/jpackage-state/@version").findFirst().map( - Node::getNodeValue).orElse(null); - - if (!platform.equals(getPlatform()) || !version.equals(getVersion())) { - throw new InavlidAppImageFileException(); + final var isPlatformValid = XmlUtils.queryNodes(doc, xPath, "/jpackage-state/@platform").findFirst().map( + Node::getNodeValue).map(getPlatform()::equals).orElse(false); + if (!isPlatformValid) { + throw new InvalidAppImageFileException(); } - var props = AppImageProperties.main(doc, xPath); + final var isVersionValid = XmlUtils.queryNodes(doc, xPath, "/jpackage-state/@version").findFirst().map( + Node::getNodeValue).map(getVersion()::equals).orElse(false); + if (!isVersionValid) { + throw new InvalidAppImageFileException(); + } - Launcher mainLauncher = new Launcher.Unsupported() { - @Override - public String name() { - return props.get("main-launcher"); - } + final AppImageProperties props; + try { + props = AppImageProperties.main(doc, xPath); + } catch (IllegalArgumentException ex) { + throw new InvalidAppImageFileException(ex); + } - @Override - public Optional startupInfo() { - return startupInfo; + final var additionalLaunchers = AppImageProperties.launchers(doc, xPath).stream().map(launcherProps -> { + try { + return new LauncherInfo(launcherProps.get("name"), + launcherProps.find("service").map(Boolean::parseBoolean).orElse(false), launcherProps.getExtra()); + } catch (IllegalArgumentException ex) { + throw new InvalidAppImageFileException(ex); } - - private final Optional startupInfo = Optional.of(new LauncherStartupInfo.Unsupported() { - @Override - public String qualifiedClassName() { - return props.get("main-class"); - } - }); - }; - - List additionalLaunchers = AppImageProperties.launchers(doc, xPath).stream().map(launcherProps -> { - Launcher launcher = new Launcher.Unsupported() { - @Override - public String name() { - return launcherProps.get("name"); - } - - @Override - public boolean isService() { - return Boolean.parseBoolean(launcherProps.get("service")); - } - - @Override - public Map extraAppImageFileData() { - return launcherProps.getExtra(); - } - }; - return launcher; }).toList(); - return new AppImageFile2(new Application.Unsupported() { - @Override - public String version() { - return props.get("app-version"); - } - - @Override - public List launchers() { - return Stream.concat(Stream.of(mainLauncher), additionalLaunchers.stream()).toList(); - } + return new AppImageFile2(new ApplicationData(props.get("app-version"), props.get("main-launcher"), + props.get("main-class"), props.getExtra(), additionalLaunchers)); - @Override - public Map extraAppImageFileData() { - return props.getExtra(); - } - }); } catch (XPathExpressionException ex) { // This should never happen as XPath expressions should be correct throw new RuntimeException(ex); @@ -260,36 +216,24 @@ public Map extraAppImageFileData() { // Exception reading input XML (probably malformed XML) throw new IOException(ex); } catch (NoSuchFileException ex) { - throw buildConfigException("error.foreign-app-image", appImageDir).create(); - } catch (InavlidAppImageFileException ex) { + throw I18N.buildConfigException("error.foreign-app-image", appImageDir).create(); + } catch (InvalidAppImageFileException ex) { // Invalid input XML - throw buildConfigException("error.invalid-app-image", appImageDir, - FILENAME).create(); + throw I18N.buildConfigException("error.invalid-app-image", appImageDir, FILENAME).create(); } } - static Stream queryNodes(Node xml, XPath xPath, String xpathExpr) throws XPathExpressionException { - NodeList nodes = (NodeList) xPath.evaluate(xpathExpr, xml, XPathConstants.NODESET); - return Optional.ofNullable(nodes).map(AppImageFile2::toStream).orElseGet(Stream::of); - } - - static Stream toStream(NodeList nodes) { - return Optional.ofNullable(nodes).map(v -> { - return IntStream.range(0, v.getLength()).mapToObj(v::item); - }).orElseGet(Stream::of); - } - - static Stream toStream(NamedNodeMap nodes) { - return Optional.ofNullable(nodes).map(v -> { - return IntStream.range(0, v.getLength()).mapToObj(v::item); - }).orElseGet(Stream::of); + static boolean getBooleanExtraFieldValue(String fieldId, AppImageFile2 appImageFile) { + Objects.requireNonNull(fieldId); + Objects.requireNonNull(appImageFile); + return Optional.ofNullable(appImageFile.getExtra().get(fieldId)).map(Boolean::parseBoolean).orElse(false); } - private static String getVersion() { + static String getVersion() { return System.getProperty("java.version"); } - private static String getPlatform() { + static String getPlatform() { return PLATFORM_LABELS.get(OperatingSystem.current()); } @@ -300,28 +244,35 @@ private AppImageProperties(Map data, Set stdKeys) { } static AppImageProperties main(Document xml, XPath xPath) throws XPathExpressionException { - var data = queryNodes(xml, xPath, "/jpackage-state/*/text()").map(node -> { - return Map.entry(node.getParentNode().getNodeName(), node.getNodeValue()); - }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a)); - return new AppImageProperties(data, Set.of("app-version", "main-launcher", "main-class")); + final var data = queryProperties(xml.getDocumentElement(), xPath, MAIN_PROPERTIES_XPATH_QUERY); + return new AppImageProperties(data, MAIN_ELEMENT_NAMES); } - static AppImageProperties launcher(Node node) { - var data = toStream(node.getAttributes()).map(attrNode -> { - return Map.entry(attrNode.getNodeName(), attrNode.getNodeValue()); - }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); - return new AppImageProperties(data, Set.of("name", "service")); + static AppImageProperties launcher(Element addLauncherNode, XPath xPath) throws XPathExpressionException { + final var attrData = XmlUtils.toStream(addLauncherNode.getAttributes()) + .collect(toMap(Node::getNodeName, Node::getNodeValue)); + + final var extraData = queryProperties(addLauncherNode, xPath, LAUNCHER_PROPERTIES_XPATH_QUERY); + + final Map data = new HashMap<>(attrData); + data.putAll(extraData); + + return new AppImageProperties(data, LAUNCHER_ATTR_NAMES); } - static List launchers(Document xml, XPath xPath) - throws XPathExpressionException { - return queryNodes(xml, xPath, "/jpackage-state/add-launcher").map( - AppImageProperties::launcher).toList(); + static List launchers(Document xml, XPath xPath) throws XPathExpressionException { + return XmlUtils.queryNodes(xml, xPath, "/jpackage-state/add-launcher") + .map(Element.class::cast).map(toFunction(e -> { + return launcher(e, xPath); + })).toList(); } String get(String name) { - return Optional.ofNullable(data.get(name)).orElseThrow( - InavlidAppImageFileException::new); + return find(name).orElseThrow(InvalidAppImageFileException::new); + } + + Optional find(String name) { + return Optional.ofNullable(data.get(name)); } Map getExtra() { @@ -330,19 +281,92 @@ Map getExtra() { return extra; } + private static Map queryProperties(Element e, XPath xPath, String xpathExpr) + throws XPathExpressionException { + return XmlUtils.queryNodes(e, xPath, xpathExpr) + .map(Element.class::cast) + .collect(toMap(Node::getNodeName, selectedElement -> { + return XmlUtils.elementValue(selectedElement, xPath); + }, (a, b) -> b)); + } + + private static String xpathQueryForExtraProperties(Set excludeNames) { + final String otherElementNames = excludeNames.stream().map(name -> { + return String.format("name() != '%s'", name); + }).collect(joining(" and ")); + + return String.format("*[(%s) and not(*)]", otherElementNames); + } + private final Map data; private final Set stdKeys; + + private static final Set LAUNCHER_ATTR_NAMES = Set.of("name", "service"); + private static final String LAUNCHER_PROPERTIES_XPATH_QUERY = xpathQueryForExtraProperties(LAUNCHER_ATTR_NAMES); + + private static final Set MAIN_ELEMENT_NAMES = Set.of("app-version", "main-launcher", "main-class"); + private static final String MAIN_PROPERTIES_XPATH_QUERY; + + static { + final String nonEmptyMainElements = MAIN_ELEMENT_NAMES.stream().map(name -> { + return String.format("/jpackage-state/%s[text()]", name); + }).collect(joining("|")); + + MAIN_PROPERTIES_XPATH_QUERY = String.format("%s|/jpackage-state/%s", nonEmptyMainElements, + xpathQueryForExtraProperties(Stream.concat(MAIN_ELEMENT_NAMES.stream(), + Stream.of("add-launcher")).collect(toSet()))); + } } record LauncherInfo(String name, boolean service, Map extra) { LauncherInfo { - if (name == null || name.isBlank()) { - throw new InavlidAppImageFileException(); + Objects.requireNonNull(name); + Objects.requireNonNull(extra); + if (name.isBlank()) { + throw new IllegalArgumentException(); } } } - private static class InavlidAppImageFileException extends RuntimeException { + private record ApplicationData(String version, String mainLauncherName, String mainLauncherMainClassName, + Map extra, List additionalLaunchers) { + + ApplicationData { + Objects.requireNonNull(version); + Objects.requireNonNull(mainLauncherName); + Objects.requireNonNull(mainLauncherMainClassName); + Objects.requireNonNull(extra); + Objects.requireNonNull(additionalLaunchers); + + for (final var property : List.of(version, mainLauncherName, mainLauncherMainClassName)) { + if (property.isBlank()) { + throw new IllegalArgumentException(); + } + } + } + + ApplicationData(Application app) { + this(app, app.mainLauncher().orElseThrow()); + } + + private ApplicationData(Application app, Launcher mainLauncher) { + this(app.version(), mainLauncher.name(), mainLauncher.startupInfo().orElseThrow().qualifiedClassName(), + app.extraAppImageFileData(), app.additionalLaunchers().stream().map(launcher -> { + return new LauncherInfo(launcher.name(), launcher.isService(), + launcher.extraAppImageFileData()); + }).toList()); + } + } + + private static class InvalidAppImageFileException extends RuntimeException { + + InvalidAppImageFileException() { + } + + InvalidAppImageFileException(Throwable t) { + super(t); + } + private static final long serialVersionUID = 1L; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index a27b2d42c437e..7e5296ad00a90 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -227,9 +227,7 @@ default boolean isService() { * @return the additional properties of this application for the application * entry in ".jpackage" file */ - default Map extraAppImageFileData() { - return Map.of(); - } + Map extraAppImageFileData(); /** * Gets the file associations of all application launchers of this application. @@ -248,64 +246,6 @@ default Stream fileAssociations() { */ record Stub(String name, String description, String version, String vendor, String copyright, Optional srcDir, List contentDirs, AppImageLayout imageLayout, Optional runtimeBuilder, - List launchers) implements Application { - } - - /** - * Implementation of {@link Application} interface in which every method throws - * {@link UnsupportedOperationException} exception. - */ - class Unsupported implements Application { - - @Override - public String name() { - throw new UnsupportedOperationException(); - } - - @Override - public String description() { - throw new UnsupportedOperationException(); - } - - @Override - public String version() { - throw new UnsupportedOperationException(); - } - - @Override - public String vendor() { - throw new UnsupportedOperationException(); - } - - @Override - public String copyright() { - throw new UnsupportedOperationException(); - } - - @Override - public Optional srcDir() { - throw new UnsupportedOperationException(); - } - - @Override - public List contentDirs() { - throw new UnsupportedOperationException(); - } - - @Override - public AppImageLayout imageLayout() { - throw new UnsupportedOperationException(); - } - - @Override - public Optional runtimeBuilder() { - throw new UnsupportedOperationException(); - } - - @Override - public List launchers() { - throw new UnsupportedOperationException(); - } + List launchers, Map extraAppImageFileData) implements Application { } - } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java index 4cb52243c8341..f744d61477edd 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java @@ -114,17 +114,6 @@ default InputStream executableResource() { return ResourceLocator.class.getResourceAsStream("jpackageapplauncher"); } - /** - * Gets the additional properties for application launcher entries in the app - * image (".jpackage") file. - * - * @return the additional properties for application launcher entries in - * ".jpackage" file - */ - default Map extraAppImageFileData() { - return Map.of(); - } - /** * Gets the icon for this launcher or an empty {@link Optional} instance if the * launcher is requested to have no icon. @@ -183,52 +172,19 @@ default boolean hasCustomIcon() { String defaultIconResourceName(); /** - * Default implementation of {@link Launcher} interface. + * Gets the additional properties for application launcher entries in the app + * image (".jpackage") file. + * + * @return the additional properties for application launcher entries in + * ".jpackage" file */ - record Stub(String name, Optional startupInfo, List fileAssociations, - boolean isService, String description, Optional icon, String defaultIconResourceName) - implements Launcher { - } + Map extraAppImageFileData(); /** - * Implementation of {@link Launcher} interface in which every method throws - * {@link UnsupportedOperationException} exception. + * Default implementation of {@link Launcher} interface. */ - class Unsupported implements Launcher { - - @Override - public String name() { - throw new UnsupportedOperationException(); - } - - @Override - public Optional startupInfo() { - throw new UnsupportedOperationException(); - } - - @Override - public List fileAssociations() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isService() { - throw new UnsupportedOperationException(); - } - - @Override - public String description() { - throw new UnsupportedOperationException(); - } - - @Override - public Optional icon() { - throw new UnsupportedOperationException(); - } - - @Override - public String defaultIconResourceName() { - throw new UnsupportedOperationException(); - } + record Stub(String name, Optional startupInfo, List fileAssociations, + boolean isService, String description, Optional icon, String defaultIconResourceName, + Map extraAppImageFileData) implements Launcher { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java index d6af4bd430dec..bbceaa7dc30e8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java @@ -87,31 +87,4 @@ record Stub(String qualifiedClassName, List javaOptions, implements LauncherStartupInfo { } - - /** - * Implementation of {@link LauncherStartupInfo} interface in which every method - * throws {@link UnsupportedOperationException} exception. - */ - class Unsupported implements LauncherStartupInfo { - - @Override - public String qualifiedClassName() { - throw new UnsupportedOperationException(); - } - - @Override - public List javaOptions() { - throw new UnsupportedOperationException(); - } - - @Override - public List defaultParameters() { - throw new UnsupportedOperationException(); - } - - @Override - public List classPath() { - throw new UnsupportedOperationException(); - } - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java index 56aa3aa9f3648..e1320ad7aca2a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,10 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Collection; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -41,6 +45,13 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stax.StAXResult; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; public final class XmlUtils { @@ -110,4 +121,29 @@ public static DocumentBuilderFactory initDocumentBuilderFactory() { } return dbf; } + + public static Stream queryNodes(Node xml, XPath xPath, String xpathExpr) throws XPathExpressionException { + return toStream((NodeList) xPath.evaluate(xpathExpr, xml, XPathConstants.NODESET)); + } + + public static Stream toStream(NodeList nodes) { + return Optional.ofNullable(nodes).map(v -> { + return IntStream.range(0, v.getLength()).mapToObj(v::item); + }).orElseGet(Stream::of); + } + + public static Stream toStream(NamedNodeMap nodes) { + return Optional.ofNullable(nodes).map(v -> { + return IntStream.range(0, v.getLength()).mapToObj(v::item); + }).orElseGet(Stream::of); + } + + public static String elementValue(Element e, XPath xPath) { + try { + return queryNodes(e, xPath, "text()").map(Node::getNodeValue).collect(Collectors.joining()); + } catch (XPathExpressionException ex) { + // Should never happen + throw new RuntimeException(ex); + } + } } From d2c3e88241462dec5a79ecec72038bf436cf6259 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 21 Jan 2025 14:01:41 -0500 Subject: [PATCH 0235/1101] Add missing parameter to Application.Stub() ctor call. --- .../share/classes/jdk/jpackage/internal/ApplicationBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 07616d5d671a3..5005ec1236646 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -75,7 +75,7 @@ Application create() throws ConfigException { Optional.ofNullable(copyright).orElseGet(DEFAULTS::copyright), Optional.ofNullable(srcDir), Optional.ofNullable(contentDirs).orElseGet(List::of), - appImageLayout, Optional.ofNullable(runtimeBuilder), launchersAsList); + appImageLayout, Optional.ofNullable(runtimeBuilder), launchersAsList, Map.of()); } ApplicationBuilder runtimeBuilder(RuntimeBuilder v) { From afb597b4f75240a71ece6344c010a0a6988bc7e0 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 21 Jan 2025 14:05:33 -0500 Subject: [PATCH 0236/1101] Remove redundant Optional.ofNullable() call from WinLauncher.extraAppImageFileData() call. --- .../classes/jdk/jpackage/internal/model/WinLauncher.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java index b6c7f1d103d43..5cc64a18d72c2 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java @@ -24,11 +24,11 @@ */ package jdk.jpackage.internal.model; +import static java.util.stream.Collectors.toMap; + import java.io.InputStream; import java.util.Map; import java.util.Optional; -import java.util.Set; -import static java.util.stream.Collectors.toMap; import jdk.jpackage.internal.resources.ResourceLocator; import jdk.jpackage.internal.util.CompositeProxy; @@ -47,8 +47,7 @@ default InputStream executableResource() { @Override default Map extraAppImageFileData() { - return Optional.ofNullable(shortcuts()).orElseGet(Set::of).stream().collect( - toMap(WinShortcut::name, v -> Boolean.toString(true))); + return shortcuts().stream().collect(toMap(WinShortcut::name, v -> Boolean.toString(true))); } public static WinLauncher create(Launcher launcher, WinLauncherMixin mixin) { From 1674663eb633aaab45b07be8c81c4e310a10a9d5 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 21 Jan 2025 14:18:35 -0500 Subject: [PATCH 0237/1101] Reworked AppImageFile2 to get rid of Launcher.Unsupported, Application.Unsupported, and LauncherStartupInfo..Unsupported classes. Bugfixes in AppImageFile2. --- .../jdk/jpackage/internal/AppImageFile2.java | 282 ++++++++++-------- .../jpackage/internal/ApplicationBuilder.java | 2 +- .../jpackage/internal/model/Application.java | 64 +--- .../jdk/jpackage/internal/model/Launcher.java | 64 +--- .../internal/model/LauncherStartupInfo.java | 27 -- .../jdk/jpackage/internal/util/XmlUtils.java | 38 ++- 6 files changed, 203 insertions(+), 274 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java index 8fa6d43aea820..62ef3a2d96a9f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,60 +24,52 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.LauncherStartupInfo; -import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.ApplicationLayout; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.toSet; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; + import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.NoSuchFileException; +import java.nio.file.Path; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; -import static java.util.stream.Collectors.toMap; -import java.util.stream.IntStream; import java.util.stream.Stream; import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; - import jdk.internal.util.OperatingSystem; -import static jdk.jpackage.internal.I18N.buildConfigException; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.util.XmlUtils; import org.w3c.dom.Document; -import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Element; import org.w3c.dom.Node; -import org.w3c.dom.NodeList; import org.xml.sax.SAXException; final class AppImageFile2 { AppImageFile2(Application app) { + this(new ApplicationData(app)); + } - final var mainLauncher = app.mainLauncher().orElseThrow(); + private AppImageFile2(ApplicationData app) { appVersion = app.version(); - launcherName = mainLauncher.name(); - mainClass = mainLauncher.startupInfo().orElseThrow().qualifiedClassName(); - extra = app.extraAppImageFileData(); + launcherName = app.mainLauncherName(); + mainClass = app.mainLauncherMainClassName(); + extra = app.extra; creatorVersion = getVersion(); creatorPlatform = getPlatform(); - addLauncherInfos = app.additionalLaunchers().stream().map(launcher -> { - return new LauncherInfo(launcher.name(), launcher.isService(), - launcher.extraAppImageFileData()); - }).toList(); - - for (var str : List.of(appVersion, launcherName, mainClass)) { - if (str == null || str.isBlank()) { - throw new InavlidAppImageFileException(); - } - } + addLauncherInfos = app.additionalLaunchers; } /** @@ -143,7 +135,7 @@ void save(ApplicationLayout appLayout) throws IOException { xml.writeEndElement(); xml.writeStartElement("main-class"); - xml.writeCharacters(launcherName); + xml.writeCharacters(mainClass); xml.writeEndElement(); for (var extraKey : extra.keySet().stream().sorted().toList()) { @@ -182,77 +174,41 @@ static Path getPathInAppImage(ApplicationLayout appLayout) { static AppImageFile2 load(Path appImageDir, ApplicationLayout appLayout) throws ConfigException, IOException { var srcFilePath = getPathInAppImage(appLayout.resolveAt(appImageDir)); try { - Document doc = XmlUtils.initDocumentBuilder().parse(Files.newInputStream(srcFilePath)); - - XPath xPath = XPathFactory.newInstance().newXPath(); + final Document doc = XmlUtils.initDocumentBuilder().parse(Files.newInputStream(srcFilePath)); - String platform = queryNodes(doc, xPath, "/jpackage-state/@platform").findFirst().map( - Node::getNodeValue).orElse(null); + final XPath xPath = XPathFactory.newInstance().newXPath(); - String version = queryNodes(doc, xPath, "/jpackage-state/@version").findFirst().map( - Node::getNodeValue).orElse(null); - - if (!platform.equals(getPlatform()) || !version.equals(getVersion())) { - throw new InavlidAppImageFileException(); + final var isPlatformValid = XmlUtils.queryNodes(doc, xPath, "/jpackage-state/@platform").findFirst().map( + Node::getNodeValue).map(getPlatform()::equals).orElse(false); + if (!isPlatformValid) { + throw new InvalidAppImageFileException(); } - var props = AppImageProperties.main(doc, xPath); + final var isVersionValid = XmlUtils.queryNodes(doc, xPath, "/jpackage-state/@version").findFirst().map( + Node::getNodeValue).map(getVersion()::equals).orElse(false); + if (!isVersionValid) { + throw new InvalidAppImageFileException(); + } - Launcher mainLauncher = new Launcher.Unsupported() { - @Override - public String name() { - return props.get("main-launcher"); - } + final AppImageProperties props; + try { + props = AppImageProperties.main(doc, xPath); + } catch (IllegalArgumentException ex) { + throw new InvalidAppImageFileException(ex); + } - @Override - public Optional startupInfo() { - return startupInfo; + final var additionalLaunchers = AppImageProperties.launchers(doc, xPath).stream().map(launcherProps -> { + try { + return new LauncherInfo(launcherProps.get("name"), + launcherProps.find("service").map(Boolean::parseBoolean).orElse(false), launcherProps.getExtra()); + } catch (IllegalArgumentException ex) { + throw new InvalidAppImageFileException(ex); } - - private final Optional startupInfo = Optional.of(new LauncherStartupInfo.Unsupported() { - @Override - public String qualifiedClassName() { - return props.get("main-class"); - } - }); - }; - - List additionalLaunchers = AppImageProperties.launchers(doc, xPath).stream().map(launcherProps -> { - Launcher launcher = new Launcher.Unsupported() { - @Override - public String name() { - return launcherProps.get("name"); - } - - @Override - public boolean isService() { - return Boolean.parseBoolean(launcherProps.get("service")); - } - - @Override - public Map extraAppImageFileData() { - return launcherProps.getExtra(); - } - }; - return launcher; }).toList(); - return new AppImageFile2(new Application.Unsupported() { - @Override - public String version() { - return props.get("app-version"); - } - - @Override - public List launchers() { - return Stream.concat(Stream.of(mainLauncher), additionalLaunchers.stream()).toList(); - } + return new AppImageFile2(new ApplicationData(props.get("app-version"), props.get("main-launcher"), + props.get("main-class"), props.getExtra(), additionalLaunchers)); - @Override - public Map extraAppImageFileData() { - return props.getExtra(); - } - }); } catch (XPathExpressionException ex) { // This should never happen as XPath expressions should be correct throw new RuntimeException(ex); @@ -260,36 +216,24 @@ public Map extraAppImageFileData() { // Exception reading input XML (probably malformed XML) throw new IOException(ex); } catch (NoSuchFileException ex) { - throw buildConfigException("error.foreign-app-image", appImageDir).create(); - } catch (InavlidAppImageFileException ex) { + throw I18N.buildConfigException("error.foreign-app-image", appImageDir).create(); + } catch (InvalidAppImageFileException ex) { // Invalid input XML - throw buildConfigException("error.invalid-app-image", appImageDir, - FILENAME).create(); + throw I18N.buildConfigException("error.invalid-app-image", appImageDir, FILENAME).create(); } } - static Stream queryNodes(Node xml, XPath xPath, String xpathExpr) throws XPathExpressionException { - NodeList nodes = (NodeList) xPath.evaluate(xpathExpr, xml, XPathConstants.NODESET); - return Optional.ofNullable(nodes).map(AppImageFile2::toStream).orElseGet(Stream::of); - } - - static Stream toStream(NodeList nodes) { - return Optional.ofNullable(nodes).map(v -> { - return IntStream.range(0, v.getLength()).mapToObj(v::item); - }).orElseGet(Stream::of); - } - - static Stream toStream(NamedNodeMap nodes) { - return Optional.ofNullable(nodes).map(v -> { - return IntStream.range(0, v.getLength()).mapToObj(v::item); - }).orElseGet(Stream::of); + static boolean getBooleanExtraFieldValue(String fieldId, AppImageFile2 appImageFile) { + Objects.requireNonNull(fieldId); + Objects.requireNonNull(appImageFile); + return Optional.ofNullable(appImageFile.getExtra().get(fieldId)).map(Boolean::parseBoolean).orElse(false); } - private static String getVersion() { + static String getVersion() { return System.getProperty("java.version"); } - private static String getPlatform() { + static String getPlatform() { return PLATFORM_LABELS.get(OperatingSystem.current()); } @@ -300,28 +244,35 @@ private AppImageProperties(Map data, Set stdKeys) { } static AppImageProperties main(Document xml, XPath xPath) throws XPathExpressionException { - var data = queryNodes(xml, xPath, "/jpackage-state/*/text()").map(node -> { - return Map.entry(node.getParentNode().getNodeName(), node.getNodeValue()); - }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a)); - return new AppImageProperties(data, Set.of("app-version", "main-launcher", "main-class")); + final var data = queryProperties(xml.getDocumentElement(), xPath, MAIN_PROPERTIES_XPATH_QUERY); + return new AppImageProperties(data, MAIN_ELEMENT_NAMES); } - static AppImageProperties launcher(Node node) { - var data = toStream(node.getAttributes()).map(attrNode -> { - return Map.entry(attrNode.getNodeName(), attrNode.getNodeValue()); - }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); - return new AppImageProperties(data, Set.of("name", "service")); + static AppImageProperties launcher(Element addLauncherNode, XPath xPath) throws XPathExpressionException { + final var attrData = XmlUtils.toStream(addLauncherNode.getAttributes()) + .collect(toMap(Node::getNodeName, Node::getNodeValue)); + + final var extraData = queryProperties(addLauncherNode, xPath, LAUNCHER_PROPERTIES_XPATH_QUERY); + + final Map data = new HashMap<>(attrData); + data.putAll(extraData); + + return new AppImageProperties(data, LAUNCHER_ATTR_NAMES); } - static List launchers(Document xml, XPath xPath) - throws XPathExpressionException { - return queryNodes(xml, xPath, "/jpackage-state/add-launcher").map( - AppImageProperties::launcher).toList(); + static List launchers(Document xml, XPath xPath) throws XPathExpressionException { + return XmlUtils.queryNodes(xml, xPath, "/jpackage-state/add-launcher") + .map(Element.class::cast).map(toFunction(e -> { + return launcher(e, xPath); + })).toList(); } String get(String name) { - return Optional.ofNullable(data.get(name)).orElseThrow( - InavlidAppImageFileException::new); + return find(name).orElseThrow(InvalidAppImageFileException::new); + } + + Optional find(String name) { + return Optional.ofNullable(data.get(name)); } Map getExtra() { @@ -330,19 +281,92 @@ Map getExtra() { return extra; } + private static Map queryProperties(Element e, XPath xPath, String xpathExpr) + throws XPathExpressionException { + return XmlUtils.queryNodes(e, xPath, xpathExpr) + .map(Element.class::cast) + .collect(toMap(Node::getNodeName, selectedElement -> { + return XmlUtils.elementValue(selectedElement, xPath); + }, (a, b) -> b)); + } + + private static String xpathQueryForExtraProperties(Set excludeNames) { + final String otherElementNames = excludeNames.stream().map(name -> { + return String.format("name() != '%s'", name); + }).collect(joining(" and ")); + + return String.format("*[(%s) and not(*)]", otherElementNames); + } + private final Map data; private final Set stdKeys; + + private static final Set LAUNCHER_ATTR_NAMES = Set.of("name", "service"); + private static final String LAUNCHER_PROPERTIES_XPATH_QUERY = xpathQueryForExtraProperties(LAUNCHER_ATTR_NAMES); + + private static final Set MAIN_ELEMENT_NAMES = Set.of("app-version", "main-launcher", "main-class"); + private static final String MAIN_PROPERTIES_XPATH_QUERY; + + static { + final String nonEmptyMainElements = MAIN_ELEMENT_NAMES.stream().map(name -> { + return String.format("/jpackage-state/%s[text()]", name); + }).collect(joining("|")); + + MAIN_PROPERTIES_XPATH_QUERY = String.format("%s|/jpackage-state/%s", nonEmptyMainElements, + xpathQueryForExtraProperties(Stream.concat(MAIN_ELEMENT_NAMES.stream(), + Stream.of("add-launcher")).collect(toSet()))); + } } record LauncherInfo(String name, boolean service, Map extra) { LauncherInfo { - if (name == null || name.isBlank()) { - throw new InavlidAppImageFileException(); + Objects.requireNonNull(name); + Objects.requireNonNull(extra); + if (name.isBlank()) { + throw new IllegalArgumentException(); } } } - private static class InavlidAppImageFileException extends RuntimeException { + private record ApplicationData(String version, String mainLauncherName, String mainLauncherMainClassName, + Map extra, List additionalLaunchers) { + + ApplicationData { + Objects.requireNonNull(version); + Objects.requireNonNull(mainLauncherName); + Objects.requireNonNull(mainLauncherMainClassName); + Objects.requireNonNull(extra); + Objects.requireNonNull(additionalLaunchers); + + for (final var property : List.of(version, mainLauncherName, mainLauncherMainClassName)) { + if (property.isBlank()) { + throw new IllegalArgumentException(); + } + } + } + + ApplicationData(Application app) { + this(app, app.mainLauncher().orElseThrow()); + } + + private ApplicationData(Application app, Launcher mainLauncher) { + this(app.version(), mainLauncher.name(), mainLauncher.startupInfo().orElseThrow().qualifiedClassName(), + app.extraAppImageFileData(), app.additionalLaunchers().stream().map(launcher -> { + return new LauncherInfo(launcher.name(), launcher.isService(), + launcher.extraAppImageFileData()); + }).toList()); + } + } + + private static class InvalidAppImageFileException extends RuntimeException { + + InvalidAppImageFileException() { + } + + InvalidAppImageFileException(Throwable t) { + super(t); + } + private static final long serialVersionUID = 1L; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 07616d5d671a3..5005ec1236646 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -75,7 +75,7 @@ Application create() throws ConfigException { Optional.ofNullable(copyright).orElseGet(DEFAULTS::copyright), Optional.ofNullable(srcDir), Optional.ofNullable(contentDirs).orElseGet(List::of), - appImageLayout, Optional.ofNullable(runtimeBuilder), launchersAsList); + appImageLayout, Optional.ofNullable(runtimeBuilder), launchersAsList, Map.of()); } ApplicationBuilder runtimeBuilder(RuntimeBuilder v) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index a27b2d42c437e..7e5296ad00a90 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -227,9 +227,7 @@ default boolean isService() { * @return the additional properties of this application for the application * entry in ".jpackage" file */ - default Map extraAppImageFileData() { - return Map.of(); - } + Map extraAppImageFileData(); /** * Gets the file associations of all application launchers of this application. @@ -248,64 +246,6 @@ default Stream fileAssociations() { */ record Stub(String name, String description, String version, String vendor, String copyright, Optional srcDir, List contentDirs, AppImageLayout imageLayout, Optional runtimeBuilder, - List launchers) implements Application { - } - - /** - * Implementation of {@link Application} interface in which every method throws - * {@link UnsupportedOperationException} exception. - */ - class Unsupported implements Application { - - @Override - public String name() { - throw new UnsupportedOperationException(); - } - - @Override - public String description() { - throw new UnsupportedOperationException(); - } - - @Override - public String version() { - throw new UnsupportedOperationException(); - } - - @Override - public String vendor() { - throw new UnsupportedOperationException(); - } - - @Override - public String copyright() { - throw new UnsupportedOperationException(); - } - - @Override - public Optional srcDir() { - throw new UnsupportedOperationException(); - } - - @Override - public List contentDirs() { - throw new UnsupportedOperationException(); - } - - @Override - public AppImageLayout imageLayout() { - throw new UnsupportedOperationException(); - } - - @Override - public Optional runtimeBuilder() { - throw new UnsupportedOperationException(); - } - - @Override - public List launchers() { - throw new UnsupportedOperationException(); - } + List launchers, Map extraAppImageFileData) implements Application { } - } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java index 4cb52243c8341..f744d61477edd 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java @@ -114,17 +114,6 @@ default InputStream executableResource() { return ResourceLocator.class.getResourceAsStream("jpackageapplauncher"); } - /** - * Gets the additional properties for application launcher entries in the app - * image (".jpackage") file. - * - * @return the additional properties for application launcher entries in - * ".jpackage" file - */ - default Map extraAppImageFileData() { - return Map.of(); - } - /** * Gets the icon for this launcher or an empty {@link Optional} instance if the * launcher is requested to have no icon. @@ -183,52 +172,19 @@ default boolean hasCustomIcon() { String defaultIconResourceName(); /** - * Default implementation of {@link Launcher} interface. + * Gets the additional properties for application launcher entries in the app + * image (".jpackage") file. + * + * @return the additional properties for application launcher entries in + * ".jpackage" file */ - record Stub(String name, Optional startupInfo, List fileAssociations, - boolean isService, String description, Optional icon, String defaultIconResourceName) - implements Launcher { - } + Map extraAppImageFileData(); /** - * Implementation of {@link Launcher} interface in which every method throws - * {@link UnsupportedOperationException} exception. + * Default implementation of {@link Launcher} interface. */ - class Unsupported implements Launcher { - - @Override - public String name() { - throw new UnsupportedOperationException(); - } - - @Override - public Optional startupInfo() { - throw new UnsupportedOperationException(); - } - - @Override - public List fileAssociations() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isService() { - throw new UnsupportedOperationException(); - } - - @Override - public String description() { - throw new UnsupportedOperationException(); - } - - @Override - public Optional icon() { - throw new UnsupportedOperationException(); - } - - @Override - public String defaultIconResourceName() { - throw new UnsupportedOperationException(); - } + record Stub(String name, Optional startupInfo, List fileAssociations, + boolean isService, String description, Optional icon, String defaultIconResourceName, + Map extraAppImageFileData) implements Launcher { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java index d6af4bd430dec..bbceaa7dc30e8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java @@ -87,31 +87,4 @@ record Stub(String qualifiedClassName, List javaOptions, implements LauncherStartupInfo { } - - /** - * Implementation of {@link LauncherStartupInfo} interface in which every method - * throws {@link UnsupportedOperationException} exception. - */ - class Unsupported implements LauncherStartupInfo { - - @Override - public String qualifiedClassName() { - throw new UnsupportedOperationException(); - } - - @Override - public List javaOptions() { - throw new UnsupportedOperationException(); - } - - @Override - public List defaultParameters() { - throw new UnsupportedOperationException(); - } - - @Override - public List classPath() { - throw new UnsupportedOperationException(); - } - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java index 56aa3aa9f3648..e1320ad7aca2a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,10 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Collection; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -41,6 +45,13 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stax.StAXResult; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; public final class XmlUtils { @@ -110,4 +121,29 @@ public static DocumentBuilderFactory initDocumentBuilderFactory() { } return dbf; } + + public static Stream queryNodes(Node xml, XPath xPath, String xpathExpr) throws XPathExpressionException { + return toStream((NodeList) xPath.evaluate(xpathExpr, xml, XPathConstants.NODESET)); + } + + public static Stream toStream(NodeList nodes) { + return Optional.ofNullable(nodes).map(v -> { + return IntStream.range(0, v.getLength()).mapToObj(v::item); + }).orElseGet(Stream::of); + } + + public static Stream toStream(NamedNodeMap nodes) { + return Optional.ofNullable(nodes).map(v -> { + return IntStream.range(0, v.getLength()).mapToObj(v::item); + }).orElseGet(Stream::of); + } + + public static String elementValue(Element e, XPath xPath) { + try { + return queryNodes(e, xPath, "text()").map(Node::getNodeValue).collect(Collectors.joining()); + } catch (XPathExpressionException ex) { + // Should never happen + throw new RuntimeException(ex); + } + } } From 6a08a5ad89fef655f96bdb415450510a591f0652 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 21 Jan 2025 16:46:24 -0500 Subject: [PATCH 0238/1101] Implement Object.equals(), Object.hashCode(), and Object.toString() for CompositeProxy to make it IDE friendly --- .../internal/util/CompositeProxy.java | 51 ++++++++++++++- .../internal/util/CompositeProxyTest.java | 62 +++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java index 56602eb096bfa..36352cc88a5b7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java @@ -405,9 +405,58 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl } else if (method.isDefault()) { return InvocationHandler.invokeDefault(proxy, method, args); } else { - throw new UnsupportedOperationException(String.format("No handler for %s", method)); + handler = OBJECT_METHOD_DISPATCH.get(method); + if (handler != null) { + return handler.invoke(proxy, args); + } else { + throw new UnsupportedOperationException(String.format("No handler for %s", method)); + } + } + } + + private static String objectToString(Object obj) { + return obj.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(obj)); + } + + private static boolean objectEquals(Object obj, Object other) { + return obj == other; + } + + private static Method getMethod(Class type, String methodName, Class...paramaterTypes) { + try { + return type.getDeclaredMethod(methodName, paramaterTypes); + } catch (NoSuchMethodException|SecurityException ex) { + throw new InternalError(ex); } } + + static class ObjectMethodHandler extends HandlerOfMethod { + + ObjectMethodHandler(Method method) { + super(method); + } + + @Override + public Object invoke(Object proxy, Object[] args) throws Throwable { + if (args == null) { + return method.invoke(null, proxy); + } else { + final var newArgs = new Object[args.length + 1]; + newArgs[0] = proxy; + System.arraycopy(args, 0, newArgs, 1, args.length); + return method.invoke(null, newArgs); + } + } + } + + private static final Map OBJECT_METHOD_DISPATCH = Map.of( + getMethod(Object.class, "toString"), + new ObjectMethodHandler(getMethod(CompositeProxyInvocationHandler.class, "objectToString", Object.class)), + getMethod(Object.class, "equals", Object.class), + new ObjectMethodHandler(getMethod(CompositeProxyInvocationHandler.class, "objectEquals", Object.class, Object.class)), + getMethod(Object.class, "hashCode"), + new ObjectMethodHandler(getMethod(System.class, "identityHashCode", Object.class)) + ); } private static HandlerOfMethod createHandlerForDefaultMethod(Method method, InvokeTunnel invokeTunnel) { diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java index 72c036340d93a..163246dbe9271 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java @@ -23,8 +23,13 @@ package jdk.jpackage.internal.util; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; public class CompositeProxyTest { @@ -257,6 +262,63 @@ public String sayBye() { assertEquals("ciao,bye", proxy.talk()); } + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testBasicObjectMethods(boolean withOverrides) { + interface A { + default void foo() {} + } + + interface B { + default void bar() {} + } + + interface C extends A, B { + } + + final A aImpl; + final B bImpl; + + if (withOverrides) { + aImpl = new A() { + @Override + public String toString() { + return "theA"; + } + + @Override + public boolean equals(Object other) { + return true; + } + + @Override + public int hashCode() { + return 7; + } + }; + + bImpl = new B() { + @Override + public String toString() { + return "theB"; + } + }; + } else { + aImpl = new A() {}; + bImpl = new B() {}; + } + + var proxy = CompositeProxy.create(C.class, aImpl, bImpl); + var proxy2 = CompositeProxy.create(C.class, aImpl, bImpl); + + assertNotEquals(proxy.toString(), proxy2.toString()); + assertNotEquals(proxy.hashCode(), proxy2.hashCode()); + assertFalse(proxy.equals(proxy2)); + assertFalse(proxy2.equals(proxy)); + assertTrue(proxy.equals(proxy)); + assertTrue(proxy2.equals(proxy2)); + } + @Test public void testJavadocExample() { interface Sailboat { From 161a74ec794d1910afd073b10e12af20a0c6cd69 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 22 Jan 2025 10:39:16 -0500 Subject: [PATCH 0239/1101] Remove redundant null checks form PackageFile --- .../share/classes/jdk/jpackage/internal/PackageFile.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java index 75b54d92402b5..4ee8d7f68ccc3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java @@ -46,11 +46,9 @@ static Path getPathInAppImage(ApplicationLayout appLayout) { } void save(ApplicationLayout appLayout) throws IOException { - Path dstDir = appLayout.appDirectory(); - if (dstDir != null) { - Files.createDirectories(dstDir); - Files.writeString(dstDir.resolve(FILENAME), packageName); - } + final var dstDir = appLayout.appDirectory(); + Files.createDirectories(dstDir); + Files.writeString(dstDir.resolve(FILENAME), packageName); } private final String packageName; From 765a52cbf4f301220562f4eb9703d91097b09464 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 22 Jan 2025 12:15:17 -0500 Subject: [PATCH 0240/1101] Add PathUtils.normalizedAbsolutePath() and PathUtils.normalizedAbsolutePathString() --- .../classes/jdk/jpackage/internal/util/PathUtils.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java index 26d4951929175..3f125a438861e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java @@ -50,4 +50,12 @@ public static Path replaceSuffix(Path path, String suffix) { public static Path resolveNullablePath(Path base, Path path) { return Optional.ofNullable(path).map(base::resolve).orElse(null); } + + public static Path normalizedAbsolutePath(Path path) { + return path.normalize().toAbsolutePath(); + } + + public static String normalizedAbsolutePathString(Path path) { + return normalizedAbsolutePath(path).toString(); + } } From a0abc1c1b68a64d7d45b5998be6306a1b692429a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 22 Jan 2025 12:17:22 -0500 Subject: [PATCH 0241/1101] Move CompositeProxyTunnel to shared code as it is used on both mac and linux --- .../classes/jdk/jpackage/internal/CompositeProxyTunnel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/jdk.jpackage/{linux => share}/classes/jdk/jpackage/internal/CompositeProxyTunnel.java (95%) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/CompositeProxyTunnel.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CompositeProxyTunnel.java similarity index 95% rename from src/jdk.jpackage/linux/classes/jdk/jpackage/internal/CompositeProxyTunnel.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/CompositeProxyTunnel.java index 463b9ec07e55d..661264a94a448 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/CompositeProxyTunnel.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CompositeProxyTunnel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it From e4778e8068760ec50f23d63d2de0989fe8f4978d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 22 Jan 2025 12:20:00 -0500 Subject: [PATCH 0242/1101] Added CollectionUtils.toSet() --- .../internal/util/CollectionUtils.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java index 0b6988058fab9..3ea2dd484794d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java @@ -23,6 +23,10 @@ package jdk.jpackage.internal.util; import java.util.Collection; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * This class consists exclusively of static methods that operate on or return collections. @@ -43,4 +47,20 @@ public static > C toCollection(Collectio Collection tmp = v; return (C) tmp; } + + /** + * Converts the given collection to {@link Set}. + * + * @param the type of elements in this output collection + * @param v the input collection. Null is permitted. + * @return the input collection if it is of type {@link Set} or a new + * {@link Set} instance created from the input collection + */ + public static Set toSet(Collection col) { + if (col instanceof Set set) { + return set; + } else { + return Optional.ofNullable(col).map(Collection::stream).orElseGet(Stream::of).collect(Collectors.toSet()); + } + } } From 97547156de7d66ed9943ce50d2cf961166bfc3f1 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 22 Jan 2025 15:27:35 -0500 Subject: [PATCH 0243/1101] - Rework FromParams, WinFromParams, LinuxFromParams to use BundlerParamInfo.copyInto() and BundlerParamInfo.findIn() instead of BundlerParamInfo.fetchFrom() where applicable. - Added scopes to AppImageBuilder. - Added BundlerParamInfo.createBundlerParam() without ID. - Simplified FileAssociationGroup. --- .../jpackage/internal/LinuxFromParams.java | 76 +++++---- .../jpackage/internal/AppImageBuilder.java | 112 ++++++++----- .../jpackage/internal/BuildEnvFromParams.java | 8 +- .../jpackage/internal/BundlerParamInfo.java | 5 + .../internal/FileAssociationGroup.java | 67 ++++---- .../jdk/jpackage/internal/FromParams.java | 121 +++++++------- .../jpackage/internal/LauncherBuilder.java | 142 +++++++---------- .../jpackage/internal/LauncherFromParams.java | 107 ++++++++----- .../jdk/jpackage/internal/WinFromParams.java | 147 +++++++----------- .../internal/WinMsiPackageBuilder.java | 12 +- 10 files changed, 417 insertions(+), 380 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java index 44508415d8ac1..3fbf7d410e630 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java @@ -24,10 +24,6 @@ */ package jdk.jpackage.internal; -import java.io.IOException; -import jdk.jpackage.internal.model.ConfigException; -import java.util.Map; -import java.util.stream.Stream; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import static jdk.jpackage.internal.FromParams.createApplicationBuilder; import static jdk.jpackage.internal.FromParams.createApplicationBundlerParam; @@ -35,27 +31,31 @@ import static jdk.jpackage.internal.FromParams.createPackageBundlerParam; import static jdk.jpackage.internal.LinuxAppImageBuilder.APPLICATION_LAYOUT; import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; + +import java.io.IOException; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; +import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxApplication; import jdk.jpackage.internal.model.LinuxLauncher; import jdk.jpackage.internal.model.LinuxLauncherMixin; import jdk.jpackage.internal.model.LinuxPackage; import jdk.jpackage.internal.model.StandardPackageType; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; -import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; final class LinuxFromParams { private static LinuxApplication createLinuxApplication( Map params) throws ConfigException, IOException { - var launcherFromParams = new LauncherFromParams(); - var app = createApplicationBuilder(params, toFunction(launcherParams -> { - var launcher = launcherFromParams.create(launcherParams); - var shortcut = Stream.of(SHORTCUT_HINT, LINUX_SHORTCUT_HINT).filter(param -> { - return launcherParams.containsKey(param.getID()); - }).map(param -> { - return param.fetchFrom(launcherParams); - }).findFirst(); + final var launcherFromParams = new LauncherFromParams(); + final var app = createApplicationBuilder(params, toFunction(launcherParams -> { + final var launcher = launcherFromParams.create(launcherParams); + final var shortcut = Stream.of(SHORTCUT_HINT, LINUX_SHORTCUT_HINT).map(param -> { + return param.findIn(launcherParams); + }).filter(Optional::isPresent).map(Optional::get).findFirst(); return LinuxLauncher.create(launcher, new LinuxLauncherMixin.Stub(shortcut)); }), APPLICATION_LAYOUT).create(); return LinuxApplication.create(app); @@ -64,32 +64,43 @@ private static LinuxApplication createLinuxApplication( private static LinuxPackageBuilder createLinuxPackageBuilder( Map params, StandardPackageType type) throws ConfigException, IOException { - var app = APPLICATION.fetchFrom(params); + final var app = APPLICATION.fetchFrom(params); + + final var superPkgBuilder = createPackageBuilder(params, app, type); - var pkgBuilder = createPackageBuilder(params, app, type); + final var pkgBuilder = new LinuxPackageBuilder(superPkgBuilder); - return new LinuxPackageBuilder(pkgBuilder) - .additionalDependencies(LINUX_PACKAGE_DEPENDENCIES.fetchFrom(params)) - .category(LINUX_CATEGORY.fetchFrom(params)) - .menuGroupName(LINUX_MENU_GROUP.fetchFrom(params)) - .release(RELEASE.fetchFrom(params)) - .directName(LINUX_PACKAGE_NAME.fetchFrom(params)); + LINUX_PACKAGE_DEPENDENCIES.copyInto(params, pkgBuilder::additionalDependencies); + LINUX_CATEGORY.copyInto(params, pkgBuilder::category); + LINUX_MENU_GROUP.copyInto(params, pkgBuilder::menuGroupName); + RELEASE.copyInto(params, pkgBuilder::release); + LINUX_PACKAGE_NAME.copyInto(params, pkgBuilder::directName); + + return pkgBuilder; } private static LinuxPackage createLinuxRpmPackage( Map params) throws ConfigException, IOException { - var pkgBuilder = createLinuxPackageBuilder(params, LINUX_RPM); - return new LinuxRpmPackageBuilder(pkgBuilder) - .licenseType(LICENSE_TYPE.fetchFrom(params)) - .create(); + + final var superPkgBuilder = createLinuxPackageBuilder(params, LINUX_RPM); + + final var pkgBuilder = new LinuxRpmPackageBuilder(superPkgBuilder); + + LICENSE_TYPE.copyInto(params, pkgBuilder::licenseType); + + return pkgBuilder.create(); } private static LinuxPackage createLinuxDebPackage( Map params) throws ConfigException, IOException { - var pkgBuilder = createLinuxPackageBuilder(params, LINUX_DEB); - return new LinuxDebPackageBuilder(pkgBuilder) - .maintainerEmail(MAINTAINER_EMAIL.fetchFrom(params)) - .create(); + + final var superPkgBuilder = createLinuxPackageBuilder(params, LINUX_DEB); + + final var pkgBuilder = new LinuxDebPackageBuilder(superPkgBuilder); + + MAINTAINER_EMAIL.copyInto(params, pkgBuilder::maintainerEmail); + + return pkgBuilder.create(); } static final BundlerParamInfo APPLICATION = createApplicationBundlerParam( @@ -105,8 +116,7 @@ private static LinuxPackage createLinuxDebPackage( Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(), Boolean.class, params -> false, - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) - ? false : Boolean.valueOf(s) + (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s) ); private static final BundlerParamInfo LINUX_CATEGORY = createStringBundlerParam( diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java index 7fd7a4b16f325..370960d61156e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -25,28 +25,31 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.ApplicationLayout; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.function.Function; import java.util.stream.Stream; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.CustomLauncherIcon; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.function.ExceptionBox; -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; final class AppImageBuilder { @@ -57,13 +60,11 @@ private Builder() { } Builder addItem(AppImageItem v) { - Objects.requireNonNull(v); - Optional.ofNullable(customAppImageItemGroups.get(curGroup)).orElseGet(() -> { - List items = new ArrayList<>(); - customAppImageItemGroups.put(curGroup, items); - return items; - }).add(v); - return this; + return addItem(v, Scope.ALL); + } + + Builder addApplicationItem(AppImageItem v) { + return addItem(v, Scope.APPLICATION_ONLY); } Builder itemGroup(AppImageItemGroup v) { @@ -74,10 +75,6 @@ Builder itemGroup(AppImageItemGroup v) { Builder excludeDirFromCopying(Path path) { Objects.requireNonNull(path); - - if (excludeCopyDirs == null) { - excludeCopyDirs = new ArrayList<>(); - } excludeCopyDirs.add(path); return this; } @@ -90,9 +87,18 @@ AppImageBuilder create(Package pkg) { return new AppImageBuilder(pkg, excludeCopyDirs, customAppImageItemGroups); } - private List excludeCopyDirs; + private Builder addItem(AppImageItem v, Set scope) { + Optional.ofNullable(customAppImageItemGroups.get(curGroup)).orElseGet(() -> { + List items = new ArrayList<>(); + customAppImageItemGroups.put(curGroup, items); + return items; + }).add(new ScopedAppImageItem(v, scope)); + return this; + } + + private List excludeCopyDirs = new ArrayList<>(); private AppImageItemGroup curGroup = AppImageItemGroup.END; - private Map> customAppImageItemGroups = new HashMap<>(); + private Map> customAppImageItemGroups = new HashMap<>(); } static Builder build() { @@ -108,50 +114,84 @@ enum AppImageItemGroup { END } + private enum Scope { + APPLICATION, + PACKAGE; + + final static Set APPLICATION_ONLY = Set.of(APPLICATION); + final static Set ALL = EnumSet.allOf(Scope.class); + } + + private record ScopedAppImageItem(AppImageItem item, Set scope) { + ScopedAppImageItem { + Objects.requireNonNull(item); + Objects.requireNonNull(scope); + } + + boolean isInScope(Scope v) { + return scope.contains(v); + } + } + @FunctionalInterface interface AppImageItem { void write(BuildEnv env, Application app, ApplicationLayout appLayout) throws IOException, PackagerException; } - private AppImageBuilder(Application app, ApplicationLayout appLayout, - List excludeCopyDirs, boolean withAppImageFile, - Map> customAppImageItemGroups) { + private AppImageBuilder(Scope scope, Application app, ApplicationLayout appLayout, + List excludeCopyDirs, Map> customAppImageItemGroups) { + this.app = Objects.requireNonNull(app); this.appLayout = Objects.requireNonNull(appLayout); + Objects.requireNonNull(scope); + Objects.requireNonNull(excludeCopyDirs); + Objects.requireNonNull(customAppImageItemGroups); + appImageItemGroups = new HashMap<>(); + appImageItemGroups.put(AppImageItemGroup.RUNTIME, List.of( createRuntimeAppImageItem())); appImageItemGroups.put(AppImageItemGroup.CONTENT, List.of( - createContentAppImageItem( - Optional.ofNullable(excludeCopyDirs).orElseGet(List::of)))); + createContentAppImageItem(excludeCopyDirs))); appImageItemGroups.put(AppImageItemGroup.LAUNCHERS, List.of( createLaunchersAppImageItem())); - if (withAppImageFile) { - appImageItemGroups.put(AppImageItemGroup.APP_IMAGE_FILE, List.of( - createAppImageFileAppImageItem())); + + switch (scope) { + case APPLICATION -> { + appImageItemGroups.put(AppImageItemGroup.APP_IMAGE_FILE, List.of( + createAppImageFileAppImageItem())); + } + + default -> { + // NOP + } } for (var e : customAppImageItemGroups.entrySet()) { - var group = e.getKey(); - var mutableItems = Optional.ofNullable(appImageItemGroups.get(group)).map(items -> { + final var group = e.getKey(); + final var mutableItems = Optional.ofNullable(appImageItemGroups.get(group)).map(items -> { return new ArrayList<>(items); }).orElseGet(() -> { return new ArrayList<>(); }); - mutableItems.addAll(e.getValue()); - appImageItemGroups.put(group, mutableItems); + mutableItems.addAll(e.getValue().stream().filter(item -> { + return item.isInScope(scope); + }).map(ScopedAppImageItem::item).toList()); + if (!mutableItems.isEmpty()) { + appImageItemGroups.put(group, mutableItems); + } } } private AppImageBuilder(Application app, List excludeCopyDirs, - Map> customAppImageItemGroups) { - this(app, app.asApplicationLayout().orElseThrow(), excludeCopyDirs, true, customAppImageItemGroups); + Map> customAppImageItemGroups) { + this(Scope.APPLICATION, app, app.asApplicationLayout().orElseThrow(), excludeCopyDirs, customAppImageItemGroups); } private AppImageBuilder(Package pkg, List excludeCopyDirs, - Map> customAppImageItemGroups) { - this(pkg.app(), pkg.asPackageApplicationLayout().orElseThrow(), excludeCopyDirs, false, customAppImageItemGroups); + Map> customAppImageItemGroups) { + this(Scope.PACKAGE, pkg.app(), pkg.asPackageApplicationLayout().orElseThrow(), excludeCopyDirs, customAppImageItemGroups); } private static void copyRecursive(Path srcDir, Path dstDir, List excludeDirs) throws IOException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java index 2c782ea9eb0eb..2de872f59fe73 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java @@ -24,12 +24,14 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; -import java.util.Map; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; +import java.util.Map; + +import jdk.jpackage.internal.model.ConfigException; + final class BuildEnvFromParams { static BuildEnv create(Map params) throws ConfigException { @@ -51,5 +53,5 @@ static BuildEnv create(Map params) throws ConfigExceptio } static final BundlerParamInfo BUILD_ENV = BundlerParamInfo.createBundlerParam( - "env", BuildEnvFromParams::create); + BuildEnv.class, BuildEnvFromParams::create); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java index 11b461f2f2cbe..8df38af320a5c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java @@ -74,6 +74,11 @@ static BundlerParamInfo createBundlerParam(String id, Class va return new BundlerParamInfo(id, valueType, ThrowingFunction.toFunction(valueCtor), null); } + static BundlerParamInfo createBundlerParam(Class valueType, + ThrowingFunction, U> valueCtor) { + return createBundlerParam(valueType.getName(), valueType, valueCtor); + } + static boolean toBoolean(String value, Map params) { if (value == null || "null".equalsIgnoreCase(value)) { return false; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java index c4ea9e0d028a9..30258e520f8d1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,14 +30,14 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.function.Function; import java.util.function.Predicate; import java.util.function.UnaryOperator; -import static java.util.stream.Collectors.toSet; import java.util.stream.Stream; import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.util.CollectionUtils; final record FileAssociationGroup(List items) { + FileAssociationGroup { Objects.requireNonNull(items); } @@ -66,27 +66,40 @@ static Builder build() { return new Builder(); } + static class FileAssociationException extends Exception { + + private static final long serialVersionUID = 1L; + } + + static final class FileAssociationNoMimesException extends FileAssociationException { + + private static final long serialVersionUID = 1L; + } + + static final class FileAssociationNoExtensionsException extends FileAssociationException { + + private static final long serialVersionUID = 1L; + } + static final class Builder { - FileAssociationGroup create() { - Function> forExtension = ext -> { - if (mimeTypes.isEmpty()) { - return Stream.of(createFileAssociation(Optional.empty(), ext)); - } else { - return mimeTypes.stream().map(faMimeType -> { - return createFileAssociation(Optional.of(faMimeType), ext); - }); - } - }; - - Stream faStream; - if (extensions.isEmpty()) { - faStream = forExtension.apply(null); - } else { - faStream = extensions.stream().flatMap(forExtension); + private Builder() { + } + + FileAssociationGroup create() throws FileAssociationException { + if (mimeTypes == null || mimeTypes.isEmpty()) { + throw new FileAssociationNoMimesException(); } - return new FileAssociationGroup(faStream.toList()); + if (extensions == null || extensions.isEmpty()) { + throw new FileAssociationNoExtensionsException(); + } + + return new FileAssociationGroup(mimeTypes.stream().map(mimeType -> { + return extensions.stream().map(ext -> { + return createFileAssociation(mimeType, ext); + }); + }).flatMap(x -> x).toList()); } Builder icon(Path v) { @@ -100,23 +113,19 @@ Builder description(String v) { } Builder mimeTypes(Collection v) { - mimeTypes = conv(v); + mimeTypes = CollectionUtils.toSet(v); return this; } Builder extensions(Collection v) { - extensions = conv(v); + extensions = CollectionUtils.toSet(v); return this; } - private static Set conv(Collection col) { - return Optional.ofNullable(col).map(Collection::stream).orElseGet( - Stream::of).collect(toSet()); - } - - private FileAssociation createFileAssociation(Optional mimeType, String ext) { + private FileAssociation createFileAssociation(String mimeType, String ext) { Objects.requireNonNull(ext); - return new FileAssociation.Stub(Optional.ofNullable(description), Optional.ofNullable(icon), mimeType.orElse(null), ext); + Objects.requireNonNull(mimeType); + return new FileAssociation.Stub(Optional.ofNullable(description), Optional.ofNullable(icon), mimeType, ext); } private Path icon; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java index 0796dd74a0224..36255840a33d3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,21 +24,12 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.Launcher; -import java.io.IOException; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; -import jdk.jpackage.internal.AppImageFile2.LauncherInfo; import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; import static jdk.jpackage.internal.StandardBundlerParam.ADD_MODULES; import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.NAME; import static jdk.jpackage.internal.StandardBundlerParam.COPYRIGHT; import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; @@ -50,15 +41,28 @@ import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; import static jdk.jpackage.internal.StandardBundlerParam.LIMIT_MODULES; import static jdk.jpackage.internal.StandardBundlerParam.MODULE_PATH; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.SOURCE_DIR; import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; +import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage; import static jdk.jpackage.internal.StandardBundlerParam.isRuntimeInstaller; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import jdk.jpackage.internal.AppImageFile2.LauncherInfo; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLaunchers; import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.RuntimeLayout; import jdk.jpackage.internal.util.function.ThrowingFunction; @@ -69,16 +73,17 @@ static ApplicationBuilder createApplicationBuilder(Map p Function, Launcher> launcherMapper, ApplicationLayout appLayout) throws ConfigException, IOException { - var appBuilder = new ApplicationBuilder() - .name(APP_NAME.fetchFrom(params)) - .description(DESCRIPTION.fetchFrom(params)) - .version(VERSION.fetchFrom(params)) - .vendor(VENDOR.fetchFrom(params)) - .copyright(COPYRIGHT.fetchFrom(params)) - .srcDir(SOURCE_DIR.fetchFrom(params)) - .contentDirs(APP_CONTENT.fetchFrom(params)); + final var appBuilder = new ApplicationBuilder(); - var isRuntimeInstaller = isRuntimeInstaller(params); + APP_NAME.copyInto(params, appBuilder::name); + DESCRIPTION.copyInto(params, appBuilder::description); + appBuilder.version(VERSION.fetchFrom(params)); + VENDOR.copyInto(params, appBuilder::vendor); + COPYRIGHT.copyInto(params, appBuilder::copyright); + SOURCE_DIR.copyInto(params, appBuilder::srcDir); + APP_CONTENT.copyInto(params, appBuilder::contentDirs); + + final var isRuntimeInstaller = isRuntimeInstaller(params); if (isRuntimeInstaller) { appBuilder.appImageLayout(RuntimeLayout.DEFAULT); @@ -86,34 +91,32 @@ static ApplicationBuilder createApplicationBuilder(Map p appBuilder.appImageLayout(appLayout); } - var predefinedAppImage = getPredefinedAppImage(params); - if (isRuntimeInstaller) { - } else if (predefinedAppImage != null) { - var appIMafeFile = AppImageFile2.load(predefinedAppImage, appLayout); - appBuilder.initFromAppImage(appIMafeFile, launcherInfo -> { + // NOP if building Java runtime installer + } else if (hasPredefinedAppImage(params)) { + final var appImageFile = PREDEFINED_APP_IMAGE_FILE.fetchFrom(params); + appBuilder.initFromAppImage(appImageFile, launcherInfo -> { var launcherParams = mapLauncherInfo(launcherInfo); return launcherMapper.apply(mergeParams(params, launcherParams)); }); } else { - var launchers = createLaunchers(params, launcherMapper); + final var launchers = createLaunchers(params, launcherMapper); - var runtimeBuilderBuilder = new RuntimeBuilderBuilder() - .modulePath(MODULE_PATH.fetchFrom(params)); + final var runtimeBuilderBuilder = new RuntimeBuilderBuilder(); - Path predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); - if (predefinedRuntimeImage != null) { - runtimeBuilderBuilder.forRuntime(predefinedRuntimeImage); - } else { - var startupInfos = launchers.asList().stream() + MODULE_PATH.copyInto(params, runtimeBuilderBuilder::modulePath); + + final var predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.findIn(params); + predefinedRuntimeImage.ifPresentOrElse(runtimeBuilderBuilder::forRuntime, () -> { + final var startupInfos = launchers.asList().stream() .map(Launcher::startupInfo) .map(Optional::orElseThrow).toList(); - runtimeBuilderBuilder.forNewRuntime(startupInfos) - .addModules(ADD_MODULES.fetchFrom(params)) - .limitModules(LIMIT_MODULES.fetchFrom(params)) - .options(JLINK_OPTIONS.fetchFrom(params)) - .appy(); - } + final var jlinkOptionsBuilder = runtimeBuilderBuilder.forNewRuntime(startupInfos); + ADD_MODULES.copyInto(params, jlinkOptionsBuilder::addModules); + LIMIT_MODULES.copyInto(params, jlinkOptionsBuilder::limitModules); + JLINK_OPTIONS.copyInto(params, jlinkOptionsBuilder::options); + jlinkOptionsBuilder.appy(); + }); appBuilder.launchers(launchers).runtimeBuilder(runtimeBuilderBuilder.create()); } @@ -124,38 +127,34 @@ static ApplicationBuilder createApplicationBuilder(Map p static PackageBuilder createPackageBuilder( Map params, Application app, PackageType type) throws ConfigException { - return new PackageBuilder(app, type) - .name(INSTALLER_NAME.fetchFrom(params)) - .description(DESCRIPTION.fetchFrom(params)) - .version(VERSION.fetchFrom(params)) - .aboutURL(ABOUT_URL.fetchFrom(params)) - .licenseFile(Optional.ofNullable(LICENSE_FILE.fetchFrom(params)).map(Path::of).orElse(null)) - .predefinedAppImage(getPredefinedAppImage(params)) - .installDir(Optional.ofNullable(INSTALL_DIR.fetchFrom(params)).map(Path::of).orElse(null)); + + final var builder = new PackageBuilder(app, type); + + builder.name(INSTALLER_NAME.fetchFrom(params)); + DESCRIPTION.copyInto(params, builder::description); + VERSION.copyInto(params, builder::version); + ABOUT_URL.copyInto(params, builder::aboutURL); + LICENSE_FILE.findIn(params).map(Path::of).ifPresent(builder::licenseFile); + builder.predefinedAppImage(getPredefinedAppImage(params)); + INSTALL_DIR.findIn(params).map(Path::of).ifPresent(builder::installDir); + + return builder; } static BundlerParamInfo createApplicationBundlerParam( - ThrowingFunction, T> valueFunc) { - return BundlerParamInfo.createBundlerParam("target.application", params -> { - var app = valueFunc.apply(params); - params.put(APPLICATION.getID(), app); - return app; - }); + ThrowingFunction, T> ctor) { + return BundlerParamInfo.createBundlerParam(Application.class, ctor); } static BundlerParamInfo createPackageBundlerParam( - ThrowingFunction, T> valueFunc) { - return BundlerParamInfo.createBundlerParam("target.package", params -> { - var pkg = valueFunc.apply(params); - params.put(PACKAGE.getID(), pkg); - return pkg; - }); + ThrowingFunction, T> ctor) { + return BundlerParamInfo.createBundlerParam(jdk.jpackage.internal.model.Package.class, ctor); } private static ApplicationLaunchers createLaunchers( Map params, Function, Launcher> launcherMapper) { - var launchers = Optional.ofNullable(ADD_LAUNCHERS.fetchFrom(params)).orElseGet(List::of); + var launchers = ADD_LAUNCHERS.findIn(params).orElseGet(List::of); var mainLauncher = launcherMapper.apply(params); var additionalLaunchers = launchers.stream().map(launcherParams -> { @@ -167,7 +166,7 @@ private static ApplicationLaunchers createLaunchers( private static Map mapLauncherInfo(LauncherInfo launcherInfo) { Map launcherParams = new HashMap<>(); - launcherParams.put(APP_NAME.getID(), launcherInfo.name()); + launcherParams.put(NAME.getID(), launcherInfo.name()); launcherParams.put(LAUNCHER_AS_SERVICE.getID(), Boolean.toString(launcherInfo.service())); launcherParams.putAll(launcherInfo.extra()); return launcherParams; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java index 1f4912cecf5a6..b3e434fa817e8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,49 +24,40 @@ */ package jdk.jpackage.internal; +import static jdk.jpackage.internal.I18N.buildConfigException; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; + import java.nio.file.Path; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.function.Predicate; -import java.util.stream.IntStream; -import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; -import static jdk.internal.util.OperatingSystem.LINUX; -import static jdk.internal.util.OperatingSystem.MACOS; -import static jdk.internal.util.OperatingSystem.WINDOWS; -import static jdk.jpackage.internal.I18N.buildConfigException; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.CustomLauncherIcon; import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.Launcher.Stub; -import jdk.jpackage.internal.model.LauncherStartupInfo; -import jdk.jpackage.internal.util.function.ExceptionBox; -import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; -import static jdk.jpackage.internal.model.ConfigException.rethrowConfigException; -import jdk.jpackage.internal.model.CustomLauncherIcon; import jdk.jpackage.internal.model.LauncherIcon; +import jdk.jpackage.internal.model.LauncherStartupInfo; final class LauncherBuilder { Launcher create() throws ConfigException { - try { - CustomLauncherIcon.fromLauncherIcon(icon) - .map(CustomLauncherIcon::path) - .ifPresent(toConsumer(LauncherBuilder::validateIcon)); + CustomLauncherIcon.fromLauncherIcon(icon) + .map(CustomLauncherIcon::path) + .ifPresent(toConsumer(LauncherBuilder::validateIcon)); - var fa = createFileAssociations(faSources.stream()).toList(); + final var fa = createFileAssociations(faSources, Optional.ofNullable(faTraits).orElse(DEFAULT_FA_TRAITS)); - Objects.requireNonNull(name); - Objects.requireNonNull(description); - Objects.requireNonNull(defaultIconResourceName); + Objects.requireNonNull(defaultIconResourceName); - return new Stub(name, Optional.ofNullable(startupInfo), fa, isService, description, Optional.ofNullable(icon), defaultIconResourceName); - } catch (RuntimeException ex) { - throw ConfigException.rethrowConfigException(ex); - } + final var nonNullName = deriveNonNullName(); + + return new Stub(nonNullName, Optional.ofNullable(startupInfo), fa, + isService, Optional.ofNullable(description).orElse(nonNullName), + Optional.ofNullable(icon), defaultIconResourceName, + Optional.ofNullable(extraAppImageFileData).orElseGet(Map::of)); } LauncherBuilder name(String v) { @@ -79,13 +70,13 @@ LauncherBuilder startupInfo(LauncherStartupInfo v) { return this; } - LauncherBuilder faSources(List v) { + LauncherBuilder faGroups(List v) { faSources = v; return this; } - LauncherBuilder faPrediacate(Predicate v) { - faPrediacate = v; + LauncherBuilder faTraits(FileAssociationTraits v) { + faTraits = v; return this; } @@ -109,96 +100,73 @@ LauncherBuilder defaultIconResourceName(String v) { return this; } - static boolean isFileAssociationValid(FileAssociation src) { - toConsumer(LauncherBuilder::verifyFileAssociation).accept(src); + LauncherBuilder extraAppImageFileData(Map v) { + extraAppImageFileData = v; + return this; + } - return Optional.ofNullable(src.extension()).isPresent(); + private String deriveNonNullName() { + return Optional.ofNullable(name).orElseGet(() -> startupInfo.simpleClassName()); } static void validateIcon(Path icon) throws ConfigException { switch (OperatingSystem.current()) { case WINDOWS -> { if (!icon.getFileName().toString().toLowerCase().endsWith(".ico")) { - throw buildConfigException() - .message("message.icon-not-ico", icon).create(); + throw buildConfigException().message("message.icon-not-ico", icon).create(); } } case LINUX -> { if (!icon.getFileName().toString().endsWith(".png")) { - throw buildConfigException() - .message("message.icon-not-png", icon).create(); + throw buildConfigException().message("message.icon-not-png", icon).create(); } } case MACOS -> { if (!icon.getFileName().toString().endsWith(".icns")) { - throw buildConfigException() - .message("message.icon-not-icns", icon).create(); + throw buildConfigException().message("message.icon-not-icns", icon).create(); } } + default -> { + throw new UnsupportedOperationException(); + } } } - private Stream createFileAssociations( - Stream sources) throws ConfigException { + record FileAssociationTraits() { + } - var sourcesAsArray = sources.toArray(FileAssociationGroup[]::new); + private static List createFileAssociations( + List groups, FileAssociationTraits faTraits) throws ConfigException { - var stream = IntStream.range(0, sourcesAsArray.length).mapToObj(idx -> { - return Map.entry(idx + 1, sourcesAsArray[idx]); - }).map(entry -> { - try { - var faGroup = FileAssociationGroup.filter(faPrediacate).apply(entry.getValue()); - if (faGroup.isEmpty()) { - return null; - } else { - return Map.entry(entry.getKey(), faGroup); - } - } catch (ExceptionBox ex) { - if (ex.getCause() instanceof ConfigException cfgException) { - throw rethrowUnchecked(buildConfigException() - .cause(cfgException.getCause()) - .message(cfgException.getMessage(), entry.getKey()) - .advice(cfgException.getAdvice(), entry.getKey()) - .create()); - } else { - throw ex; - } - } - }).filter(Objects::nonNull).peek(entry -> { - var faGroup = entry.getValue(); - if (faGroup.items().size() != faGroup.items().stream().map(FileAssociation::extension).distinct().count()) { - throw rethrowUnchecked(buildConfigException() - .message("error.too-many-content-types-for-file-association", entry.getKey()) - .advice("error.too-many-content-types-for-file-association.advice", entry.getKey()) - .create()); + Objects.requireNonNull(groups); + Objects.requireNonNull(faTraits); + + int faID = 1; + for (var group : groups) { + final var scanResult = new FileAssociationScaner().scan(group.items()); + + if (!scanResult.extensionsWithMultipleMimeTypes().isEmpty()) { + throw buildConfigException() + .message("error.too-many-content-types-for-file-association", faID) + .advice("error.too-many-content-types-for-file-association.advice", faID) + .create(); } - }).map(entry -> { - return entry.getValue().items().stream(); - }).flatMap(x -> x); - - try { - return stream.toList().stream(); - } catch (RuntimeException ex) { - throw rethrowConfigException(ex); - } - } - private static void verifyFileAssociation(FileAssociation src) throws ConfigException { - if (Optional.ofNullable(src.mimeType()).isEmpty()) { - throw buildConfigException() - .noformat() - .message("error.no-content-types-for-file-association") - .advice("error.no-content-types-for-file-association.advice") - .create(); + faID++; } + + return FileAssociationGroup.flatMap(groups.stream()).toList(); } private String name; private LauncherStartupInfo startupInfo; private List faSources; - private Predicate faPrediacate = LauncherBuilder::isFileAssociationValid; + private FileAssociationTraits faTraits; private boolean isService; private String description; private LauncherIcon icon; private String defaultIconResourceName; + private Map extraAppImageFileData; + + private static final FileAssociationTraits DEFAULT_FA_TRAITS = new FileAssociationTraits(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java index 3ac98eb9a190d..b79a2fe7be5f9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java @@ -24,18 +24,7 @@ */ package jdk.jpackage.internal; -import java.nio.file.Path; -import java.util.List; -import jdk.jpackage.internal.model.Launcher; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.function.Predicate; -import jdk.internal.util.OperatingSystem; -import static jdk.internal.util.OperatingSystem.LINUX; -import static jdk.internal.util.OperatingSystem.MACOS; -import static jdk.internal.util.OperatingSystem.WINDOWS; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import static jdk.jpackage.internal.I18N.buildConfigException; import static jdk.jpackage.internal.StandardBundlerParam.ARGUMENTS; import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; import static jdk.jpackage.internal.StandardBundlerParam.FA_CONTENT_TYPE; @@ -43,54 +32,92 @@ import static jdk.jpackage.internal.StandardBundlerParam.FA_EXTENSIONS; import static jdk.jpackage.internal.StandardBundlerParam.FA_ICON; import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; -import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.JAVA_OPTIONS; +import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; +import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_DATA; +import static jdk.jpackage.internal.StandardBundlerParam.NAME; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.stream.IntStream; +import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.CustomLauncherIcon; import jdk.jpackage.internal.model.DefaultLauncherIcon; import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.LauncherIcon; -record LauncherFromParams(Predicate faPredicate) { +record LauncherFromParams(Optional, FileAssociation>> faExtension) { LauncherFromParams { - Objects.requireNonNull(faPredicate); + Objects.requireNonNull(faExtension); } LauncherFromParams() { - this(LauncherBuilder::isFileAssociationValid); + this(Optional.empty()); } Launcher create(Map params) throws ConfigException { - var builder = new LauncherBuilder() - .description(DESCRIPTION.fetchFrom(params)) - .icon(toLauncherIcon(ICON.fetchFrom(params))) - .isService(LAUNCHER_AS_SERVICE.fetchFrom(params)) - .name(APP_NAME.fetchFrom(params)) - .defaultIconResourceName(defaultIconResourceName()) - .faPrediacate(faPredicate); - - if (PREDEFINED_APP_IMAGE.fetchFrom(params) == null) { - builder.startupInfo(new LauncherStartupInfoBuilder() - .launcherData(StandardBundlerParam.LAUNCHER_DATA.fetchFrom(params)) - .defaultParameters(ARGUMENTS.fetchFrom(params)) - .javaOptions(JAVA_OPTIONS.fetchFrom(params)) - .create()); + final var builder = new LauncherBuilder().defaultIconResourceName(defaultIconResourceName()); + + DESCRIPTION.copyInto(params, builder::description); + builder.icon(toLauncherIcon(ICON.findIn(params).orElse(null))); + LAUNCHER_AS_SERVICE.copyInto(params, builder::isService); + NAME.copyInto(params, builder::name); + + if (PREDEFINED_APP_IMAGE.findIn(params).isEmpty()) { + final var startupInfoBuilder = new LauncherStartupInfoBuilder(); + + startupInfoBuilder.launcherData(LAUNCHER_DATA.fetchFrom(params)); + ARGUMENTS.copyInto(params, startupInfoBuilder::defaultParameters); + JAVA_OPTIONS.copyInto(params, startupInfoBuilder::javaOptions); + + builder.startupInfo(startupInfoBuilder.create()); } - var faSources = Optional.ofNullable( - FILE_ASSOCIATIONS.fetchFrom(params)).orElseGet(List::of).stream().map(faParams -> { - return FileAssociationGroup.build() - .description(FA_DESCRIPTION.fetchFrom(faParams)) - .icon(FA_ICON.fetchFrom(faParams)) - .extensions(FA_EXTENSIONS.fetchFrom(faParams)) - .mimeTypes(FA_CONTENT_TYPE.fetchFrom(faParams)) - .create(); + final var faParamsList = FILE_ASSOCIATIONS.findIn(params).orElseGet(List::of); + + final var faGroups = IntStream.range(0, faParamsList.size()).mapToObj(idx -> { + final var faParams = faParamsList.get(idx); + return toSupplier(() -> { + final var faGroupBuilder = FileAssociationGroup.build(); + + FA_DESCRIPTION.copyInto(faParams, faGroupBuilder::description); + FA_ICON.copyInto(faParams, faGroupBuilder::icon); + FA_EXTENSIONS.copyInto(faParams, faGroupBuilder::extensions); + FA_CONTENT_TYPE.copyInto(faParams, faGroupBuilder::mimeTypes); + + final var faID = idx + 1; + + final FileAssociationGroup faGroup; + try { + faGroup = faGroupBuilder.create(); + } catch (FileAssociationGroup.FileAssociationNoMimesException ex) { + throw buildConfigException() + .message("error.no-content-types-for-file-association", faID) + .advice("error.no-content-types-for-file-association.advice", faID) + .create(); + } + + if (faExtension.isPresent()) { + return new FileAssociationGroup(faGroup.items().stream().map(fa -> { + return faExtension.get().apply(fa, params); + }).toList()); + } else { + return faGroup; + } + }).get(); }).toList(); - return builder.faSources(faSources).create(); + return builder.faGroups(faGroups).create(); } private static LauncherIcon toLauncherIcon(Path launcherIconPath) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java index ba85415c2a3ff..807ae316ea8a9 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,15 +24,8 @@ */ package jdk.jpackage.internal; -import java.io.IOException; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.WinMsiPackage; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; import static java.util.stream.Collectors.toSet; +import static jdk.jpackage.internal.BundlerParamInfo.createBooleanBundlerParam; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import static jdk.jpackage.internal.FromParams.createApplicationBuilder; import static jdk.jpackage.internal.FromParams.createApplicationBundlerParam; @@ -43,75 +36,80 @@ import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; import static jdk.jpackage.internal.WinAppImageBuilder.APPLICATION_LAYOUT; import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; -import jdk.jpackage.internal.model.WinApplication; -import jdk.jpackage.internal.model.WinLauncher; import static jdk.jpackage.internal.model.WinLauncherMixin.WinShortcut.WIN_SHORTCUT_DESKTOP; import static jdk.jpackage.internal.model.WinLauncherMixin.WinShortcut.WIN_SHORTCUT_START_MENU; -import jdk.jpackage.internal.model.WinLauncherMixin; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.WinApplication; +import jdk.jpackage.internal.model.WinLauncher; +import jdk.jpackage.internal.model.WinLauncherMixin; +import jdk.jpackage.internal.model.WinMsiPackage; + final class WinFromParams { private static WinApplication createWinApplication( Map params) throws ConfigException, IOException { - var launcherFromParams = new LauncherFromParams(); - var app = createApplicationBuilder(params, toFunction(launcherParams -> { - var launcher = launcherFromParams.create(launcherParams); - boolean isConsole = CONSOLE_HINT.fetchFrom(launcherParams); + final var launcherFromParams = new LauncherFromParams(); + + final var app = createApplicationBuilder(params, toFunction(launcherParams -> { + + final var launcher = launcherFromParams.create(launcherParams); - var shortcuts = Map.of(WIN_SHORTCUT_DESKTOP, List.of(SHORTCUT_HINT, + final boolean isConsole = CONSOLE_HINT.findIn(launcherParams).orElse(false); + + final var shortcuts = Map.of(WIN_SHORTCUT_DESKTOP, List.of(SHORTCUT_HINT, WIN_SHORTCUT_HINT), WIN_SHORTCUT_START_MENU, List.of(MENU_HINT, WIN_MENU_HINT)).entrySet().stream().filter(e -> { - var shortcutParams = e.getValue(); - if (launcherParams.containsKey(shortcutParams.get(0).getID())) { - // This is an explicit shortcut configuration for an addition launcher - return shortcutParams.get(0).fetchFrom(launcherParams); - } else { - return shortcutParams.get(1).fetchFrom(launcherParams); - } + + final var shortcutParams = e.getValue(); + + return shortcutParams.get(0).findIn(launcherParams).orElseGet(() -> { + return shortcutParams.get(1).findIn(launcherParams).orElse(false); + }); }).map(Map.Entry::getKey).collect(toSet()); return WinLauncher.create(launcher, new WinLauncherMixin.Stub(isConsole, shortcuts)); + }), APPLICATION_LAYOUT).create(); + return WinApplication.create(app); } private static WinMsiPackage createWinMsiPackage(Map params) throws ConfigException, IOException { - var app = APPLICATION.fetchFrom(params); + final var app = APPLICATION.fetchFrom(params); - var pkgBuilder = createPackageBuilder(params, app, WIN_MSI); + final var superPkgBuilder = createPackageBuilder(params, app, WIN_MSI); - final Path serviceInstaller; - if (!app.isService()) { - serviceInstaller = null; - } else { - serviceInstaller = Optional.ofNullable(RESOURCE_DIR.fetchFrom(params)).map( - resourceDir -> { - return resourceDir.resolve("service-installer.exe"); - }).orElse(null); - } + final var pkgBuilder = new WinMsiPackageBuilder(superPkgBuilder); - return new WinMsiPackageBuilder(pkgBuilder) - .helpURL(HELP_URL.fetchFrom(params)) - .isSystemWideInstall(MSI_SYSTEM_WIDE.fetchFrom(params)) - .serviceInstaller(serviceInstaller) - .startMenuGroupName(MENU_GROUP.fetchFrom(params)) - .updateURL(UPDATE_URL.fetchFrom(params)) - .upgradeCode(getUpgradeCode(params)) - .withInstallDirChooser(INSTALLDIR_CHOOSER.fetchFrom(params)) - .withShortcutPrompt(SHORTCUT_PROMPT.fetchFrom(params)) - .create(); - } + HELP_URL.copyInto(params, pkgBuilder::helpURL); + MSI_SYSTEM_WIDE.copyInto(params, pkgBuilder::isSystemWideInstall); + MENU_GROUP.copyInto(params, pkgBuilder::startMenuGroupName); + UPDATE_URL.copyInto(params, pkgBuilder::updateURL); + INSTALLDIR_CHOOSER.copyInto(params, pkgBuilder::withInstallDirChooser); + SHORTCUT_PROMPT.copyInto(params, pkgBuilder::withShortcutPrompt); + + if (app.isService()) { + RESOURCE_DIR.copyInto(params, resourceDir -> { + pkgBuilder.serviceInstaller(resourceDir.resolve("service-installer.exe")); + }); + } - private static UUID getUpgradeCode(Map params) throws ConfigException { try { - return Optional.ofNullable(UPGRADE_UUID.fetchFrom(params)).map(UUID::fromString).orElse( - null); + UPGRADE_UUID.findIn(params).map(UUID::fromString).ifPresent(pkgBuilder::upgradeCode); } catch (IllegalArgumentException ex) { throw new ConfigException(ex); } + + return pkgBuilder.create(); } static final BundlerParamInfo APPLICATION = createApplicationBundlerParam( @@ -120,61 +118,34 @@ private static UUID getUpgradeCode(Map params) throws Co static final BundlerParamInfo MSI_PACKAGE = createPackageBundlerParam( WinFromParams::createWinMsiPackage); - private static final BundlerParamInfo WIN_MENU_HINT = new BundlerParamInfo<>( - Arguments.CLIOptions.WIN_MENU_HINT.getId(), - Boolean.class, - p -> false, - // valueOf(null) is false, - // and we actually do want null in some cases - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); + private static final BundlerParamInfo WIN_MENU_HINT = createBooleanBundlerParam( + Arguments.CLIOptions.WIN_MENU_HINT.getId()); - private static final BundlerParamInfo WIN_SHORTCUT_HINT = new BundlerParamInfo<>( - Arguments.CLIOptions.WIN_SHORTCUT_HINT.getId(), - Boolean.class, - p -> false, - // valueOf(null) is false, - // and we actually do want null in some cases - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)); + private static final BundlerParamInfo WIN_SHORTCUT_HINT = createBooleanBundlerParam( + Arguments.CLIOptions.WIN_SHORTCUT_HINT.getId()); - public static final BundlerParamInfo CONSOLE_HINT = new BundlerParamInfo<>( - Arguments.CLIOptions.WIN_CONSOLE_HINT.getId(), - Boolean.class, - params -> false, - // valueOf(null) is false, - // and we actually do want null in some cases - (s, p) -> (s == null - || "null".equalsIgnoreCase(s)) ? true : Boolean.valueOf(s)); + public static final BundlerParamInfo CONSOLE_HINT = createBooleanBundlerParam( + Arguments.CLIOptions.WIN_CONSOLE_HINT.getId()); private static final BundlerParamInfo INSTALLDIR_CHOOSER = new BundlerParamInfo<>( Arguments.CLIOptions.WIN_DIR_CHOOSER.getId(), Boolean.class, - params -> false, + null, (s, p) -> Boolean.valueOf(s) ); private static final BundlerParamInfo SHORTCUT_PROMPT = new BundlerParamInfo<>( Arguments.CLIOptions.WIN_SHORTCUT_PROMPT.getId(), Boolean.class, - params -> false, + null, (s, p) -> Boolean.valueOf(s) ); - private static final BundlerParamInfo MENU_GROUP = new BundlerParamInfo<>( - Arguments.CLIOptions.WIN_MENU_GROUP.getId(), - String.class, - params -> I18N.getString("param.menu-group.default"), - (s, p) -> s - ); + private static final BundlerParamInfo MENU_GROUP = createStringBundlerParam( + Arguments.CLIOptions.WIN_MENU_GROUP.getId()); - private static final BundlerParamInfo MSI_SYSTEM_WIDE = new BundlerParamInfo<>( - Arguments.CLIOptions.WIN_PER_USER_INSTALLATION.getId(), - Boolean.class, - params -> true, // MSIs default to system wide - // valueOf(null) is false, - // and we actually do want null - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? null - : Boolean.valueOf(s) - ); + private static final BundlerParamInfo MSI_SYSTEM_WIDE = createBooleanBundlerParam( + Arguments.CLIOptions.WIN_PER_USER_INSTALLATION.getId()); private static final BundlerParamInfo HELP_URL = createStringBundlerParam( Arguments.CLIOptions.WIN_HELP_URL.getId()); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java index 9fe992930e3d3..737bf97f2d607 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java @@ -24,13 +24,15 @@ */ package jdk.jpackage.internal; +import static jdk.jpackage.internal.I18N.buildConfigException; + import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; import java.util.Optional; import java.util.UUID; -import static jdk.jpackage.internal.I18N.buildConfigException; + import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.MsiVersion; @@ -66,7 +68,7 @@ WinMsiPackage create() throws ConfigException { withShortcutPrompt, Optional.ofNullable(helpURL), Optional.ofNullable(updateURL), - startMenuGroupName, + Optional.ofNullable(startMenuGroupName).orElseGet(DEFAULTS::startMenuGroupName), isSystemWideInstall, Optional.ofNullable(upgradeCode).orElseGet(() -> upgradeCode(pkg.app())), productCode(pkg.app(), pkg.version()), @@ -126,14 +128,18 @@ private static UUID createNameUUID(String... components) { return UUID.nameUUIDFromBytes(key.getBytes(StandardCharsets.UTF_8)); } + record Defaults(String startMenuGroupName) {} + private boolean withInstallDirChooser; private boolean withShortcutPrompt; private String helpURL; private String updateURL; private String startMenuGroupName; - private boolean isSystemWideInstall; + private boolean isSystemWideInstall = true; private Path serviceInstaller; private UUID upgradeCode; private final PackageBuilder pkgBuilder; + + private static final Defaults DEFAULTS = new Defaults(I18N.getString("param.menu-group.default")); } From e56484348273186a187ce17a72f116b15c8ae197 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 22 Jan 2025 15:29:00 -0500 Subject: [PATCH 0244/1101] Use correct default description for application which is the name of the application. --- .../jdk/jpackage/internal/ApplicationBuilder.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 5005ec1236646..d9fa8fcbd0010 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -69,7 +69,7 @@ Application create() throws ConfigException { return new Application.Stub( effectiveName, - Optional.ofNullable(description).orElseGet(DEFAULTS::description), + Optional.ofNullable(description).orElse(effectiveName), Optional.ofNullable(version).orElseGet(DEFAULTS::version), Optional.ofNullable(vendor).orElseGet(DEFAULTS::vendor), Optional.ofNullable(copyright).orElseGet(DEFAULTS::copyright), @@ -147,7 +147,10 @@ ApplicationBuilder contentDirs(List v) { return this; } - private record Defaults(String description, String version, String vendor, String copyright) { + private record Defaults(String version, String vendor) { + String copyright() { + return I18N.format("param.copyright.default", new Date()); + } } private String name; @@ -162,8 +165,6 @@ private record Defaults(String description, String version, String vendor, Strin private ApplicationLaunchers launchers; private static final Defaults DEFAULTS = new Defaults( - I18N.getString("param.description.default"), "1.0", - I18N.getString("param.vendor.default"), - I18N.format("param.copyright.default", new Date())); + I18N.getString("param.vendor.default")); } From 779c92d099540da96514b3a8a8a059230991be48 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 22 Jan 2025 19:05:20 -0500 Subject: [PATCH 0245/1101] Mast be in 97547156de7d66ed9943ce50d2cf961166bfc3f1 commit --- .../internal/FileAssociationScaner.java | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationScaner.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationScaner.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationScaner.java new file mode 100644 index 0000000000000..b8186e8ca6673 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationScaner.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import static java.util.stream.Collectors.collectingAndThen; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.toMap; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import jdk.jpackage.internal.model.FileAssociation; + +final class FileAssociationScaner { + + record Result(Map> mimeTypesWithMultipleExtensions, + Map> extensionsWithMultipleMimeTypes, + Map> duplicates) { + } + + Result scan(Collection fileAssociations) { + if (fileAssociations.stream().map(Box::new).distinct().count() != fileAssociations.size()) { + throw new IllegalArgumentException("Multiple occurrences of the same fa instance in the given container"); + } + + final var mimeTypesWithMultipleExtensions = fileAssociations.stream().collect( + collectingAndThen(groupingBy(MimeType::new), FileAssociationScaner::filterDuplicates)); + final var extensionsWithMultipleMimeTypes = fileAssociations.stream().collect( + collectingAndThen(groupingBy(Extension::new), FileAssociationScaner::filterDuplicates)); + final var duplicates = fileAssociations.stream().collect( + collectingAndThen(groupingBy(MimeTypeWithExtension::new), FileAssociationScaner::filterDuplicates)); + + return new Result(mimeTypesWithMultipleExtensions, extensionsWithMultipleMimeTypes, duplicates); + } + + private static Map> filterDuplicates(Map> v) { + return v.entrySet().stream().filter(e -> { + return e.getValue().size() > 1; + }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + record MimeTypeWithExtension(String mimeType, String extension) { + MimeTypeWithExtension(FileAssociation fa) { + this(fa.mimeType(), fa.extension()); + } + } + + record MimeType(String value) { + MimeType(FileAssociation fa) { + this(fa.mimeType()); + } + } + + record Extension(String value) { + Extension(FileAssociation fa) { + this(fa.extension()); + } + } + + private static class Box { + Box(FileAssociation value) { + this.value = value; + } + + @Override + public boolean equals(Object other) { + return value == ((Box)other).value; + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + private final FileAssociation value; + } +} From 481bb9b89713b8455dfe0dd7c59cf4b312078a6d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 22 Jan 2025 19:08:02 -0500 Subject: [PATCH 0246/1101] Make PathUtils.normalizedAbsolutePath() and PathUtils.normalizedAbsolutePathString() null safe --- .../jdk/jpackage/internal/util/PathUtils.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java index 3f125a438861e..7ffb4ddfaa772 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java @@ -52,10 +52,18 @@ public static Path resolveNullablePath(Path base, Path path) { } public static Path normalizedAbsolutePath(Path path) { - return path.normalize().toAbsolutePath(); + if (path != null) { + return path.normalize().toAbsolutePath(); + } else { + return null; + } } public static String normalizedAbsolutePathString(Path path) { - return normalizedAbsolutePath(path).toString(); + if (path != null) { + return normalizedAbsolutePath(path).toString(); + } else { + return null; + } } } From 2219408084a52f6ba271bf4620f778e613c4f77a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 22 Jan 2025 19:08:54 -0500 Subject: [PATCH 0247/1101] Add AppImageBuilder.addPackageItem() --- .../share/classes/jdk/jpackage/internal/AppImageBuilder.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java index 370960d61156e..d0b2daaf30e02 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -67,6 +67,10 @@ Builder addApplicationItem(AppImageItem v) { return addItem(v, Scope.APPLICATION_ONLY); } + Builder addPackageItem(AppImageItem v) { + return addItem(v, Scope.PACKAGE_ONLY); + } + Builder itemGroup(AppImageItemGroup v) { Objects.requireNonNull(v); curGroup = v; @@ -119,6 +123,7 @@ private enum Scope { PACKAGE; final static Set APPLICATION_ONLY = Set.of(APPLICATION); + final static Set PACKAGE_ONLY = Set.of(PACKAGE); final static Set ALL = EnumSet.allOf(Scope.class); } From 2fe9574597d1f9453ebe3b64f60af4813d52904f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 22 Jan 2025 19:10:52 -0500 Subject: [PATCH 0248/1101] Rework AppImageFile to test AppImageFile2 --- .../jpackage/internal/AppImageFileTest.java | 390 +++++++++--------- 1 file changed, 198 insertions(+), 192 deletions(-) diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java index 875e71593f336..0769d42dcd5ff 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java @@ -23,253 +23,259 @@ package jdk.jpackage.internal; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.LinkedHashMap; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrowsExactly; -import static org.junit.jupiter.api.Assertions.assertTrue; +import jdk.jpackage.internal.AppImageFile2.LauncherInfo; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLaunchers; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.LauncherStartupInfo; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; public class AppImageFileTest { + static AppImageBuilder build() { + return new AppImageBuilder(); + } + + static class AppImageBuilder { + + AppImageBuilder version(String v) { + version = Objects.requireNonNull(v); + return this; + } + + AppImageBuilder launcherName(String v) { + launcherName = Objects.requireNonNull(v); + return this; + } + + AppImageBuilder mainClass(String v) { + mainClass = Objects.requireNonNull(v); + return this; + } + + AppImageBuilder addExtra(Map v) { + extra.putAll(v); + return this; + } + + AppImageBuilder addExtra(String key, String value) { + extra.putAll(Map.of(key, value)); + return this; + } + + AppImageBuilder addlauncher(String name) { + return addlauncher(name, false); + } + + AppImageBuilder addlauncher(String name, boolean isService) { + return addlauncher(name, isService, Map.of()); + } + + AppImageBuilder addlauncher(String name, boolean isService, Map extra) { + Objects.requireNonNull(name); + Objects.requireNonNull(extra); + addLauncherInfos.add(new LauncherInfo(name, isService, extra)); + return this; + } + + AppImageBuilder addlauncher(String name, Map extra) { + return addlauncher(name, false, extra); + } + + AppImageFile2 create() { + final var additionalLaunchers = addLauncherInfos.stream().map(li -> { + return (Launcher)new Launcher.Stub(li.name(), Optional.empty(), + List.of(), li.service(), null, Optional.empty(), null, li.extra()); + }).toList(); + + final var startupInfo = new LauncherStartupInfo.Stub(mainClass, List.of(), List.of(), List.of()); + final var mainLauncher = new Launcher.Stub(launcherName, Optional.of(startupInfo), + List.of(), false, null, Optional.empty(), null, Map.of()); + + final var app = new Application.Stub(null, null, version, null, null, + Optional.empty(), List.of(), null, Optional.empty(), + new ApplicationLaunchers(mainLauncher, additionalLaunchers).asList(), extra); + + return new AppImageFile2(app); + } + + void createInDir(Path dir) { + final var file = create(); + final var copy = toSupplier(() -> { + file.save(DUMMY_LAYOUT.resolveAt(dir)); + return AppImageFile2.load(dir, DUMMY_LAYOUT); + }).get(); + + assertEquals(file, copy); + } + + private String version = "1.0"; + private String launcherName = "Foo"; + private String mainClass = "Main"; + private Map extra = new HashMap<>(); + private List addLauncherInfos = new ArrayList<>(); + } + @Test - public void testIdentity() throws IOException { - Map params = new LinkedHashMap<>(); - params.put(Arguments.CLIOptions.NAME.getId(), "Foo"); - params.put(Arguments.CLIOptions.APPCLASS.getId(), "TestClass"); - params.put(Arguments.CLIOptions.VERSION.getId(), "2.3"); - params.put(Arguments.CLIOptions.DESCRIPTION.getId(), "Duck is the King"); - AppImageFile aif = create(params); - - assertEquals("Foo", aif.getLauncherName()); + public void testSimple() { + build().createInDir(tempFolder); + } + + @ParameterizedTest + @MethodSource + public void testExtra(Map extra) { + build().addExtra(extra).createInDir(tempFolder); + } + + private static Stream> testExtra() { + return Stream.of(Map.of("a", "b"), Map.of("foo", "")); } @Test - public void testInvalidCommandLine() throws IOException { - // Just make sure AppImageFile will tolerate jpackage params that would - // never create app image at both load/save phases. - // People would edit this file just because they can. - // We should be ready to handle curious minds. - Map params = new LinkedHashMap<>(); - params.put("invalidParamName", "randomStringValue"); - params.put(Arguments.CLIOptions.APPCLASS.getId(), "TestClass"); - params.put(Arguments.CLIOptions.MAIN_JAR.getId(), "test.jar"); - create(params); - - params = new LinkedHashMap<>(); - params.put(Arguments.CLIOptions.NAME.getId(), "foo"); - params.put(Arguments.CLIOptions.APPCLASS.getId(), "TestClass"); - params.put(Arguments.CLIOptions.VERSION.getId(), "1.0"); - create(params); + public void testAdditionalLaunchers() { + build().addlauncher("T") + .addlauncher("U", true) + .addlauncher("F", Map.of("prop", "one", "prop2", "two", "prop3", "")) + .createInDir(tempFolder); } @ParameterizedTest @MethodSource - public void testInavlidXml(String[] xmlData) throws IOException { - Exception ex = assertThrowsExactly(RuntimeException.class, () -> createFromXml(xmlData)); - assertTrue(ex.getMessage().contains("generated by another jpackage version or malformed")); - assertTrue(ex.getMessage().endsWith(".jpackage.xml\" file")); + public void testInavlidXml(List xmlData) throws IOException { + assertThrowsExactly(ConfigException.class, () -> createFromXml(xmlData), () -> { + return I18N.format("error.invalid-app-image", tempFolder, ".jpackage.xml"); + }); } - private static Stream testInavlidXml() { - return Stream.of( - makeArguments((Object)new String[] {""}), - makeArguments((Object)new String[] {""}), - makeArguments((Object)new String[] {JPACKAGE_STATE_OPEN, ""}), - makeArguments((Object)new String[] { - JPACKAGE_STATE_OPEN, - "", - "" - }), - makeArguments((Object)new String[] { - JPACKAGE_STATE_OPEN, - "Foo", - "", - "" - }), - makeArguments((Object)new String[] { - JPACKAGE_STATE_OPEN, - "A", - "B", - "" - }) + private static Stream> testInavlidXml() { + return Stream.of(List.of(""), + List.of(""), + createXml(), + createXml(""), + createXml("Foo", ""), + createXml("A") ); } @ParameterizedTest @MethodSource - public void testValidXml(String expectedLauncherName, String xmlData[]) throws IOException { - var file = createFromXml(xmlData); - assertEquals(expectedLauncherName, file.getLauncherName()); - assertTrue(file.getAddLaunchers().isEmpty()); + public void testValidXml(AppImageFile2 expected, List xmlData) throws IOException, ConfigException { + final var actual = createFromXml(xmlData); + assertEquals(expected, actual); } - private static Stream testValidXml() { + private static Stream testValidXml() { return Stream.of( - makeArguments("Foo", List.of( - JPACKAGE_STATE_OPEN, - "1.0", - "Foo", - "main.Class", - "false", - "false", - "").toArray(String[]::new) + Arguments.of(build().version("72").launcherName("Y").mainClass("main.Class").create(), createXml( + "Y", + "72", + "main.Class") ), - makeArguments("Boo", List.of( - JPACKAGE_STATE_OPEN, - "1.0", - "Boo", - "Bar", - "main.Class", - "false", - "false", - "").toArray(String[]::new) + Arguments.of(build().addExtra("x", "property-x").addExtra("signed", "false") + .addExtra("y", "").addlauncher("another-launcher").addlauncher("service-launcher", true) + .addlauncher("launcher-with-extra", Map.of("a", "", "b", "", "c", "Q")) + .addlauncher("service-launcher-with-extra", true, Map.of("h", "F")).create(), createXml( + "1.0", + "Main", + "", + "property-x", + "false", + "", + "", + "Q", + "F", + "Foo") ), - makeArguments("duke", List.of( - JPACKAGE_STATE_OPEN, - "1.0", - "duke", - "main.Class", - "false", - "false", - "", - "").toArray(String[]::new) + Arguments.of(build().addExtra("signed", "FalsE").create(), createXml( + "1.2", + "1.0", + "OverwrittenMain", + "Main", + "Bar", + "Foo", + "false", + "FalsE") + ), + Arguments.of(build().addExtra("signed", "true").addExtra("with-comment", "ab") + .addlauncher("a", Map.of("bar", "foo")).create(), createXml( + "1.0", + "Main", + "Foo", + "true", + "ab", + "foofootrue", + "false", + "") ) ); } - @Test - public void testMainLauncherName() throws IOException { - Map params = new LinkedHashMap<>(); - params.put("name", "Foo"); - params.put("main-class", "main.Class"); - params.put("description", "Duck App Description"); - AppImageFile aif = create(params); - - assertEquals("Foo", aif.getLauncherName()); - } - - @Test - public void testMainClass() throws IOException { - Map params = new LinkedHashMap<>(); - params.put("name", "Foo"); - params.put("main-class", "main.Class"); - params.put("description", "Duck App Description"); - AppImageFile aif = create(params); - - assertEquals("main.Class", aif.getMainClass()); - } - - @Test - public void testMacSign() throws IOException { - Map params = new LinkedHashMap<>(); - params.put("name", "Foo"); - params.put("main-class", "main.Class"); - params.put("description", "Duck App Description"); - params.put("mac-sign", Boolean.TRUE); - AppImageFile aif = create(params); - - assertTrue(aif.isSigned()); - } - - @Test - public void testCopyAsSigned() throws IOException { - Map params = new LinkedHashMap<>(); - params.put("name", "Foo"); - params.put("main-class", "main.Class"); - params.put("description", "Duck App Description"); - params.put("mac-sign", Boolean.FALSE); - - AppImageFile aif = create(params); - assertFalse(aif.isSigned()); - - aif = aif.copyAsSigned(); - assertTrue(aif.isSigned()); - } - - @Test - public void testMacAppStore() throws IOException { - Map params = new LinkedHashMap<>(); - params.put("name", "Foo"); - params.put("main-class", "main.Class"); - params.put("description", "Duck App Description"); - params.put("mac-app-store", Boolean.TRUE); - AppImageFile aif = create(params); - - assertTrue(aif.isAppStore()); - } - - @Test - public void testAddLaunchers() throws IOException { - Map params = new LinkedHashMap<>(); - List> launchersAsMap = new ArrayList<>(); - - Map addLauncher2Params = new LinkedHashMap<>(); - addLauncher2Params.put("name", "Launcher2Name"); - launchersAsMap.add(addLauncher2Params); - - Map addLauncher3Params = new LinkedHashMap<>(); - addLauncher3Params.put("name", "Launcher3Name"); - launchersAsMap.add(addLauncher3Params); - - params.put("name", "Duke App"); - params.put("main-class", "main.Class"); - params.put("description", "Duke App Description"); - params.put("add-launcher", launchersAsMap); - AppImageFile aif = create(params); - - List addLaunchers = aif.getAddLaunchers(); - assertEquals(2, addLaunchers.size()); - List names = new ArrayList<>(); - names.add(addLaunchers.get(0).getName()); - names.add(addLaunchers.get(1).getName()); - - assertTrue(names.contains("Launcher2Name")); - assertTrue(names.contains("Launcher3Name")); - } - - private AppImageFile create(Map params) throws IOException { - AppImageFile.save(tempFolder, params); - return AppImageFile.load(tempFolder); - } - - private AppImageFile createFromXml(String... xmlData) throws IOException { - Path path = AppImageFile.getPathInAppImage(tempFolder); + private AppImageFile2 createFromXml(List xmlData) throws IOException, ConfigException { + Path path = AppImageFile2.getPathInAppImage(DUMMY_LAYOUT.resolveAt(tempFolder)); path.toFile().mkdirs(); Files.delete(path); List data = new ArrayList<>(); data.add(""); - data.addAll(List.of(xmlData)); + data.addAll(xmlData); Files.write(path, data, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); - AppImageFile image = AppImageFile.load(tempFolder); + AppImageFile2 image = AppImageFile2.load(tempFolder, DUMMY_LAYOUT); return image; } - static org.junit.jupiter.params.provider.Arguments makeArguments(Object ... args) { - return org.junit.jupiter.params.provider.Arguments.of(args); + private static void assertEquals(AppImageFile2 expected, AppImageFile2 actual) { + assertPropertyEquals(expected, actual, AppImageFile2::getAppVersion); + assertPropertyEquals(expected, actual, AppImageFile2::getLauncherName); + assertPropertyEquals(expected, actual, AppImageFile2::getMainClass); + assertPropertyEquals(expected, actual, AppImageFile2::getExtra); + Assertions.assertEquals(additionaLaunchersAsMap(expected), additionaLaunchersAsMap(actual)); + } + + private static Map additionaLaunchersAsMap(AppImageFile2 file) { + return file.getAddLaunchers().stream().collect(Collectors.toMap(AppImageFile2.LauncherInfo::name, x -> x)); + } + + private static void assertPropertyEquals(T expected, T actual, Function getProperty) { + Assertions.assertEquals(getProperty.apply(expected), getProperty.apply(actual)); + } + + private static final List createXml(String ...xml) { + final List content = new ArrayList<>(); + content.add(String.format("", AppImageFile2.getPlatform(), AppImageFile2.getVersion())); + content.addAll(List.of(xml)); + content.add(""); + return content; } @TempDir private Path tempFolder; - private static final String JPACKAGE_STATE_OPEN = String.format( - "", - AppImageFile.getPlatform(), AppImageFile.getVersion()); - + private static final ApplicationLayout DUMMY_LAYOUT = ApplicationLayout.build().setAll("").create(); } From 1c21766ec02038ea5388bb08c61e4e6f82300f47 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 22 Jan 2025 19:23:29 -0500 Subject: [PATCH 0249/1101] It works on osx. 61 test pass, 152 fail --- .../internal/AppImageInfoPListFile.java | 85 +++ .../jdk/jpackage/internal/AppImageSigner.java | 207 ++++--- .../jdk/jpackage/internal/Codesign.java | 66 +-- .../jdk/jpackage/internal/CodesignConfig.java | 101 ++++ .../jdk/jpackage/internal/MacAppBundler.java | 42 +- .../jpackage/internal/MacAppImageBuilder.java | 519 +----------------- .../internal/MacAppImageBuilder2.java | 88 ++- .../internal/MacAppImageFileExtras.java | 36 ++ .../internal/MacApplicationBuilder.java | 218 ++++++++ .../internal/MacApplicationLayout.java | 46 ++ .../internal/MacApplicationLayoutMixin.java | 39 ++ .../internal/MacBaseInstallerBundler.java | 18 +- .../internal/MacCertificateUtils.java | 68 +++ .../internal/MacFileAssociationBuilder.java | 129 +++++ .../jdk/jpackage/internal/MacFromParams.java | 192 +++++++ .../internal/MacLaunchersAsServices.java | 2 +- .../jdk/jpackage/internal/MacPkgBundler.java | 5 +- .../jdk/jpackage/internal/SigningConfig.java | 99 ---- .../internal/SigningConfigBuilder.java | 180 ++++++ .../internal/SigningIdentifierImpl.java | 54 ++ .../jdk/jpackage/internal/TempKeychain.java | 104 ++++ .../internal/model/MacApplication.java | 26 +- .../internal/model/MacApplicationMixin.java | 15 +- .../model/MacFileAssociationMixin.java | 4 +- .../jpackage/internal/model/MacLauncher.java | 34 ++ .../internal/model/SigningConfig.java | 44 ++ .../internal/model/SigningIdentifier.java | 35 ++ .../internal/{ => util}/PListUtils.java | 27 +- .../internal/AbstractAppImageBuilder.java | 122 ---- .../jpackage/internal/AbstractBundler.java | 8 - .../jdk/jpackage/internal/AppImageFile.java | 484 ---------------- .../jdk/jpackage/internal/FromParams.java | 1 - .../internal/StandardBundlerParam.java | 61 +- .../share/classes/module-info.java | 2 +- test/jdk/tools/jpackage/share/BasicTest.java | 8 +- 35 files changed, 1737 insertions(+), 1432 deletions(-) create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageInfoPListFile.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayout.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayoutMixin.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFileAssociationBuilder.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java delete mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfig.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentifierImpl.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/TempKeychain.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacLauncher.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningConfig.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentifier.java rename src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/{ => util}/PListUtils.java (81%) delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageInfoPListFile.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageInfoPListFile.java new file mode 100644 index 0000000000000..7a7f93aced4da --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageInfoPListFile.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.util.XmlUtils.initDocumentBuilder; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +import jdk.jpackage.internal.model.DottedVersion; + +/** + * Mandatory elements of Info.plist file of app image. + */ +record AppImageInfoPListFile(String bundleIdentifier, String bundleName, String copyright, + DottedVersion shortVersion, DottedVersion bundleVersion, String category) { + + static final class InvalidPlistFileException extends Exception { + InvalidPlistFileException(Throwable cause) { + super(cause); + } + + private static final long serialVersionUID = 1L; + } + + static AppImageInfoPListFile loadFromInfoPList(Path infoPListFile) + throws IOException, InvalidPlistFileException, SAXException { + final var doc = initDocumentBuilder().parse(Files.newInputStream(infoPListFile)); + + XPath xPath = XPathFactory.newInstance().newXPath(); + + try { + return new AppImageInfoPListFile( + getStringValue(doc, xPath, "CFBundleIdentifier"), + getStringValue(doc, xPath, "CFBundleName"), + getStringValue(doc, xPath, "NSHumanReadableCopyright"), + DottedVersion.greedy(getStringValue(doc, xPath, "CFBundleShortVersionString")), + DottedVersion.greedy(getStringValue(doc, xPath, "CFBundleVersion")), + getStringValue(doc, xPath, "LSApplicationCategoryType")); + } catch (XPathExpressionException ex) { + // This should never happen as XPath expressions should be correct + throw new RuntimeException(ex); + } catch (Exception ex) { + throw new InvalidPlistFileException(ex); + } + } + + private static String getStringValue(Document doc, XPath xPath, String elementName) throws XPathExpressionException { + // Query for the value of element preceding + // element with value equal to the value of `elementName` + return (String) xPath.evaluate(String.format("//string[preceding-sibling::key = \"%s\"][1]", elementName), + doc, XPathConstants.STRING); + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java index 534e9bc3aa88d..65980da72f091 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,108 +24,168 @@ */ package jdk.jpackage.internal; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toSet; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; + import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.PosixFilePermission; import java.util.EnumSet; +import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.Consumer; -import static java.util.stream.Collectors.toSet; +import java.util.function.Predicate; +import java.util.stream.Stream; import jdk.jpackage.internal.Codesign.CodesignException; import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.MacApplication; +import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.function.ExceptionBox; -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; final class AppImageSigner { - static Consumer createSigner(Application app, SigningConfig signingCfg) { + static Consumer createSigner(MacApplication app, CodesignConfig signingCfg) { return toConsumer(appImage -> { try { - new AppImageSigner(app, signingCfg).accept(appImage); + new AppImageSigner(Codesigners.create(signingCfg)).sign(app, appImage); } catch (CodesignException ex) { - throw Codesign.handleCodesignException(app, ex); + throw handleCodesignException(app, ex); } catch (ExceptionBox ex) { if (ex.getCause() instanceof CodesignException codesignEx) { - Codesign.handleCodesignException(app, codesignEx); + handleCodesignException(app, codesignEx); } throw ex; } }); } - static Consumer createUnsigner(Application app) { - return toConsumer(new AppImageSigner(app)::accept); + static Consumer createUnsigner(MacApplication app) { + return toConsumer(appImage -> { + new AppImageSigner(Codesigners.nop()).sign(app, appImage); + }); + } + + static final class SignFilter implements Predicate { + + SignFilter(Application app, Path appImage) { + Objects.requireNonNull(appImage); + + launchers = app.asApplicationLayout().map(appLayout -> { + return appLayout.resolveAt(appImage); + }).map(ApplicationLayout::launchersDirectory).map(launchersDir -> { + return app.launchers().stream().map(Launcher::executableNameWithSuffix).map(launchersDir::resolve).collect(toSet()); + }).orElseGet(Set::of); + } + + @Override + public boolean test(Path path) { + if (!Files.isRegularFile(path)) { + return false; + } + + if (Files.isExecutable(path) || path.getFileName().toString().endsWith(".dylib")) { + if (path.toString().contains("dylib.dSYM/Contents") || launchers.contains(path)) { + return false; + } + + return true; + } + + return false; + } + + private final Set launchers; } - void accept(Path appImage) throws IOException, CodesignException { - var appLayout = ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT.resolveAt(appImage); + private void sign(MacApplication app, Path appImage) throws CodesignException, IOException { + + final var fileFilter = new SignFilter(app, appImage); try (var content = Files.walk(appImage)) { - var launchersDir = appLayout.launchersDirectory(); - content.filter(path -> { - return testDoSign(launchersDir, path); - }).forEachOrdered(toConsumer(path -> { + content.filter(fileFilter).forEach(toConsumer(path -> { final var origPerms = ensureCanWrite(path); try { unsign(path); sign(path); } finally { - if (origPerms != null) { + if (!origPerms.isEmpty()) { Files.setPosixFilePermissions(path, origPerms); } } })); } - codesignDir.accept(appLayout.runtimeDirectory()); + // Sign runtime root directory if present + app.asApplicationLayout().map(appLayout -> { + return appLayout.resolveAt(appImage); + }).map(MacApplicationLayout.class::cast).map(MacApplicationLayout::runtimeRootDirectory).ifPresent(codesigners); - var frameworkPath = appImage.resolve("Contents/Frameworks"); + final var frameworkPath = appImage.resolve("Contents/Frameworks"); if (Files.isDirectory(frameworkPath)) { try (var content = Files.list(frameworkPath)) { content.forEach(toConsumer(path -> { - codesignDir.accept(path); + codesigners.codesignDir().accept(path); })); } } - // sign the app itself - codesignDir.accept(appImage); + // Sign the app image itself + codesigners.accept(appImage); } - private static Set ensureCanWrite(Path path) throws IOException { - final var origPerms = Files.getPosixFilePermissions(path); - if (origPerms.contains(PosixFilePermission.OWNER_WRITE)) { - return null; - } else { - var pfp = EnumSet.copyOf(origPerms); - pfp.add(PosixFilePermission.OWNER_WRITE); - Files.setPosixFilePermissions(path, pfp); - return origPerms; + private static Set ensureCanWrite(Path path) { + try { + final var origPerms = Files.getPosixFilePermissions(path); + if (origPerms.contains(PosixFilePermission.OWNER_WRITE)) { + return Set.of(); + } else { + final var newPerms = EnumSet.copyOf(origPerms); + newPerms.add(PosixFilePermission.OWNER_WRITE); + Files.setPosixFilePermissions(path, newPerms); + return origPerms; + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); } } - private boolean testDoSign(Path launchersDir, Path path) { - if (!Files.isRegularFile(path)) { - return false; - } + private static CodesignException handleCodesignException(MacApplication app, CodesignException ex) { + // Log output of "codesign" in case of error. It should help + // user to diagnose issues when using --mac-app-image-sign-identity. + // In addition add possible reason for failure. For example + // "--app-content" can fail "codesign". - if (!Files.isExecutable(path) && !path.getFileName().toString().endsWith(".dylib")) { - return false; + if (!app.contentDirs().isEmpty()) { + Log.info(I18N.getString("message.codesign.failed.reason.app.content")); } - if (path.toString().contains("dylib.dSYM/Contents")) { - return false; + // Signing might not work without Xcode with command line + // developer tools. Show user if Xcode is missing as possible + // reason. + if (!isXcodeDevToolsInstalled()) { + Log.info(I18N.getString("message.codesign.failed.reason.xcode.tools")); } - if (path.getParent().equals(launchersDir) && launcherExecutables.contains(path.getFileName().toString())) { - // Don't sign launchers + // Log "codesign" output + Log.info(I18N.format("error.tool.failed.with.output", "codesign")); + Log.info(Stream.of(ex.getOutput()).collect(joining("\n")).strip()); + + return ex; + } + + private static boolean isXcodeDevToolsInstalled() { + try { + return Executor.of("/usr/bin/xcrun", "--help").setQuiet(true).execute() == 0; + } catch (IOException ex) { return false; } - - return true; } private static void unsign(Path path) throws IOException { @@ -136,32 +196,55 @@ private static void unsign(Path path) throws IOException { } private void sign(Path path) { - var codesign = Files.isExecutable(path) ? codesignExecutableFile : codesignOtherFile; - codesign.accept(path); + codesigners.accept(path); } - private AppImageSigner(Application app) { - launcherExecutables = app.launchers().stream().map( - Launcher::executableNameWithSuffix).collect(toSet()); - Consumer nop = path -> {}; - codesignExecutableFile = nop; - codesignOtherFile = nop; - codesignDir = nop; + private AppImageSigner(Codesigners codesigners) { + this.codesigners = Objects.requireNonNull(codesigners); } - private AppImageSigner(Application app, SigningConfig signingCfg) { - launcherExecutables = app.launchers().stream().map( - Launcher::executableNameWithSuffix).collect(toSet()); + private record Codesigners(Consumer codesignFile, Consumer codesignExecutableFile, Consumer codesignDir) implements Consumer { + Codesigners { + Objects.requireNonNull(codesignFile); + Objects.requireNonNull(codesignExecutableFile); + Objects.requireNonNull(codesignDir); + } - var signingCfgWithoutEntitlements = SigningConfig.build(signingCfg).entitlements(null).create(); + @Override + public void accept(Path path) { + findCodesigner(path).orElseThrow(() -> { + return new IllegalArgumentException(String.format("No codesigner for %s path", PathUtils.normalizedAbsolutePathString(path))); + }).accept(path); + } + + private Optional> findCodesigner(Path path) { + if (Files.isDirectory(path)) { + return Optional.of(codesignDir); + } else if (Files.isRegularFile(path)) { + if (Files.isExecutable(path)) { + return Optional.of(codesignExecutableFile); + } else { + return Optional.of(codesignFile); + } + } + return Optional.empty(); + } - codesignExecutableFile = Codesign.build(signingCfg).quiet(true).create().asConsumer(); - codesignOtherFile = Codesign.build(signingCfgWithoutEntitlements).quiet(true).create().asConsumer(); - codesignDir = Codesign.build(signingCfgWithoutEntitlements).force(true).create().asConsumer(); + static Codesigners nop() { + Consumer nop = path -> {}; + return new Codesigners(nop, nop, nop); + } + + static Codesigners create(CodesignConfig signingCfg) { + final var signingCfgWithoutEntitlements = CodesignConfig.build().from(signingCfg).entitlements(null).create(); + + final var codesignExecutableFile = Codesign.build(signingCfg::toCodesignArgs).quiet(true).create().asConsumer(); + final var codesignFile = Codesign.build(signingCfgWithoutEntitlements::toCodesignArgs).quiet(true).create().asConsumer(); + final var codesignDir = Codesign.build(signingCfgWithoutEntitlements::toCodesignArgs).force(true).create().asConsumer(); + + return new Codesigners(codesignFile, codesignExecutableFile, codesignDir); + } } - private final Set launcherExecutables; - private final Consumer codesignExecutableFile; - private final Consumer codesignOtherFile; - private final Consumer codesignDir; + private final Codesigners codesigners; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Codesign.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Codesign.java index b585571b58d31..39d372701751d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Codesign.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Codesign.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; + import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; @@ -31,15 +33,13 @@ import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; -import static java.util.stream.Collectors.joining; +import java.util.function.Supplier; import java.util.stream.Stream; -import jdk.jpackage.internal.model.Application; -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; -final class Codesign { +public final class Codesign { - final static class CodesignException extends Exception { + public final static class CodesignException extends Exception { CodesignException(String[] output) { this.output = output; @@ -54,16 +54,16 @@ String[] getOutput() { private static final long serialVersionUID = 1L; } - final static class Builder { + public final static class Builder { - private Builder(SigningConfig signingCfg) { - this.signingCfg = Objects.requireNonNull(signingCfg); + private Builder(Supplier> args) { + this.args = Objects.requireNonNull(args); } Codesign create() { List cmdline = new ArrayList<>(); cmdline.add("/usr/bin/codesign"); - cmdline.addAll(signingCfg.toCodesignArgs()); + cmdline.addAll(args.get()); if (force) { cmdline.add("--force"); } @@ -73,26 +73,26 @@ Codesign create() { } : null); } - Builder force(boolean v) { + public Builder force(boolean v) { force = v; return this; } - Builder quiet(boolean v) { + public Builder quiet(boolean v) { quiet = v; return this; } - private final SigningConfig signingCfg; + private final Supplier> args; private boolean force; private boolean quiet; } - static Builder build(SigningConfig signingCfg) { - return new Builder(signingCfg); + public static Builder build(Supplier> args) { + return new Builder(args); } - void applyTo(Path path) throws IOException, CodesignException { + public void applyTo(Path path) throws IOException, CodesignException { var exec = Executor.of(Stream.concat( cmdline.stream(), @@ -105,47 +105,15 @@ void applyTo(Path path) throws IOException, CodesignException { } } - Consumer asConsumer() { + public Consumer asConsumer() { return toConsumer(this::applyTo); } - static CodesignException handleCodesignException(Application app, CodesignException ex) { - // Log output of "codesign" in case of error. It should help - // user to diagnose issues when using --mac-app-image-sign-identity. - // In addition add possible reason for failure. For example - // "--app-content" can fail "codesign". - - if (!Optional.ofNullable(app.contentDirs()).orElseGet(List::of).isEmpty()) { - Log.info(I18N.getString("message.codesign.failed.reason.app.content")); - } - - // Signing might not work without Xcode with command line - // developer tools. Show user if Xcode is missing as possible - // reason. - if (!isXcodeDevToolsInstalled()) { - Log.info(I18N.getString("message.codesign.failed.reason.xcode.tools")); - } - - // Log "codesign" output - Log.info(I18N.format("error.tool.failed.with.output", "codesign")); - Log.info(Stream.of(ex.getOutput()).collect(joining("\n")).strip()); - - return ex; - } - private Codesign(List cmdline, Consumer configureExecutor) { this.cmdline = Objects.requireNonNull(cmdline); this.configureExecutor = Optional.ofNullable(configureExecutor); } - private static boolean isXcodeDevToolsInstalled() { - try { - return Executor.of("/usr/bin/xcrun", "--help").execute() == 0; - } catch (IOException ex) { - return false; - } - } - private final List cmdline; private final Optional> configureExecutor; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java new file mode 100644 index 0000000000000..fa89d3a567823 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import jdk.jpackage.internal.model.SigningIdentifier; +import jdk.jpackage.internal.model.SigningConfig; +import jdk.jpackage.internal.util.PathUtils; + + +record CodesignConfig(Optional identifier, + Optional entitlements, Optional keyChain) { + + static final class Builder { + + private Builder() { + } + + CodesignConfig create() { + return new CodesignConfig(Optional.ofNullable(identifier), + Optional.ofNullable(entitlements), Optional.ofNullable(keyChain)); + } + + Builder entitlements(Path v) { + entitlements = v; + return this; + } + + Builder identifier(SigningIdentifier v) { + identifier = v; + return this; + } + + Builder keyChain(Path v) { + keyChain = v; + return this; + } + + Builder from(SigningConfig v) { + return identifier(v.identifier().orElse(null)) + .entitlements(v.entitlements().orElse(null)) + .keyChain(v.keyChain().orElse(null)); + } + + Builder from(CodesignConfig v) { + return identifier(v.identifier().orElse(null)) + .entitlements(v.entitlements().orElse(null)) + .keyChain(v.keyChain().orElse(null)); + } + + private SigningIdentifier identifier; + private Path entitlements; + private Path keyChain; + } + + static Builder build() { + return new Builder(); + } + + List toCodesignArgs() { + List args = new ArrayList<>(List.of("-s", identifier.map(SigningIdentifier::name).orElse(ADHOC_SIGNING_IDENTIFIER), "-vvvv")); + + if (identifier.isPresent()) { + args.addAll(List.of("--timestamp", "--options", "runtime")); + identifier.flatMap(SigningIdentifier::prefix).ifPresent(identifierPrefix -> { + args.addAll(List.of("--prefix", identifierPrefix)); + }); + keyChain.map(PathUtils::normalizedAbsolutePathString).ifPresent(theKeyChain -> args.addAll(List.of("--keychain", theKeyChain))); + entitlements.map(PathUtils::normalizedAbsolutePathString).ifPresent(theEntitlements -> args.addAll(List.of("--entitlements", theEntitlements))); + } + + return args; + } + + static final String ADHOC_SIGNING_IDENTIFIER = "-"; +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index 3c564cf88222c..61d186266dc6b 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -25,24 +25,40 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; -import java.text.MessageFormat; -import java.util.Map; -import java.util.Optional; +import static jdk.jpackage.internal.MacAppImageBuilder.APP_STORE; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; -import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; import static jdk.jpackage.internal.StandardBundlerParam.MAIN_CLASS; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; +import static jdk.jpackage.internal.StandardBundlerParam.VERSION; + +import java.text.MessageFormat; +import java.util.Map; +import java.util.Optional; +import jdk.jpackage.internal.model.ConfigException; public class MacAppBundler extends AppImageBundler { public MacAppBundler() { - setAppImageSupplier((params, imageOutDir) -> { - var builder = new MacAppImageBuilder(imageOutDir, isDependentTask()); - builder.prepareApplicationFiles(params); - }); - setParamsValidator(MacAppBundler::doValidate); + setAppImageSupplier((params, output) -> { + + // Order is important! + final var app = MacFromParams.APPLICATION.fetchFrom(params); + final var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + + final var appImageBuilderBuilder = MacAppImageBuilder2.build().excludeDirFromCopying(output.getParent()); + + if (isDependentTask()) { + final var pkg = Optional.of(MacFromParams.PACKAGE.fetchFrom(params)); + appImageBuilderBuilder.addItem((theEnv, theApp, appLayout) -> { + new PackageFile(pkg.orElseThrow().packageName()).save(appLayout); + }); + } + + final var appImageBuilder = appImageBuilderBuilder.create(app); + + appImageBuilder.execute(BuildEnv.withAppImageDir(env, output)); + }); + setParamsValidator(MacAppBundler::doValidate); } public static final BundlerParamInfo DEVELOPER_ID_APP_SIGNING_KEY = @@ -93,7 +109,9 @@ public MacAppBundler() { static String getIdentifier(Map params) { String s = MAIN_CLASS.fetchFrom(params); - if (s == null) return null; + if (s == null) { + return null; + } int idx = s.lastIndexOf("."); if (idx >= 1) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java index f4ece2b8a1b16..66a42d1fc6ab1 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -25,12 +25,19 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ApplicationLayout; +import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; +import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; +import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT; +import static jdk.jpackage.internal.StandardBundlerParam.ICON; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; +import static jdk.jpackage.internal.StandardBundlerParam.createResource; +import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage; + import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.PrintStream; -import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.PosixFilePermission; @@ -38,10 +45,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; -import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.ResourceBundle; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; @@ -52,55 +57,27 @@ import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; -import jdk.internal.util.OperatingSystem; import jdk.internal.util.OSVersion; -import static jdk.jpackage.internal.MacAppBundler.BUNDLE_ID_SIGNING_PREFIX; -import static jdk.jpackage.internal.MacAppBundler.DEVELOPER_ID_APP_SIGNING_KEY; -import static jdk.jpackage.internal.MacAppBundler.APP_IMAGE_SIGN_IDENTITY; -import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; -import static jdk.jpackage.internal.MacBaseInstallerBundler.INSTALLER_SIGN_IDENTITY; -import static jdk.jpackage.internal.StandardBundlerParam.createResource; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT; -import static jdk.jpackage.internal.StandardBundlerParam.COPYRIGHT; -import static jdk.jpackage.internal.StandardBundlerParam.FA_CONTENT_TYPE; -import static jdk.jpackage.internal.StandardBundlerParam.FA_DESCRIPTION; -import static jdk.jpackage.internal.StandardBundlerParam.FA_EXTENSIONS; -import static jdk.jpackage.internal.StandardBundlerParam.FA_ICON; -import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; -import static jdk.jpackage.internal.StandardBundlerParam.ICON; -import static jdk.jpackage.internal.StandardBundlerParam.MAIN_CLASS; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; -import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; -import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; -import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; -import static jdk.jpackage.internal.StandardBundlerParam.createResource; -public class MacAppImageBuilder extends AbstractAppImageBuilder { +public class MacAppImageBuilder { private static final ResourceBundle I18N = ResourceBundle.getBundle( "jdk.jpackage.internal.resources.MacResources"); - private static final String TEMPLATE_BUNDLE_ICON = "JavaApp.icns"; - private static final String OS_TYPE_CODE = "APPL"; - private static final String TEMPLATE_INFO_PLIST_LITE = - "Info-lite.plist.template"; - private static final String TEMPLATE_RUNTIME_INFO_PLIST = - "Runtime-Info.plist.template"; - - private final Path root; - private final Path contentsDir; - private final Path resourcesDir; - private final Path macOSDir; - private final Path runtimeDir; - private final Path runtimeRoot; - - private final boolean withPackageFile; - private static List keyChains; + static final BundlerParamInfo APP_STORE = + new BundlerParamInfo<>( + Arguments.CLIOptions.MAC_APP_STORE.getId(), + Boolean.class, + params -> { + return false; + }, + // valueOf(null) is false, we actually do want null in some cases + (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? + null : Boolean.valueOf(s) + ); + public static final BundlerParamInfo MAC_CF_BUNDLE_NAME = new BundlerParamInfo<>( Arguments.CLIOptions.MAC_BUNDLE_NAME.getId(), @@ -156,7 +133,7 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { params -> { try { Path path = CONFIG_ROOT.fetchFrom(params).resolve( - getLauncherName(params) + ".entitlements"); + APP_NAME.fetchFrom(params) + ".entitlements"); String defPath = (APP_STORE.fetchFrom(params) ? "sandbox.plist" : "entitlements.plist"); createResource(defPath, params) @@ -171,454 +148,6 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { (s, p) -> Path.of(s) ); - private static final BundlerParamInfo FA_MAC_CFBUNDLETYPEROLE = - new BundlerParamInfo<>( - Arguments.MAC_CFBUNDLETYPEROLE, - String.class, - params -> "Editor", - (s, p) -> s - ); - - private static final BundlerParamInfo FA_MAC_LSHANDLERRANK = - new BundlerParamInfo<>( - Arguments.MAC_LSHANDLERRANK, - String.class, - params -> "Owner", - (s, p) -> s - ); - - private static final BundlerParamInfo FA_MAC_NSSTORETYPEKEY = - new BundlerParamInfo<>( - Arguments.MAC_NSSTORETYPEKEY, - String.class, - params -> null, - (s, p) -> s - ); - - private static final BundlerParamInfo FA_MAC_NSDOCUMENTCLASS = - new BundlerParamInfo<>( - Arguments.MAC_NSDOCUMENTCLASS, - String.class, - params -> null, - (s, p) -> s - ); - - private static final BundlerParamInfo FA_MAC_LSTYPEISPACKAGE = - new BundlerParamInfo<>( - Arguments.MAC_LSTYPEISPACKAGE, - String.class, - params -> null, - (s, p) -> s - ); - - private static final BundlerParamInfo FA_MAC_LSDOCINPLACE = - new BundlerParamInfo<>( - Arguments.MAC_LSDOCINPLACE, - String.class, - params -> null, - (s, p) -> s - ); - - private static final BundlerParamInfo FA_MAC_UIDOCBROWSER = - new BundlerParamInfo<>( - Arguments.MAC_UIDOCBROWSER, - String.class, - params -> null, - (s, p) -> s - ); - - @SuppressWarnings("unchecked") - private static final BundlerParamInfo> FA_MAC_NSEXPORTABLETYPES = - new BundlerParamInfo<>( - Arguments.MAC_NSEXPORTABLETYPES, - (Class>) (Object) List.class, - params -> null, - (s, p) -> Arrays.asList(s.split("(,|\\s)+")) - ); - - @SuppressWarnings("unchecked") - private static final BundlerParamInfo> FA_MAC_UTTYPECONFORMSTO = - new BundlerParamInfo<>( - Arguments.MAC_UTTYPECONFORMSTO, - (Class>) (Object) List.class, - params -> Arrays.asList("public.data"), - (s, p) -> Arrays.asList(s.split("(,|\\s)+")) - ); - - public MacAppImageBuilder(Path imageOutDir, boolean withPackageFile) { - super(imageOutDir); - - this.root = imageOutDir; - this.withPackageFile = withPackageFile; - this.contentsDir = root.resolve("Contents"); - this.resourcesDir = appLayout.destktopIntegrationDirectory(); - this.macOSDir = appLayout.launchersDirectory(); - this.runtimeDir = appLayout.runtimeDirectory(); - this.runtimeRoot = this.runtimeDir.resolve("Contents/Home"); - } - - private void writeEntry(InputStream in, Path dstFile) throws IOException { - Files.createDirectories(dstFile.getParent()); - Files.copy(in, dstFile); - } - - @Override - public void prepareApplicationFiles(Map params) - throws IOException { - // If predefined app image is provided, then just sign it and return. - Path predefinedAppImage = PREDEFINED_APP_IMAGE.fetchFrom(params); - if (predefinedAppImage != null) { - // Mark app image as signed, before we signing it. - AppImageFile appImageFile = - AppImageFile.load(predefinedAppImage); - if (!appImageFile.isSigned()) { - appImageFile.copyAsSigned().save(predefinedAppImage); - } else { - appImageFile = null; - } - - try { - doSigning(params); - } catch (Exception ex) { - // Restore original app image file if signing failed - if (appImageFile != null) { - appImageFile.save(predefinedAppImage); - } - - throw ex; - } - - return; - } - - Files.createDirectories(macOSDir); - - Map originalParams = new HashMap<>(params); - // Generate PkgInfo - Path pkgInfoFile = contentsDir.resolve("PkgInfo"); - Files.createFile(pkgInfoFile); - writePkgInfo(pkgInfoFile); - - Path executable = macOSDir.resolve(getLauncherName(params)); - - // create the main app launcher - try (InputStream is_launcher = - getResourceAsStream("jpackageapplauncher")) { - // Copy executable and library to MacOS folder - writeEntry(is_launcher, executable); - } - executable.toFile().setExecutable(true, false); - // generate main app launcher config file - writeCfgFile(params); - - // create additional app launcher(s) and config file(s) - List> entryPoints = - ADD_LAUNCHERS.fetchFrom(params); - for (Map entryPoint : entryPoints) { - Map tmp = - AddLauncherArguments.merge(originalParams, entryPoint); - - // add executable for add launcher - Path addExecutable = macOSDir.resolve(getLauncherName(tmp)); - try (InputStream is = getResourceAsStream("jpackageapplauncher");) { - writeEntry(is, addExecutable); - } - addExecutable.toFile().setExecutable(true, false); - - // add config file for add launcher - writeCfgFile(tmp); - } - - // Copy class path entries to Java folder - copyApplication(params); - - if (withPackageFile) { - new PackageFile(APP_NAME.fetchFrom(params)).save( - ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT.resolveAt(root)); - } - - /*********** Take care of "config" files *******/ - - createResource(TEMPLATE_BUNDLE_ICON, params) - .setCategory("icon") - .setExternal(ICON_ICNS.fetchFrom(params)) - .saveToFile(resourcesDir.resolve(APP_NAME.fetchFrom(params) - + ".icns")); - - // copy file association icons - for (Map fa : FILE_ASSOCIATIONS.fetchFrom(params)) { - Path f = FA_ICON.fetchFrom(fa); - if (IOUtils.exists(f)) { - IOUtils.copyFile(f, resourcesDir.resolve(f.getFileName())); - - } - } - - copyRuntimeFiles(params); - - doSigning(params); - } - - private void copyRuntimeFiles(Map params) - throws IOException { - // Generate Info.plist - writeInfoPlist(contentsDir.resolve("Info.plist"), params); - - // generate java runtime info.plist - writeRuntimeInfoPlist( - runtimeDir.resolve("Contents/Info.plist"), params); - - // copy library - Path runtimeMacOSDir = Files.createDirectories( - runtimeDir.resolve("Contents/MacOS")); - - final Path jliName = Path.of("libjli.dylib"); - try (Stream walk = Files.walk(runtimeRoot.resolve("lib"))) { - final Path jli = walk - .filter(file -> file.getFileName().equals(jliName)) - .findFirst() - .get(); - Files.copy(jli, runtimeMacOSDir.resolve(jliName)); - } - } - - private void doSigning(Map params) - throws IOException { - - if (Optional.ofNullable( - SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.TRUE)) { - try { - addNewKeychain(params); - } catch (InterruptedException e) { - Log.error(e.getMessage()); - } - String signingIdentity = null; - // Try --mac-app-image-sign-identity first if set - if (!APP_IMAGE_SIGN_IDENTITY.getIsDefaultValue(params)) { - signingIdentity = APP_IMAGE_SIGN_IDENTITY.fetchFrom(params); - } else { - // Check if INSTALLER_SIGN_IDENTITY is set and if it is set - // then do not sign app image, otherwise use --mac-signing-key-user-name - if (INSTALLER_SIGN_IDENTITY.getIsDefaultValue(params)) { - // --mac-sign and/or --mac-signing-key-user-name case - signingIdentity = DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params); - } - } - if (signingIdentity != null) { - signAppBundle(params, root, signingIdentity, - BUNDLE_ID_SIGNING_PREFIX.fetchFrom(params), - ENTITLEMENTS.fetchFrom(params)); - } else { - // Case when user requested to sign installer only - signAppBundle(params, root, "-", null, null); - } - restoreKeychainList(params); - } else if (OperatingSystem.isMacOS()) { - signAppBundle(params, root, "-", null, null); - } else { - // Calling signAppBundle() without signingIdentity will result in - // unsigning app bundle - signAppBundle(params, root, null, null, null); - } - } - - private static String getLauncherName(Map params) { - return APP_NAME.fetchFrom(params); - } - - private String getBundleName(Map params) { - if (MAC_CF_BUNDLE_NAME.fetchFrom(params) != null) { - String bn = MAC_CF_BUNDLE_NAME.fetchFrom(params); - if (bn.length() > 16) { - Log.error(MessageFormat.format(I18N.getString( - "message.bundle-name-too-long-warning"), - MAC_CF_BUNDLE_NAME.getID(), bn)); - } - return MAC_CF_BUNDLE_NAME.fetchFrom(params); - } else if (APP_NAME.fetchFrom(params) != null) { - return APP_NAME.fetchFrom(params); - } else { - String nm = MAIN_CLASS.fetchFrom(params); - if (nm.length() > 16) { - nm = nm.substring(0, 16); - } - return nm; - } - } - - private void writeRuntimeInfoPlist(Path file, - Map params) throws IOException { - Map data = new HashMap<>(); - String identifier = StandardBundlerParam.isRuntimeInstaller(params) ? - MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params) : - "com.oracle.java." + MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params); - data.put("CF_BUNDLE_IDENTIFIER", identifier); - String name = StandardBundlerParam.isRuntimeInstaller(params) ? - getBundleName(params): "Java Runtime Image"; - data.put("CF_BUNDLE_NAME", name); - String ver = VERSION.fetchFrom(params); - String sver = ver; - int index = ver.indexOf("."); - if (index > 0 && ((index + 1) < ver.length())) { - index = ver.indexOf(".", index + 1); - if (index > 0 ) { - sver = ver.substring(0, index); - } - } - data.put("CF_BUNDLE_VERSION", ver); - data.put("CF_BUNDLE_SHORT_VERSION_STRING", sver); - - createResource(TEMPLATE_RUNTIME_INFO_PLIST, params) - .setPublicName("Runtime-Info.plist") - .setCategory(I18N.getString("resource.runtime-info-plist")) - .setSubstitutionData(data) - .saveToFile(file); - } - - private void writeStringArrayPlist(StringBuilder sb, String key, - List values) { - if (values != null && !values.isEmpty()) { - sb.append(" ").append(key).append("\n").append(" \n"); - values.forEach((value) -> { - sb.append(" ").append(value).append("\n"); - }); - sb.append(" \n"); - } - } - - private void writeStringPlist(StringBuilder sb, String key, String value) { - if (value != null && !value.isEmpty()) { - sb.append(" ").append(key).append("\n").append(" ") - .append(value).append("\n").append("\n"); - } - } - - private void writeBoolPlist(StringBuilder sb, String key, String value) { - if (value != null && !value.isEmpty()) { - sb.append(" ").append(key).append("\n").append(" <") - .append(value).append("/>\n").append("\n"); - } - } - - private void writeInfoPlist(Path file, Map params) - throws IOException { - Log.verbose(MessageFormat.format(I18N.getString( - "message.preparing-info-plist"), file.toAbsolutePath())); - - //prepare config for exe - //Note: do not need CFBundleDisplayName if we don't support localization - Map data = new HashMap<>(); - data.put("DEPLOY_ICON_FILE", APP_NAME.fetchFrom(params) + ".icns"); - data.put("DEPLOY_BUNDLE_IDENTIFIER", - MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params)); - data.put("DEPLOY_BUNDLE_NAME", - getBundleName(params)); - data.put("DEPLOY_BUNDLE_COPYRIGHT", COPYRIGHT.fetchFrom(params)); - data.put("DEPLOY_LAUNCHER_NAME", getLauncherName(params)); - data.put("DEPLOY_BUNDLE_SHORT_VERSION", VERSION.fetchFrom(params)); - data.put("DEPLOY_BUNDLE_CFBUNDLE_VERSION", VERSION.fetchFrom(params)); - data.put("DEPLOY_APP_CATEGORY", "public.app-category." + - APP_CATEGORY.fetchFrom(params)); - - StringBuilder bundleDocumentTypes = new StringBuilder(); - StringBuilder exportedTypes = new StringBuilder(); - for (Map - fileAssociation : FILE_ASSOCIATIONS.fetchFrom(params)) { - - List extensions = FA_EXTENSIONS.fetchFrom(fileAssociation); - if (extensions == null) { - Log.verbose(I18N.getString( - "message.creating-association-with-null-extension")); - } - - String itemContentType = MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params) - + "." + ((extensions == null || extensions.isEmpty()) - ? "mime" : extensions.get(0)); - String description = FA_DESCRIPTION.fetchFrom(fileAssociation); - Path icon = FA_ICON.fetchFrom(fileAssociation); - - bundleDocumentTypes.append(" \n"); - writeStringArrayPlist(bundleDocumentTypes, "LSItemContentTypes", - Arrays.asList(itemContentType)); - writeStringPlist(bundleDocumentTypes, "CFBundleTypeName", description); - writeStringPlist(bundleDocumentTypes, "LSHandlerRank", - FA_MAC_LSHANDLERRANK.fetchFrom(fileAssociation)); - writeStringPlist(bundleDocumentTypes, "CFBundleTypeRole", - FA_MAC_CFBUNDLETYPEROLE.fetchFrom(fileAssociation)); - writeStringPlist(bundleDocumentTypes, "NSPersistentStoreTypeKey", - FA_MAC_NSSTORETYPEKEY.fetchFrom(fileAssociation)); - writeStringPlist(bundleDocumentTypes, "NSDocumentClass", - FA_MAC_NSDOCUMENTCLASS.fetchFrom(fileAssociation)); - writeBoolPlist(bundleDocumentTypes, "LSIsAppleDefaultForType", - "true"); - writeBoolPlist(bundleDocumentTypes, "LSTypeIsPackage", - FA_MAC_LSTYPEISPACKAGE.fetchFrom(fileAssociation)); - writeBoolPlist(bundleDocumentTypes, "LSSupportsOpeningDocumentsInPlace", - FA_MAC_LSDOCINPLACE.fetchFrom(fileAssociation)); - writeBoolPlist(bundleDocumentTypes, "UISupportsDocumentBrowser", - FA_MAC_UIDOCBROWSER.fetchFrom(fileAssociation)); - if (IOUtils.exists(icon)) { - writeStringPlist(bundleDocumentTypes, "CFBundleTypeIconFile", - icon.getFileName().toString()); - } - bundleDocumentTypes.append(" \n"); - - exportedTypes.append(" \n"); - writeStringPlist(exportedTypes, "UTTypeIdentifier", - itemContentType); - writeStringPlist(exportedTypes, "UTTypeDescription", - description); - writeStringArrayPlist(exportedTypes, "UTTypeConformsTo", - FA_MAC_UTTYPECONFORMSTO.fetchFrom(fileAssociation)); - - if (IOUtils.exists(icon)) { - writeStringPlist(exportedTypes, "UTTypeIconFile", - icon.getFileName().toString()); - } - exportedTypes.append("\n") - .append(" UTTypeTagSpecification\n") - .append(" \n") - .append("\n"); - writeStringArrayPlist(exportedTypes, "public.filename-extension", - extensions); - writeStringArrayPlist(exportedTypes, "public.mime-type", - FA_CONTENT_TYPE.fetchFrom(fileAssociation)); - writeStringArrayPlist(exportedTypes, "NSExportableTypes", - FA_MAC_NSEXPORTABLETYPES.fetchFrom(fileAssociation)); - exportedTypes.append(" \n").append(" \n"); - } - String associationData; - if (bundleDocumentTypes.length() > 0) { - associationData = - "\n CFBundleDocumentTypes\n \n" - + bundleDocumentTypes.toString() - + " \n\n" - + " UTExportedTypeDeclarations\n \n" - + exportedTypes.toString() - + " \n"; - } else { - associationData = ""; - } - data.put("DEPLOY_FILE_ASSOCIATIONS", associationData); - - createResource(TEMPLATE_INFO_PLIST_LITE, params) - .setCategory(I18N.getString("resource.app-info-plist")) - .setSubstitutionData(data) - .setPublicName("Info.plist") - .saveToFile(file); - } - - private void writePkgInfo(Path file) throws IOException { - //hardcoded as it does not seem we need to change it ever - String signature = "????"; - - try (Writer out = Files.newBufferedWriter(file)) { - out.write(OS_TYPE_CODE + signature); - out.flush(); - } - } - public static void addNewKeychain(Map params) throws IOException, InterruptedException { if (OSVersion.current().compareTo(new OSVersion(10, 12)) < 0) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java index e1a67e5a4a65f..71695df10cef2 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,16 @@ */ package jdk.jpackage.internal; +import static jdk.jpackage.internal.util.PListUtils.writeArray; +import static jdk.jpackage.internal.util.PListUtils.writeBoolean; +import static jdk.jpackage.internal.util.PListUtils.writeDict; +import static jdk.jpackage.internal.util.PListUtils.writeKey; +import static jdk.jpackage.internal.util.PListUtils.writeString; +import static jdk.jpackage.internal.util.PListUtils.writeStringArray; +import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; +import static jdk.jpackage.internal.util.function.ThrowingBiConsumer.toBiConsumer; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + import java.io.IOException; import java.io.StringWriter; import java.nio.charset.StandardCharsets; @@ -38,25 +48,18 @@ import javax.xml.stream.XMLStreamWriter; import jdk.jpackage.internal.AppImageBuilder.AppImageItem; import jdk.jpackage.internal.AppImageBuilder.AppImageItemGroup; -import static jdk.jpackage.internal.PListUtils.writeArray; -import jdk.jpackage.internal.model.MacApplication; -import jdk.jpackage.internal.model.MacFileAssociation; -import static jdk.jpackage.internal.PListUtils.writeBoolean; -import static jdk.jpackage.internal.PListUtils.writeDict; -import static jdk.jpackage.internal.PListUtils.writeKey; -import static jdk.jpackage.internal.PListUtils.writeString; -import static jdk.jpackage.internal.PListUtils.writeStringArray; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.FileAssociation; -import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; +import jdk.jpackage.internal.model.MacApplication; +import jdk.jpackage.internal.model.MacFileAssociation; +import jdk.jpackage.internal.model.SigningConfig; import jdk.jpackage.internal.util.function.ThrowingConsumer; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; final class MacAppImageBuilder2 { static AppImageBuilder.Builder build() { - return new AppImageBuilder.Builder() + return AppImageBuilder.build() .itemGroup(AppImageItemGroup.RUNTIME) .addItem(MacAppImageBuilder2::writeRuntimeInfoPlist) .addItem(MacAppImageBuilder2::copyJliLib) @@ -64,19 +67,25 @@ static AppImageBuilder.Builder build() { .addItem(new ApplicationIcon()) .addItem(MacAppImageBuilder2::writePkgInfoFile) .addItem(MacAppImageBuilder2::writeFileAssociationIcons) - .addItem(MacAppImageBuilder2::writeAppInfoPlist); + .addItem(MacAppImageBuilder2::writeAppInfoPlist) + .itemGroup(AppImageItemGroup.END) + .addItem(MacAppImageBuilder2::sign); } private static void copyJliLib(BuildEnv env, Application app, ApplicationLayout appLayout) throws IOException { - final Path jliName = Path.of("libjli.dylib"); - try (var walk = Files.walk(appLayout.runtimeDirectory().resolve("Contents/Home/lib"))) { - final Path jli = walk + final var runtimeMacOSDir = ((MacApplicationLayout)appLayout).runtimeRootDirectory().resolve("Contents/MacOS"); + + final var jliName = Path.of("libjli.dylib"); + + try (var walk = Files.walk(appLayout.runtimeDirectory().resolve("lib"))) { + final var jli = walk .filter(file -> file.getFileName().equals(jliName)) .findFirst() - .get(); - Files.copy(jli, appLayout.launchersDirectory().resolve(jliName)); + .orElseThrow(); + Files.createDirectories(runtimeMacOSDir); + Files.copy(jli, runtimeMacOSDir.resolve(jliName)); } } @@ -95,7 +104,7 @@ private static void writeRuntimeInfoPlist(BuildEnv env, Application app, .setPublicName("Runtime-Info.plist") .setCategory(I18N.getString("resource.runtime-info-plist")) .setSubstitutionData(data) - .saveToFile(appLayout.runtimeDirectory().resolve("Contents/Info.plist")); + .saveToFile(((MacApplicationLayout)appLayout).runtimeRootDirectory().resolve("Contents/Info.plist")); } private static void writeAppInfoPlist(BuildEnv env, Application app, @@ -131,6 +140,35 @@ private static void writeAppInfoPlist(BuildEnv env, Application app, .saveToFile(appLayout.contentDirectory().resolve("Info.plist")); } + private static void sign(BuildEnv env, Application app, ApplicationLayout appLayout) throws IOException { + + final var macApp = ((MacApplication)app); + + final var codesignConfigBuilder = CodesignConfig.build(); + macApp.signingConfig().ifPresent(codesignConfigBuilder::from); + + if (macApp.sign() && macApp.signingConfig().flatMap(SigningConfig::entitlements).isEmpty()) { + final var entitlementsDefaultResource = macApp.signingConfig().map( + SigningConfig::entitlementsResourceName).orElseThrow(); + + final var entitlementsFile = env.configDir().resolve(app.name() + ".entitlements"); + + env.createResource(entitlementsDefaultResource) + .setCategory(I18N.getString("resource.entitlements")) + .saveToFile(entitlementsFile); + + codesignConfigBuilder.entitlements(entitlementsFile); + } + + final Runnable signAction = () -> { + AppImageSigner.createSigner(macApp, codesignConfigBuilder.create()).accept(env.appImageDir()); + }; + + macApp.signingConfig().flatMap(SigningConfig::keyChain).ifPresentOrElse(keyChain -> { + toBiConsumer(TempKeychain::withKeychain).accept(keyChain, unused -> signAction.run()); + }, signAction); + } + private static void writeCFBundleDocumentTypes(XMLStreamWriter xml, MacApplication app) throws XMLStreamException, IOException { writeKey(xml, "CFBundleDocumentTypes"); @@ -209,10 +247,11 @@ static Path getPath(Application app, ApplicationLayout appLayout) { @Override public void write(BuildEnv env, Application app, ApplicationLayout appLayout) throws IOException { - env.createResource("JavaApp.icns") - .setCategory("icon") - .setExternal(((MacApplication)app).icon()) - .saveToFile(getPath(app, appLayout)); + final var resource = env.createResource("JavaApp.icns").setCategory("icon"); + + ((MacApplication)app).icon().ifPresent(resource::setExternal); + + resource.saveToFile(getPath(app, appLayout)); } } @@ -231,4 +270,7 @@ private static void writePkgInfoFile(BuildEnv env, Application app, Files.write(appLayout.contentDirectory().resolve("PkgInfo"), "APPL????".getBytes(StandardCharsets.ISO_8859_1)); } + + final static MacApplicationLayout APPLICATION_LAYOUT = MacApplicationLayout.create( + ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT, Path.of("Contents/runtime")); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java new file mode 100644 index 0000000000000..742f1940e25f5 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.AppImageFile2.getBooleanExtraFieldValue; + +import jdk.jpackage.internal.model.MacApplication.ExtraAppImageFileField; + +record MacAppImageFileExtras(boolean signed) { + + MacAppImageFileExtras(AppImageFile2 appImageFile) { + this(getBooleanExtraFieldValue(ExtraAppImageFileField.SIGNED.fieldName(), appImageFile)); + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java new file mode 100644 index 0000000000000..192ba494d48cd --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.LauncherStartupInfo; +import jdk.jpackage.internal.model.MacApplication; +import jdk.jpackage.internal.model.MacApplicationMixin; +import jdk.jpackage.internal.model.SigningConfig; + +final class MacApplicationBuilder { + + MacApplicationBuilder(Application app) { + this.app = Objects.requireNonNull(app); + } + + private MacApplicationBuilder(MacApplicationBuilder other) { + this(other.app); + icon = other.icon; + bundleName = other.bundleName; + bundleIdentifier = other.bundleIdentifier; + category = other.category; + externalInfoPlistFile = other.externalInfoPlistFile; + } + + MacApplicationBuilder icon(Path v) { + icon = v; + return this; + } + + MacApplicationBuilder bundleName(String v) { + bundleName = v; + return this; + } + + MacApplicationBuilder bundleIdentifier(String v) { + bundleIdentifier = v; + return this; + } + + MacApplicationBuilder category(String v) { + category = v; + return this; + } + + MacApplicationBuilder externalInfoPlistFile(Path v) { + externalInfoPlistFile = v; + return this; + } + + MacApplicationBuilder signingBuilder(SigningConfigBuilder v) { + signingBuilder = v; + return this; + } + + MacApplication create() throws ConfigException { + if (externalInfoPlistFile != null) { + return createCopyForExternalInfoPlistFile().create(); + } + + final var mixin = new MacApplicationMixin.Stub(validatedIcon(), validatedBundleName(), + validatedBundleIdentifier(), validatedCategory(), createSigningConfig()); + + return MacApplication.create(app, mixin); + } + + static boolean isValidBundleIdentifier(String id) { + for (int i = 0; i < id.length(); i++) { + char a = id.charAt(i); + // We check for ASCII codes first which we accept. If check fails, + // check if it is acceptable extended ASCII or unicode character. + if ((a >= 'A' && a <= 'Z') || (a >= 'a' && a <= 'z') + || (a >= '0' && a <= '9') || (a == '-' || a == '.')) { + continue; + } + return false; + } + return true; + } + + private MacApplicationBuilder createCopyForExternalInfoPlistFile() throws ConfigException { + try { + final var plistFile = AppImageInfoPListFile.loadFromInfoPList(externalInfoPlistFile); + + final var builder = new MacApplicationBuilder(this); + + builder.externalInfoPlistFile(null); + + if (builder.bundleName == null) { + builder.bundleName(plistFile.bundleName()); + } + + if (builder.bundleIdentifier == null) { + builder.bundleIdentifier(plistFile.bundleIdentifier()); + } + + if (builder.category == null) { + builder.category(plistFile.category()); + } + + return builder; + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } catch (Exception ex) { + throw I18N.buildConfigException("message.app-image-requires-identifier") + .advice("message.app-image-requires-identifier.advice") + .cause(ex) + .create(); + } + } + + private Optional createSigningConfig() throws ConfigException { + if (signingBuilder != null) { + return Optional.of(signingBuilder.create()); + } else { + return Optional.empty(); + } + } + + private String validatedBundleName() throws ConfigException { + final var value = Optional.ofNullable(bundleName).orElseGet(() -> { + final var appName = app.name(); + if (appName.length() > MAX_BUNDLE_NAME_LENGTH) { + return appName.substring(0, MAX_BUNDLE_NAME_LENGTH); + } else { + return appName; + } + }); + + if (value.length() > MAX_BUNDLE_NAME_LENGTH) { + Log.error(I18N.format("message.bundle-name-too-long-warning", "--mac-package-name", value)); + } + + return value; + } + + private String validatedBundleIdentifier() throws ConfigException { + final var value = Optional.ofNullable(bundleIdentifier).orElseGet(() -> { + return toSupplier(() -> { + return app.mainLauncher() + .flatMap(Launcher::startupInfo) + .map(LauncherStartupInfo::simpleClassName) + .orElseThrow(() -> { + return I18N.buildConfigException("message.app-image-requires-identifier") + .advice("message.app-image-requires-identifier.advice") + .create(); + }); + }).get(); + }); + + if (!isValidBundleIdentifier(value)) { + throw I18N.buildConfigException("message.invalid-identifier", value) + .advice("message.invalid-identifier.advice") + .create(); + } + + return value; + } + + private String validatedCategory() throws ConfigException { + return Optional.ofNullable(category).orElseGet(DEFAULTS::category); + } + + private Optional validatedIcon() throws ConfigException { + if (icon != null) { + LauncherBuilder.validateIcon(icon); + } + + return Optional.ofNullable(icon); + } + + private record Defaults(String category) { + } + + private Path icon; + private String bundleName; + private String bundleIdentifier; + private String category; + private Path externalInfoPlistFile; + private SigningConfigBuilder signingBuilder; + + private final Application app; + + private static final Defaults DEFAULTS = new Defaults("utilities"); + + private static final int MAX_BUNDLE_NAME_LENGTH = 16; +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayout.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayout.java new file mode 100644 index 0000000000000..a5867c121633a --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayout.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; + +import java.nio.file.Path; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.util.CompositeProxy; + +interface MacApplicationLayout extends ApplicationLayout, MacApplicationLayoutMixin { + + static MacApplicationLayout create(ApplicationLayout layout, Path runtimeRootDir) { + return CompositeProxy.build() + .invokeTunnel(CompositeProxyTunnel.INSTANCE) + .create(MacApplicationLayout.class, layout, new MacApplicationLayoutMixin.Stub(runtimeRootDir)); + } + + @Override + default MacApplicationLayout resolveAt(Path root) { + return create(ApplicationLayout.super.resolveAt(root), + resolveNullablePath(root, runtimeRootDirectory())); + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayoutMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayoutMixin.java new file mode 100644 index 0000000000000..0d7f3c695e6f0 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayoutMixin.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; + +// Must be publc to allow access from AppImageLayout.toPathGroup() +public interface MacApplicationLayoutMixin { + + /** + * Path to the root Java runtime directory in the application image. + * The root Java runtime directory should have "Contents/Home" subdirectory. + */ + Path runtimeRootDirectory(); + + record Stub(Path runtimeRootDirectory) implements MacApplicationLayoutMixin {} +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index 388715ac1e42e..2757d738a59b9 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -39,12 +39,25 @@ import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import jdk.jpackage.internal.util.FileUtils; public abstract class MacBaseInstallerBundler extends AbstractBundler { + static final BundlerParamInfo IMAGES_ROOT = + new BundlerParamInfo<>( + "imagesRoot", + Path.class, + params -> { + // Order is important + MacFromParams.APPLICATION.fetchFrom(params); + final var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + return env.buildRoot().resolve("images"); + }, + (s, p) -> null); + private final BundlerParamInfo APP_IMAGE_TEMP_ROOT = new BundlerParamInfo<>( "mac.app.imageRoot", @@ -156,7 +169,8 @@ protected void validateAppImageAndBundeler( I18N.getString( "message.app-image-requires-app-name.advice")); } - if (AppImageFile.load(applicationImage).isSigned()) { + + if (new MacAppImageFileExtras(PREDEFINED_APP_IMAGE_FILE.fetchFrom(params)).signed()) { var appLayout = ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT.resolveAt(applicationImage); if (!Files.exists( PackageFile.getPathInAppImage(appLayout))) { @@ -191,7 +205,7 @@ protected Path prepareAppBundle(Map params) // Create PackageFile if predefined app image is not signed if (!StandardBundlerParam.isRuntimeInstaller(params) && - !AppImageFile.load(predefinedImage).isSigned()) { + !new MacAppImageFileExtras(PREDEFINED_APP_IMAGE_FILE.fetchFrom(params)).signed()) { new PackageFile(APP_NAME.fetchFrom(params)).save( ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT.resolveAt(appDir)); // We need to re-sign app image after adding ".package" to it. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java new file mode 100644 index 0000000000000..972db5810c01e --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import jdk.jpackage.internal.util.PathUtils; + +public final class MacCertificateUtils { + + public static Collection findCertificates(Optional keychain, Optional certificateNameFilter) { + List args = new ArrayList<>(); + args.add("/usr/bin/security"); + args.add("find-certificate"); + args.add("-a"); + certificateNameFilter.ifPresent(filter -> args.addAll(List.of("-c", filter))); + args.add("-p"); // PEM format + keychain.map(PathUtils::normalizedAbsolutePathString).ifPresent(args::add); + + return toSupplier(() -> { + final byte[] pemCertificatesBuffer = Executor.of(args.toArray(String[]::new)) + .setQuiet(true).saveOutput(true).executeExpectSuccess() + .getOutput().stream().reduce(new StringBuilder(), StringBuilder::append, StringBuilder::append).toString().getBytes(StandardCharsets.US_ASCII); + + try (var in = new ByteArrayInputStream(pemCertificatesBuffer)) { + final var cf = CertificateFactory.getInstance("X.509"); + return cf.generateCertificates(in); + } + }).get(); + } + + public static Collection filterX509Certificates(Collection certs) { + return certs.stream().filter(X509Certificate.class::isInstance).map(X509Certificate.class::cast).toList(); + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFileAssociationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFileAssociationBuilder.java new file mode 100644 index 0000000000000..78140c5c78ea6 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFileAssociationBuilder.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.model.MacFileAssociation; +import jdk.jpackage.internal.model.MacFileAssociationMixin; + +final class MacFileAssociationBuilder { + + MacFileAssociation create(FileAssociation fa) throws ConfigException { + Objects.requireNonNull(fa); + + final var mixin = new MacFileAssociationMixin.Stub( + Optional.ofNullable(cfBundleTypeName).orElse(DEFAULTS.cfBundleTypeName), + Optional.ofNullable(cfBundleTypeRole).orElse(DEFAULTS.cfBundleTypeRole), + Optional.ofNullable(lsHandlerRank).orElse(DEFAULTS.lsHandlerRank), + Optional.ofNullable(lsTypeIsPackage).orElse(DEFAULTS.lsTypeIsPackage), + Optional.ofNullable(nsDocumentClass).orElse(DEFAULTS.nsDocumentClass), + Optional.ofNullable(nsPersistentStoreTypeKey).orElse(DEFAULTS.nsPersistentStoreTypeKey), + Optional.ofNullable(lsSupportsOpeningDocumentsInPlace).orElse(DEFAULTS.lsSupportsOpeningDocumentsInPlace), + Optional.ofNullable(uiSupportsDocumentBrowser).orElse(DEFAULTS.uiSupportsDocumentBrowser), + Optional.ofNullable(utTypeConformsTo).orElse(DEFAULTS.utTypeConformsTo), + Optional.ofNullable(nsExportableTypes).orElse(DEFAULTS.nsExportableTypes)); + + return MacFileAssociation.create(fa, mixin); + } + + MacFileAssociationBuilder cfBundleTypeName(String v) { + cfBundleTypeName = v; + return this; + } + + MacFileAssociationBuilder cfBundleTypeRole(String v) { + cfBundleTypeRole = v; + return this; + } + + MacFileAssociationBuilder lsHandlerRank(String v) { + lsHandlerRank = v; + return this; + } + + MacFileAssociationBuilder lsTypeIsPackage(boolean v) { + lsTypeIsPackage = v; + return this; + } + + MacFileAssociationBuilder nsDocumentClass(String v) { + nsDocumentClass = v; + return this; + } + + MacFileAssociationBuilder nsPersistentStoreTypeKey(String v) { + nsPersistentStoreTypeKey = v; + return this; + } + + MacFileAssociationBuilder lsSupportsOpeningDocumentsInPlace(boolean v) { + lsSupportsOpeningDocumentsInPlace = v; + return this; + } + + MacFileAssociationBuilder uiSupportsDocumentBrowser(boolean v) { + uiSupportsDocumentBrowser = v; + return this; + } + + MacFileAssociationBuilder utTypeConformsTo(List v) { + utTypeConformsTo = v; + return this; + } + + MacFileAssociationBuilder nsExportableTypes(List v) { + nsExportableTypes = v; + return this; + } + + private String cfBundleTypeName; + private String cfBundleTypeRole; + private String lsHandlerRank; + private String nsDocumentClass; + private String nsPersistentStoreTypeKey; + private boolean lsTypeIsPackage; + private boolean lsSupportsOpeningDocumentsInPlace; + private boolean uiSupportsDocumentBrowser; + private List utTypeConformsTo; + private List nsExportableTypes; + + private static final MacFileAssociationBuilder DEFAULTS = new MacFileAssociationBuilder() + .lsHandlerRank("Owner") + .cfBundleTypeRole("Editor") + .cfBundleTypeName("") + .lsTypeIsPackage(false) + .nsDocumentClass("") + .nsPersistentStoreTypeKey("") + .lsSupportsOpeningDocumentsInPlace(false) + .uiSupportsDocumentBrowser(false) + .utTypeConformsTo(List.of("public.data")) + .nsExportableTypes(List.of()); + +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java new file mode 100644 index 0000000000000..3df92347a7615 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.BundlerParamInfo.createBooleanBundlerParam; +import static jdk.jpackage.internal.BundlerParamInfo.createPathBundlerParam; +import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; +import static jdk.jpackage.internal.FromParams.createApplicationBuilder; +import static jdk.jpackage.internal.FromParams.createApplicationBundlerParam; +import static jdk.jpackage.internal.FromParams.createPackageBundlerParam; +import static jdk.jpackage.internal.MacAppImageBuilder.APP_STORE; +import static jdk.jpackage.internal.MacAppImageBuilder2.APPLICATION_LAYOUT; +import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; +import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; +import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; +import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import jdk.jpackage.internal.SigningConfigBuilder.CertificateNameFilter; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.MacApplication; +import jdk.jpackage.internal.model.MacFileAssociation; +import jdk.jpackage.internal.model.MacLauncher; +import jdk.jpackage.internal.model.PackageType; + + +final class MacFromParams { + + private static MacApplication createMacApplication( + Map params) throws ConfigException, IOException { + + final var launcherFromParams = new LauncherFromParams(Optional.of(MacFromParams::createMacFa)); + + final var app = createApplicationBuilder(params, toFunction(launcherParams -> { + var launcher = launcherFromParams.create(launcherParams); + return MacLauncher.create(launcher); + }), APPLICATION_LAYOUT).create(); + + final var appBuilder = new MacApplicationBuilder(app); + + MAC_CF_BUNDLE_NAME.copyInto(params, appBuilder::bundleName); + MAC_CF_BUNDLE_IDENTIFIER.copyInto(params, appBuilder::bundleIdentifier); + APP_CATEGORY.copyInto(params, appBuilder::category); + + final boolean sign; + + if (hasPredefinedAppImage(params)) { + final var appImageFileExtras = new MacAppImageFileExtras(PREDEFINED_APP_IMAGE_FILE.fetchFrom(params)); + sign = appImageFileExtras.signed(); + } else { + sign = SIGN_BUNDLE.findIn(params).orElse(false); + } + + if (sign) { + final var signingBuilder = new SigningConfigBuilder(); + app.mainLauncher().flatMap(Launcher::startupInfo).ifPresent(signingBuilder::signingIdentifierPrefix); + BUNDLE_ID_SIGNING_PREFIX.copyInto(params, signingBuilder::signingIdentifierPrefix); + SIGNING_KEYCHAIN.copyInto(params, v -> signingBuilder.keyChain(Path.of(v))); + ENTITLEMENTS.copyInto(params, signingBuilder::entitlements); + APP_IMAGE_SIGN_IDENTITY.copyInto(params, signingBuilder::signingIdentifier); + + final boolean appStore = APP_STORE.findIn(params).orElse(false); + + final var certificateNameFilter = appStore ? CertificateNameFilter.APP_STORE_APP_IMAGE : CertificateNameFilter.APP_IMAGE; + + signingBuilder.addCertificateNameFilters(certificateNameFilter.getFilters(SIGNING_KEY_USER.findIn(params))); + + appBuilder.signingBuilder(signingBuilder); + } + + return appBuilder.create(); + } + + private static MacFileAssociation createMacFa(FileAssociation fa, Map params) { + + final var builder = new MacFileAssociationBuilder(); + + FA_MAC_CFBUNDLETYPEROLE.copyInto(params, builder::cfBundleTypeRole); + FA_MAC_LSHANDLERRANK.copyInto(params, builder::lsHandlerRank); + FA_MAC_NSSTORETYPEKEY.copyInto(params, builder::nsPersistentStoreTypeKey); + FA_MAC_NSDOCUMENTCLASS.copyInto(params, builder::nsDocumentClass); + FA_MAC_LSTYPEISPACKAGE.copyInto(params, builder::lsTypeIsPackage); + FA_MAC_LSDOCINPLACE.copyInto(params, builder::lsSupportsOpeningDocumentsInPlace); + FA_MAC_UIDOCBROWSER.copyInto(params, builder::uiSupportsDocumentBrowser); + FA_MAC_NSEXPORTABLETYPES.copyInto(params, builder::nsExportableTypes); + FA_MAC_UTTYPECONFORMSTO.copyInto(params, builder::utTypeConformsTo); + + return toFunction(builder::create).apply(fa); + } + + static final BundlerParamInfo APPLICATION = createApplicationBundlerParam( + MacFromParams::createMacApplication); + + // FIXME: This is just a stub. Replace with DMG and PKG packages + static final BundlerParamInfo PACKAGE = createPackageBundlerParam(params -> { + final var app = APPLICATION.fetchFrom(params); + final var builder = FromParams.createPackageBuilder(params, app, new PackageType () {}); + + builder.installDir(Path.of("/foo/bar")); + + return builder.create(); + }); + + public static final BundlerParamInfo MAC_CF_BUNDLE_NAME = createStringBundlerParam( + Arguments.CLIOptions.MAC_BUNDLE_NAME.getId()); + + public static final BundlerParamInfo APP_CATEGORY = createStringBundlerParam( + Arguments.CLIOptions.MAC_CATEGORY.getId()); + + public static final BundlerParamInfo ENTITLEMENTS = createPathBundlerParam( + Arguments.CLIOptions.MAC_ENTITLEMENTS.getId()); + + + public static final BundlerParamInfo MAC_CF_BUNDLE_IDENTIFIER = createStringBundlerParam( + Arguments.CLIOptions.MAC_BUNDLE_IDENTIFIER.getId()); + + public static final BundlerParamInfo BUNDLE_ID_SIGNING_PREFIX = createStringBundlerParam( + Arguments.CLIOptions.MAC_BUNDLE_SIGNING_PREFIX.getId()); + + public static final BundlerParamInfo APP_IMAGE_SIGN_IDENTITY = createStringBundlerParam( + Arguments.CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getId()); + + private static final BundlerParamInfo FA_MAC_CFBUNDLETYPEROLE = createStringBundlerParam( + Arguments.MAC_CFBUNDLETYPEROLE); + + private static final BundlerParamInfo FA_MAC_LSHANDLERRANK = createStringBundlerParam( + Arguments.MAC_LSHANDLERRANK); + + private static final BundlerParamInfo FA_MAC_NSSTORETYPEKEY = createStringBundlerParam( + Arguments.MAC_NSSTORETYPEKEY); + + private static final BundlerParamInfo FA_MAC_NSDOCUMENTCLASS = createStringBundlerParam( + Arguments.MAC_NSDOCUMENTCLASS); + + private static final BundlerParamInfo FA_MAC_LSTYPEISPACKAGE = createBooleanBundlerParam( + Arguments.MAC_LSTYPEISPACKAGE); + + private static final BundlerParamInfo FA_MAC_LSDOCINPLACE = createBooleanBundlerParam( + Arguments.MAC_LSDOCINPLACE); + + private static final BundlerParamInfo FA_MAC_UIDOCBROWSER = createBooleanBundlerParam( + Arguments.MAC_UIDOCBROWSER); + + @SuppressWarnings("unchecked") + private static final BundlerParamInfo> FA_MAC_NSEXPORTABLETYPES = + new BundlerParamInfo<>( + Arguments.MAC_NSEXPORTABLETYPES, + (Class>) (Object) List.class, + params -> null, + (s, p) -> Arrays.asList(s.split("(,|\\s)+")) + ); + + @SuppressWarnings("unchecked") + private static final BundlerParamInfo> FA_MAC_UTTYPECONFORMSTO = + new BundlerParamInfo<>( + Arguments.MAC_UTTYPECONFORMSTO, + (Class>) (Object) List.class, + params -> null, + (s, p) -> Arrays.asList(s.split("(,|\\s)+")) + ); +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index 1dfc6f81d7464..70d81f690bd33 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -49,7 +49,7 @@ static ShellCustomAction create(Map params, Path outputDir) throws IOException { // Order is important! - var pkg = FromParams.PACKAGE.fetchFrom(params); + var pkg = MacFromParams.PACKAGE.fetchFrom(params); var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); if (pkg.isRuntimeInstaller()) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index a4c7e69699004..6d18d001b509c 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -56,11 +56,8 @@ import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; -import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; -import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; -import static jdk.jpackage.internal.MacBaseInstallerBundler.INSTALLER_SIGN_IDENTITY; import static jdk.jpackage.internal.MacAppBundler.APP_IMAGE_SIGN_IDENTITY; -import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; +import static jdk.jpackage.internal.MacAppImageBuilder.APP_STORE; import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; import static jdk.jpackage.internal.StandardBundlerParam.createResource; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfig.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfig.java deleted file mode 100644 index ca2a5cacd0213..0000000000000 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfig.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal; - -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - - -record SigningConfig(String signingIdentity, String identifierPrefix, Path entitlements, String keyChain) { - - static final class Builder { - - private Builder(String signingIdentity) { - this.signingIdentity = Objects.requireNonNull(signingIdentity); - } - - SigningConfig create() { - return new SigningConfig(signingIdentity, identifierPrefix, entitlements, keyChain); - } - - Builder entitlements(Path v) { - entitlements = v; - return this; - } - - Builder identifierPrefix(String v) { - identifierPrefix = v; - return this; - } - - Builder keyChain(String v) { - keyChain = v; - return this; - } - - private final String signingIdentity; - private String identifierPrefix; - private Path entitlements; - private String keyChain; - } - - static Builder build(String signingIdentity) { - return new Builder(signingIdentity); - } - - static Builder build(SigningConfig signingCfg) { - return new Builder(signingCfg.signingIdentity) - .entitlements(signingCfg.entitlements) - .identifierPrefix(signingCfg.identifierPrefix) - .keyChain(signingCfg.keyChain); - } - - SigningConfig { - Objects.requireNonNull(signingIdentity); - } - - List toCodesignArgs() { - List args = new ArrayList<>(List.of("-s", signingIdentity, "-vvvv")); - - if (!signingIdentity.equals("-")) { - args.addAll(List.of("--timestamp", "--options", "runtime", - "--prefix", identifierPrefix)); - if (keyChain != null && !keyChain.isEmpty()) { - args.addAll(List.of("--keychain", keyChain)); - } - - if (entitlements != null) { - args.addAll(List.of("--entitlements", - entitlements.toString())); - } - } - - return args; - } -} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java new file mode 100644 index 0000000000000..2b1f793ec7e73 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import static java.util.stream.Collectors.toMap; +import static jdk.jpackage.internal.MacCertificateUtils.filterX509Certificates; +import static jdk.jpackage.internal.MacCertificateUtils.findCertificates; + +import java.nio.file.Path; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; +import javax.naming.InvalidNameException; +import javax.naming.ldap.LdapName; +import javax.naming.ldap.Rdn; +import javax.security.auth.x500.X500Principal; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LauncherStartupInfo; +import jdk.jpackage.internal.model.SigningConfig; +import jdk.jpackage.internal.model.SigningIdentifier; + +final class SigningConfigBuilder { + + SigningConfigBuilder signingIdentifier(String v) { + signingIdentifier = v; + return this; + } + + SigningConfigBuilder signingIdentifierPrefix(LauncherStartupInfo mainLauncherStartupInfo) { + final var pkgName = mainLauncherStartupInfo.packageName(); + if (!pkgName.isEmpty()) { + signingIdentifierPrefix(pkgName + "."); + } + return this; + } + + SigningConfigBuilder signingIdentifierPrefix(String v) { + signingIdentifierPrefix = v; + return this; + } + + SigningConfigBuilder addCertificateNameFilters(String ...certificateNameFilters) { + return addCertificateNameFilters(List.of(certificateNameFilters)); + } + + SigningConfigBuilder addCertificateNameFilters(Collection certificateNameFilters) { + this.certificateNameFilters.addAll(certificateNameFilters); + return this; + } + + SigningConfigBuilder keyChain(Path v) { + keyChain = v; + return this; + } + + SigningConfigBuilder entitlements(Path v) { + entitlements = v; + return this; + } + + SigningConfig create() throws ConfigException { + return new SigningConfig.Stub(validatedSigningIdentifier(), validatedEntitlements(), + validatedKeyChain(), "sandbox.plist"); + } + + private Optional validatedEntitlements() throws ConfigException { + return Optional.ofNullable(entitlements); + } + + private Optional validatedKeyChain() throws ConfigException { + return Optional.ofNullable(keyChain); + } + + private Optional validatedSigningIdentifier() throws ConfigException { + if (signingIdentifier != null) { + return Optional.of(new SigningIdentifierImpl(signingIdentifier, Optional.ofNullable(signingIdentifierPrefix))); + } + + final var validatedKeyChain = validatedKeyChain(); + + final var signingIdentifierMap = certificateNameFilters.stream().collect(toMap(x -> x, certificateNameFilter -> { + return filterX509Certificates(findCertificates(validatedKeyChain, Optional.of(certificateNameFilter))).stream() + .map(SigningConfigBuilder::findSubjectCN) + .filter(Optional::isPresent) + .map(Optional::get).toList(); + })); + + for (var certificateNameFilter : certificateNameFilters) { + final var signingIdentifiers = signingIdentifierMap.get(certificateNameFilter); + switch (signingIdentifiers.size()) { + case 0 -> { + break; + } + case 1 -> { + return Optional.of(new SigningIdentifierImpl(signingIdentifiers.get(0), Optional.ofNullable(signingIdentifierPrefix))); + } + default -> { + // Multiple certificates matching the same criteria found + // FIXME: warn the user? + break; + } + } + } + + throw I18N.buildConfigException("error.cert.not.found", validatedKeyChain).create(); + } + + private static Optional findSubjectCN(X509Certificate cert) { + final LdapName ldapName; + try { + ldapName = new LdapName(cert.getSubjectX500Principal().getName(X500Principal.RFC2253)); + } catch (InvalidNameException e) { + return Optional.empty(); + } + + return ldapName.getRdns().stream().filter(rdn -> { + return rdn.getType().equalsIgnoreCase("CN"); + }).map(Rdn::getValue).map(Object::toString).findFirst(); + } + + enum CertificateNameFilter { + APP_IMAGE("3rd Party Mac Developer Application: "), + PKG_INSTALLER("3rd Party Mac Developer Installer: "), + APP_STORE_APP_IMAGE("3rd Party Mac Developer Application: ", "Developer ID Application: "), + APP_STORE_PKG_INSTALLER("3rd Party Mac Developer Installer: ", "Developer ID Installer: "); + + CertificateNameFilter(String ... prefixes) { + filters = List.of(prefixes); + } + + List getFilters(Optional certificateNameFilter) { + if (certificateNameFilter.map(CertificateNameFilter::useAsIs).orElse(false)) { + return List.of(certificateNameFilter.orElseThrow()); + } else { + return certificateNameFilter.map(filter -> { + return filters.stream().map(stdFilter -> { + return stdFilter + filter; + }).toList(); + }).orElse(filters); + } + } + + private static boolean useAsIs(String certificateNameFilter) { + return Stream.of("3rd Party Mac", "Developer ID").noneMatch(certificateNameFilter::startsWith); + } + + private final List filters; + } + + private String signingIdentifier; + private String signingIdentifierPrefix; + private List certificateNameFilters = new ArrayList<>(); + private Path keyChain; + private Path entitlements; +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentifierImpl.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentifierImpl.java new file mode 100644 index 0000000000000..ae4e7736e355a --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentifierImpl.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.CodesignConfig.ADHOC_SIGNING_IDENTIFIER; + +import java.util.Objects; +import java.util.Optional; +import jdk.jpackage.internal.model.SigningIdentifier; + +record SigningIdentifierImpl(String name, Optional prefix) implements SigningIdentifier { + + SigningIdentifierImpl { + Objects.requireNonNull(name); + Objects.requireNonNull(prefix); + + if (ADHOC_SIGNING_IDENTIFIER.equals(name)) { + throw new IllegalArgumentException("Adhoc signing identifier no allowed"); + } + + if (name.contains(".") == prefix.isPresent()) { + throw new IllegalArgumentException("name and prefix mismatch"); + } + + prefix.ifPresent(thePrefix -> { + if (!thePrefix.endsWith(".")) { + throw new IllegalArgumentException("Illegal prefix"); + } + }); + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/TempKeychain.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/TempKeychain.java new file mode 100644 index 0000000000000..2425640671b2b --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/TempKeychain.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Predicate; +import jdk.internal.util.OSVersion; +import jdk.jpackage.internal.util.PathUtils; +import jdk.jpackage.internal.util.function.ThrowingConsumer; + +final class TempKeychain implements Closeable { + + static void withKeychain(Path keyChain, ThrowingConsumer keyChainConsumer) throws Throwable { + Objects.requireNonNull(keyChain); + if (OSVersion.current().compareTo(new OSVersion(10, 12)) < 0) { + // we need this for OS X 10.12+ + try (var tempKeychain = new TempKeychain(keyChain)) { + keyChainConsumer.accept(tempKeychain.keyChain()); + } + } else { + keyChainConsumer.accept(PathUtils.normalizedAbsolutePath(keyChain)); + } + } + + TempKeychain(Path keyChain) throws IOException { + this.keyChain = PathUtils.normalizedAbsolutePath(keyChain); + + // Get the current keychain list + final List cmdOutput; + try { + cmdOutput = Executor.of("/usr/bin/security", "list-keychains").saveOutput(true).executeExpectSuccess().getOutput(); + } catch (IOException ex) { + throw I18N.buildException().message("message.keychain.error").cause(ex).create(IOException::new); // FIXME: should be PackagerException + } + + // Typical output of /usr/bin/security command is: + // "/Users/foo/Library/Keychains/login.keychain-db" + // "/Library/Keychains/System.keychain" + final var origKeychains = cmdOutput.stream().map(String::trim).map(str -> { + // Strip enclosing double quotes + return str.substring(1, str.length() - 1); + }).toList(); + + final var keychainMissing = origKeychains.stream().map(Path::of).filter(Predicate.isEqual(keyChain)).findAny().isEmpty(); + if (keychainMissing) { + List args = new ArrayList<>(); + args.add("/usr/bin/security"); + args.add("list-keychains"); + args.add("-s"); + args.addAll(origKeychains); + + restoreKeychainsCmd = List.copyOf(args); + + args.add(keyChain.toString()); + + Executor.of(args.toArray(String[]::new)).executeExpectSuccess(); + } else { + restoreKeychainsCmd = List.of(); + } + } + + Path keyChain() { + return keyChain; + } + + @Override + public void close() throws IOException { + if (restoreKeychainsCmd.isEmpty()) { + Executor.of(restoreKeychainsCmd.toArray(String[]::new)).executeExpectSuccess(); + } + } + + private final Path keyChain; + private final List restoreKeychainsCmd; +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java index b9b67a6d6f318..c8109ca8db2dd 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,9 @@ */ package jdk.jpackage.internal.model; -import java.util.Map; import static java.util.stream.Collectors.joining; + +import java.util.Map; import java.util.stream.IntStream; import jdk.jpackage.internal.util.CompositeProxy; @@ -42,13 +43,30 @@ default DottedVersion shortVersion() { }).collect(joining("."))); } + default boolean sign() { + return signingConfig().isPresent(); + } + @Override default Map extraAppImageFileData() { - return Map.of("signed", Boolean.toString(signed()), "app-store", - Boolean.toString(appStore())); + return Map.of(ExtraAppImageFileField.SIGNED.fieldName(), Boolean.toString(sign())); } public static MacApplication create(Application app, MacApplicationMixin mixin) { return CompositeProxy.create(MacApplication.class, app, mixin); } + + public enum ExtraAppImageFileField { + SIGNED("signed"); + + ExtraAppImageFileField(String fieldName) { + this.fieldName = fieldName; + } + + public String fieldName() { + return fieldName; + } + + private final String fieldName; + } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java index 6e2dd40570f9e..db23b7f8a5b4d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java @@ -25,10 +25,11 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; +import java.util.Optional; public interface MacApplicationMixin { - Path icon(); + Optional icon(); String bundleName(); @@ -36,15 +37,9 @@ public interface MacApplicationMixin { String category(); - boolean signed(); - - boolean appStore(); - - Path entitlements(); - - record Stub(Path icon, String bundleName, String bundleIdentifier, String category, - boolean signed, boolean appStore, Path entitlements) implements - MacApplicationMixin { + Optional signingConfig(); + record Stub(Optional icon, String bundleName, String bundleIdentifier, + String category, Optional signingConfig) implements MacApplicationMixin { } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociationMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociationMixin.java index 919140bb31aaa..973e885d1296b 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociationMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociationMixin.java @@ -34,7 +34,7 @@ public interface MacFileAssociationMixin { String lsHandlerRank(); - String lsTypeIsPackage(); + boolean lsTypeIsPackage(); String nsDocumentClass(); @@ -49,7 +49,7 @@ public interface MacFileAssociationMixin { List nsExportableTypes(); record Stub(String cfBundleTypeName, String cfBundleTypeRole, - String lsHandlerRank, String lsTypeIsPackage, String nsDocumentClass, + String lsHandlerRank, boolean lsTypeIsPackage, String nsDocumentClass, String nsPersistentStoreTypeKey, boolean lsSupportsOpeningDocumentsInPlace, boolean uiSupportsDocumentBrowser, List utTypeConformsTo, diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacLauncher.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacLauncher.java new file mode 100644 index 0000000000000..09ddde8cd15c8 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacLauncher.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import jdk.jpackage.internal.util.CompositeProxy; + +public interface MacLauncher extends Launcher { + + public static MacLauncher create(Launcher launcher) { + return CompositeProxy.create(MacLauncher.class, launcher); + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningConfig.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningConfig.java new file mode 100644 index 0000000000000..e90f54a6a86a2 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningConfig.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.model; + +import java.nio.file.Path; +import java.util.Optional; + +public interface SigningConfig { + + Optional identifier(); + + Optional entitlements(); + + String entitlementsResourceName(); + + Optional keyChain(); + + record Stub(Optional identifier, Optional entitlements, + Optional keyChain, String entitlementsResourceName) implements SigningConfig { + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentifier.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentifier.java new file mode 100644 index 0000000000000..f5408b769e309 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentifier.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.model; + +import java.util.Optional; + +public interface SigningIdentifier { + + String name(); + + Optional prefix(); +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/PListUtils.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/util/PListUtils.java similarity index 81% rename from src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/PListUtils.java rename to src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/util/PListUtils.java index 2a4a4c654bea9..c41e7d31f3559 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/PListUtils.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/util/PListUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,29 +22,30 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.util; + +import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; import java.io.IOException; + import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import jdk.jpackage.internal.util.XmlConsumer; -import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; -final class PListUtils { +public final class PListUtils { - static void writeBoolean(XMLStreamWriter xml, String key, boolean value) + public static void writeBoolean(XMLStreamWriter xml, String key, boolean value) throws XMLStreamException { writeKey(xml, key); xml.writeEmptyElement(Boolean.toString(value)); } - static void writeString(XMLStreamWriter xml, String key, Object value) + public static void writeString(XMLStreamWriter xml, String key, Object value) throws XMLStreamException { writeKey(xml, key); writeString(xml, value); } - static void writeStringArray(XMLStreamWriter xml, String key, Iterable values) + public static void writeStringArray(XMLStreamWriter xml, String key, Iterable values) throws XMLStreamException, IOException { writeKey(xml, key); writeArray(xml, toXmlConsumer(() -> { @@ -54,7 +55,7 @@ static void writeStringArray(XMLStreamWriter xml, String key, Iterable values })); } - static void writeStringArray(XMLStreamWriter xml, String key, Object... values) + public static void writeStringArray(XMLStreamWriter xml, String key, Object... values) throws XMLStreamException, IOException { writeKey(xml, key); writeArray(xml, toXmlConsumer(() -> { @@ -64,17 +65,17 @@ static void writeStringArray(XMLStreamWriter xml, String key, Object... values) })); } - static void writeDict(XMLStreamWriter xml, XmlConsumer content) + public static void writeDict(XMLStreamWriter xml, XmlConsumer content) throws XMLStreamException, IOException { writeElement(xml, "dict", content); } - static void writeArray(XMLStreamWriter xml, XmlConsumer content) + public static void writeArray(XMLStreamWriter xml, XmlConsumer content) throws XMLStreamException, IOException { writeElement(xml, "array", content); } - static void writePList(XMLStreamWriter xml, XmlConsumer content) + public static void writePList(XMLStreamWriter xml, XmlConsumer content) throws XMLStreamException, IOException { xml.writeDTD("plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"https://www.apple.com/DTDs/PropertyList-1.0.dtd\""); xml.writeStartElement("plist"); @@ -83,7 +84,7 @@ static void writePList(XMLStreamWriter xml, XmlConsumer content) xml.writeEndElement(); } - static void writeKey(XMLStreamWriter xml, String key) + public static void writeKey(XMLStreamWriter xml, String key) throws XMLStreamException { writeElement(xml, "key", key); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java deleted file mode 100644 index 5a7995760f9b0..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal; - -import jdk.jpackage.internal.model.LauncherStartupInfo; -import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.ApplicationLayout; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Map; -import java.util.List; -import java.util.Optional; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.SOURCE_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; -import static jdk.jpackage.internal.StandardBundlerParam.OUTPUT_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import jdk.jpackage.internal.resources.ResourceLocator; -import jdk.jpackage.internal.util.FileUtils; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; - -/* - * AbstractAppImageBuilder - * This is sub-classed by each of the platform dependent AppImageBuilder - * classes, and contains resource processing code common to all platforms. - */ - -public abstract class AbstractAppImageBuilder { - - private final Path root; - protected final ApplicationLayout appLayout; - - public AbstractAppImageBuilder(Path root) { - this.root = root; - appLayout = ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT.resolveAt(root); - } - - public InputStream getResourceAsStream(String name) { - return ResourceLocator.class.getResourceAsStream(name); - } - - public abstract void prepareApplicationFiles( - Map params) throws IOException; - - protected void writeCfgFile(Map params) throws - IOException { - new CfgFile(new Application.Unsupported() { - @Override - public String version() { - return VERSION.fetchFrom(params); - } - }, new Launcher.Unsupported() { - @Override - public Optional startupInfo() { - return toSupplier(() -> new LauncherFromParams().create(params).startupInfo()).get(); - } - - @Override - public String name() { - return APP_NAME.fetchFrom(params); - } - }).create(appLayout, appLayout); - } - - protected void copyApplication(Map params) - throws IOException { - Path inputPath = SOURCE_DIR.fetchFrom(params); - if (inputPath != null) { - inputPath = inputPath.toAbsolutePath(); - - List excludes = new ArrayList<>(); - - for (var path : List.of(TEMP_ROOT.fetchFrom(params), OUTPUT_DIR.fetchFrom(params), root)) { - if (Files.isDirectory(path)) { - path = path.toAbsolutePath(); - if (path.startsWith(inputPath) && !Files.isSameFile(path, inputPath)) { - excludes.add(path); - } - } - } - - FileUtils.copyRecursive(inputPath, - appLayout.appDirectory().toAbsolutePath(), excludes); - } - - AppImageFile.save(root, params); - - List items = APP_CONTENT.fetchFrom(params); - for (Path item : items) { - FileUtils.copyRecursive(item, - appLayout.contentDirectory().resolve(item.getFileName())); - } - } -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java index 234b2c34047bc..d43c1fd8c78e1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java @@ -40,14 +40,6 @@ */ abstract class AbstractBundler implements Bundler { - static final BundlerParamInfo IMAGES_ROOT = - new BundlerParamInfo<>( - "imagesRoot", - Path.class, - params -> - StandardBundlerParam.TEMP_ROOT.fetchFrom(params).resolve("images"), - (s, p) -> null); - @Override public String toString() { return getName(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java deleted file mode 100644 index 1c0c9b6900251..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal; - -import jdk.jpackage.internal.model.ApplicationLayout; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.NoSuchFileException; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -import jdk.internal.util.OperatingSystem; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.w3c.dom.NamedNodeMap; -import org.xml.sax.SAXException; - -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.MAIN_CLASS; -import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; -import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; -import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; -import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; -import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; -import jdk.jpackage.internal.util.XmlUtils; - -final class AppImageFile { - - // These values will be loaded from AppImage xml file. - private final String appVersion; - private final String launcherName; - private final String mainClass; - private final List addLauncherInfos; - private final String creatorVersion; - private final String creatorPlatform; - private final boolean signed; - private final boolean appStore; - - private static final String FILENAME = ".jpackage.xml"; - - private static final Map PLATFORM_LABELS = Map.of( - OperatingSystem.LINUX, "linux", - OperatingSystem.WINDOWS, "windows", - OperatingSystem.MACOS, "macOS"); - - private AppImageFile(Path appImageDir, String appVersion, String launcherName, - String mainClass, List launcherInfos, - String creatorVersion, String creatorPlatform, String signedStr, - String appStoreStr) { - boolean isValid = true; - - if (appVersion == null || appVersion.length() == 0) { - isValid = false; - } - - if (launcherName == null || launcherName.length() == 0) { - isValid = false; - } - - if (mainClass == null || mainClass.length() == 0) { - isValid = false; - } - - for (var launcher : launcherInfos) { - if ("".equals(launcher.getName())) { - isValid = false; - } - } - - if (!Objects.equals(getVersion(), creatorVersion)) { - isValid = false; - } - - if (!Objects.equals(getPlatform(), creatorPlatform)) { - isValid = false; - } - - if (signedStr == null || - !("true".equals(signedStr) || "false".equals(signedStr))) { - isValid = false; - } - - if (appStoreStr == null || - !("true".equals(appStoreStr) || "false".equals(appStoreStr))) { - isValid = false; - } - - if (!isValid) { - throw new RuntimeException(MessageFormat.format(I18N.getString( - "error.invalid-app-image"), appImageDir, - AppImageFile.getPathInAppImage(appImageDir))); - } - - this.appVersion = appVersion; - this.launcherName = launcherName; - this.mainClass = mainClass; - this.addLauncherInfos = launcherInfos; - this.creatorVersion = creatorVersion; - this.creatorPlatform = creatorPlatform; - this.signed = "true".equals(signedStr); - this.appStore = "true".equals(appStoreStr); - } - - /** - * Returns list of additional launchers configured for the application. - * Each item in the list is not null or empty string. - * Returns empty list for application without additional launchers. - */ - List getAddLaunchers() { - return addLauncherInfos; - } - - /** - * Returns application version. Never returns null or empty value. - */ - String getAppVersion() { - return appVersion; - } - - /** - * Returns main application launcher name. Never returns null or empty value. - */ - String getLauncherName() { - return launcherName; - } - - /** - * Returns main class name. Never returns null or empty value. - */ - String getMainClass() { - return mainClass; - } - - boolean isSigned() { - return signed; - } - - boolean isAppStore() { - return appStore; - } - - /** - * Returns path to application image info file. - * @param appImageDir - path to application image - */ - static Path getPathInAppImage(Path appImageDir) { - return ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT - .resolveAt(appImageDir) - .appDirectory() - .resolve(FILENAME); - } - - /** - * Saves file with application image info in application image using values - * from current instance. - * @param appImageDir - path to application image - * @throws IOException - */ - void save(Path appImageDir) throws IOException { - AppImageFile.save(appImageDir, null, this); - } - - /** - * Saves file with application image info in application image. - * @param appImageDir - path to application image - * @param params - parameters used to generate application image - * @throws IOException - */ - static void save(Path appImageDir, Map params) - throws IOException { - AppImageFile.save(appImageDir, params, null); - } - - /** - * Saves file with application image info in application image using params - * or appImage. Both params or appImage cannot be valid. - * @param appImageDir - path to application image - * @param params - parameters used to generate application image - * @param appImage - instance of already existing application image file - * @throws IOException - * @throws IllegalArgumentException - If both params and appImage are null or - * If both params and appImage are not null - */ - private static void save(Path appImageDir, - Map params, - AppImageFile appImage) throws IOException { - if ((params == null && appImage == null) || - (params != null && appImage != null)) { - throw new IllegalArgumentException(); - } - - final String appVersionSave; - final String mainLauncherSave; - final String mainClassSave; - final String signedSave; - final String appStoreSave; - final List addLauncherInfoSave; - if (params != null) { - appVersionSave = VERSION.fetchFrom(params); - mainLauncherSave = APP_NAME.fetchFrom(params); - mainClassSave = MAIN_CLASS.fetchFrom(params); - signedSave = SIGN_BUNDLE.fetchFrom(params).toString(); - appStoreSave = APP_STORE.fetchFrom(params).toString(); - addLauncherInfoSave = null; - } else { - appVersionSave = appImage.getAppVersion(); - mainLauncherSave = appImage.getLauncherName(); - mainClassSave = appImage.getMainClass(); - signedSave = String.valueOf(appImage.isSigned()); - appStoreSave = String.valueOf(appImage.isAppStore()); - addLauncherInfoSave = appImage.getAddLaunchers(); - } - - XmlUtils.createXml(getPathInAppImage(appImageDir), xml -> { - xml.writeStartElement("jpackage-state"); - xml.writeAttribute("version", getVersion()); - xml.writeAttribute("platform", getPlatform()); - - xml.writeStartElement("app-version"); - xml.writeCharacters(appVersionSave); - xml.writeEndElement(); - - xml.writeStartElement("main-launcher"); - xml.writeCharacters(mainLauncherSave); - xml.writeEndElement(); - - xml.writeStartElement("main-class"); - xml.writeCharacters(mainClassSave); - xml.writeEndElement(); - - xml.writeStartElement("signed"); - xml.writeCharacters(signedSave); - xml.writeEndElement(); - - xml.writeStartElement("app-store"); - xml.writeCharacters(appStoreSave); - xml.writeEndElement(); - - if (addLauncherInfoSave != null) { - for (var li : addLauncherInfoSave) { - addLauncherInfo(xml, li); - } - } else { - List> addLaunchers = - ADD_LAUNCHERS.fetchFrom(params); - - for (var launcherParams : addLaunchers) { - var li = new LauncherInfo(launcherParams); - addLauncherInfo(xml, li); - } - } - }); - } - - static void addLauncherInfo(XMLStreamWriter xml, LauncherInfo li) - throws XMLStreamException { - xml.writeStartElement("add-launcher"); - xml.writeAttribute("name", li.getName()); - xml.writeAttribute("shortcut", Boolean.toString(li.isShortcut())); - xml.writeAttribute("menu", Boolean.toString(li.isMenu())); - xml.writeAttribute("service", Boolean.toString(li.isService())); - xml.writeEndElement(); - } - - /** - * Loads application image info from application image. - * @param appImageDir - path to application image - * @return valid info about application image or null - * @throws IOException - */ - static AppImageFile load(Path appImageDir) { - try { - Document doc = readXml(appImageDir); - - XPath xPath = XPathFactory.newInstance().newXPath(); - - String appVersion = xpathQueryNullable(xPath, - "/jpackage-state/app-version/text()", doc); - - String mainLauncher = xpathQueryNullable(xPath, - "/jpackage-state/main-launcher/text()", doc); - - String mainClass = xpathQueryNullable(xPath, - "/jpackage-state/main-class/text()", doc); - - List launcherInfos = new ArrayList<>(); - - String platform = xpathQueryNullable(xPath, - "/jpackage-state/@platform", doc); - - String version = xpathQueryNullable(xPath, - "/jpackage-state/@version", doc); - - String signedStr = xpathQueryNullable(xPath, - "/jpackage-state/signed/text()", doc); - - String appStoreStr = xpathQueryNullable(xPath, - "/jpackage-state/app-store/text()", doc); - - NodeList launcherNodes = (NodeList) xPath.evaluate( - "/jpackage-state/add-launcher", doc, - XPathConstants.NODESET); - - for (int i = 0; i != launcherNodes.getLength(); i++) { - launcherInfos.add(new LauncherInfo(launcherNodes.item(i))); - } - - return new AppImageFile(appImageDir, appVersion, mainLauncher, - mainClass, launcherInfos, version, platform, signedStr, - appStoreStr); - } catch (XPathExpressionException ex) { - // This should never happen as XPath expressions should be correct - throw new RuntimeException(ex); - } catch (NoSuchFileException nsfe) { - // non jpackage generated app-image (no app/.jpackage.xml) - throw new RuntimeException(MessageFormat.format(I18N.getString( - "error.foreign-app-image"), appImageDir)); - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - } - - /** - * Returns copy of AppImageFile, but with signed set to true if AppImageFile - * is not marked as signed. If AppImageFile already signed it will return - * instance to itself. - */ - AppImageFile copyAsSigned() { - if (isSigned()) { - return this; - } - - // Pass null for appImageDir, it is used only to show location of - // .jpackage.xml in case of error. copyAsSigned() should not produce - // invalid app image file. - return new AppImageFile(null, getAppVersion(), - getLauncherName(), getMainClass(), getAddLaunchers(), - getVersion(), getPlatform(), "true", String.valueOf(isAppStore())); - } - - static Document readXml(Path appImageDir) throws IOException { - try { - Path path = getPathInAppImage(appImageDir); - - DocumentBuilderFactory dbf = - DocumentBuilderFactory.newDefaultInstance(); - dbf.setFeature( - "http://apache.org/xml/features/nonvalidating/load-external-dtd", - false); - DocumentBuilder b = dbf.newDocumentBuilder(); - return b.parse(Files.newInputStream(path)); - } catch (ParserConfigurationException | SAXException ex) { - // Let caller sort this out - throw new IOException(ex); - } - } - - /** - * Returns list of LauncherInfo objects configured for the application. - * The first item in the returned list is main launcher. - * Following items in the list are names of additional launchers. - */ - static List getLaunchers(Path appImageDir, - Map params) { - List launchers = new ArrayList<>(); - if (appImageDir != null) { - AppImageFile appImageInfo = AppImageFile.load(appImageDir); - launchers.add(new LauncherInfo( - appImageInfo.getLauncherName(), params)); - launchers.addAll(appImageInfo.getAddLaunchers()); - return launchers; - } - - launchers.add(new LauncherInfo(params)); - ADD_LAUNCHERS.fetchFrom(params).stream() - .map(launcherParams -> new LauncherInfo(launcherParams)) - .forEach(launchers::add); - return launchers; - } - - private static String xpathQueryNullable(XPath xPath, String xpathExpr, - Document xml) throws XPathExpressionException { - NodeList nodes = (NodeList) xPath.evaluate(xpathExpr, xml, - XPathConstants.NODESET); - if (nodes != null && nodes.getLength() > 0) { - return nodes.item(0).getNodeValue(); - } - return null; - } - - static String getVersion() { - return System.getProperty("java.version"); - } - - static String getPlatform() { - return PLATFORM_LABELS.get(OperatingSystem.current()); - } - - static class LauncherInfo { - private final String name; - private final boolean shortcut; - private final boolean menu; - private final boolean service; - - private LauncherInfo(Map params) { - this(APP_NAME.fetchFrom(params), params); - } - - private LauncherInfo(String name, Map params) { - this.name = name; - this.shortcut = SHORTCUT_HINT.fetchFrom(params); - this.menu = MENU_HINT.fetchFrom(params); - this.service = LAUNCHER_AS_SERVICE.fetchFrom(params); - } - - private LauncherInfo(Node node) { - this.name = getAttribute(node, "name"); - this.shortcut = !"false".equals(getAttribute(node, "shortcut")); - this.menu = !"false".equals(getAttribute(node, "menu")); - this.service = !"false".equals(getAttribute(node, "service")); - } - - private String getAttribute(Node item, String attr) { - NamedNodeMap attrs = item.getAttributes(); - Node attrNode = attrs.getNamedItem(attr); - return ((attrNode == null) ? null : attrNode.getNodeValue()); - } - - public String getName() { - return name; - } - - public boolean isShortcut() { - return shortcut; - } - - public boolean isMenu() { - return menu; - } - - public boolean isService() { - return service; - } - } - -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java index 36255840a33d3..597848da5fa18 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -186,5 +186,4 @@ private static ApplicationLaunchers createLaunchers( } static final BundlerParamInfo APPLICATION = createApplicationBundlerParam(null); - static final BundlerParamInfo PACKAGE = createPackageBundlerParam(null); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index 8c905ba3ee6f1..bae3d4deaba5d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -67,19 +67,8 @@ final class StandardBundlerParam { "--no-man-pages", "--no-header-files"}; - static final BundlerParamInfo LAUNCHER_DATA = - new BundlerParamInfo<>( - "launcherData", - LauncherData.class, - params -> { - try { - return LauncherData.create(params); - } catch (ConfigException | IOException ex) { - throw new RuntimeException(ex); - } - }, - null - ); + static final BundlerParamInfo LAUNCHER_DATA = BundlerParamInfo.createBundlerParam( + LauncherData.class, LauncherData::create); static final BundlerParamInfo SOURCE_DIR = new BundlerParamInfo<>( @@ -107,6 +96,16 @@ final class StandardBundlerParam { null ); + static final BundlerParamInfo PREDEFINED_APP_IMAGE_FILE = BundlerParamInfo.createBundlerParam( + AppImageFile2.class, params -> { + if (hasPredefinedAppImage(params)) { + var appImage = getPredefinedAppImage(params); + return AppImageFile2.load(appImage, PLATFORM_APPLICATION_LAYOUT); + } else { + return null; + } + }); + static final BundlerParamInfo MAIN_CLASS = new BundlerParamInfo<>( Arguments.CLIOptions.APPCLASS.getId(), @@ -115,9 +114,7 @@ final class StandardBundlerParam { if (isRuntimeInstaller(params)) { return null; } else if (hasPredefinedAppImage(params)) { - var appImage = getPredefinedAppImage(params); - return toBiFunction(AppImageFile2::load).apply( - appImage, PLATFORM_APPLICATION_LAYOUT).getMainClass(); + PREDEFINED_APP_IMAGE_FILE.fetchFrom(params).getMainClass(); } return LAUNCHER_DATA.fetchFrom(params).qualifiedClassName(); }, @@ -155,12 +152,9 @@ final class StandardBundlerParam { "application-name", String.class, params -> { - Path appImage = PREDEFINED_APP_IMAGE.fetchFrom(params); String appName = NAME.fetchFrom(params); - if (appImage != null) { - String name = toBiFunction(AppImageFile2::load).apply( - appImage, PLATFORM_APPLICATION_LAYOUT).getLauncherName(); - appName = (name != null) ? name : appName; + if (hasPredefinedAppImage(params)) { + appName = PREDEFINED_APP_IMAGE_FILE.fetchFrom(params).getLauncherName(); } else if (appName == null) { String s = MAIN_CLASS.fetchFrom(params); if (s != null) { @@ -527,22 +521,6 @@ private static Path findPathOfModule( List modulePath, String moduleName) null : Boolean.valueOf(s) ); - static final BundlerParamInfo APP_STORE = - new BundlerParamInfo<>( - Arguments.CLIOptions.MAC_APP_STORE.getId(), - Boolean.class, - params -> { - if (hasPredefinedAppImage(params)) { - return AppImageFile.load(getPredefinedAppImage(params)) - .isAppStore(); - } - return false; - }, - // valueOf(null) is false, we actually do want null in some cases - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? - null : Boolean.valueOf(s) - ); - static boolean isRuntimeInstaller(Map params) { if (params.containsKey(MODULE.getID()) || params.containsKey(MAIN_JAR.getID()) || @@ -572,8 +550,13 @@ static Path getPredefinedAppImage(Map params) { static OverridableResource createResource(String defaultName, Map params) { - return new OverridableResource(defaultName, ResourceLocator.class).setResourceDir( - RESOURCE_DIR.fetchFrom(params)); + final OverridableResource resource; + if (defaultName == null) { + resource = new OverridableResource(); + } else { + resource = new OverridableResource(defaultName, ResourceLocator.class); + } + return resource.setResourceDir(RESOURCE_DIR.fetchFrom(params)); } private static String getDefaultAppVersion(Map params) { diff --git a/src/jdk.jpackage/share/classes/module-info.java b/src/jdk.jpackage/share/classes/module-info.java index ea41abd75d832..e5cd2cb3f9548 100644 --- a/src/jdk.jpackage/share/classes/module-info.java +++ b/src/jdk.jpackage/share/classes/module-info.java @@ -53,7 +53,7 @@ module jdk.jpackage { requires jdk.internal.opt; requires jdk.jlink; - + requires java.naming; requires java.desktop; uses jdk.jpackage.internal.Bundler; diff --git a/test/jdk/tools/jpackage/share/BasicTest.java b/test/jdk/tools/jpackage/share/BasicTest.java index d479f4a35d084..f21c181a7cab5 100644 --- a/test/jdk/tools/jpackage/share/BasicTest.java +++ b/test/jdk/tools/jpackage/share/BasicTest.java @@ -45,7 +45,7 @@ import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.internal.util.function.ThrowingConsumer; -import jdk.tools.jlink.internal.LinkableRuntimeImage; +//import jdk.tools.jlink.internal.LinkableRuntimeImage; import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE_AND_UNPACK; /* @@ -60,6 +60,12 @@ public final class BasicTest { + private static class LinkableRuntimeImage { + static boolean isLinkableRuntime() { + return false; + } + } + public static Collection addModulesParams() { List params = new ArrayList<>(); params.add(new Object[][] { new String[] { "--add-modules", "ALL-DEFAULT" } }); From 10970d20245ccfdb2ce155e38291ed02ad89e8f4 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 22 Jan 2025 19:50:18 -0500 Subject: [PATCH 0250/1101] Rename AppImageFile2 into AppImageFile --- .../internal/LinuxPackageBundler.java | 2 +- .../internal/MacAppImageFileExtras.java | 4 +-- .../jpackage/internal/AppImageBuilder.java | 2 +- .../{AppImageFile2.java => AppImageFile.java} | 12 +++---- .../jpackage/internal/ApplicationBuilder.java | 4 +-- .../jdk/jpackage/internal/FromParams.java | 2 +- .../internal/StandardBundlerParam.java | 6 ++-- .../internal/WixAppImageFragmentBuilder.java | 2 +- .../jpackage/internal/AppImageFileTest.java | 32 +++++++++---------- 9 files changed, 33 insertions(+), 33 deletions(-) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{AppImageFile2.java => AppImageFile.java} (97%) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 64cb04ae82198..6addb9a349c08 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -133,7 +133,7 @@ public final Path execute(Map params, if (srcLayout instanceof ApplicationLayout appLayout) { // Copy app layout omitting application image info file. - srcLayoutPathGroup.ghostPath(AppImageFile2.getPathInAppImage(appLayout)); + srcLayoutPathGroup.ghostPath(AppImageFile.getPathInAppImage(appLayout)); } srcLayoutPathGroup.copy(AppImageLayout.toPathGroup( diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java index 742f1940e25f5..4e8a1bdffafce 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java @@ -24,13 +24,13 @@ */ package jdk.jpackage.internal; -import static jdk.jpackage.internal.AppImageFile2.getBooleanExtraFieldValue; +import static jdk.jpackage.internal.AppImageFile.getBooleanExtraFieldValue; import jdk.jpackage.internal.model.MacApplication.ExtraAppImageFileField; record MacAppImageFileExtras(boolean signed) { - MacAppImageFileExtras(AppImageFile2 appImageFile) { + MacAppImageFileExtras(AppImageFile appImageFile) { this(getBooleanExtraFieldValue(ExtraAppImageFileField.SIGNED.fieldName(), appImageFile)); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java index d0b2daaf30e02..92e5e6def5a6a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java @@ -271,7 +271,7 @@ private static AppImageItem createRuntimeAppImageItem() { private static AppImageItem createAppImageFileAppImageItem() { return (env, app, appLayout) -> { - new AppImageFile2(app).save(appLayout); + new AppImageFile(app).save(appLayout); }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java similarity index 97% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index 62ef3a2d96a9f..806a9d7360669 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile2.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -55,13 +55,13 @@ import org.xml.sax.SAXException; -final class AppImageFile2 { +final class AppImageFile { - AppImageFile2(Application app) { + AppImageFile(Application app) { this(new ApplicationData(app)); } - private AppImageFile2(ApplicationData app) { + private AppImageFile(ApplicationData app) { appVersion = app.version(); launcherName = app.mainLauncherName(); @@ -171,7 +171,7 @@ static Path getPathInAppImage(ApplicationLayout appLayout) { * @param appImageDir - path at which to resolve the given application layout * @param appLayout - application layout */ - static AppImageFile2 load(Path appImageDir, ApplicationLayout appLayout) throws ConfigException, IOException { + static AppImageFile load(Path appImageDir, ApplicationLayout appLayout) throws ConfigException, IOException { var srcFilePath = getPathInAppImage(appLayout.resolveAt(appImageDir)); try { final Document doc = XmlUtils.initDocumentBuilder().parse(Files.newInputStream(srcFilePath)); @@ -206,7 +206,7 @@ static AppImageFile2 load(Path appImageDir, ApplicationLayout appLayout) throws } }).toList(); - return new AppImageFile2(new ApplicationData(props.get("app-version"), props.get("main-launcher"), + return new AppImageFile(new ApplicationData(props.get("app-version"), props.get("main-launcher"), props.get("main-class"), props.getExtra(), additionalLaunchers)); } catch (XPathExpressionException ex) { @@ -223,7 +223,7 @@ static AppImageFile2 load(Path appImageDir, ApplicationLayout appLayout) throws } } - static boolean getBooleanExtraFieldValue(String fieldId, AppImageFile2 appImageFile) { + static boolean getBooleanExtraFieldValue(String fieldId, AppImageFile appImageFile) { Objects.requireNonNull(fieldId); Objects.requireNonNull(appImageFile); return Optional.ofNullable(appImageFile.getExtra().get(fieldId)).map(Boolean::parseBoolean).orElse(false); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index d9fa8fcbd0010..2dfc421638ebb 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -33,7 +33,7 @@ import java.util.Objects; import java.util.Optional; import java.util.function.Function; -import jdk.jpackage.internal.AppImageFile2.LauncherInfo; +import jdk.jpackage.internal.AppImageFile.LauncherInfo; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLaunchers; @@ -83,7 +83,7 @@ ApplicationBuilder runtimeBuilder(RuntimeBuilder v) { return this; } - ApplicationBuilder initFromAppImage(AppImageFile2 appImageFile, + ApplicationBuilder initFromAppImage(AppImageFile appImageFile, Function mapper) { if (version == null) { version = appImageFile.getAppVersion(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java index 597848da5fa18..e66e6da114769 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -57,7 +57,7 @@ import java.util.Map; import java.util.Optional; import java.util.function.Function; -import jdk.jpackage.internal.AppImageFile2.LauncherInfo; +import jdk.jpackage.internal.AppImageFile.LauncherInfo; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLaunchers; import jdk.jpackage.internal.model.ApplicationLayout; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index bae3d4deaba5d..17b55ead23ad8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -96,11 +96,11 @@ final class StandardBundlerParam { null ); - static final BundlerParamInfo PREDEFINED_APP_IMAGE_FILE = BundlerParamInfo.createBundlerParam( - AppImageFile2.class, params -> { + static final BundlerParamInfo PREDEFINED_APP_IMAGE_FILE = BundlerParamInfo.createBundlerParam( + AppImageFile.class, params -> { if (hasPredefinedAppImage(params)) { var appImage = getPredefinedAppImage(params); - return AppImageFile2.load(appImage, PLATFORM_APPLICATION_LAYOUT); + return AppImageFile.load(appImage, PLATFORM_APPLICATION_LAYOUT); } else { return null; } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index c125868d29f71..fa21928899099 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -201,7 +201,7 @@ private void initAppImageLayouts(AppImageLayout appImageLayout, Path appImageRoo if (srcAppImageLayout instanceof ApplicationLayout appLayout) { // Don't want app image info file in installed application. - var appImageFile = AppImageFile2.getPathInAppImage(appLayout); + var appImageFile = AppImageFile.getPathInAppImage(appLayout); appImagePathGroup.ghostPath(appImageFile); installedAppImage = (ApplicationLayout)installedAppImageLayout; diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java index 0769d42dcd5ff..09456abe58478 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java @@ -39,7 +39,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.AppImageFile2.LauncherInfo; +import jdk.jpackage.internal.AppImageFile.LauncherInfo; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLaunchers; import jdk.jpackage.internal.model.ApplicationLayout; @@ -106,7 +106,7 @@ AppImageBuilder addlauncher(String name, Map extra) { return addlauncher(name, false, extra); } - AppImageFile2 create() { + AppImageFile create() { final var additionalLaunchers = addLauncherInfos.stream().map(li -> { return (Launcher)new Launcher.Stub(li.name(), Optional.empty(), List.of(), li.service(), null, Optional.empty(), null, li.extra()); @@ -120,14 +120,14 @@ AppImageFile2 create() { Optional.empty(), List.of(), null, Optional.empty(), new ApplicationLaunchers(mainLauncher, additionalLaunchers).asList(), extra); - return new AppImageFile2(app); + return new AppImageFile(app); } void createInDir(Path dir) { final var file = create(); final var copy = toSupplier(() -> { file.save(DUMMY_LAYOUT.resolveAt(dir)); - return AppImageFile2.load(dir, DUMMY_LAYOUT); + return AppImageFile.load(dir, DUMMY_LAYOUT); }).get(); assertEquals(file, copy); @@ -183,7 +183,7 @@ private static Stream> testInavlidXml() { @ParameterizedTest @MethodSource - public void testValidXml(AppImageFile2 expected, List xmlData) throws IOException, ConfigException { + public void testValidXml(AppImageFile expected, List xmlData) throws IOException, ConfigException { final var actual = createFromXml(xmlData); assertEquals(expected, actual); } @@ -234,8 +234,8 @@ private static Stream testValidXml() { ); } - private AppImageFile2 createFromXml(List xmlData) throws IOException, ConfigException { - Path path = AppImageFile2.getPathInAppImage(DUMMY_LAYOUT.resolveAt(tempFolder)); + private AppImageFile createFromXml(List xmlData) throws IOException, ConfigException { + Path path = AppImageFile.getPathInAppImage(DUMMY_LAYOUT.resolveAt(tempFolder)); path.toFile().mkdirs(); Files.delete(path); @@ -246,20 +246,20 @@ private AppImageFile2 createFromXml(List xmlData) throws IOException, Co Files.write(path, data, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); - AppImageFile2 image = AppImageFile2.load(tempFolder, DUMMY_LAYOUT); + AppImageFile image = AppImageFile.load(tempFolder, DUMMY_LAYOUT); return image; } - private static void assertEquals(AppImageFile2 expected, AppImageFile2 actual) { - assertPropertyEquals(expected, actual, AppImageFile2::getAppVersion); - assertPropertyEquals(expected, actual, AppImageFile2::getLauncherName); - assertPropertyEquals(expected, actual, AppImageFile2::getMainClass); - assertPropertyEquals(expected, actual, AppImageFile2::getExtra); + private static void assertEquals(AppImageFile expected, AppImageFile actual) { + assertPropertyEquals(expected, actual, AppImageFile::getAppVersion); + assertPropertyEquals(expected, actual, AppImageFile::getLauncherName); + assertPropertyEquals(expected, actual, AppImageFile::getMainClass); + assertPropertyEquals(expected, actual, AppImageFile::getExtra); Assertions.assertEquals(additionaLaunchersAsMap(expected), additionaLaunchersAsMap(actual)); } - private static Map additionaLaunchersAsMap(AppImageFile2 file) { - return file.getAddLaunchers().stream().collect(Collectors.toMap(AppImageFile2.LauncherInfo::name, x -> x)); + private static Map additionaLaunchersAsMap(AppImageFile file) { + return file.getAddLaunchers().stream().collect(Collectors.toMap(AppImageFile.LauncherInfo::name, x -> x)); } private static void assertPropertyEquals(T expected, T actual, Function getProperty) { @@ -268,7 +268,7 @@ private static void assertPropertyEquals(T expected, T actual, Function createXml(String ...xml) { final List content = new ArrayList<>(); - content.add(String.format("", AppImageFile2.getPlatform(), AppImageFile2.getVersion())); + content.add(String.format("", AppImageFile.getPlatform(), AppImageFile.getVersion())); content.addAll(List.of(xml)); content.add(""); return content; From 2f64f7bbfa9e5108824ac2051cb000da554a12b3 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 23 Jan 2025 12:12:31 -0500 Subject: [PATCH 0251/1101] Order packaging tests by packaging type. Helps to produce stable test logs --- .../jdk/jpackage/test/PackageTest.java | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index fd6d5e2da6bc7..e3dcdd8cba781 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,12 +29,12 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.ListIterator; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; @@ -393,23 +393,13 @@ protected void runAction(Action... action) { } private List> createPackageTypeHandlers() { - return NATIVE.stream() - .map(type -> { - Handler handler = handlers.entrySet().stream() - .filter(entry -> !entry.getValue().isVoid()) - .filter(entry -> entry.getKey() == type) - .map(entry -> entry.getValue()) - .findAny().orElse(null); - Map.Entry result = null; - if (handler != null) { - result = Map.entry(type, handler); - } - return result; - }) - .filter(Objects::nonNull) - .map(entry -> createPackageTypeHandler( - entry.getKey(), entry.getValue())) - .collect(Collectors.toList()); + return handlers.entrySet().stream() + .filter(entry -> !entry.getValue().isVoid()) + .filter(entry -> NATIVE.contains(entry.getKey())) + .sorted(Comparator.comparing(Map.Entry::getKey)) + .map(entry -> { + return createPackageTypeHandler(entry.getKey(), entry.getValue()); + }).toList(); } private Consumer createPackageTypeHandler( From 29438b540b5303a17369bd4928c71ec91f3b385b Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 24 Jan 2025 23:23:59 -0500 Subject: [PATCH 0252/1101] Initial version of async action pipeline --- .../jpackage/internal/pipeline/Action.java | 38 +++ .../internal/pipeline/ActionException.java | 35 +++ .../internal/pipeline/ActionGraph.java | 93 +++++++ .../pipeline/ActionPipelineBuilder.java | 232 ++++++++++++++++++ .../internal/pipeline/ConditionalAction.java | 44 ++++ .../jpackage/internal/pipeline/Context.java | 29 +++ .../internal/pipeline/CycleException.java | 24 ++ .../internal/pipeline/DirectedEdge.java | 49 ++++ .../internal/pipeline/DirectedEdgeUtils.java | 116 +++++++++ .../internal/pipeline/ActionGraphTest.java | 118 +++++++++ .../pipeline/ActionPipelineBuilderTest.java | 144 +++++++++++ .../pipeline/DirectedEdgeUtilsTest.java | 157 ++++++++++++ 12 files changed, 1079 insertions(+) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Action.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionException.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionGraph.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ConditionalAction.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Context.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CycleException.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdge.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdgeUtils.java create mode 100644 test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionGraphTest.java create mode 100644 test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java create mode 100644 test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeUtilsTest.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Action.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Action.java new file mode 100644 index 0000000000000..ef0bccf9e3d2f --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Action.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import java.util.function.Predicate; + +@FunctionalInterface +public interface Action { + + void execute(T context) throws ActionException; + + static Action createConditionalAction(Predicate predicate, Action action) { + return new ConditionalAction<>(action, predicate); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionException.java new file mode 100644 index 0000000000000..91b9cf1d8533a --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionException.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.pipeline; + +public class ActionException extends Exception { + + private static final long serialVersionUID = 1L; + + public ActionException(Throwable cause) { + super(cause); + } + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionGraph.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionGraph.java new file mode 100644 index 0000000000000..3548a4acc355a --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionGraph.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static java.util.stream.Collectors.toSet; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * A directed acyclic (supposedly) graph. + * + * @see https://en.wikipedia.org/wiki/Directed_acyclic_graph + */ +final class ActionGraph { + + void addEdge(T from, T to) { + edges.add(DirectedEdge.create(from, to)); + } + + // TBD: Implement transient reduction + + Set getNodeDependencies(T node) { + return DirectedEdgeUtils.getEdgesTo(node, edges).stream().map(DirectedEdge::from).collect(toSet()); + } + + List topologicalSort() throws CycleException { + final Set> edgesCopy = new HashSet<>(edges); + + // Kahn's algorithm from https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm + // Variable names picked from the algorithm pseudo-code. + + // Empty list that will contain the sorted elements. + final List L = new ArrayList<>(); + + // Set of all nodes with no incoming edge. + var S = DirectedEdgeUtils.getNoIncomingEdgeNodes(edgesCopy, HashSet::new); + + do { + final Set newS = new HashSet<>(); + + for (final var n : S) { + L.add(n); + for (final var e : DirectedEdgeUtils.getEdgesFrom(n, edgesCopy)) { + edgesCopy.remove(e); + final var m = e.to(); + if (DirectedEdgeUtils.getEdgesTo(m, edgesCopy).isEmpty()) { + newS.add(m); + } + } + } + + S = newS; + + } while(!S.isEmpty()); + + if (!edgesCopy.isEmpty()) { + // Graph has at least one cycle. + throw new CycleException(DirectedEdgeUtils.getNodes(edgesCopy)); + } else { + // A topologically sorted order. + return Collections.unmodifiableList(L); + } + } + + final Set> edges = new HashSet<>(); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java new file mode 100644 index 0000000000000..35b68b4e0473f --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import jdk.jpackage.internal.util.function.ExceptionBox; + +public final class ActionPipelineBuilder { + + ActionPipelineBuilder() { + rootAction = new RootAction<>(); + actions = new HashSet<>(); + actions.add(rootAction); + actionGraph = new ActionGraph<>(); + } + + public final class ActionSpecBuilder { + + ActionSpecBuilder(Action action) { + Objects.requireNonNull(action); + this.action = action; + } + + public ActionSpecBuilder dependent(Action v) { + dependent = v; + return this; + } + + public ActionSpecBuilder addDependency(Action v) { + Objects.requireNonNull(v); + dependencies.add(v); + return this; + } + + public ActionSpecBuilder addDependencies(Collection> v) { + Objects.requireNonNull(v); + v.forEach(Objects::requireNonNull); + dependencies.addAll(v); + return this; + } + + public ActionPipelineBuilder add() { + actionGraph.addEdge(action, validatedDependent()); + + actions.add(action); + actions.addAll(dependencies); + dependencies.forEach(dependency -> { + actionGraph.addEdge(dependency, action); + }); + + return ActionPipelineBuilder.this; + } + + @SuppressWarnings("unchecked") + private Action validatedDependent() { + if (dependent == null) { + return rootAction; + } else { + if (!actions.contains(dependent)) { + throw new IllegalArgumentException("Unknown dependent action"); + } + return dependent; + } + } + + private Set> dependencies = new LinkedHashSet<>(); + private Action dependent; + private final Action action; + } + + public ActionSpecBuilder action(Action action) { + return new ActionSpecBuilder(action); + } + + public ActionPipelineBuilder executor(Executor v) { + Objects.requireNonNull(v); + executor = v; + return this; + } + + public ActionPipelineBuilder sequentialExecutor() { + executor = Executors.newSingleThreadExecutor(); + return this; + } + + public Action create() { + final List> orderedActions; + + try { + orderedActions = actionGraph.topologicalSort(); + } catch (CycleException ex) { + throw new UnsupportedOperationException(ex); + } + + final var dependentActions = orderedActions.stream().map(action -> { + final var dependencies = actionGraph.getNodeDependencies(action); + return new DependentAction(action, dependencies); + }).toList(); + + return new Impl<>(dependentActions, executor); + } + + private record DependentAction(Action action, Set> dependencies) { + + DependentAction { + Objects.requireNonNull(action); + Objects.requireNonNull(dependencies); + dependencies.forEach(Objects::requireNonNull); + } + } + + private record RunnableAdapter(Action action, U context, + Optional> dependenciesFuture) implements Runnable { + + RunnableAdapter { + Objects.requireNonNull(action); + Objects.requireNonNull(context); + Objects.requireNonNull(dependenciesFuture); + } + + @Override + public void run() { + try { + dependenciesFuture.ifPresent(CompletableFuture::join); + } catch (CancellationException|CompletionException ex) { + return; + } + + try { + action.execute(context); + } catch (ActionException ex) { + throw ExceptionBox.rethrowUnchecked(ex); + } + } + } + + private record Impl(List> dependentActions, Executor executor) implements Action { + + Impl { + Objects.requireNonNull(dependentActions); + dependentActions.forEach(Objects::requireNonNull); + Objects.requireNonNull(executor); + } + + @Override + public void execute(U context) throws ActionException { + final var rootAction = scheduleActions(context); + rootAction.join(); + } + + private CompletableFuture scheduleActions(U context) { + + final Map, CompletableFuture> scheduledActions = new HashMap<>(); + + CompletableFuture rootAction = null; + for (final var dependentAction : dependentActions) { + final Optional> dependenciesFuture; + if (dependentAction.dependencies().isEmpty()) { + dependenciesFuture = Optional.empty(); + } else { + final var dependencyFutures = dependentAction.dependencies().stream() + .map(scheduledActions::get) + .toArray(CompletableFuture[]::new); + dependenciesFuture = Optional.of(CompletableFuture.allOf(dependencyFutures)); + } + + final var actionAsRunnable = new RunnableAdapter<>(dependentAction.action(), context, dependenciesFuture); + + rootAction = CompletableFuture.runAsync(actionAsRunnable, executor); + + scheduledActions.put(dependentAction.action(), rootAction); + } + + return rootAction; + } + } + + private static class RootAction implements Action { + + @Override + public void execute(U context) throws ActionException { + } + + @Override + public String toString() { + return String.format("%s(root)", super.toString()); + } + } + + private final Action rootAction; + private final Set> actions; + private final ActionGraph> actionGraph; + + private Executor executor; + +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ConditionalAction.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ConditionalAction.java new file mode 100644 index 0000000000000..71da034a02cd0 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ConditionalAction.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import java.util.Objects; +import java.util.function.Predicate; + +record ConditionalAction(Action action, Predicate predicate) implements Action { + + ConditionalAction { + Objects.requireNonNull(action); + Objects.requireNonNull(predicate); + } + + @Override + public void execute(T context) throws ActionException { + if (predicate.test(context)) { + action.execute(context); + } + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Context.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Context.java new file mode 100644 index 0000000000000..749c24c70409c --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Context.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +public interface Context { +} \ No newline at end of file diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CycleException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CycleException.java new file mode 100644 index 0000000000000..cf79150186714 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CycleException.java @@ -0,0 +1,24 @@ +package jdk.jpackage.internal.pipeline; + +import java.util.Objects; +import java.util.Set; + +public final class CycleException extends Exception { + + CycleException(Set cycle) { + Objects.requireNonNull(cycle); + if (cycle.isEmpty()) { + throw new IllegalArgumentException("Empty cyclic nodes"); + } + + this.cycle = cycle; + } + + Set getCycleNodes() { + return cycle; + } + + private final Set cycle; + + private static final long serialVersionUID = 1L; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdge.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdge.java new file mode 100644 index 0000000000000..7425e3c4b8648 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdge.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import java.util.Objects; +import java.util.stream.Stream; + +record DirectedEdge(T from, T to) { + + DirectedEdge { + Objects.requireNonNull(from); + Objects.requireNonNull(to); + + if (from.equals(to)) { + throw new IllegalArgumentException("Same node"); + } + } + + static DirectedEdge create(U from, U to) { + return new DirectedEdge(from, to); + } + + Stream asStream() { + return Stream.of(from, to); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdgeUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdgeUtils.java new file mode 100644 index 0000000000000..cbe157e22b09f --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdgeUtils.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static java.util.stream.Collectors.toCollection; +import static java.util.stream.Collectors.toSet; + +import java.util.Collection; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; + +final class DirectedEdgeUtils { + + static Set getNodes(Collection> edges) { + return getNodes(edges, Optional.empty()); + } + + static Set getNodes(Collection> edges, Supplier> collectionCtor) { + return getNodes(edges, Optional.of(collectionCtor)); + } + + static Set getNoIncomingEdgeNodes(Collection> edges) { + return getNoIncomingEdgeNodes(edges, Optional.empty()); + } + + static Set getNoIncomingEdgeNodes(Collection> edges, Supplier> collectionCtor) { + return getNoIncomingEdgeNodes(edges, Optional.of(collectionCtor)); + } + + static Collection> getEdgesTo(T node, Collection> edges) { + return getEdgesTo(node, edges, Optional.empty()); + } + + static Collection> getEdgesTo(T node, Collection> edges, + Supplier>> collectionCtor) { + return getEdgesTo(node, edges, Optional.of(collectionCtor)); + } + + static Collection> getEdgesFrom(T node, Collection> edges) { + return getEdgesFrom(node, edges, Optional.empty()); + } + + static Collection> getEdgesFrom(T node, Collection> edges, + Supplier>> collectionCtor) { + return getEdgesFrom(node, edges, Optional.of(collectionCtor)); + } + + private static Set getNodes(Collection> edges, Optional>> collectionCtor) { + return collectToSet(edges.parallelStream().flatMap(DirectedEdge::asStream), collectionCtor); + } + + private static Collection> getEdgesTo(T node, Collection> edges, + Optional>>> collectionCtor) { + return filterEdges(node, edges, DirectedEdge::to, collectionCtor); + } + + private static Collection> getEdgesFrom(T node, Collection> edges, + Optional>>> collectionCtor) { + return filterEdges(node, edges, DirectedEdge::from, collectionCtor); + } + + private static Set getNoIncomingEdgeNodes(Collection> edges, Optional>> collectionCtor) { + final Set noIncomingEdgeNodes = getNodes(edges, collectionCtor); + final var incomingEdgeNodes = edges.parallelStream().map(DirectedEdge::to).collect(toSet()); + noIncomingEdgeNodes.removeAll(incomingEdgeNodes); + return noIncomingEdgeNodes; + } + + private static Set collectToSet(Stream stream, Optional>> collectionCtor) { + return collectionCtor.map(ctor -> stream.collect(toCollection(ctor))).orElseGet(() -> { + return stream.collect(toSet()); + }); + } + + private static Collection collect(Stream stream, Optional>> collectionCtor) { + return collectionCtor.map(ctor -> stream.collect(toCollection(ctor))).orElseGet(() -> { + return stream.toList(); + }); + } + + private static Collection> filterEdges(T node, Collection> edges, + Function, T> getNode, Optional>>> collectionCtor) { + Objects.requireNonNull(node); + Objects.requireNonNull(getNode); + return collect(edges.parallelStream().filter(edge -> { + return getNode.apply(edge).equals(node); + }), collectionCtor); + } +} diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionGraphTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionGraphTest.java new file mode 100644 index 0000000000000..f414af7bef6e9 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionGraphTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +final class ActionGraphTest { + + @Test + public void testCyclicDependenciesSimple() { + assertThrows(IllegalArgumentException.class, () -> addEdge(A, A)); + } + + @ParameterizedTest + @MethodSource + public void testCyclicDependencies(List> edges, Set expectedCycleNodes) { + edges.forEach(this::addEdge); + final var ex = assertThrows(CycleException.class, graph::topologicalSort); + assertEquals(expectedCycleNodes, ex.getCycleNodes()); + } + + private static Stream testCyclicDependencies() { + return Stream.of( + // A <- B <- C + // | + // + <- C <- B + new Object[] { List.of(edge(B, A), edge(C, B), edge(C, A), edge(B, C)), Set.of(A, B, C) }, + + // A <- B <- D + // | + // + <- D <- C + // | + // + <- L <- B + new Object[] { List.of(edge(B, A), edge(D, B), edge(D, A), edge(C, D), edge(L, D), edge(B, L)), Set.of(A, B, D, L) } + ); + } + + @ParameterizedTest + @MethodSource + public void testTopologicalSort(List> edges, List expectedNodes) throws CycleException { + edges.forEach(this::addEdge); + final var actualNodes = graph.topologicalSort(); + assertEquals(expectedNodes, actualNodes); + } + + private static Stream testTopologicalSort() { + return Stream.of( + // A <- B <- C + // | + // + <- D <- B <- K <- C + // | + // + <- K + new Object[] { List.of(edge(B, A), edge(C, B), edge(D, A), edge(K, D), edge(B, D), edge(K, B), edge(C, K)), List.of(C, K, B, D, A) }, + + // A <- B <- C <- K + // | + // + <- D <- B <- K + // | + // + <- K + new Object[] { List.of(edge(B, A), edge(C, B), edge(D, A), edge(K, D), edge(B, D), edge(K, B), edge(K, C)), List.of(K, C, B, D, A) }, + + // D <- C <- B <- A + // | + // + <- A + new Object[] { List.of(edge(A, B), edge(B, C), edge(C, D), edge(A, D)), List.of(A, B, C, D) } + ); + } + + private static DirectedEdge edge(String from, String to) { + return DirectedEdge.create(from, to); + } + + private void addEdge(String from, String to) { + graph.addEdge(from, to); + } + + private void addEdge(DirectedEdge edge) { + graph.addEdge(edge.from(), edge.to()); + } + + private final ActionGraph graph = new ActionGraph<>(); + + private final static String A = "A"; + private final static String B = "B"; + private final static String C = "C"; + private final static String D = "D"; + private final static String K = "K"; + private final static String L = "L"; +} diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java new file mode 100644 index 0000000000000..e1face96664ae --- /dev/null +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static java.util.stream.Collectors.joining; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.locks.LockSupport; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +final class ActionPipelineBuilderTest { + + record TestContext(StringBuffer sb) implements Context { + } + + enum TestAction implements Action { + A, + B, + C, + D, + K, + L; + + @Override + public void execute(TestContext context) throws ActionException { + LockSupport.parkNanos(Duration.ofMillis(100).toNanos()); + context.sb().append(name()); + System.out.println(String.format("[%s] append=[%s]; result=[%s]", Thread.currentThread(), name(), context.sb)); + } + } + + record ActionSpec(TestAction action, List dependencies, TestAction dependent) { + } + + private final static class ActionSpecBuilder { + + ActionSpecBuilder(TestAction action) { + this.action = Objects.requireNonNull(action); + } + + ActionSpecBuilder to(TestAction action) { + dependent = action; + return this; + } + + ActionSpecBuilder from(TestAction ... actions) { + dependencies.addAll(List.of(actions)); + return this; + } + + ActionSpec create() { + return new ActionSpec(action, dependencies, dependent); + } + + private final TestAction action; + private final List dependencies = new ArrayList<>(); + private TestAction dependent; + } + + @ParameterizedTest + @MethodSource("testData") + public void testSequential(List actionSpecs, String expectedString) throws ActionException { + testIt(new ForkJoinPool(1), actionSpecs, expectedString); + } + + @ParameterizedTest + @MethodSource("testData") + public void testParallel(List actionSpecs, String expectedString) throws ActionException { + testIt(new ForkJoinPool(2), actionSpecs, expectedString); + } + + private void testIt(ForkJoinPool fjp, List actionSpecs, String expectedString) throws ActionException { + final var builder = new ActionPipelineBuilder(); + builder.executor(fjp); + + actionSpecs.forEach(actionSpec -> { + builder.action(actionSpec.action).addDependencies(actionSpec.dependencies).dependent(actionSpec.dependent).add(); + }); + + final var context = new TestContext(new StringBuffer()); + + System.out.println("Execution started"); + builder.create().execute(context); + System.out.println("Execution ended"); + + assertEquals(expectedString, context.sb.toString()); + } + + private static Stream testData() { + return Stream.of( + new Object[] { List.of(action(A).create()), "A" }, + new Object[] { List.of(action(B).from(A).create()), "AB" }, + + // D <- C <- B <- A + // | + // + <- A + new Object[] { List.of(action(D).create(), action(C).from(B).to(D).create(), action(A).to(B).create(), action(A).to(D).create()), "ABCD" }, + + new Object[] { Stream.of(TestAction.values()) + .map(ActionPipelineBuilderTest::action) + .map(ActionSpecBuilder::create).toList(), Stream.of(TestAction.values()).map(Enum::name).collect(joining()) } + ); + } + + private static ActionSpecBuilder action(TestAction action) { + return new ActionSpecBuilder(action); + } + + private final static TestAction A = TestAction.A; + private final static TestAction B = TestAction.B; + private final static TestAction C = TestAction.C; + private final static TestAction D = TestAction.D; + private final static TestAction K = TestAction.K; + private final static TestAction L = TestAction.L; +} diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeUtilsTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeUtilsTest.java new file mode 100644 index 0000000000000..8cbe9deb125b4 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeUtilsTest.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +final class DirectedEdgeUtilsTest { + + @ParameterizedTest + @MethodSource + public void testGetNodes(List> edges, Set expectedNodes) { + final var actualNodes = DirectedEdgeUtils.getNodes(edges); + + assertEquals(expectedNodes, actualNodes); + + assertEquals(expectedNodes, DirectedEdgeUtils.getNodes(edges, HashSet::new)); + assertEquals(expectedNodes, DirectedEdgeUtils.getNodes(edges, LinkedHashSet::new)); + } + + private static Stream testGetNodes() { + return Stream.of( + new Object[] { List.of(edge(A, B)), Set.of(A, B) }, + new Object[] { List.of(edge(A, B), edge(A, B)), Set.of(A, B) }, + new Object[] { List.of(edge(A, B), edge(B, A)), Set.of(A, B) }, + new Object[] { List.of(edge(A, B), edge(D, B)), Set.of(A, B, D) } + ); + } + + @ParameterizedTest + @MethodSource + public void testGetNoIncomingEdgeNodes(List> edges, Set expectedNodes) { + final var actualNodes = DirectedEdgeUtils.getNoIncomingEdgeNodes(edges); + + assertEquals(expectedNodes, actualNodes); + + assertEquals(expectedNodes, DirectedEdgeUtils.getNoIncomingEdgeNodes(edges, HashSet::new)); + assertEquals(expectedNodes, DirectedEdgeUtils.getNoIncomingEdgeNodes(edges, LinkedHashSet::new)); + } + + private static Stream testGetNoIncomingEdgeNodes() { + return Stream.of( + new Object[] { List.of(edge(A, B)), Set.of(A) }, + new Object[] { List.of(edge(A, B), edge(A, B)), Set.of(A) }, + new Object[] { List.of(edge(A, B), edge(B, A)), Set.of() }, + new Object[] { List.of(edge(A, B), edge(D, B)), Set.of(A, D) }, + // A <- B <- D + // | + // + <- D <- C + // | + // + <- L <- B + new Object[] { List.of(edge(B, A), edge(D, B), edge(D, A), edge(C, D), edge(L, D), edge(B, L)), Set.of(C) } + ); + } + + @ParameterizedTest + @MethodSource + public void testGetEdgesTo(String node, List> edges, List> expectedEdges) { + final var actualEdges = DirectedEdgeUtils.getEdgesTo(node, edges); + + if (expectedEdges == SAME_LIST) { + expectedEdges = edges; + } + + assertEqualsSorted(expectedEdges, actualEdges); + + assertEqualsSorted(expectedEdges, DirectedEdgeUtils.getEdgesTo(node, edges, ArrayList::new)); + assertEqualsSorted(new LinkedHashSet<>(expectedEdges), DirectedEdgeUtils.getEdgesTo(node, edges, HashSet::new)); + } + + private static Stream testGetEdgesTo() { + return Stream.of( + new Object[] { A, List.of(edge(A, B)), List.of() }, + new Object[] { B, List.of(edge(A, B)), SAME_LIST }, + new Object[] { B, List.of(edge(A, B), edge(A, B)), SAME_LIST }, + new Object[] { B, List.of(edge(A, B), edge(B, C)), List.of(edge(A, B)) }, + new Object[] { B, List.of(edge(A, B), edge(B, C), edge(C, D)), List.of(edge(A, B)) }, + new Object[] { B, List.of(edge(A, B), edge(A, C), edge(D, B)), List.of(edge(A, B), edge(D, B)) } + ); + } + + @ParameterizedTest + @MethodSource + public void testGetEdgesFrom(String node, List> edges, List> expectedEdges) { + final var actualEdges = DirectedEdgeUtils.getEdgesFrom(node, edges); + + if (expectedEdges == SAME_LIST) { + expectedEdges = edges; + } + + assertEqualsSorted(expectedEdges, actualEdges); + + assertEqualsSorted(expectedEdges, DirectedEdgeUtils.getEdgesFrom(node, edges, ArrayList::new)); + assertEqualsSorted(new LinkedHashSet<>(expectedEdges), DirectedEdgeUtils.getEdgesFrom(node, edges, HashSet::new)); + } + + private static Stream testGetEdgesFrom() { + return Stream.of( + new Object[] { A, List.of(edge(A, B)), SAME_LIST }, + new Object[] { B, List.of(edge(A, B)), List.of() }, + new Object[] { A, List.of(edge(A, B), edge(A, B)), SAME_LIST }, + new Object[] { B, List.of(edge(A, B), edge(B, C)), List.of(edge(B, C)) }, + new Object[] { B, List.of(edge(A, B), edge(B, C), edge(C, D)), List.of(edge(B, C)) }, + new Object[] { D, List.of(edge(D, B), edge(D, A), edge(C, D)), List.of(edge(D, B), edge(D, A)) } + ); + } + + private static DirectedEdge edge(String from, String to) { + return DirectedEdge.create(from, to); + } + + private static void assertEqualsSorted(Collection> expected, Collection> actual) { + assertEquals(expected.stream().sorted(EDGE_COMPARATOR).toList(), actual.stream().sorted(EDGE_COMPARATOR).toList()); + } + + private final static List SAME_LIST = new ArrayList<>(); + + private final static Comparator> EDGE_COMPARATOR = + Comparator., String>comparing(DirectedEdge::from).thenComparing(DirectedEdge::to); + + private final static String A = "A"; + private final static String B = "B"; + private final static String C = "C"; + private final static String D = "D"; + private final static String L = "L"; +} From 88d2f52f1451678e0b80e54d908c715849a892a4 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 25 Jan 2025 01:23:24 -0500 Subject: [PATCH 0253/1101] Keep order of actions when scheduling. Works for sequential executor only. --- .../internal/pipeline/ActionGraph.java | 206 +++++++------ .../pipeline/ActionPipelineBuilder.java | 63 ++-- .../internal/pipeline/DirectedEdgeUtils.java | 236 +++++++------- .../internal/pipeline/ActionGraphTest.java | 245 ++++++++------- .../pipeline/ActionPipelineBuilderTest.java | 291 +++++++++--------- 5 files changed, 549 insertions(+), 492 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionGraph.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionGraph.java index 3548a4acc355a..e68f21bc222e9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionGraph.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionGraph.java @@ -1,93 +1,113 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -import static java.util.stream.Collectors.toSet; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * A directed acyclic (supposedly) graph. - * - * @see https://en.wikipedia.org/wiki/Directed_acyclic_graph - */ -final class ActionGraph { - - void addEdge(T from, T to) { - edges.add(DirectedEdge.create(from, to)); - } - - // TBD: Implement transient reduction - - Set getNodeDependencies(T node) { - return DirectedEdgeUtils.getEdgesTo(node, edges).stream().map(DirectedEdge::from).collect(toSet()); - } - - List topologicalSort() throws CycleException { - final Set> edgesCopy = new HashSet<>(edges); - - // Kahn's algorithm from https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm - // Variable names picked from the algorithm pseudo-code. - - // Empty list that will contain the sorted elements. - final List L = new ArrayList<>(); - - // Set of all nodes with no incoming edge. - var S = DirectedEdgeUtils.getNoIncomingEdgeNodes(edgesCopy, HashSet::new); - - do { - final Set newS = new HashSet<>(); - - for (final var n : S) { - L.add(n); - for (final var e : DirectedEdgeUtils.getEdgesFrom(n, edgesCopy)) { - edgesCopy.remove(e); - final var m = e.to(); - if (DirectedEdgeUtils.getEdgesTo(m, edgesCopy).isEmpty()) { - newS.add(m); - } - } - } - - S = newS; - - } while(!S.isEmpty()); - - if (!edgesCopy.isEmpty()) { - // Graph has at least one cycle. - throw new CycleException(DirectedEdgeUtils.getNodes(edgesCopy)); - } else { - // A topologically sorted order. - return Collections.unmodifiableList(L); - } - } - - final Set> edges = new HashSet<>(); -} +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static java.util.stream.Collectors.toSet; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; + +/** + * A directed acyclic (supposedly) graph. + * + * @see https://en.wikipedia.org/wiki/Directed_acyclic_graph + */ +final class ActionGraph { + + void addEdge(T from, T to) { + edges.add(DirectedEdge.create(from, to)); + } + + // TBD: Implement transient reduction + + Set getNodeDependencies(T node) { + return DirectedEdgeUtils.getEdgesTo(node, edges).stream().map(DirectedEdge::from).collect(toSet()); + } + + List topologicalSort() throws CycleException { + return topologicalSort(Optional.empty()); + } + + List topologicalSort(Comparator sorter) throws CycleException { + return topologicalSort(Optional.of(sorter)); + } + + private List topologicalSort(Optional> sorter) throws CycleException { + final Set> edgesCopy = new HashSet<>(edges); + + // Kahn's algorithm from https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm + // Variable names picked from the algorithm pseudo-code. + + // Empty list that will contain the sorted elements. + final List L = new ArrayList<>(); + + if (sorter.isEmpty()) { + // Set of all nodes with no incoming edge. + var S = DirectedEdgeUtils.getNoIncomingEdgeNodes(edgesCopy, HashSet::new); + do { + final var newS = new HashSet(); + for (final var n : S) { + kahlSortIteration(edgesCopy, n, newS, L); + } + S = newS; + } while(!S.isEmpty()); + } else { + // Set of all nodes with no incoming edge. + final var S = DirectedEdgeUtils.getNoIncomingEdgeNodes(edgesCopy, () -> new TreeSet<>(sorter.orElseThrow())); + while (!S.isEmpty()) { + final var n = S.removeFirst(); + kahlSortIteration(edgesCopy, n, S, L); + } + } + + if (!edgesCopy.isEmpty()) { + // Graph has at least one cycle. + throw new CycleException(DirectedEdgeUtils.getNodes(edgesCopy)); + } else { + // A topologically sorted order. + return Collections.unmodifiableList(L); + } + } + + private static void kahlSortIteration(Set> edges, U n, Set S, List L) { + L.add(n); + for (final var e : DirectedEdgeUtils.getEdgesFrom(n, edges)) { + edges.remove(e); + final var m = e.to(); + if (DirectedEdgeUtils.getEdgesTo(m, edges).isEmpty()) { + S.add(m); + } + } + } + + final Set> edges = new HashSet<>(); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java index 35b68b4e0473f..21a3f3ca03bc9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java @@ -25,9 +25,10 @@ package jdk.jpackage.internal.pipeline; +import java.util.ArrayList; import java.util.Collection; +import java.util.Comparator; import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -44,10 +45,9 @@ public final class ActionPipelineBuilder { ActionPipelineBuilder() { - rootAction = new RootAction<>(); - actions = new HashSet<>(); - actions.add(rootAction); + actions = new HashMap<>(); actionGraph = new ActionGraph<>(); + rootAction = addAction(new RootAction<>()); } public final class ActionSpecBuilder { @@ -76,26 +76,33 @@ public ActionSpecBuilder addDependencies(Collection> v) { } public ActionPipelineBuilder add() { - actionGraph.addEdge(action, validatedDependent()); - actions.add(action); - actions.addAll(dependencies); - dependencies.forEach(dependency -> { - actionGraph.addEdge(dependency, action); + final List> seqDependencies = new ArrayList<>(); + + for (final var dependency : dependencies) { + seqDependencies.add(addAction(dependency)); + } + + final var seqAction = addAction(action); + + seqDependencies.forEach(seqDependency -> { + actionGraph.addEdge(seqDependency, seqAction); }); + actionGraph.addEdge(seqAction, validatedDependent()); + return ActionPipelineBuilder.this; } - @SuppressWarnings("unchecked") - private Action validatedDependent() { + private SequencedAction validatedDependent() { if (dependent == null) { return rootAction; } else { - if (!actions.contains(dependent)) { + final var seqDependent = actions.get(dependent); + if (seqDependent == null) { throw new IllegalArgumentException("Unknown dependent action"); } - return dependent; + return seqDependent; } } @@ -120,23 +127,36 @@ public ActionPipelineBuilder sequentialExecutor() { } public Action create() { - final List> orderedActions; + final List> orderedActions; try { - orderedActions = actionGraph.topologicalSort(); + orderedActions = actionGraph.topologicalSort(Comparator.comparing(SequencedAction::seqNumber)); } catch (CycleException ex) { throw new UnsupportedOperationException(ex); } final var dependentActions = orderedActions.stream().map(action -> { - final var dependencies = actionGraph.getNodeDependencies(action); - return new DependentAction(action, dependencies); + final var dependencies = actionGraph.getNodeDependencies(action).stream() + .map(SequencedAction::action).toList(); + return new DependentAction(action.action, dependencies); }).toList(); return new Impl<>(dependentActions, executor); } - private record DependentAction(Action action, Set> dependencies) { + private SequencedAction addAction(Action action) { + Objects.requireNonNull(action); + var seqAction = actions.get(action); + if (seqAction == null) { + seqAction = new SequencedAction<>(action, seqNumber++); + actions.put(action, seqAction); + } + return seqAction; + } + + private record SequencedAction(Action action, int seqNumber) {} + + private record DependentAction(Action action, List> dependencies) { DependentAction { Objects.requireNonNull(action); @@ -223,9 +243,10 @@ public String toString() { } } - private final Action rootAction; - private final Set> actions; - private final ActionGraph> actionGraph; + private final SequencedAction rootAction; + private int seqNumber; + private final Map, SequencedAction> actions; + private final ActionGraph> actionGraph; private Executor executor; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdgeUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdgeUtils.java index cbe157e22b09f..28661fea40d73 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdgeUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdgeUtils.java @@ -1,116 +1,120 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -import static java.util.stream.Collectors.toCollection; -import static java.util.stream.Collectors.toSet; - -import java.util.Collection; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Stream; - -final class DirectedEdgeUtils { - - static Set getNodes(Collection> edges) { - return getNodes(edges, Optional.empty()); - } - - static Set getNodes(Collection> edges, Supplier> collectionCtor) { - return getNodes(edges, Optional.of(collectionCtor)); - } - - static Set getNoIncomingEdgeNodes(Collection> edges) { - return getNoIncomingEdgeNodes(edges, Optional.empty()); - } - - static Set getNoIncomingEdgeNodes(Collection> edges, Supplier> collectionCtor) { - return getNoIncomingEdgeNodes(edges, Optional.of(collectionCtor)); - } - - static Collection> getEdgesTo(T node, Collection> edges) { - return getEdgesTo(node, edges, Optional.empty()); - } - - static Collection> getEdgesTo(T node, Collection> edges, - Supplier>> collectionCtor) { - return getEdgesTo(node, edges, Optional.of(collectionCtor)); - } - - static Collection> getEdgesFrom(T node, Collection> edges) { - return getEdgesFrom(node, edges, Optional.empty()); - } - - static Collection> getEdgesFrom(T node, Collection> edges, - Supplier>> collectionCtor) { - return getEdgesFrom(node, edges, Optional.of(collectionCtor)); - } - - private static Set getNodes(Collection> edges, Optional>> collectionCtor) { - return collectToSet(edges.parallelStream().flatMap(DirectedEdge::asStream), collectionCtor); - } - - private static Collection> getEdgesTo(T node, Collection> edges, - Optional>>> collectionCtor) { - return filterEdges(node, edges, DirectedEdge::to, collectionCtor); - } - - private static Collection> getEdgesFrom(T node, Collection> edges, - Optional>>> collectionCtor) { - return filterEdges(node, edges, DirectedEdge::from, collectionCtor); - } - - private static Set getNoIncomingEdgeNodes(Collection> edges, Optional>> collectionCtor) { - final Set noIncomingEdgeNodes = getNodes(edges, collectionCtor); - final var incomingEdgeNodes = edges.parallelStream().map(DirectedEdge::to).collect(toSet()); - noIncomingEdgeNodes.removeAll(incomingEdgeNodes); - return noIncomingEdgeNodes; - } - - private static Set collectToSet(Stream stream, Optional>> collectionCtor) { - return collectionCtor.map(ctor -> stream.collect(toCollection(ctor))).orElseGet(() -> { - return stream.collect(toSet()); - }); - } - - private static Collection collect(Stream stream, Optional>> collectionCtor) { - return collectionCtor.map(ctor -> stream.collect(toCollection(ctor))).orElseGet(() -> { - return stream.toList(); - }); - } - - private static Collection> filterEdges(T node, Collection> edges, - Function, T> getNode, Optional>>> collectionCtor) { - Objects.requireNonNull(node); - Objects.requireNonNull(getNode); - return collect(edges.parallelStream().filter(edge -> { - return getNode.apply(edge).equals(node); - }), collectionCtor); - } -} +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static java.util.stream.Collectors.toCollection; +import static java.util.stream.Collectors.toSet; + +import java.util.Collection; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; + +final class DirectedEdgeUtils { + + static Set getNodes(Collection> edges) { + return getNodes(edges, Optional.empty()); + } + + @SuppressWarnings("unchecked") + static > U getNodes(Collection> edges, Supplier collectionCtor) { + return (U)getNodes(edges, Optional.of(collectionCtor)); + } + + static Set getNoIncomingEdgeNodes(Collection> edges) { + return getNoIncomingEdgeNodes(edges, Optional.empty()); + } + + @SuppressWarnings("unchecked") + static > U getNoIncomingEdgeNodes(Collection> edges, Supplier collectionCtor) { + return (U)getNoIncomingEdgeNodes(edges, Optional.of(collectionCtor)); + } + + static Collection> getEdgesTo(T node, Collection> edges) { + return getEdgesTo(node, edges, Optional.empty()); + } + + static Collection> getEdgesTo(T node, Collection> edges, + Supplier>> collectionCtor) { + return getEdgesTo(node, edges, Optional.of(collectionCtor)); + } + + static Collection> getEdgesFrom(T node, Collection> edges) { + return getEdgesFrom(node, edges, Optional.empty()); + } + + static Collection> getEdgesFrom(T node, Collection> edges, + Supplier>> collectionCtor) { + return getEdgesFrom(node, edges, Optional.of(collectionCtor)); + } + + private static > Set getNodes(Collection> edges, Optional> collectionCtor) { + return collectToSet(edges.parallelStream().flatMap(DirectedEdge::asStream), collectionCtor); + } + + private static Collection> getEdgesTo(T node, Collection> edges, + Optional>>> collectionCtor) { + return filterEdges(node, edges, DirectedEdge::to, collectionCtor); + } + + private static Collection> getEdgesFrom(T node, Collection> edges, + Optional>>> collectionCtor) { + return filterEdges(node, edges, DirectedEdge::from, collectionCtor); + } + + private static > Set getNoIncomingEdgeNodes(Collection> edges, Optional> collectionCtor) { + final Set noIncomingEdgeNodes = getNodes(edges, collectionCtor); + final var incomingEdgeNodes = edges.parallelStream().map(DirectedEdge::to).collect(toSet()); + noIncomingEdgeNodes.removeAll(incomingEdgeNodes); + return noIncomingEdgeNodes; + } + + private static > Set collectToSet(Stream stream, Optional> collectionCtor) { + if (collectionCtor.isEmpty()) { + return stream.collect(toSet()); + } else { + return stream.collect(toCollection(collectionCtor.orElseThrow())); + } + } + + private static Collection collect(Stream stream, Optional>> collectionCtor) { + return collectionCtor.map(ctor -> stream.collect(toCollection(ctor))).orElseGet(() -> { + return stream.toList(); + }); + } + + private static Collection> filterEdges(T node, Collection> edges, + Function, T> getNode, Optional>>> collectionCtor) { + Objects.requireNonNull(node); + Objects.requireNonNull(getNode); + return collect(edges.parallelStream().filter(edge -> { + return getNode.apply(edge).equals(node); + }), collectionCtor); + } +} diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionGraphTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionGraphTest.java index f414af7bef6e9..84d09e12e7e95 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionGraphTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionGraphTest.java @@ -1,118 +1,127 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import java.util.List; -import java.util.Set; -import java.util.stream.Stream; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -final class ActionGraphTest { - - @Test - public void testCyclicDependenciesSimple() { - assertThrows(IllegalArgumentException.class, () -> addEdge(A, A)); - } - - @ParameterizedTest - @MethodSource - public void testCyclicDependencies(List> edges, Set expectedCycleNodes) { - edges.forEach(this::addEdge); - final var ex = assertThrows(CycleException.class, graph::topologicalSort); - assertEquals(expectedCycleNodes, ex.getCycleNodes()); - } - - private static Stream testCyclicDependencies() { - return Stream.of( - // A <- B <- C - // | - // + <- C <- B - new Object[] { List.of(edge(B, A), edge(C, B), edge(C, A), edge(B, C)), Set.of(A, B, C) }, - - // A <- B <- D - // | - // + <- D <- C - // | - // + <- L <- B - new Object[] { List.of(edge(B, A), edge(D, B), edge(D, A), edge(C, D), edge(L, D), edge(B, L)), Set.of(A, B, D, L) } - ); - } - - @ParameterizedTest - @MethodSource - public void testTopologicalSort(List> edges, List expectedNodes) throws CycleException { - edges.forEach(this::addEdge); - final var actualNodes = graph.topologicalSort(); - assertEquals(expectedNodes, actualNodes); - } - - private static Stream testTopologicalSort() { - return Stream.of( - // A <- B <- C - // | - // + <- D <- B <- K <- C - // | - // + <- K - new Object[] { List.of(edge(B, A), edge(C, B), edge(D, A), edge(K, D), edge(B, D), edge(K, B), edge(C, K)), List.of(C, K, B, D, A) }, - - // A <- B <- C <- K - // | - // + <- D <- B <- K - // | - // + <- K - new Object[] { List.of(edge(B, A), edge(C, B), edge(D, A), edge(K, D), edge(B, D), edge(K, B), edge(K, C)), List.of(K, C, B, D, A) }, - - // D <- C <- B <- A - // | - // + <- A - new Object[] { List.of(edge(A, B), edge(B, C), edge(C, D), edge(A, D)), List.of(A, B, C, D) } - ); - } - - private static DirectedEdge edge(String from, String to) { - return DirectedEdge.create(from, to); - } - - private void addEdge(String from, String to) { - graph.addEdge(from, to); - } - - private void addEdge(DirectedEdge edge) { - graph.addEdge(edge.from(), edge.to()); - } - - private final ActionGraph graph = new ActionGraph<>(); - - private final static String A = "A"; - private final static String B = "B"; - private final static String C = "C"; - private final static String D = "D"; - private final static String K = "K"; - private final static String L = "L"; -} +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +final class ActionGraphTest { + + @Test + public void testCyclicDependenciesSimple() { + assertThrows(IllegalArgumentException.class, () -> addEdge(A, A)); + } + + @ParameterizedTest + @MethodSource + public void testCyclicDependencies(List> edges, Set expectedCycleNodes) { + edges.forEach(this::addEdge); + final var ex = assertThrows(CycleException.class, graph::topologicalSort); + assertEquals(expectedCycleNodes, ex.getCycleNodes()); + } + + private static Stream testCyclicDependencies() { + return Stream.of( + // A <- B <- C + // | + // + <- C <- B + new Object[] { List.of(edge(B, A), edge(C, B), edge(C, A), edge(B, C)), Set.of(A, B, C) }, + + // A <- B <- D + // | + // + <- D <- C + // | + // + <- L <- B + new Object[] { List.of(edge(B, A), edge(D, B), edge(D, A), edge(C, D), edge(L, D), edge(B, L)), Set.of(A, B, D, L) } + ); + } + + @ParameterizedTest + @MethodSource + public void testTopologicalSort(Comparator sorter, List> edges, List expectedNodes) throws CycleException { + edges.forEach(this::addEdge); + final List actualNodes; + if (sorter != null) { + actualNodes = graph.topologicalSort(sorter); + } else { + actualNodes = graph.topologicalSort(); + } + assertEquals(expectedNodes, actualNodes); + } + + private static Stream testTopologicalSort() { + return Stream.of( + // A <- B <- C + // | + // + <- D <- B <- K <- C + // | + // + <- K + new Object[] { null, List.of(edge(B, A), edge(C, B), edge(D, A), edge(K, D), edge(B, D), edge(K, B), edge(C, K)), List.of(C, K, B, D, A) }, + + // A <- B <- C <- K + // | + // + <- D <- B <- K + // | + // + <- K + new Object[] { null, List.of(edge(B, A), edge(C, B), edge(D, A), edge(K, D), edge(B, D), edge(K, B), edge(K, C)), List.of(K, C, B, D, A) }, + + // D <- C <- B <- A + // | + // + <- A + new Object[] { null, List.of(edge(A, B), edge(B, C), edge(C, D), edge(A, D)), List.of(A, B, C, D) }, + + new Object[] { Comparator.naturalOrder(), List.of(edge(A, L), edge(C, L), edge(B, L), edge(D, L)), List.of(A, B, C, D, L) }, + new Object[] { Comparator.reverseOrder(), List.of(edge(A, L), edge(C, L), edge(B, L), edge(D, L)), List.of(D, C, B, A, L) } + ); + } + + private static DirectedEdge edge(String from, String to) { + return DirectedEdge.create(from, to); + } + + private void addEdge(String from, String to) { + graph.addEdge(from, to); + } + + private void addEdge(DirectedEdge edge) { + graph.addEdge(edge.from(), edge.to()); + } + + private final ActionGraph graph = new ActionGraph<>(); + + private final static String A = "A"; + private final static String B = "B"; + private final static String C = "C"; + private final static String D = "D"; + private final static String K = "K"; + private final static String L = "L"; +} diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java index e1face96664ae..ad55b8978c021 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java @@ -1,144 +1,147 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -import static java.util.stream.Collectors.joining; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.time.Duration; -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.locks.LockSupport; -import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -final class ActionPipelineBuilderTest { - - record TestContext(StringBuffer sb) implements Context { - } - - enum TestAction implements Action { - A, - B, - C, - D, - K, - L; - - @Override - public void execute(TestContext context) throws ActionException { - LockSupport.parkNanos(Duration.ofMillis(100).toNanos()); - context.sb().append(name()); - System.out.println(String.format("[%s] append=[%s]; result=[%s]", Thread.currentThread(), name(), context.sb)); - } - } - - record ActionSpec(TestAction action, List dependencies, TestAction dependent) { - } - - private final static class ActionSpecBuilder { - - ActionSpecBuilder(TestAction action) { - this.action = Objects.requireNonNull(action); - } - - ActionSpecBuilder to(TestAction action) { - dependent = action; - return this; - } - - ActionSpecBuilder from(TestAction ... actions) { - dependencies.addAll(List.of(actions)); - return this; - } - - ActionSpec create() { - return new ActionSpec(action, dependencies, dependent); - } - - private final TestAction action; - private final List dependencies = new ArrayList<>(); - private TestAction dependent; - } - - @ParameterizedTest - @MethodSource("testData") - public void testSequential(List actionSpecs, String expectedString) throws ActionException { - testIt(new ForkJoinPool(1), actionSpecs, expectedString); - } - - @ParameterizedTest - @MethodSource("testData") - public void testParallel(List actionSpecs, String expectedString) throws ActionException { - testIt(new ForkJoinPool(2), actionSpecs, expectedString); - } - - private void testIt(ForkJoinPool fjp, List actionSpecs, String expectedString) throws ActionException { - final var builder = new ActionPipelineBuilder(); - builder.executor(fjp); - - actionSpecs.forEach(actionSpec -> { - builder.action(actionSpec.action).addDependencies(actionSpec.dependencies).dependent(actionSpec.dependent).add(); - }); - - final var context = new TestContext(new StringBuffer()); - - System.out.println("Execution started"); - builder.create().execute(context); - System.out.println("Execution ended"); - - assertEquals(expectedString, context.sb.toString()); - } - - private static Stream testData() { - return Stream.of( - new Object[] { List.of(action(A).create()), "A" }, - new Object[] { List.of(action(B).from(A).create()), "AB" }, - - // D <- C <- B <- A - // | - // + <- A - new Object[] { List.of(action(D).create(), action(C).from(B).to(D).create(), action(A).to(B).create(), action(A).to(D).create()), "ABCD" }, - - new Object[] { Stream.of(TestAction.values()) - .map(ActionPipelineBuilderTest::action) - .map(ActionSpecBuilder::create).toList(), Stream.of(TestAction.values()).map(Enum::name).collect(joining()) } - ); - } - - private static ActionSpecBuilder action(TestAction action) { - return new ActionSpecBuilder(action); - } - - private final static TestAction A = TestAction.A; - private final static TestAction B = TestAction.B; - private final static TestAction C = TestAction.C; - private final static TestAction D = TestAction.D; - private final static TestAction K = TestAction.K; - private final static TestAction L = TestAction.L; -} +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static java.util.stream.Collectors.joining; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.locks.LockSupport; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +final class ActionPipelineBuilderTest { + + record TestContext(StringBuffer sb) implements Context { + } + + enum TestAction implements Action { + A, + B, + C, + D, + K, + L; + + @Override + public void execute(TestContext context) throws ActionException { + LockSupport.parkNanos(Duration.ofMillis(100).toNanos()); + context.sb().append(name()); + } + } + + record ActionSpec(TestAction action, List dependencies, TestAction dependent) { + } + + private final static class ActionSpecBuilder { + + ActionSpecBuilder(TestAction action) { + this.action = Objects.requireNonNull(action); + } + + ActionSpecBuilder to(TestAction action) { + dependent = action; + return this; + } + + ActionSpecBuilder from(TestAction ... actions) { + dependencies.addAll(List.of(actions)); + return this; + } + + ActionSpec create() { + return new ActionSpec(action, dependencies, dependent); + } + + private final TestAction action; + private final List dependencies = new ArrayList<>(); + private TestAction dependent; + } + + @ParameterizedTest + @MethodSource("testData") + public void testSequential(List actionSpecs, String expectedString) throws ActionException { + testIt(new ForkJoinPool(1), actionSpecs, expectedString); + } + + @ParameterizedTest + @MethodSource("testData") + public void testParallel(List actionSpecs, String expectedString) throws ActionException { + testIt(new ForkJoinPool(4), actionSpecs, expectedString); + } + + private void testIt(ForkJoinPool fjp, List actionSpecs, String expectedString) throws ActionException { + final var builder = new ActionPipelineBuilder(); + builder.executor(fjp); + + actionSpecs.forEach(actionSpec -> { + builder.action(actionSpec.action).addDependencies(actionSpec.dependencies).dependent(actionSpec.dependent).add(); + }); + + final var context = new TestContext(new StringBuffer()); + + builder.create().execute(context); + + assertEquals(expectedString, context.sb.toString()); + } + + private static Stream testData() { + return Stream.of( + new Object[] { List.of(action(A).create()), "A" }, + new Object[] { List.of(action(B).from(A).create()), "AB" }, + + // D <- C <- B <- A + // | + // + <- A + new Object[] { List.of(action(D).create(), action(C).from(B).to(D).create(), action(A).to(B).create(), action(A).to(D).create()), "ABCD" }, + + new Object[] { Stream.of(TestAction.values()) + .map(ActionPipelineBuilderTest::action) + .map(ActionSpecBuilder::create).toList(), Stream.of(TestAction.values()).map(Enum::name).collect(joining()) }, + + new Object[] { Stream.of(TestAction.values()) + .sorted(Comparator.reverseOrder()) + .map(ActionPipelineBuilderTest::action) + .map(ActionSpecBuilder::create).toList(), Stream.of(TestAction.values()).sorted(Comparator.reverseOrder()).map(Enum::name).collect(joining()) } + ); + } + + private static ActionSpecBuilder action(TestAction action) { + return new ActionSpecBuilder(action); + } + + private final static TestAction A = TestAction.A; + private final static TestAction B = TestAction.B; + private final static TestAction C = TestAction.C; + private final static TestAction D = TestAction.D; + private final static TestAction K = TestAction.K; + private final static TestAction L = TestAction.L; +} From efe33bfb094543a1090bca67753d497b15cd9c41 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 27 Jan 2025 12:37:22 -0500 Subject: [PATCH 0254/1101] Rework using java.util.concurrent.CountedCompleter --- .../internal/AppImageInfoPListFile.java | 170 +++++------ .../jdk/jpackage/internal/CodesignConfig.java | 2 +- .../internal/MacFileAssociationBuilder.java | 258 ++++++++--------- .../internal/SigningIdentifierImpl.java | 108 +++---- .../internal/model/SigningIdentifier.java | 70 ++--- .../jpackage/internal/model/package-info.java | 66 ++--- .../jpackage/internal/pipeline/Action.java | 93 +++--- .../internal/pipeline/ActionException.java | 35 --- .../internal/pipeline/ActionGraph.java | 113 -------- .../pipeline/ActionPipelineBuilder.java | 181 ++---------- .../internal/pipeline/BinaryMatrix.java | 239 ++++++++++++++++ .../internal/pipeline/ConditionalAction.java | 88 +++--- .../jpackage/internal/pipeline/Context.java | 56 ++-- .../pipeline/CountedCompleterBuilder.java | 199 +++++++++++++ .../internal/pipeline/CycleException.java | 24 -- .../internal/pipeline/DirectedEdge.java | 101 +++---- .../internal/pipeline/DirectedEdgeUtils.java | 120 -------- .../internal/pipeline/ImmutableDAG.java | 270 ++++++++++++++++++ .../internal/pipeline/ActionGraphTest.java | 127 -------- .../pipeline/ActionPipelineBuilderTest.java | 45 ++- .../internal/pipeline/BinaryMatrixTest.java | 254 ++++++++++++++++ .../pipeline/DirectedEdgeUtilsTest.java | 157 ---------- .../internal/pipeline/ImmutableDAGTest.java | 199 +++++++++++++ 23 files changed, 1733 insertions(+), 1242 deletions(-) delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionException.java delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionGraph.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CycleException.java delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdgeUtils.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java delete mode 100644 test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionGraphTest.java create mode 100644 test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java delete mode 100644 test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeUtilsTest.java create mode 100644 test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageInfoPListFile.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageInfoPListFile.java index 7a7f93aced4da..3468a7ea1740d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageInfoPListFile.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageInfoPListFile.java @@ -1,85 +1,85 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal; - -import static jdk.jpackage.internal.util.XmlUtils.initDocumentBuilder; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; - -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -import org.w3c.dom.Document; -import org.xml.sax.SAXException; - -import jdk.jpackage.internal.model.DottedVersion; - -/** - * Mandatory elements of Info.plist file of app image. - */ -record AppImageInfoPListFile(String bundleIdentifier, String bundleName, String copyright, - DottedVersion shortVersion, DottedVersion bundleVersion, String category) { - - static final class InvalidPlistFileException extends Exception { - InvalidPlistFileException(Throwable cause) { - super(cause); - } - - private static final long serialVersionUID = 1L; - } - - static AppImageInfoPListFile loadFromInfoPList(Path infoPListFile) - throws IOException, InvalidPlistFileException, SAXException { - final var doc = initDocumentBuilder().parse(Files.newInputStream(infoPListFile)); - - XPath xPath = XPathFactory.newInstance().newXPath(); - - try { - return new AppImageInfoPListFile( - getStringValue(doc, xPath, "CFBundleIdentifier"), - getStringValue(doc, xPath, "CFBundleName"), - getStringValue(doc, xPath, "NSHumanReadableCopyright"), - DottedVersion.greedy(getStringValue(doc, xPath, "CFBundleShortVersionString")), - DottedVersion.greedy(getStringValue(doc, xPath, "CFBundleVersion")), - getStringValue(doc, xPath, "LSApplicationCategoryType")); - } catch (XPathExpressionException ex) { - // This should never happen as XPath expressions should be correct - throw new RuntimeException(ex); - } catch (Exception ex) { - throw new InvalidPlistFileException(ex); - } - } - - private static String getStringValue(Document doc, XPath xPath, String elementName) throws XPathExpressionException { - // Query for the value of element preceding - // element with value equal to the value of `elementName` - return (String) xPath.evaluate(String.format("//string[preceding-sibling::key = \"%s\"][1]", elementName), - doc, XPathConstants.STRING); - } -} +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.util.XmlUtils.initDocumentBuilder; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +import jdk.jpackage.internal.model.DottedVersion; + +/** + * Mandatory elements of Info.plist file of app image. + */ +record AppImageInfoPListFile(String bundleIdentifier, String bundleName, String copyright, + DottedVersion shortVersion, DottedVersion bundleVersion, String category) { + + static final class InvalidPlistFileException extends Exception { + InvalidPlistFileException(Throwable cause) { + super(cause); + } + + private static final long serialVersionUID = 1L; + } + + static AppImageInfoPListFile loadFromInfoPList(Path infoPListFile) + throws IOException, InvalidPlistFileException, SAXException { + final var doc = initDocumentBuilder().parse(Files.newInputStream(infoPListFile)); + + XPath xPath = XPathFactory.newInstance().newXPath(); + + try { + return new AppImageInfoPListFile( + getStringValue(doc, xPath, "CFBundleIdentifier"), + getStringValue(doc, xPath, "CFBundleName"), + getStringValue(doc, xPath, "NSHumanReadableCopyright"), + DottedVersion.greedy(getStringValue(doc, xPath, "CFBundleShortVersionString")), + DottedVersion.greedy(getStringValue(doc, xPath, "CFBundleVersion")), + getStringValue(doc, xPath, "LSApplicationCategoryType")); + } catch (XPathExpressionException ex) { + // This should never happen as XPath expressions should be correct + throw new RuntimeException(ex); + } catch (Exception ex) { + throw new InvalidPlistFileException(ex); + } + } + + private static String getStringValue(Document doc, XPath xPath, String elementName) throws XPathExpressionException { + // Query for the value of element preceding + // element with value equal to the value of `elementName` + return (String) xPath.evaluate(String.format("//string[preceding-sibling::key = \"%s\"][1]", elementName), + doc, XPathConstants.STRING); + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java index fa89d3a567823..7717fca2f7d72 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java @@ -66,7 +66,7 @@ Builder from(SigningConfig v) { .entitlements(v.entitlements().orElse(null)) .keyChain(v.keyChain().orElse(null)); } - + Builder from(CodesignConfig v) { return identifier(v.identifier().orElse(null)) .entitlements(v.entitlements().orElse(null)) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFileAssociationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFileAssociationBuilder.java index 78140c5c78ea6..1ee76dab247ff 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFileAssociationBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFileAssociationBuilder.java @@ -1,129 +1,129 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.FileAssociation; -import jdk.jpackage.internal.model.MacFileAssociation; -import jdk.jpackage.internal.model.MacFileAssociationMixin; - -final class MacFileAssociationBuilder { - - MacFileAssociation create(FileAssociation fa) throws ConfigException { - Objects.requireNonNull(fa); - - final var mixin = new MacFileAssociationMixin.Stub( - Optional.ofNullable(cfBundleTypeName).orElse(DEFAULTS.cfBundleTypeName), - Optional.ofNullable(cfBundleTypeRole).orElse(DEFAULTS.cfBundleTypeRole), - Optional.ofNullable(lsHandlerRank).orElse(DEFAULTS.lsHandlerRank), - Optional.ofNullable(lsTypeIsPackage).orElse(DEFAULTS.lsTypeIsPackage), - Optional.ofNullable(nsDocumentClass).orElse(DEFAULTS.nsDocumentClass), - Optional.ofNullable(nsPersistentStoreTypeKey).orElse(DEFAULTS.nsPersistentStoreTypeKey), - Optional.ofNullable(lsSupportsOpeningDocumentsInPlace).orElse(DEFAULTS.lsSupportsOpeningDocumentsInPlace), - Optional.ofNullable(uiSupportsDocumentBrowser).orElse(DEFAULTS.uiSupportsDocumentBrowser), - Optional.ofNullable(utTypeConformsTo).orElse(DEFAULTS.utTypeConformsTo), - Optional.ofNullable(nsExportableTypes).orElse(DEFAULTS.nsExportableTypes)); - - return MacFileAssociation.create(fa, mixin); - } - - MacFileAssociationBuilder cfBundleTypeName(String v) { - cfBundleTypeName = v; - return this; - } - - MacFileAssociationBuilder cfBundleTypeRole(String v) { - cfBundleTypeRole = v; - return this; - } - - MacFileAssociationBuilder lsHandlerRank(String v) { - lsHandlerRank = v; - return this; - } - - MacFileAssociationBuilder lsTypeIsPackage(boolean v) { - lsTypeIsPackage = v; - return this; - } - - MacFileAssociationBuilder nsDocumentClass(String v) { - nsDocumentClass = v; - return this; - } - - MacFileAssociationBuilder nsPersistentStoreTypeKey(String v) { - nsPersistentStoreTypeKey = v; - return this; - } - - MacFileAssociationBuilder lsSupportsOpeningDocumentsInPlace(boolean v) { - lsSupportsOpeningDocumentsInPlace = v; - return this; - } - - MacFileAssociationBuilder uiSupportsDocumentBrowser(boolean v) { - uiSupportsDocumentBrowser = v; - return this; - } - - MacFileAssociationBuilder utTypeConformsTo(List v) { - utTypeConformsTo = v; - return this; - } - - MacFileAssociationBuilder nsExportableTypes(List v) { - nsExportableTypes = v; - return this; - } - - private String cfBundleTypeName; - private String cfBundleTypeRole; - private String lsHandlerRank; - private String nsDocumentClass; - private String nsPersistentStoreTypeKey; - private boolean lsTypeIsPackage; - private boolean lsSupportsOpeningDocumentsInPlace; - private boolean uiSupportsDocumentBrowser; - private List utTypeConformsTo; - private List nsExportableTypes; - - private static final MacFileAssociationBuilder DEFAULTS = new MacFileAssociationBuilder() - .lsHandlerRank("Owner") - .cfBundleTypeRole("Editor") - .cfBundleTypeName("") - .lsTypeIsPackage(false) - .nsDocumentClass("") - .nsPersistentStoreTypeKey("") - .lsSupportsOpeningDocumentsInPlace(false) - .uiSupportsDocumentBrowser(false) - .utTypeConformsTo(List.of("public.data")) - .nsExportableTypes(List.of()); - -} +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.model.MacFileAssociation; +import jdk.jpackage.internal.model.MacFileAssociationMixin; + +final class MacFileAssociationBuilder { + + MacFileAssociation create(FileAssociation fa) throws ConfigException { + Objects.requireNonNull(fa); + + final var mixin = new MacFileAssociationMixin.Stub( + Optional.ofNullable(cfBundleTypeName).orElse(DEFAULTS.cfBundleTypeName), + Optional.ofNullable(cfBundleTypeRole).orElse(DEFAULTS.cfBundleTypeRole), + Optional.ofNullable(lsHandlerRank).orElse(DEFAULTS.lsHandlerRank), + Optional.ofNullable(lsTypeIsPackage).orElse(DEFAULTS.lsTypeIsPackage), + Optional.ofNullable(nsDocumentClass).orElse(DEFAULTS.nsDocumentClass), + Optional.ofNullable(nsPersistentStoreTypeKey).orElse(DEFAULTS.nsPersistentStoreTypeKey), + Optional.ofNullable(lsSupportsOpeningDocumentsInPlace).orElse(DEFAULTS.lsSupportsOpeningDocumentsInPlace), + Optional.ofNullable(uiSupportsDocumentBrowser).orElse(DEFAULTS.uiSupportsDocumentBrowser), + Optional.ofNullable(utTypeConformsTo).orElse(DEFAULTS.utTypeConformsTo), + Optional.ofNullable(nsExportableTypes).orElse(DEFAULTS.nsExportableTypes)); + + return MacFileAssociation.create(fa, mixin); + } + + MacFileAssociationBuilder cfBundleTypeName(String v) { + cfBundleTypeName = v; + return this; + } + + MacFileAssociationBuilder cfBundleTypeRole(String v) { + cfBundleTypeRole = v; + return this; + } + + MacFileAssociationBuilder lsHandlerRank(String v) { + lsHandlerRank = v; + return this; + } + + MacFileAssociationBuilder lsTypeIsPackage(boolean v) { + lsTypeIsPackage = v; + return this; + } + + MacFileAssociationBuilder nsDocumentClass(String v) { + nsDocumentClass = v; + return this; + } + + MacFileAssociationBuilder nsPersistentStoreTypeKey(String v) { + nsPersistentStoreTypeKey = v; + return this; + } + + MacFileAssociationBuilder lsSupportsOpeningDocumentsInPlace(boolean v) { + lsSupportsOpeningDocumentsInPlace = v; + return this; + } + + MacFileAssociationBuilder uiSupportsDocumentBrowser(boolean v) { + uiSupportsDocumentBrowser = v; + return this; + } + + MacFileAssociationBuilder utTypeConformsTo(List v) { + utTypeConformsTo = v; + return this; + } + + MacFileAssociationBuilder nsExportableTypes(List v) { + nsExportableTypes = v; + return this; + } + + private String cfBundleTypeName; + private String cfBundleTypeRole; + private String lsHandlerRank; + private String nsDocumentClass; + private String nsPersistentStoreTypeKey; + private boolean lsTypeIsPackage; + private boolean lsSupportsOpeningDocumentsInPlace; + private boolean uiSupportsDocumentBrowser; + private List utTypeConformsTo; + private List nsExportableTypes; + + private static final MacFileAssociationBuilder DEFAULTS = new MacFileAssociationBuilder() + .lsHandlerRank("Owner") + .cfBundleTypeRole("Editor") + .cfBundleTypeName("") + .lsTypeIsPackage(false) + .nsDocumentClass("") + .nsPersistentStoreTypeKey("") + .lsSupportsOpeningDocumentsInPlace(false) + .uiSupportsDocumentBrowser(false) + .utTypeConformsTo(List.of("public.data")) + .nsExportableTypes(List.of()); + +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentifierImpl.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentifierImpl.java index ae4e7736e355a..69c1df75693d6 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentifierImpl.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentifierImpl.java @@ -1,54 +1,54 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal; - -import static jdk.jpackage.internal.CodesignConfig.ADHOC_SIGNING_IDENTIFIER; - -import java.util.Objects; -import java.util.Optional; -import jdk.jpackage.internal.model.SigningIdentifier; - -record SigningIdentifierImpl(String name, Optional prefix) implements SigningIdentifier { - - SigningIdentifierImpl { - Objects.requireNonNull(name); - Objects.requireNonNull(prefix); - - if (ADHOC_SIGNING_IDENTIFIER.equals(name)) { - throw new IllegalArgumentException("Adhoc signing identifier no allowed"); - } - - if (name.contains(".") == prefix.isPresent()) { - throw new IllegalArgumentException("name and prefix mismatch"); - } - - prefix.ifPresent(thePrefix -> { - if (!thePrefix.endsWith(".")) { - throw new IllegalArgumentException("Illegal prefix"); - } - }); - } -} +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.CodesignConfig.ADHOC_SIGNING_IDENTIFIER; + +import java.util.Objects; +import java.util.Optional; +import jdk.jpackage.internal.model.SigningIdentifier; + +record SigningIdentifierImpl(String name, Optional prefix) implements SigningIdentifier { + + SigningIdentifierImpl { + Objects.requireNonNull(name); + Objects.requireNonNull(prefix); + + if (ADHOC_SIGNING_IDENTIFIER.equals(name)) { + throw new IllegalArgumentException("Adhoc signing identifier no allowed"); + } + + if (name.contains(".") == prefix.isPresent()) { + throw new IllegalArgumentException("name and prefix mismatch"); + } + + prefix.ifPresent(thePrefix -> { + if (!thePrefix.endsWith(".")) { + throw new IllegalArgumentException("Illegal prefix"); + } + }); + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentifier.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentifier.java index f5408b769e309..3450184758822 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentifier.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentifier.java @@ -1,35 +1,35 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.model; - -import java.util.Optional; - -public interface SigningIdentifier { - - String name(); - - Optional prefix(); -} +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.model; + +import java.util.Optional; + +public interface SigningIdentifier { + + String name(); + + Optional prefix(); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/package-info.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/package-info.java index 7044fcfb2169f..1b57359c883d2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/package-info.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/package-info.java @@ -1,34 +1,34 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * Classes and interfaces of the internal application packaging model. - * - * Primary entities are: {@link Application}, {@link jdk.jpackage.internal.model.Package}, and {@link Launcher}. - * - * @apiNote - * All methods of all interfaces and classes in this package return non-null values unless stated otherwise. - */ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Classes and interfaces of the internal application packaging model. + * + * Primary entities are: {@link Application}, {@link jdk.jpackage.internal.model.Package}, and {@link Launcher}. + * + * @apiNote + * All methods of all interfaces and classes in this package return non-null values unless stated otherwise. + */ package jdk.jpackage.internal.model; \ No newline at end of file diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Action.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Action.java index ef0bccf9e3d2f..a6c926def410a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Action.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Action.java @@ -1,38 +1,55 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -import java.util.function.Predicate; - -@FunctionalInterface -public interface Action { - - void execute(T context) throws ActionException; - - static Action createConditionalAction(Predicate predicate, Action action) { - return new ConditionalAction<>(action, predicate); - } -} +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import java.util.function.Predicate; + +@FunctionalInterface +public interface Action { + + void execute(T context); + + static Action createConditionalAction(Predicate predicate, Action action) { + return new ConditionalAction<>(action, predicate); + } + + @SuppressWarnings("unchecked") + static Action rootAction() { + return (Action)ROOT_ACTION; + } + + static final Action ROOT_ACTION = new Action<>() { + + @Override + public void execute(Context context) { + } + + @Override + public String toString() { + return super.toString() + "(root)"; + } + }; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionException.java deleted file mode 100644 index 91b9cf1d8533a..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal.pipeline; - -public class ActionException extends Exception { - - private static final long serialVersionUID = 1L; - - public ActionException(Throwable cause) { - super(cause); - } - -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionGraph.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionGraph.java deleted file mode 100644 index e68f21bc222e9..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionGraph.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -import static java.util.stream.Collectors.toSet; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; - -/** - * A directed acyclic (supposedly) graph. - * - * @see https://en.wikipedia.org/wiki/Directed_acyclic_graph - */ -final class ActionGraph { - - void addEdge(T from, T to) { - edges.add(DirectedEdge.create(from, to)); - } - - // TBD: Implement transient reduction - - Set getNodeDependencies(T node) { - return DirectedEdgeUtils.getEdgesTo(node, edges).stream().map(DirectedEdge::from).collect(toSet()); - } - - List topologicalSort() throws CycleException { - return topologicalSort(Optional.empty()); - } - - List topologicalSort(Comparator sorter) throws CycleException { - return topologicalSort(Optional.of(sorter)); - } - - private List topologicalSort(Optional> sorter) throws CycleException { - final Set> edgesCopy = new HashSet<>(edges); - - // Kahn's algorithm from https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm - // Variable names picked from the algorithm pseudo-code. - - // Empty list that will contain the sorted elements. - final List L = new ArrayList<>(); - - if (sorter.isEmpty()) { - // Set of all nodes with no incoming edge. - var S = DirectedEdgeUtils.getNoIncomingEdgeNodes(edgesCopy, HashSet::new); - do { - final var newS = new HashSet(); - for (final var n : S) { - kahlSortIteration(edgesCopy, n, newS, L); - } - S = newS; - } while(!S.isEmpty()); - } else { - // Set of all nodes with no incoming edge. - final var S = DirectedEdgeUtils.getNoIncomingEdgeNodes(edgesCopy, () -> new TreeSet<>(sorter.orElseThrow())); - while (!S.isEmpty()) { - final var n = S.removeFirst(); - kahlSortIteration(edgesCopy, n, S, L); - } - } - - if (!edgesCopy.isEmpty()) { - // Graph has at least one cycle. - throw new CycleException(DirectedEdgeUtils.getNodes(edgesCopy)); - } else { - // A topologically sorted order. - return Collections.unmodifiableList(L); - } - } - - private static void kahlSortIteration(Set> edges, U n, Set S, List L) { - L.add(n); - for (final var e : DirectedEdgeUtils.getEdgesFrom(n, edges)) { - edges.remove(e); - final var m = e.to(); - if (DirectedEdgeUtils.getEdgesTo(m, edges).isEmpty()) { - S.add(m); - } - } - } - - final Set> edges = new HashSet<>(); -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java index 21a3f3ca03bc9..113cd2b55dc65 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java @@ -25,31 +25,15 @@ package jdk.jpackage.internal.pipeline; -import java.util.ArrayList; import java.util.Collection; -import java.util.Comparator; -import java.util.HashMap; import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.concurrent.CancellationException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import jdk.jpackage.internal.util.function.ExceptionBox; +import java.util.concurrent.ForkJoinPool; public final class ActionPipelineBuilder { - ActionPipelineBuilder() { - actions = new HashMap<>(); - actionGraph = new ActionGraph<>(); - rootAction = addAction(new RootAction<>()); - } - public final class ActionSpecBuilder { ActionSpecBuilder(Action action) { @@ -76,36 +60,21 @@ public ActionSpecBuilder addDependencies(Collection> v) { } public ActionPipelineBuilder add() { - - final List> seqDependencies = new ArrayList<>(); - - for (final var dependency : dependencies) { - seqDependencies.add(addAction(dependency)); + if (actionGraphBuilder == null) { + actionGraphBuilder = new ImmutableDAG.Builder<>(); + actionGraphBuilder.addEdge(action, Action.rootAction()); + actionGraphBuilder.canAddEdgeToUnknownNode(false); + } else { + actionGraphBuilder.addEdge(action, Optional.ofNullable(dependent).orElseGet(Action::rootAction)); } - final var seqAction = addAction(action); - - seqDependencies.forEach(seqDependency -> { - actionGraph.addEdge(seqDependency, seqAction); - }); - - actionGraph.addEdge(seqAction, validatedDependent()); + for (var dependency : dependencies) { + actionGraphBuilder.addEdge(dependency, action); + } return ActionPipelineBuilder.this; } - private SequencedAction validatedDependent() { - if (dependent == null) { - return rootAction; - } else { - final var seqDependent = actions.get(dependent); - if (seqDependent == null) { - throw new IllegalArgumentException("Unknown dependent action"); - } - return seqDependent; - } - } - private Set> dependencies = new LinkedHashSet<>(); private Action dependent; private final Action action; @@ -115,139 +84,41 @@ public ActionSpecBuilder action(Action action) { return new ActionSpecBuilder(action); } - public ActionPipelineBuilder executor(Executor v) { + public ActionPipelineBuilder executor(ForkJoinPool v) { Objects.requireNonNull(v); - executor = v; + fjp = v; return this; } public ActionPipelineBuilder sequentialExecutor() { - executor = Executors.newSingleThreadExecutor(); + fjp = new ForkJoinPool(1); return this; } public Action create() { - final List> orderedActions; - - try { - orderedActions = actionGraph.topologicalSort(Comparator.comparing(SequencedAction::seqNumber)); - } catch (CycleException ex) { - throw new UnsupportedOperationException(ex); - } - - final var dependentActions = orderedActions.stream().map(action -> { - final var dependencies = actionGraph.getNodeDependencies(action).stream() - .map(SequencedAction::action).toList(); - return new DependentAction(action.action, dependencies); - }).toList(); - - return new Impl<>(dependentActions, executor); - } - - private SequencedAction addAction(Action action) { - Objects.requireNonNull(action); - var seqAction = actions.get(action); - if (seqAction == null) { - seqAction = new SequencedAction<>(action, seqNumber++); - actions.put(action, seqAction); - } - return seqAction; - } - - private record SequencedAction(Action action, int seqNumber) {} - - private record DependentAction(Action action, List> dependencies) { - - DependentAction { - Objects.requireNonNull(action); - Objects.requireNonNull(dependencies); - dependencies.forEach(Objects::requireNonNull); - } - } + final var actionGraph = actionGraphBuilder.create(); - private record RunnableAdapter(Action action, U context, - Optional> dependenciesFuture) implements Runnable { + final var countedCompleterBuilder = new CountedCompleterBuilder<>(actionGraph); - RunnableAdapter { - Objects.requireNonNull(action); - Objects.requireNonNull(context); - Objects.requireNonNull(dependenciesFuture); - } - - @Override - public void run() { - try { - dependenciesFuture.ifPresent(CompletableFuture::join); - } catch (CancellationException|CompletionException ex) { - return; - } - - try { - action.execute(context); - } catch (ActionException ex) { - throw ExceptionBox.rethrowUnchecked(ex); - } - } + return new WrapperAction<>(countedCompleterBuilder, fjp); } - private record Impl(List> dependentActions, Executor executor) implements Action { - - Impl { - Objects.requireNonNull(dependentActions); - dependentActions.forEach(Objects::requireNonNull); - Objects.requireNonNull(executor); - } - - @Override - public void execute(U context) throws ActionException { - final var rootAction = scheduleActions(context); - rootAction.join(); - } - - private CompletableFuture scheduleActions(U context) { - - final Map, CompletableFuture> scheduledActions = new HashMap<>(); - - CompletableFuture rootAction = null; - for (final var dependentAction : dependentActions) { - final Optional> dependenciesFuture; - if (dependentAction.dependencies().isEmpty()) { - dependenciesFuture = Optional.empty(); - } else { - final var dependencyFutures = dependentAction.dependencies().stream() - .map(scheduledActions::get) - .toArray(CompletableFuture[]::new); - dependenciesFuture = Optional.of(CompletableFuture.allOf(dependencyFutures)); - } - - final var actionAsRunnable = new RunnableAdapter<>(dependentAction.action(), context, dependenciesFuture); - - rootAction = CompletableFuture.runAsync(actionAsRunnable, executor); - - scheduledActions.put(dependentAction.action(), rootAction); - } + private record WrapperAction(CountedCompleterBuilder countedCompleterBuilder, + ForkJoinPool fjp) implements Action { - return rootAction; + WrapperAction { + Objects.requireNonNull(countedCompleterBuilder); + Objects.requireNonNull(fjp); } - } - - private static class RootAction implements Action { @Override - public void execute(U context) throws ActionException { + public void execute(U context) { + final var rootCompleter = countedCompleterBuilder.create(context); + fjp.invoke(rootCompleter); } - @Override - public String toString() { - return String.format("%s(root)", super.toString()); - } } - private final SequencedAction rootAction; - private int seqNumber; - private final Map, SequencedAction> actions; - private final ActionGraph> actionGraph; - - private Executor executor; - + private ImmutableDAG.Builder> actionGraphBuilder; + private ForkJoinPool fjp; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java new file mode 100644 index 0000000000000..38b724d8dae0d --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.pipeline; + +import java.util.BitSet; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Optional; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +final class BinaryMatrix { + + BinaryMatrix(BinaryMatrix other) { + rows = other.rows; + columns = other.columns; + size = other.size; + values = (BitSet)other.values.clone(); + } + + BinaryMatrix(int dimension) { + this(dimension, dimension); + } + + BinaryMatrix(int rows, int columns) { + this(rows, columns, null); + } + + BinaryMatrix(int rows, int columns, BitSet values) { + this.rows = requirePositiveInteger(rows, "Number of rows must be positive integer"); + this.columns = requirePositiveInteger(columns, "Number of columns must be positive integer"); + size = rows * columns; + this.values = Optional.ofNullable(values).orElseGet(() -> new BitSet(size)); + } + + interface Cursor { + int row(); + + int column(); + + boolean value(); + + void value(boolean value); + } + + boolean isSquare() { + return columns == rows; + } + + boolean isEmpty() { + return values.isEmpty(); + } + + int getRowCount() { + return rows; + } + + int getColumnCount() { + return columns; + } + + Iterator getRowIterator(int row) { + return new RowIterator(row); + } + + Iterator getColumnIterator(int column) { + return new ColumnIterator(column); + } + + Spliterator getRowSpliterator(int row) { + return Spliterators.spliterator(getRowIterator(row), columns, Spliterator.ORDERED); + } + + Spliterator getColumnSpliterator(int column) { + return Spliterators.spliterator(getColumnIterator(column), rows, Spliterator.ORDERED); + } + + Stream getRowAsStream(int row) { + return toStream(getRowSpliterator(row)); + } + + Stream getColumnAsStream(int column) { + return toStream(getColumnSpliterator(column)); + } + + boolean isSet(int row, int column) { + return values.get(toIndex(row, column)); + } + + void set(int row, int column, boolean value) { + values.set(toIndex(row, column), value); + } + + void set(int row, int column) { + set(row, column, true); + } + + void unset(int row, int column) { + set(row, column, false); + } + + private int toIndex(int row, int column) { + Objects.checkIndex(row, rows); + Objects.checkIndex(column, columns); + return row * columns + column; + } + + private static int requirePositiveInteger(int value, String message) { + Objects.requireNonNull(message); + if (value <= 0) { + throw new IllegalArgumentException(message); + } + return value; + } + + private static Stream toStream(Spliterator split) { + return StreamSupport.stream(split, false); + } + + /** + * Iterator over values of some selection. + */ + private abstract class SelectionIterator implements Iterator { + SelectionIterator(int index, int limit) { + this.limit = Objects.checkIndex(limit, size + 1); + this.index = Objects.checkIndex(index, limit); + } + + @Override + final public boolean hasNext() { + return index < limit; + } + + @Override + final public Cursor next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + final var value = new CursorImpl(index, BinaryMatrix.this); + + index = nextIndex(index); + + return value; + } + + protected abstract int nextIndex(int idx); + + private final int limit; + + private int index; + } + + /** + * Iterator over values of some column. + */ + private class ColumnIterator extends SelectionIterator { + ColumnIterator(int column) { + super(toIndex(0, column), size); + } + + @Override + protected int nextIndex(int idx) { + return idx + columns; + } + } + + /** + * Iterator over values of some row. + */ + private class RowIterator extends SelectionIterator { + RowIterator(int row) { + super(toIndex(row, 0), (row + 1) * columns); + } + + @Override + protected int nextIndex(int idx) { + return idx + 1; + } + } + + private record CursorImpl(int index, BinaryMatrix matrix) implements Cursor { + + CursorImpl { + Objects.checkIndex(index, matrix.size); + } + + @Override + public int row() { + return index / matrix.columns; + } + + @Override + public int column() { + return index % matrix.columns; + } + + @Override + public boolean value() { + return matrix.values.get(index); + } + + @Override + public void value(boolean value) { + matrix.values.set(index, value); + } + + } + + private final int rows; + private final int columns; + private final int size; + private final BitSet values; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ConditionalAction.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ConditionalAction.java index 71da034a02cd0..cc4e73a453c8d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ConditionalAction.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ConditionalAction.java @@ -1,44 +1,44 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -import java.util.Objects; -import java.util.function.Predicate; - -record ConditionalAction(Action action, Predicate predicate) implements Action { - - ConditionalAction { - Objects.requireNonNull(action); - Objects.requireNonNull(predicate); - } - - @Override - public void execute(T context) throws ActionException { - if (predicate.test(context)) { - action.execute(context); - } - } -} +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import java.util.Objects; +import java.util.function.Predicate; + +record ConditionalAction(Action action, Predicate predicate) implements Action { + + ConditionalAction { + Objects.requireNonNull(action); + Objects.requireNonNull(predicate); + } + + @Override + public void execute(T context) { + if (predicate.test(context)) { + action.execute(context); + } + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Context.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Context.java index 749c24c70409c..f0fdec016e4e4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Context.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Context.java @@ -1,29 +1,29 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -public interface Context { +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +public interface Context { } \ No newline at end of file diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java new file mode 100644 index 0000000000000..6058902ec425a --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static java.util.stream.Collectors.toMap; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CountedCompleter; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.StreamSupport; + +/** + * Schedules execution of actions in the given action graph. + * + * @param type parameter for {@link Action} class + */ +final class CountedCompleterBuilder { + + CountedCompleterBuilder(ImmutableDAG> actionGraph) { + this.actionGraph = Objects.requireNonNull(actionGraph); + + runOnce = StreamSupport.stream(actionGraph.getNodes().spliterator(), false).filter(node -> { + return actionGraph.getHeadsOf(node).size() > 1; + }).collect(toMap(x -> x, x -> new ActionCompleters())); + } + + CountedCompleter create(T context) { + final var rootCompleters = createRootCompleters(context); + if (rootCompleters.size() == 1) { + return rootCompleters.get(0); + } else { + return new RootCompleter(rootCompleters); + } + } + + private List> createRootCompleters(T context) { + Objects.requireNonNull(context); + + final var rootNodes = actionGraph.getNoOutgoingEdges(); + + return rootNodes.stream().map(rootNode -> { + return new ActionCompleter(null, context, rootNode); + }).toList(); + } + + private Optional registerCompleter(Action action, CountedCompleter completer) { + Objects.requireNonNull(completer); + final var dependentActions = actionGraph.getHeadsOf(action); + if (dependentActions.size() <= 1) { + return Optional.empty(); + } else { + var completers = runOnce.get(action); + if (completers == null) { + completers = new ActionCompleters(); + runOnce.put(action, completers); + } + + completers.allCompleters().add(completer); + return Optional.of(completers); + } + } + + private abstract class DependentComleter extends CountedCompleter { + + protected DependentComleter() { + } + + protected DependentComleter(CountedCompleter completer) { + super(completer); + } + + @Override + public void compute() { + final var dependencyCompleters = dependencyCompleters(); + setPendingCount(dependencyCompleters.size()); + + // ForkJoinPool will execute tasks in the reverse order of how they are scheduled. + // Reverse the order in which actions are scheduled to get them executed in the order placed in the dependency list. + // Ordering works for sequential execution only. + dependencyCompleters.reversed().forEach(CountedCompleter::fork); + + tryComplete(); + } + + protected abstract List> dependencyCompleters(); + + private static final long serialVersionUID = 1L; + } + + private final class ActionCompleter extends DependentComleter { + + ActionCompleter(CountedCompleter dependentCompleter, T context, Action action) { + super(dependentCompleter); + this.context = Objects.requireNonNull(context); + this.action = Objects.requireNonNull(action); + + dependencyCompleters = actionGraph.getTailsOf(action).stream().map(dependencyAction -> { + return new ActionCompleter(this, context, dependencyAction); + }).toList(); + + actionCompleters = registerCompleter(action, this); + } + + @Override + public void compute() { + if (actionCompleters.map(ActionCompleters::completer).map(ref -> ref.compareAndSet(null, this)).orElse(true)) { + super.compute(); + } else if(actionCompleters.isEmpty()) { + tryComplete(); + } + } + + @Override + public void onCompletion(CountedCompleter caller) { + if (actionCompleters.map(ac -> ac.isActionCompleter(this)).orElse(true)) { + action.execute(context); + actionCompleters.ifPresent(ActionCompleters::complete); + } + } + + @Override + protected List> dependencyCompleters() { + return dependencyCompleters; + } + + private final T context; + private final Action action; + private final List> dependencyCompleters; + private final Optional actionCompleters; + + private static final long serialVersionUID = 1L; + } + + private final class RootCompleter extends DependentComleter { + + RootCompleter(List> dependencyCompleters) { + this.dependencyCompleters = dependencyCompleters; + } + + @Override + protected List> dependencyCompleters() { + return dependencyCompleters; + } + + private final List> dependencyCompleters; + + private static final long serialVersionUID = 1L; + } + + private record ActionCompleters(AtomicReference> completer, + List> allCompleters) { + + ActionCompleters() { + this(new AtomicReference<>(), new ArrayList<>()); + } + + boolean isActionCompleter(CountedCompleter c) { + return c == completer.get(); + } + + void complete() { + allCompleters.forEach(c -> { + if (!isActionCompleter(c)) { + c.complete(null); + } + }); + } + } + + private final ImmutableDAG> actionGraph; + private final Map, ActionCompleters> runOnce; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CycleException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CycleException.java deleted file mode 100644 index cf79150186714..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CycleException.java +++ /dev/null @@ -1,24 +0,0 @@ -package jdk.jpackage.internal.pipeline; - -import java.util.Objects; -import java.util.Set; - -public final class CycleException extends Exception { - - CycleException(Set cycle) { - Objects.requireNonNull(cycle); - if (cycle.isEmpty()) { - throw new IllegalArgumentException("Empty cyclic nodes"); - } - - this.cycle = cycle; - } - - Set getCycleNodes() { - return cycle; - } - - private final Set cycle; - - private static final long serialVersionUID = 1L; -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdge.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdge.java index 7425e3c4b8648..dc47ccd16ee76 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdge.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdge.java @@ -1,49 +1,52 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -import java.util.Objects; -import java.util.stream.Stream; - -record DirectedEdge(T from, T to) { - - DirectedEdge { - Objects.requireNonNull(from); - Objects.requireNonNull(to); - - if (from.equals(to)) { - throw new IllegalArgumentException("Same node"); - } - } - - static DirectedEdge create(U from, U to) { - return new DirectedEdge(from, to); - } - - Stream asStream() { - return Stream.of(from, to); - } -} +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import java.util.Objects; + +record DirectedEdge(T tail, T head) { + + DirectedEdge { + Objects.requireNonNull(tail); + Objects.requireNonNull(head); + + if (tail.equals(head)) { + throw new IllegalArgumentException("Loop edge"); + } + } + + T from() { + return tail; + } + + T to() { + return head; + } + + static DirectedEdge create(U tail, U head) { + return new DirectedEdge<>(tail, head); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdgeUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdgeUtils.java deleted file mode 100644 index 28661fea40d73..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdgeUtils.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -import static java.util.stream.Collectors.toCollection; -import static java.util.stream.Collectors.toSet; - -import java.util.Collection; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Stream; - -final class DirectedEdgeUtils { - - static Set getNodes(Collection> edges) { - return getNodes(edges, Optional.empty()); - } - - @SuppressWarnings("unchecked") - static > U getNodes(Collection> edges, Supplier collectionCtor) { - return (U)getNodes(edges, Optional.of(collectionCtor)); - } - - static Set getNoIncomingEdgeNodes(Collection> edges) { - return getNoIncomingEdgeNodes(edges, Optional.empty()); - } - - @SuppressWarnings("unchecked") - static > U getNoIncomingEdgeNodes(Collection> edges, Supplier collectionCtor) { - return (U)getNoIncomingEdgeNodes(edges, Optional.of(collectionCtor)); - } - - static Collection> getEdgesTo(T node, Collection> edges) { - return getEdgesTo(node, edges, Optional.empty()); - } - - static Collection> getEdgesTo(T node, Collection> edges, - Supplier>> collectionCtor) { - return getEdgesTo(node, edges, Optional.of(collectionCtor)); - } - - static Collection> getEdgesFrom(T node, Collection> edges) { - return getEdgesFrom(node, edges, Optional.empty()); - } - - static Collection> getEdgesFrom(T node, Collection> edges, - Supplier>> collectionCtor) { - return getEdgesFrom(node, edges, Optional.of(collectionCtor)); - } - - private static > Set getNodes(Collection> edges, Optional> collectionCtor) { - return collectToSet(edges.parallelStream().flatMap(DirectedEdge::asStream), collectionCtor); - } - - private static Collection> getEdgesTo(T node, Collection> edges, - Optional>>> collectionCtor) { - return filterEdges(node, edges, DirectedEdge::to, collectionCtor); - } - - private static Collection> getEdgesFrom(T node, Collection> edges, - Optional>>> collectionCtor) { - return filterEdges(node, edges, DirectedEdge::from, collectionCtor); - } - - private static > Set getNoIncomingEdgeNodes(Collection> edges, Optional> collectionCtor) { - final Set noIncomingEdgeNodes = getNodes(edges, collectionCtor); - final var incomingEdgeNodes = edges.parallelStream().map(DirectedEdge::to).collect(toSet()); - noIncomingEdgeNodes.removeAll(incomingEdgeNodes); - return noIncomingEdgeNodes; - } - - private static > Set collectToSet(Stream stream, Optional> collectionCtor) { - if (collectionCtor.isEmpty()) { - return stream.collect(toSet()); - } else { - return stream.collect(toCollection(collectionCtor.orElseThrow())); - } - } - - private static Collection collect(Stream stream, Optional>> collectionCtor) { - return collectionCtor.map(ctor -> stream.collect(toCollection(ctor))).orElseGet(() -> { - return stream.toList(); - }); - } - - private static Collection> filterEdges(T node, Collection> edges, - Function, T> getNode, Optional>>> collectionCtor) { - Objects.requireNonNull(node); - Objects.requireNonNull(getNode); - return collect(edges.parallelStream().filter(edge -> { - return getNode.apply(edge).equals(node); - }), collectionCtor); - } -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java new file mode 100644 index 0000000000000..589a3fc318dfa --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.pipeline; + +import static java.util.stream.Collectors.toCollection; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +/** + * Immutable directed acyclic graph (DAG). + * + * @param edgeMatrix the edge matrix. [i,j] addresses an edge, where 'i' is the + * index of the head node of the edge in the node container + * and 'j' is the index of the tail node of the edge in the + * node container + * @param nodes the node container + */ +record ImmutableDAG(BinaryMatrix edgeMatrix, Nodes nodes) { + + static Builder build() { + return new Builder<>(); + } + + final static class Builder { + + Builder addEdge(U tail, U head) { + return addEdge(DirectedEdge.create(tail, head)); + } + + Builder addEdge(DirectedEdge edge) { + + final var newTailNode = !nodes.contains(edge.tail()); + final var newHeadNode = !nodes.contains(edge.head()); + + if (newHeadNode && !canAddEdgeToUnknownNode) { + throw new UnsupportedOperationException("Can not add edge to unknown node"); + } + + if (newTailNode) { + nodes.add(edge.tail()); + } + + if (newHeadNode) { + nodes.add(edge.head()); + } + + edges.add(edge); + return this; + } + + Builder canAddEdgeToUnknownNode(boolean v) { + canAddEdgeToUnknownNode = v; + return this; + } + + ImmutableDAG create() { + final var nodesAdapter = Nodes.ofList(this.nodes); + final var edgeMatrix = new BinaryMatrix(nodes.size()); + for (final var edge : edges) { + final int row = nodes.indexOf(edge.tail()); + final int column = nodes.indexOf(edge.head()); + edgeMatrix.set(row, column); + } + + if (isCyclic(edgeMatrix)) { + throw new UnsupportedOperationException("Cyclic edges not allowed"); + } + + return new ImmutableDAG<>(edgeMatrix, nodesAdapter); + } + + private boolean canAddEdgeToUnknownNode = true; + private final List nodes = new ArrayList<>(); + private final List> edges = new ArrayList<>(); + } + + interface Nodes extends Iterable { + int size(); + int indexOf(U node); + U get(int index); + + + static Nodes ofList(List list) { + return new Nodes<>() { + + @Override + public int size() { + return list.size(); + } + + @Override + public int indexOf(V node) { + final int index = list.indexOf(node); + if (index < 0) { + throw new NoSuchElementException(); + } + return index; + } + + @Override + public V get(int index) { + return list.get(index); + } + + @Override + public Iterator iterator() { + return list.iterator(); + } + + }; + } + } + + ImmutableDAG { + Objects.requireNonNull(nodes); + + Objects.requireNonNull(edgeMatrix); + if (!edgeMatrix.isSquare()) { + throw new IllegalArgumentException("Matrix must be square"); + } + + if (edgeMatrix.getColumnCount() != nodes.size()) { + throw new IllegalArgumentException("Matrix must have number of columns equal to the number of nodes"); + } + } + + Iterable getNodes() { + return nodes; + } + + /** + * Gets the list of nodes that are heads of the edges sharing the same tail, + * which is the given node. + *

+ * The returned list is ordered by the indexes of the nodes in the node + * container of this graph. + * + * @param node a node + * @return the list of nodes that are heads of the edges sharing the same tail, + * which is the given node + * + * @see Nodes + */ + List getHeadsOf(T node) { + final int tail = nodes.indexOf(node); + return getOutgoingEdges(tail, edgeMatrix).map(BinaryMatrix.Cursor::column).map(nodes::get).toList(); + } + + /** + * Gets the list of nodes that are tails of the edges sharing the same head, + * which is the given node. + *

+ * The returned list is ordered by the indexes of the nodes in the node + * container of this graph. + * + * @param node a node + * @return the list of nodes that are tails of the edges sharing the same head, + * which is the given node + * + * @see Nodes + */ + List getTailsOf(T node) { + final int head = nodes.indexOf(node); + return getIncomingEdges(head, edgeMatrix).map(BinaryMatrix.Cursor::row).map(nodes::get).toList(); + } + + /** + * Get the list of nodes without incoming edges. + *

+ * A node without incoming edges is a node that is not a head of any of the edges in the graph. + *

+ * The returned list is ordered by the indexes of the nodes in the node + * container of this graph. + * + * @return the list of nodes without incoming edges + */ + List getNoIncomingEdges() { + return getNoIncomingEdges(edgeMatrix).mapToObj(nodes::get).toList(); + } + + /** + * Get the list of nodes without outgoing edges. + *

+ * A node without outgoing edges is a node that is not a tail of any of the edges in the graph. + *

+ * The returned list is ordered by the indexes of the nodes in the node + * container of this graph. + * + * @return the list of nodes without outgoing edges + */ + List getNoOutgoingEdges() { + return getNoOutgoingEdges(edgeMatrix).mapToObj(nodes::get).toList(); + } + + private static Stream getOutgoingEdges(int node, BinaryMatrix edgeMatrix) { + return edgeMatrix.getRowAsStream(node).filter(BinaryMatrix.Cursor::value); + } + + private static Stream getIncomingEdges(int node, BinaryMatrix edgeMatrix) { + return edgeMatrix.getColumnAsStream(node).filter(BinaryMatrix.Cursor::value); + } + + private static IntStream getNoIncomingEdges(BinaryMatrix edgeMatrix) { + return IntStream.range(0, edgeMatrix.getColumnCount()).filter(column -> { + return getIncomingEdges(column, edgeMatrix).findAny().isEmpty(); + }); + } + + private static IntStream getNoOutgoingEdges(BinaryMatrix edgeMatrix) { + return IntStream.range(0, edgeMatrix.getRowCount()).filter(row -> { + return getOutgoingEdges(row, edgeMatrix).findAny().isEmpty(); + }); + } + + private static boolean isCyclic(BinaryMatrix edgeMatrix) { + + final var edgeMatrixCopy = new BinaryMatrix(edgeMatrix); + + // Use Kahn's algorithm from https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm to find cyclic edges + // Variable names picked from the algorithm pseudo-code. + + // Set of all nodes with no incoming edge. + final var S = getNoIncomingEdges(edgeMatrix).mapToObj(Integer::valueOf).collect(toCollection(ArrayList::new)); + + while (!S.isEmpty()) { + final var n = S.removeLast(); + + for (final var e : getOutgoingEdges(n, edgeMatrixCopy).toList()) { + e.value(false); // remove the edge + + final var m = e.column(); + + if (getIncomingEdges(m, edgeMatrixCopy).findAny().isEmpty()) { + // No incoming edges to 'm' node. + S.add(m); + } + } + } + + return !edgeMatrixCopy.isEmpty(); + } +} diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionGraphTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionGraphTest.java deleted file mode 100644 index 84d09e12e7e95..0000000000000 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionGraphTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import java.util.Comparator; -import java.util.List; -import java.util.Set; -import java.util.stream.Stream; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -final class ActionGraphTest { - - @Test - public void testCyclicDependenciesSimple() { - assertThrows(IllegalArgumentException.class, () -> addEdge(A, A)); - } - - @ParameterizedTest - @MethodSource - public void testCyclicDependencies(List> edges, Set expectedCycleNodes) { - edges.forEach(this::addEdge); - final var ex = assertThrows(CycleException.class, graph::topologicalSort); - assertEquals(expectedCycleNodes, ex.getCycleNodes()); - } - - private static Stream testCyclicDependencies() { - return Stream.of( - // A <- B <- C - // | - // + <- C <- B - new Object[] { List.of(edge(B, A), edge(C, B), edge(C, A), edge(B, C)), Set.of(A, B, C) }, - - // A <- B <- D - // | - // + <- D <- C - // | - // + <- L <- B - new Object[] { List.of(edge(B, A), edge(D, B), edge(D, A), edge(C, D), edge(L, D), edge(B, L)), Set.of(A, B, D, L) } - ); - } - - @ParameterizedTest - @MethodSource - public void testTopologicalSort(Comparator sorter, List> edges, List expectedNodes) throws CycleException { - edges.forEach(this::addEdge); - final List actualNodes; - if (sorter != null) { - actualNodes = graph.topologicalSort(sorter); - } else { - actualNodes = graph.topologicalSort(); - } - assertEquals(expectedNodes, actualNodes); - } - - private static Stream testTopologicalSort() { - return Stream.of( - // A <- B <- C - // | - // + <- D <- B <- K <- C - // | - // + <- K - new Object[] { null, List.of(edge(B, A), edge(C, B), edge(D, A), edge(K, D), edge(B, D), edge(K, B), edge(C, K)), List.of(C, K, B, D, A) }, - - // A <- B <- C <- K - // | - // + <- D <- B <- K - // | - // + <- K - new Object[] { null, List.of(edge(B, A), edge(C, B), edge(D, A), edge(K, D), edge(B, D), edge(K, B), edge(K, C)), List.of(K, C, B, D, A) }, - - // D <- C <- B <- A - // | - // + <- A - new Object[] { null, List.of(edge(A, B), edge(B, C), edge(C, D), edge(A, D)), List.of(A, B, C, D) }, - - new Object[] { Comparator.naturalOrder(), List.of(edge(A, L), edge(C, L), edge(B, L), edge(D, L)), List.of(A, B, C, D, L) }, - new Object[] { Comparator.reverseOrder(), List.of(edge(A, L), edge(C, L), edge(B, L), edge(D, L)), List.of(D, C, B, A, L) } - ); - } - - private static DirectedEdge edge(String from, String to) { - return DirectedEdge.create(from, to); - } - - private void addEdge(String from, String to) { - graph.addEdge(from, to); - } - - private void addEdge(DirectedEdge edge) { - graph.addEdge(edge.from(), edge.to()); - } - - private final ActionGraph graph = new ActionGraph<>(); - - private final static String A = "A"; - private final static String B = "B"; - private final static String C = "C"; - private final static String D = "D"; - private final static String K = "K"; - private final static String L = "L"; -} diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java index ad55b8978c021..4bb8579e27045 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java @@ -29,7 +29,6 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Comparator; -import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; import java.util.concurrent.ForkJoinPool; @@ -52,8 +51,9 @@ enum TestAction implements Action { L; @Override - public void execute(TestContext context) throws ActionException { - LockSupport.parkNanos(Duration.ofMillis(100).toNanos()); + public void execute(TestContext context) { + LockSupport.parkNanos(Duration.ofMillis(10).toNanos()); + System.out.println(String.format("[%s] result before append: [%s]; append %s", Thread.currentThread(), context.sb(), name())); context.sb().append(name()); } } @@ -87,18 +87,18 @@ ActionSpec create() { } @ParameterizedTest - @MethodSource("testData") - public void testSequential(List actionSpecs, String expectedString) throws ActionException { + @MethodSource("testSequentialData") + public void testSequential(List actionSpecs, String expectedString) { testIt(new ForkJoinPool(1), actionSpecs, expectedString); } @ParameterizedTest - @MethodSource("testData") - public void testParallel(List actionSpecs, String expectedString) throws ActionException { + @MethodSource("testParallelData") + public void testParallel(List actionSpecs, String expectedString) { testIt(new ForkJoinPool(4), actionSpecs, expectedString); } - private void testIt(ForkJoinPool fjp, List actionSpecs, String expectedString) throws ActionException { + private void testIt(ForkJoinPool fjp, List actionSpecs, String expectedString) { final var builder = new ActionPipelineBuilder(); builder.executor(fjp); @@ -108,21 +108,30 @@ private void testIt(ForkJoinPool fjp, List actionSpecs, String expec final var context = new TestContext(new StringBuffer()); + System.out.println(String.format("start for %s", expectedString)); builder.create().execute(context); assertEquals(expectedString, context.sb.toString()); + System.out.println("end"); } - private static Stream testData() { - return Stream.of( + private static List testData() { + return List.of( new Object[] { List.of(action(A).create()), "A" }, new Object[] { List.of(action(B).from(A).create()), "AB" }, - // D <- C <- B <- A - // | - // + <- A - new Object[] { List.of(action(D).create(), action(C).from(B).to(D).create(), action(A).to(B).create(), action(A).to(D).create()), "ABCD" }, + // D <- C <- B + // ^ ^ + // | | + // +--- A ---+ + new Object[] { List.of(action(D).create(), action(C).from(B).to(D).create(), action(A).to(B).create(), action(A).to(D).create()), "ABCD" } + ); + } + private static List testSequentialData() { + final var data = new ArrayList<>(testData()); + + data.addAll(List.of( new Object[] { Stream.of(TestAction.values()) .map(ActionPipelineBuilderTest::action) .map(ActionSpecBuilder::create).toList(), Stream.of(TestAction.values()).map(Enum::name).collect(joining()) }, @@ -131,7 +140,13 @@ private static Stream testData() { .sorted(Comparator.reverseOrder()) .map(ActionPipelineBuilderTest::action) .map(ActionSpecBuilder::create).toList(), Stream.of(TestAction.values()).sorted(Comparator.reverseOrder()).map(Enum::name).collect(joining()) } - ); + )); + + return data; + } + + private static List testParallelData() { + return testData(); } private static ActionSpecBuilder action(TestAction action) { diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java new file mode 100644 index 0000000000000..469f527eeacf8 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Iterator; +import java.util.List; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +final class BinaryMatrixTest { + + record CtorTest(int rows, int columns, boolean isSquare, boolean fail) { + + static CtorTest create(int rows, int columns) { + return new CtorTest(rows, columns, rows == columns, false); + } + + static CtorTest createFail(int rows, int columns) { + return new CtorTest(rows, columns, false, true); + } + + void test() { + if (fail) { + assertThrows(IllegalArgumentException.class, () -> new BinaryMatrix(rows, columns)); + } else { + final var matrix = new BinaryMatrix(rows, columns); + assertEquals(rows, matrix.getRowCount()); + assertEquals(columns, matrix.getColumnCount()); + assertEquals(isSquare, matrix.isSquare()); + } + } + } + + @ParameterizedTest + @MethodSource + public void testCtor(CtorTest testSpec) { + testSpec.test(); + } + + private static Stream testCtor() { + return Stream.of( + CtorTest.create(1, 2), + CtorTest.create(2, 2), + CtorTest.create(7, 4), + CtorTest.createFail(0, 1), + CtorTest.createFail(1, 0), + CtorTest.createFail(-1, 1), + CtorTest.createFail(1, -1), + CtorTest.createFail(0, 0), + CtorTest.createFail(-3, -9) + ); + } + + record MatrixSpec(int rows, int columns, String encodedMatrixData) { + + MatrixSpec(int rows, int columns) { + this(rows, columns, null); + } + + BinaryMatrix createMatrix() { + if (encodedMatrixData == null) { + return new BinaryMatrix(rows, columns); + } + + final var charArray = encodedMatrixData.toCharArray(); + + if (charArray.length != rows * columns) { + throw new IllegalArgumentException("Matrix data is not matching matrix dimensions"); + } + + final var matrixData = new BitSet(charArray.length); + + IntStream.range(0, charArray.length).forEach(index -> { + final var chr = charArray[index]; + switch (chr) { + case '0' -> { + break; + } + + case '1' -> { + matrixData.set(index); + break; + } + + default -> { + throw new IllegalArgumentException(String.format("Unrecognized character: %c", chr)); + } + } + }); + + return new BinaryMatrix(rows, columns, matrixData); + } + } + + enum Selection { + ROW, + COLUMN + } + + record SelectionTest(MatrixSpec matrixSpec, Selection type, int index, List expected) { + + static SelectionTest createRow(int rows, int columns, String encodedMatrixData, int row, int ... expected) { + return new SelectionTest(new MatrixSpec(rows, columns, encodedMatrixData), Selection.ROW, row, conv(expected)); + } + + static SelectionTest createColumn(int rows, int columns, String encodedMatrixData, int column, int ... expected) { + return new SelectionTest(new MatrixSpec(rows, columns, encodedMatrixData), Selection.COLUMN, column, conv(expected)); + } + + static SelectionTest createRow(int rows, int columns, int row) { + return new SelectionTest(new MatrixSpec(rows, columns), Selection.ROW, row, null); + } + + static SelectionTest createColumn(int rows, int columns, int column) { + return new SelectionTest(new MatrixSpec(rows, columns), Selection.COLUMN, column, null); + } + + void test() { + final var matrix = matrixSpec.createMatrix(); + if (expected == null) { + assertThrows(IndexOutOfBoundsException.class, () -> getIterator(matrix)); + assertThrows(IndexOutOfBoundsException.class, () -> getSpliterator(matrix)); + } else { + final var it = getIterator(matrix); + assertEquals(expected, readSelection(it::forEachRemaining)); + + final var split = getSpliterator(matrix); + assertEquals(expected, readSelection(split::forEachRemaining)); + } + } + + List readSelection(Consumer> forEach) { + final List actualData = new ArrayList<>(); + final int[] variableIndexValue = new int[] { -1 }; + + forEach.accept(cursor -> { + final int fixedIndex; + final int variableIndex; + switch (type) { + case ROW -> { + fixedIndex = cursor.row(); + variableIndex = cursor.column(); + } + case COLUMN -> { + fixedIndex = cursor.column(); + variableIndex = cursor.row(); + } + default -> { + throw new IllegalArgumentException(); + } + } + + assertEquals(index, fixedIndex); + assertEquals(variableIndexValue[0] + 1, variableIndex); + variableIndexValue[0] = variableIndex; + + actualData.add(cursor.value()); + }); + + return actualData; + } + + Iterator getIterator(BinaryMatrix matrix) { + switch (type) { + case ROW -> { + return matrix.getRowIterator(index); + } + case COLUMN -> { + return matrix.getColumnIterator(index); + } + default -> { + throw new IllegalArgumentException(); + } + } + } + + Spliterator getSpliterator(BinaryMatrix matrix) { + switch (type) { + case ROW -> { + return matrix.getRowSpliterator(index); + } + case COLUMN -> { + return matrix.getColumnSpliterator(index); + } + default -> { + throw new IllegalArgumentException(); + } + } + } + } + + @ParameterizedTest + @MethodSource + public void testSelection(SelectionTest testSpec) { + testSpec.test(); + } + + private static Stream testSelection() { + return Stream.of( + SelectionTest.createRow(1, 1, "0", 0, 0), + SelectionTest.createColumn(1, 1, "0", 0, 0), + SelectionTest.createRow(1, 1, "1", 0, 1), + SelectionTest.createColumn(1, 1, "1", 0, 1), + + SelectionTest.createRow(3, 2, "00" + "01" + "10", 0, 0, 0), + SelectionTest.createRow(3, 2, "00" + "01" + "10", 1, 0, 1), + SelectionTest.createRow(3, 2, "00" + "01" + "10", 2, 1, 0), + SelectionTest.createColumn(3, 2, "00" + "01" + "10", 0, 0, 0, 1), + SelectionTest.createColumn(3, 2, "00" + "01" + "10", 1, 0, 1, 0), + + SelectionTest.createRow(3, 2, -1), + SelectionTest.createRow(3, 2, 3), + SelectionTest.createRow(3, 2, 12), + + SelectionTest.createColumn(3, 2, -1), + SelectionTest.createColumn(3, 2, 2), + SelectionTest.createColumn(3, 2, 12) + ); + } + + private static List conv(int... values) { + return IntStream.of(values).mapToObj(v -> v != 0).toList(); + } +} diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeUtilsTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeUtilsTest.java deleted file mode 100644 index 8cbe9deb125b4..0000000000000 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeUtilsTest.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -final class DirectedEdgeUtilsTest { - - @ParameterizedTest - @MethodSource - public void testGetNodes(List> edges, Set expectedNodes) { - final var actualNodes = DirectedEdgeUtils.getNodes(edges); - - assertEquals(expectedNodes, actualNodes); - - assertEquals(expectedNodes, DirectedEdgeUtils.getNodes(edges, HashSet::new)); - assertEquals(expectedNodes, DirectedEdgeUtils.getNodes(edges, LinkedHashSet::new)); - } - - private static Stream testGetNodes() { - return Stream.of( - new Object[] { List.of(edge(A, B)), Set.of(A, B) }, - new Object[] { List.of(edge(A, B), edge(A, B)), Set.of(A, B) }, - new Object[] { List.of(edge(A, B), edge(B, A)), Set.of(A, B) }, - new Object[] { List.of(edge(A, B), edge(D, B)), Set.of(A, B, D) } - ); - } - - @ParameterizedTest - @MethodSource - public void testGetNoIncomingEdgeNodes(List> edges, Set expectedNodes) { - final var actualNodes = DirectedEdgeUtils.getNoIncomingEdgeNodes(edges); - - assertEquals(expectedNodes, actualNodes); - - assertEquals(expectedNodes, DirectedEdgeUtils.getNoIncomingEdgeNodes(edges, HashSet::new)); - assertEquals(expectedNodes, DirectedEdgeUtils.getNoIncomingEdgeNodes(edges, LinkedHashSet::new)); - } - - private static Stream testGetNoIncomingEdgeNodes() { - return Stream.of( - new Object[] { List.of(edge(A, B)), Set.of(A) }, - new Object[] { List.of(edge(A, B), edge(A, B)), Set.of(A) }, - new Object[] { List.of(edge(A, B), edge(B, A)), Set.of() }, - new Object[] { List.of(edge(A, B), edge(D, B)), Set.of(A, D) }, - // A <- B <- D - // | - // + <- D <- C - // | - // + <- L <- B - new Object[] { List.of(edge(B, A), edge(D, B), edge(D, A), edge(C, D), edge(L, D), edge(B, L)), Set.of(C) } - ); - } - - @ParameterizedTest - @MethodSource - public void testGetEdgesTo(String node, List> edges, List> expectedEdges) { - final var actualEdges = DirectedEdgeUtils.getEdgesTo(node, edges); - - if (expectedEdges == SAME_LIST) { - expectedEdges = edges; - } - - assertEqualsSorted(expectedEdges, actualEdges); - - assertEqualsSorted(expectedEdges, DirectedEdgeUtils.getEdgesTo(node, edges, ArrayList::new)); - assertEqualsSorted(new LinkedHashSet<>(expectedEdges), DirectedEdgeUtils.getEdgesTo(node, edges, HashSet::new)); - } - - private static Stream testGetEdgesTo() { - return Stream.of( - new Object[] { A, List.of(edge(A, B)), List.of() }, - new Object[] { B, List.of(edge(A, B)), SAME_LIST }, - new Object[] { B, List.of(edge(A, B), edge(A, B)), SAME_LIST }, - new Object[] { B, List.of(edge(A, B), edge(B, C)), List.of(edge(A, B)) }, - new Object[] { B, List.of(edge(A, B), edge(B, C), edge(C, D)), List.of(edge(A, B)) }, - new Object[] { B, List.of(edge(A, B), edge(A, C), edge(D, B)), List.of(edge(A, B), edge(D, B)) } - ); - } - - @ParameterizedTest - @MethodSource - public void testGetEdgesFrom(String node, List> edges, List> expectedEdges) { - final var actualEdges = DirectedEdgeUtils.getEdgesFrom(node, edges); - - if (expectedEdges == SAME_LIST) { - expectedEdges = edges; - } - - assertEqualsSorted(expectedEdges, actualEdges); - - assertEqualsSorted(expectedEdges, DirectedEdgeUtils.getEdgesFrom(node, edges, ArrayList::new)); - assertEqualsSorted(new LinkedHashSet<>(expectedEdges), DirectedEdgeUtils.getEdgesFrom(node, edges, HashSet::new)); - } - - private static Stream testGetEdgesFrom() { - return Stream.of( - new Object[] { A, List.of(edge(A, B)), SAME_LIST }, - new Object[] { B, List.of(edge(A, B)), List.of() }, - new Object[] { A, List.of(edge(A, B), edge(A, B)), SAME_LIST }, - new Object[] { B, List.of(edge(A, B), edge(B, C)), List.of(edge(B, C)) }, - new Object[] { B, List.of(edge(A, B), edge(B, C), edge(C, D)), List.of(edge(B, C)) }, - new Object[] { D, List.of(edge(D, B), edge(D, A), edge(C, D)), List.of(edge(D, B), edge(D, A)) } - ); - } - - private static DirectedEdge edge(String from, String to) { - return DirectedEdge.create(from, to); - } - - private static void assertEqualsSorted(Collection> expected, Collection> actual) { - assertEquals(expected.stream().sorted(EDGE_COMPARATOR).toList(), actual.stream().sorted(EDGE_COMPARATOR).toList()); - } - - private final static List SAME_LIST = new ArrayList<>(); - - private final static Comparator> EDGE_COMPARATOR = - Comparator., String>comparing(DirectedEdge::from).thenComparing(DirectedEdge::to); - - private final static String A = "A"; - private final static String B = "B"; - private final static String C = "C"; - private final static String D = "D"; - private final static String L = "L"; -} diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java new file mode 100644 index 0000000000000..8c9abe1af9714 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +final class ImmutableDAGTest { + + @ParameterizedTest + @MethodSource + public void testCyclic(List> edges) { + assertThrows(UnsupportedOperationException.class, () -> create(edges)); + } + + private static Stream>> testCyclic() { + return Stream.of( + List.of(edge(A, B), edge(B, A)), + + List.of(edge(A, B), edge(B, C), edge(C, D), edge(D, A)), + + List.of(edge(A, B), edge(B, C), edge(C, D), edge(D, B)), + + // A <- B -> L + // | ^ | + // | | | + // + <- D <- + + // | + // + <- C + List.of(edge(B, A), edge(D, B), edge(D, A), edge(C, D), edge(L, D), edge(B, L)), + List.of(edge(C, D), edge(B, A), edge(D, B), edge(D, A), edge(L, D), edge(B, L)) + ); + } + + @ParameterizedTest + @MethodSource + public void testGetNoIncomingEdges(List> edges, List expectedNodes) { + final var actualNodes = create(edges).getNoIncomingEdges(); + assertEquals(expectedNodes, actualNodes); + } + + private static Stream testGetNoIncomingEdges() { + return Stream.of( + new Object[] { List.of(edge(A, B)), List.of(A) }, + new Object[] { List.of(edge(A, B), edge(A, B)), List.of(A) }, + new Object[] { List.of(edge(A, B), edge(D, B)), List.of(A, D) }, + new Object[] { List.of(edge(D, B), edge(A, B)), List.of(D, A) }, + + new Object[] { List.of(edge(A, B), edge(C, D)), List.of(A, C) }, + + // A <- B + // | ^ + // | | + // + <- D <- L + // | + // + <- C + new Object[] { List.of(edge(B, A), edge(D, B), edge(D, A), edge(C, D), edge(L, D)), List.of(C, L) }, + new Object[] { List.of(edge(B, A), edge(L, D), edge(D, B), edge(D, A), edge(C, D)), List.of(L, C) } + ); + } + + @ParameterizedTest + @MethodSource + public void testGetNoOutgoingEdges(List> edges, List expectedNodes) { + final var actualNodes = create(edges).getNoOutgoingEdges(); + assertEquals(expectedNodes, actualNodes); + } + + private static Stream testGetNoOutgoingEdges() { + return Stream.of( + new Object[] { List.of(edge(A, B)), List.of(B) }, + new Object[] { List.of(edge(A, B), edge(C, D)), List.of(B, D) } + ); + } + + @ParameterizedTest + @MethodSource + public void testGetTailsOf(String node, List> edges, List expectedNodes) { + final var actualNodes = create(edges).getTailsOf(node); + assertEquals(actualNodes, expectedNodes); + + } + + private static Stream testGetTailsOf() { + return Stream.of( + new Object[] { A, List.of(edge(A, B)), List.of() }, + new Object[] { B, List.of(edge(A, B)), List.of(A) }, + new Object[] { B, List.of(edge(A, B), edge(A, B)), List.of(A) }, + new Object[] { B, List.of(edge(A, B), edge(B, C)), List.of(A) }, + new Object[] { B, List.of(edge(A, B), edge(B, C), edge(C, D)), List.of(A) }, + new Object[] { B, List.of(edge(A, B), edge(A, C), edge(D, B)), List.of(A, D) }, + new Object[] { B, List.of(edge(D, B), edge(A, B), edge(A, C)), List.of(D, A) } + ); + } + + @ParameterizedTest + @MethodSource + public void testGetHeadsOf(String node, List> edges, List expectedNodes) { + final var actualNodes = create(edges).getHeadsOf(node); + assertEquals(actualNodes, expectedNodes); + } + + private static Stream testGetHeadsOf() { + return Stream.of( + new Object[] { A, List.of(edge(A, B)), List.of(B) }, + new Object[] { B, List.of(edge(A, B)), List.of() }, + new Object[] { A, List.of(edge(A, B), edge(A, B)), List.of(B) }, + new Object[] { B, List.of(edge(A, B), edge(B, C)), List.of(C) }, + new Object[] { B, List.of(edge(A, B), edge(B, C), edge(C, D)), List.of(C) }, + new Object[] { D, List.of(edge(D, B), edge(D, A), edge(C, D)), List.of(B, A) }, + new Object[] { D, List.of(edge(D, A), edge(D, B), edge(C, D)), List.of(A, B) } + ); + } + + @Test + public void testSome() { + // A <- B <--- D + // ^ ^ | + // | | | + // +--- C -> L | + // | ^ | + // | | | + // +----+------+ + + final var graphBuilder = ImmutableDAG.build(); + + graphBuilder.addEdge(edge(C, L)); + graphBuilder.addEdge(edge(D, B)); + graphBuilder.addEdge(edge(B, A)); + graphBuilder.addEdge(edge(D, A)); + graphBuilder.addEdge(edge(C, A)); + graphBuilder.addEdge(edge(D, C)); + graphBuilder.addEdge(edge(C, B)); + + final var graph = graphBuilder.create(); + + assertEquals(graph.getNoIncomingEdges(), List.of(D)); + assertEquals(graph.getNoOutgoingEdges(), List.of(L, A)); + + assertEquals(graph.getHeadsOf(A), List.of()); + assertEquals(graph.getTailsOf(A), List.of(C, D, B)); + + assertEquals(graph.getHeadsOf(B), List.of(A)); + assertEquals(graph.getTailsOf(B), List.of(C, D)); + + assertEquals(graph.getHeadsOf(C), List.of(L, B, A)); + assertEquals(graph.getTailsOf(C), List.of(D)); + + assertEquals(graph.getHeadsOf(D), List.of(C, B, A)); + assertEquals(graph.getTailsOf(D), List.of()); + + assertEquals(graph.getHeadsOf(L), List.of()); + assertEquals(graph.getTailsOf(L), List.of(C)); + } + + private static ImmutableDAG create(Collection> edges) { + final var graphBuilder = ImmutableDAG.build(); + edges.forEach(graphBuilder::addEdge); + return graphBuilder.create(); + } + + private static DirectedEdge edge(String from, String to) { + return DirectedEdge.create(from, to); + } + + private final static String A = "A"; + private final static String B = "B"; + private final static String C = "C"; + private final static String D = "D"; + private final static String L = "L"; +} From cc79c8729de824a51de83caa6677bf276da53bf5 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 27 Jan 2025 23:29:10 -0500 Subject: [PATCH 0255/1101] Get rid of Context and Action interfaces, use Runnable instead. This simplified implementation a bit. Updated pipeleine unit tests to use regexp in asserts of parallel executions. All tests pass. Fixed CountedCompleterBuilder based on the code coverage report. --- .../jpackage/internal/pipeline/Action.java | 55 ----------- .../pipeline/ActionPipelineBuilder.java | 57 ++++++----- .../internal/pipeline/ConditionalAction.java | 44 --------- .../jpackage/internal/pipeline/Context.java | 29 ------ .../pipeline/CountedCompleterBuilder.java | 39 +++----- .../pipeline/ActionPipelineBuilderTest.java | 99 ++++++++++++++----- 6 files changed, 121 insertions(+), 202 deletions(-) delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Action.java delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ConditionalAction.java delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Context.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Action.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Action.java deleted file mode 100644 index a6c926def410a..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Action.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -import java.util.function.Predicate; - -@FunctionalInterface -public interface Action { - - void execute(T context); - - static Action createConditionalAction(Predicate predicate, Action action) { - return new ConditionalAction<>(action, predicate); - } - - @SuppressWarnings("unchecked") - static Action rootAction() { - return (Action)ROOT_ACTION; - } - - static final Action ROOT_ACTION = new Action<>() { - - @Override - public void execute(Context context) { - } - - @Override - public String toString() { - return super.toString() + "(root)"; - } - }; -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java index 113cd2b55dc65..b155e486659bd 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java @@ -30,42 +30,43 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.CountedCompleter; import java.util.concurrent.ForkJoinPool; -public final class ActionPipelineBuilder { +public final class ActionPipelineBuilder { public final class ActionSpecBuilder { - ActionSpecBuilder(Action action) { + ActionSpecBuilder(Runnable action) { Objects.requireNonNull(action); this.action = action; } - public ActionSpecBuilder dependent(Action v) { + public ActionSpecBuilder dependent(Runnable v) { dependent = v; return this; } - public ActionSpecBuilder addDependency(Action v) { + public ActionSpecBuilder addDependency(Runnable v) { Objects.requireNonNull(v); dependencies.add(v); return this; } - public ActionSpecBuilder addDependencies(Collection> v) { + public ActionSpecBuilder addDependencies(Collection v) { Objects.requireNonNull(v); v.forEach(Objects::requireNonNull); dependencies.addAll(v); return this; } - public ActionPipelineBuilder add() { + public ActionPipelineBuilder add() { if (actionGraphBuilder == null) { actionGraphBuilder = new ImmutableDAG.Builder<>(); - actionGraphBuilder.addEdge(action, Action.rootAction()); + actionGraphBuilder.addEdge(action, ROOT_ACTION); actionGraphBuilder.canAddEdgeToUnknownNode(false); } else { - actionGraphBuilder.addEdge(action, Optional.ofNullable(dependent).orElseGet(Action::rootAction)); + actionGraphBuilder.addEdge(action, Optional.ofNullable(dependent).orElse(ROOT_ACTION)); } for (var dependency : dependencies) { @@ -75,50 +76,60 @@ public ActionPipelineBuilder add() { return ActionPipelineBuilder.this; } - private Set> dependencies = new LinkedHashSet<>(); - private Action dependent; - private final Action action; + private Set dependencies = new LinkedHashSet<>(); + private Runnable dependent; + private final Runnable action; } - public ActionSpecBuilder action(Action action) { + public ActionSpecBuilder action(Runnable action) { return new ActionSpecBuilder(action); } - public ActionPipelineBuilder executor(ForkJoinPool v) { + public ActionPipelineBuilder executor(ForkJoinPool v) { Objects.requireNonNull(v); fjp = v; return this; } - public ActionPipelineBuilder sequentialExecutor() { + public ActionPipelineBuilder sequentialExecutor() { fjp = new ForkJoinPool(1); return this; } - public Action create() { + public Runnable create() { final var actionGraph = actionGraphBuilder.create(); - final var countedCompleterBuilder = new CountedCompleterBuilder<>(actionGraph); + final var rootCompleter = new CountedCompleterBuilder(actionGraph).create(); - return new WrapperAction<>(countedCompleterBuilder, fjp); + return new WrapperAction(rootCompleter, fjp); } - private record WrapperAction(CountedCompleterBuilder countedCompleterBuilder, - ForkJoinPool fjp) implements Action { + private record WrapperAction(CountedCompleter rootCompleter, ForkJoinPool fjp) implements Runnable { WrapperAction { - Objects.requireNonNull(countedCompleterBuilder); + Objects.requireNonNull(rootCompleter); Objects.requireNonNull(fjp); } @Override - public void execute(U context) { - final var rootCompleter = countedCompleterBuilder.create(context); + public void run() { fjp.invoke(rootCompleter); } } - private ImmutableDAG.Builder> actionGraphBuilder; + private static final Runnable ROOT_ACTION = new Runnable() { + + @Override + public void run() { + } + + @Override + public String toString() { + return super.toString() + "(root)"; + } + }; + + private ImmutableDAG.Builder actionGraphBuilder; private ForkJoinPool fjp; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ConditionalAction.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ConditionalAction.java deleted file mode 100644 index cc4e73a453c8d..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ConditionalAction.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -import java.util.Objects; -import java.util.function.Predicate; - -record ConditionalAction(Action action, Predicate predicate) implements Action { - - ConditionalAction { - Objects.requireNonNull(action); - Objects.requireNonNull(predicate); - } - - @Override - public void execute(T context) { - if (predicate.test(context)) { - action.execute(context); - } - } -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Context.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Context.java deleted file mode 100644 index f0fdec016e4e4..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/Context.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -public interface Context { -} \ No newline at end of file diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java index 6058902ec425a..dd53158291f54 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java @@ -38,12 +38,10 @@ /** * Schedules execution of actions in the given action graph. - * - * @param type parameter for {@link Action} class */ -final class CountedCompleterBuilder { +final class CountedCompleterBuilder { - CountedCompleterBuilder(ImmutableDAG> actionGraph) { + CountedCompleterBuilder(ImmutableDAG actionGraph) { this.actionGraph = Objects.requireNonNull(actionGraph); runOnce = StreamSupport.stream(actionGraph.getNodes().spliterator(), false).filter(node -> { @@ -51,8 +49,8 @@ final class CountedCompleterBuilder { }).collect(toMap(x -> x, x -> new ActionCompleters())); } - CountedCompleter create(T context) { - final var rootCompleters = createRootCompleters(context); + CountedCompleter create() { + final var rootCompleters = createRootCompleters(); if (rootCompleters.size() == 1) { return rootCompleters.get(0); } else { @@ -60,28 +58,21 @@ CountedCompleter create(T context) { } } - private List> createRootCompleters(T context) { - Objects.requireNonNull(context); - + private List> createRootCompleters() { final var rootNodes = actionGraph.getNoOutgoingEdges(); return rootNodes.stream().map(rootNode -> { - return new ActionCompleter(null, context, rootNode); + return new ActionCompleter(null, rootNode); }).toList(); } - private Optional registerCompleter(Action action, CountedCompleter completer) { + private Optional registerCompleter(Runnable action, CountedCompleter completer) { Objects.requireNonNull(completer); final var dependentActions = actionGraph.getHeadsOf(action); if (dependentActions.size() <= 1) { return Optional.empty(); } else { var completers = runOnce.get(action); - if (completers == null) { - completers = new ActionCompleters(); - runOnce.put(action, completers); - } - completers.allCompleters().add(completer); return Optional.of(completers); } @@ -116,13 +107,12 @@ public void compute() { private final class ActionCompleter extends DependentComleter { - ActionCompleter(CountedCompleter dependentCompleter, T context, Action action) { + ActionCompleter(CountedCompleter dependentCompleter, Runnable action) { super(dependentCompleter); - this.context = Objects.requireNonNull(context); this.action = Objects.requireNonNull(action); dependencyCompleters = actionGraph.getTailsOf(action).stream().map(dependencyAction -> { - return new ActionCompleter(this, context, dependencyAction); + return new ActionCompleter(this, dependencyAction); }).toList(); actionCompleters = registerCompleter(action, this); @@ -132,15 +122,13 @@ private final class ActionCompleter extends DependentComleter { public void compute() { if (actionCompleters.map(ActionCompleters::completer).map(ref -> ref.compareAndSet(null, this)).orElse(true)) { super.compute(); - } else if(actionCompleters.isEmpty()) { - tryComplete(); } } @Override public void onCompletion(CountedCompleter caller) { if (actionCompleters.map(ac -> ac.isActionCompleter(this)).orElse(true)) { - action.execute(context); + action.run(); actionCompleters.ifPresent(ActionCompleters::complete); } } @@ -150,8 +138,7 @@ protected List> dependencyCompleters() { return dependencyCompleters; } - private final T context; - private final Action action; + private final Runnable action; private final List> dependencyCompleters; private final Optional actionCompleters; @@ -194,6 +181,6 @@ void complete() { } } - private final ImmutableDAG> actionGraph; - private final Map, ActionCompleters> runOnce; + private final ImmutableDAG actionGraph; + private final Map runOnce; } diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java index 4bb8579e27045..1f922f89b2724 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java @@ -25,6 +25,7 @@ import static java.util.stream.Collectors.joining; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.time.Duration; import java.util.ArrayList; @@ -33,16 +34,16 @@ import java.util.Objects; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.locks.LockSupport; +import java.util.function.Consumer; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; final class ActionPipelineBuilderTest { - record TestContext(StringBuffer sb) implements Context { - } - - enum TestAction implements Action { + enum TestAction implements Consumer { A, B, C, @@ -51,10 +52,26 @@ enum TestAction implements Action { L; @Override - public void execute(TestContext context) { + public void accept(StringBuffer sb) { LockSupport.parkNanos(Duration.ofMillis(10).toNanos()); - System.out.println(String.format("[%s] result before append: [%s]; append %s", Thread.currentThread(), context.sb(), name())); - context.sb().append(name()); + System.out.println(String.format("[%s] result before append: [%s]; append %s", Thread.currentThread(), sb, name())); + sb.append(name()); + } + + Runnable toRunnable(StringBuffer sb) { + return new Runnable () { + + @Override + public void run() { + accept(sb); + } + + @Override + public String toString() { + return TestAction.this.toString(); + } + + }; } } @@ -88,35 +105,54 @@ ActionSpec create() { @ParameterizedTest @MethodSource("testSequentialData") - public void testSequential(List actionSpecs, String expectedString) { + public void testSequential(List actionSpecs, Object expectedString) { testIt(new ForkJoinPool(1), actionSpecs, expectedString); } @ParameterizedTest @MethodSource("testParallelData") - public void testParallel(List actionSpecs, String expectedString) { + public void testParallel(List actionSpecs, Object expectedString) { testIt(new ForkJoinPool(4), actionSpecs, expectedString); } - private void testIt(ForkJoinPool fjp, List actionSpecs, String expectedString) { - final var builder = new ActionPipelineBuilder(); + private void testIt(ForkJoinPool fjp, List actionSpecs, Object expectedString) { + final var builder = new ActionPipelineBuilder(); builder.executor(fjp); + final var sb = new StringBuffer(); + + final var actionMap = Stream.of(TestAction.values()).collect(Collectors.toMap(x -> x, x -> { + return x.toRunnable(sb); + })); + actionSpecs.forEach(actionSpec -> { - builder.action(actionSpec.action).addDependencies(actionSpec.dependencies).dependent(actionSpec.dependent).add(); + builder.action(actionMap.get(actionSpec.action)) + .addDependencies(actionSpec.dependencies.stream().map(actionMap::get).toList()) + .dependent(actionMap.get(actionSpec.dependent)) + .add(); }); - final var context = new TestContext(new StringBuffer()); - System.out.println(String.format("start for %s", expectedString)); - builder.create().execute(context); - assertEquals(expectedString, context.sb.toString()); + builder.create().run(); + + final var actualString = sb.toString(); + + if (expectedString instanceof Pattern expectedRegexp) { + assertTrue(expectedRegexp.matcher(actualString).matches(), () -> { + return String.format("Regexp %s doesn't match string %s", expectedRegexp, actualString); + }); + } else { + assertEquals(expectedString.toString(), actualString); + } + System.out.println("end"); } - private static List testData() { - return List.of( + private static List testData(boolean sequential) { + final List data = new ArrayList<>(); + + data.addAll(List.of( new Object[] { List.of(action(A).create()), "A" }, new Object[] { List.of(action(B).from(A).create()), "AB" }, @@ -125,28 +161,41 @@ private static List testData() { // | | // +--- A ---+ new Object[] { List.of(action(D).create(), action(C).from(B).to(D).create(), action(A).to(B).create(), action(A).to(D).create()), "ABCD" } - ); - } + )); - private static List testSequentialData() { - final var data = new ArrayList<>(testData()); + final var allValuesRegexp = Pattern.compile(String.format("[%s]{%d}", Stream.of(TestAction.values()).map(Enum::name).collect(joining()), TestAction.values().length)); data.addAll(List.of( new Object[] { Stream.of(TestAction.values()) .map(ActionPipelineBuilderTest::action) - .map(ActionSpecBuilder::create).toList(), Stream.of(TestAction.values()).map(Enum::name).collect(joining()) }, + .map(ActionSpecBuilder::create).toList(), + sequential ? Stream.of(TestAction.values()).map(Enum::name).collect(joining()) : allValuesRegexp }, new Object[] { Stream.of(TestAction.values()) .sorted(Comparator.reverseOrder()) .map(ActionPipelineBuilderTest::action) - .map(ActionSpecBuilder::create).toList(), Stream.of(TestAction.values()).sorted(Comparator.reverseOrder()).map(Enum::name).collect(joining()) } + .map(ActionSpecBuilder::create).toList(), + sequential ? Stream.of(TestAction.values()).sorted(Comparator.reverseOrder()).map(Enum::name).collect(joining()) : allValuesRegexp } )); + // B -> A <- C + // ^ ^ + // | | + // +--- D ---+ + data.add(new Object[] { + List.of(action(A).create(), action(B).from(D).to(A).create(), action(C).from(D).to(A).create()), + sequential ? "DCBA" : Pattern.compile("D(BC|CB)A") + }); + return data; } + private static List testSequentialData() { + return testData(true); + } + private static List testParallelData() { - return testData(); + return testData(false); } private static ActionSpecBuilder action(TestAction action) { From a810a54a901d9b4622264b8502bb16b6175305ca Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 28 Jan 2025 17:38:26 -0500 Subject: [PATCH 0256/1101] Action -> Task; Runnable -> Callable --- .../pipeline/CountedCompleterBuilder.java | 71 ++++++------ ...eBuilder.java => TaskPipelineBuilder.java} | 69 +++++------ ...Test.java => TaskPipelineBuilderTest.java} | 108 +++++++++--------- 3 files changed, 129 insertions(+), 119 deletions(-) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/{ActionPipelineBuilder.java => TaskPipelineBuilder.java} (56%) rename test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/{ActionPipelineBuilderTest.java => TaskPipelineBuilderTest.java} (54%) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java index dd53158291f54..c758341c4ae35 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java @@ -32,21 +32,22 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.Callable; import java.util.concurrent.CountedCompleter; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.StreamSupport; /** - * Schedules execution of actions in the given action graph. + * Schedules execution of tasks in the given task graph. */ final class CountedCompleterBuilder { - CountedCompleterBuilder(ImmutableDAG actionGraph) { - this.actionGraph = Objects.requireNonNull(actionGraph); + CountedCompleterBuilder(ImmutableDAG> taskGraph) { + this.taskGraph = Objects.requireNonNull(taskGraph); - runOnce = StreamSupport.stream(actionGraph.getNodes().spliterator(), false).filter(node -> { - return actionGraph.getHeadsOf(node).size() > 1; - }).collect(toMap(x -> x, x -> new ActionCompleters())); + runOnce = StreamSupport.stream(taskGraph.getNodes().spliterator(), false).filter(node -> { + return taskGraph.getHeadsOf(node).size() > 1; + }).collect(toMap(x -> x, x -> new TaskCompleters())); } CountedCompleter create() { @@ -59,20 +60,20 @@ CountedCompleter create() { } private List> createRootCompleters() { - final var rootNodes = actionGraph.getNoOutgoingEdges(); + final var rootNodes = taskGraph.getNoOutgoingEdges(); return rootNodes.stream().map(rootNode -> { - return new ActionCompleter(null, rootNode); + return new TaskCompleter(null, rootNode); }).toList(); } - private Optional registerCompleter(Runnable action, CountedCompleter completer) { + private Optional registerCompleter(Callable task, CountedCompleter completer) { Objects.requireNonNull(completer); - final var dependentActions = actionGraph.getHeadsOf(action); - if (dependentActions.size() <= 1) { + final var dependentTasks = taskGraph.getHeadsOf(task); + if (dependentTasks.size() <= 1) { return Optional.empty(); } else { - var completers = runOnce.get(action); + var completers = runOnce.get(task); completers.allCompleters().add(completer); return Optional.of(completers); } @@ -93,7 +94,7 @@ public void compute() { setPendingCount(dependencyCompleters.size()); // ForkJoinPool will execute tasks in the reverse order of how they are scheduled. - // Reverse the order in which actions are scheduled to get them executed in the order placed in the dependency list. + // Reverse the order in which tasks are scheduled to get them executed in the order placed in the dependency list. // Ordering works for sequential execution only. dependencyCompleters.reversed().forEach(CountedCompleter::fork); @@ -105,31 +106,35 @@ public void compute() { private static final long serialVersionUID = 1L; } - private final class ActionCompleter extends DependentComleter { + private final class TaskCompleter extends DependentComleter { - ActionCompleter(CountedCompleter dependentCompleter, Runnable action) { + TaskCompleter(CountedCompleter dependentCompleter, Callable task) { super(dependentCompleter); - this.action = Objects.requireNonNull(action); + this.task = Objects.requireNonNull(task); - dependencyCompleters = actionGraph.getTailsOf(action).stream().map(dependencyAction -> { - return new ActionCompleter(this, dependencyAction); + dependencyCompleters = taskGraph.getTailsOf(task).stream().map(dependencyTask -> { + return new TaskCompleter(this, dependencyTask); }).toList(); - actionCompleters = registerCompleter(action, this); + taskCompleters = registerCompleter(task, this); } @Override public void compute() { - if (actionCompleters.map(ActionCompleters::completer).map(ref -> ref.compareAndSet(null, this)).orElse(true)) { + if (taskCompleters.map(TaskCompleters::completer).map(ref -> ref.compareAndSet(null, this)).orElse(true)) { super.compute(); } } @Override public void onCompletion(CountedCompleter caller) { - if (actionCompleters.map(ac -> ac.isActionCompleter(this)).orElse(true)) { - action.run(); - actionCompleters.ifPresent(ActionCompleters::complete); + if (taskCompleters.map(ac -> ac.isTaskCompleter(this)).orElse(true)) { + try { + task.call(); + } catch (Exception ex) { + completeExceptionally(ex); + } + taskCompleters.ifPresent(TaskCompleters::complete); } } @@ -138,9 +143,9 @@ protected List> dependencyCompleters() { return dependencyCompleters; } - private final Runnable action; - private final List> dependencyCompleters; - private final Optional actionCompleters; + private final transient Callable task; + private final transient List> dependencyCompleters; + private final transient Optional taskCompleters; private static final long serialVersionUID = 1L; } @@ -156,31 +161,31 @@ protected List> dependencyCompleters() { return dependencyCompleters; } - private final List> dependencyCompleters; + private final transient List> dependencyCompleters; private static final long serialVersionUID = 1L; } - private record ActionCompleters(AtomicReference> completer, + private record TaskCompleters(AtomicReference> completer, List> allCompleters) { - ActionCompleters() { + TaskCompleters() { this(new AtomicReference<>(), new ArrayList<>()); } - boolean isActionCompleter(CountedCompleter c) { + boolean isTaskCompleter(CountedCompleter c) { return c == completer.get(); } void complete() { allCompleters.forEach(c -> { - if (!isActionCompleter(c)) { + if (!isTaskCompleter(c)) { c.complete(null); } }); } } - private final ImmutableDAG actionGraph; - private final Map runOnce; + private final ImmutableDAG> taskGraph; + private final Map, TaskCompleters> runOnce; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java similarity index 56% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java index b155e486659bd..8c0eb9642d00c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ActionPipelineBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java @@ -30,98 +30,101 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.Callable; import java.util.concurrent.CountedCompleter; import java.util.concurrent.ForkJoinPool; -public final class ActionPipelineBuilder { +public final class TaskPipelineBuilder { - public final class ActionSpecBuilder { + public final class TaskSpecBuilder { - ActionSpecBuilder(Runnable action) { - Objects.requireNonNull(action); - this.action = action; + TaskSpecBuilder(Callable task) { + Objects.requireNonNull(task); + this.task = task; } - public ActionSpecBuilder dependent(Runnable v) { + public TaskSpecBuilder dependent(Callable v) { dependent = v; return this; } - public ActionSpecBuilder addDependency(Runnable v) { + public TaskSpecBuilder addDependency(Callable v) { Objects.requireNonNull(v); dependencies.add(v); return this; } - public ActionSpecBuilder addDependencies(Collection v) { + public TaskSpecBuilder addDependencies(Collection> v) { Objects.requireNonNull(v); v.forEach(Objects::requireNonNull); dependencies.addAll(v); return this; } - public ActionPipelineBuilder add() { - if (actionGraphBuilder == null) { - actionGraphBuilder = new ImmutableDAG.Builder<>(); - actionGraphBuilder.addEdge(action, ROOT_ACTION); - actionGraphBuilder.canAddEdgeToUnknownNode(false); + public TaskPipelineBuilder add() { + if (taskGraphBuilder == null) { + taskGraphBuilder = new ImmutableDAG.Builder<>(); + taskGraphBuilder.addEdge(task, ROOT_ACTION); + taskGraphBuilder.canAddEdgeToUnknownNode(false); } else { - actionGraphBuilder.addEdge(action, Optional.ofNullable(dependent).orElse(ROOT_ACTION)); + taskGraphBuilder.addEdge(task, Optional.ofNullable(dependent).orElse(ROOT_ACTION)); } for (var dependency : dependencies) { - actionGraphBuilder.addEdge(dependency, action); + taskGraphBuilder.addEdge(dependency, task); } - return ActionPipelineBuilder.this; + return TaskPipelineBuilder.this; } - private Set dependencies = new LinkedHashSet<>(); - private Runnable dependent; - private final Runnable action; + private Set> dependencies = new LinkedHashSet<>(); + private Callable dependent; + private final Callable task; } - public ActionSpecBuilder action(Runnable action) { - return new ActionSpecBuilder(action); + public TaskSpecBuilder task(Callable task) { + return new TaskSpecBuilder(task); } - public ActionPipelineBuilder executor(ForkJoinPool v) { + public TaskPipelineBuilder executor(ForkJoinPool v) { Objects.requireNonNull(v); fjp = v; return this; } - public ActionPipelineBuilder sequentialExecutor() { + public TaskPipelineBuilder sequentialExecutor() { fjp = new ForkJoinPool(1); return this; } - public Runnable create() { - final var actionGraph = actionGraphBuilder.create(); + public Callable create() { + final var taskGraph = taskGraphBuilder.create(); - final var rootCompleter = new CountedCompleterBuilder(actionGraph).create(); + final var rootCompleter = new CountedCompleterBuilder(taskGraph).create(); - return new WrapperAction(rootCompleter, fjp); + return new WrapperTask(rootCompleter, fjp); } - private record WrapperAction(CountedCompleter rootCompleter, ForkJoinPool fjp) implements Runnable { + private record WrapperTask(CountedCompleter rootCompleter, ForkJoinPool fjp) implements Callable { - WrapperAction { + WrapperTask { Objects.requireNonNull(rootCompleter); Objects.requireNonNull(fjp); } @Override - public void run() { + public Void call() { fjp.invoke(rootCompleter); + return null; } } - private static final Runnable ROOT_ACTION = new Runnable() { + private static final Callable ROOT_ACTION = new Callable() { @Override - public void run() { + public Void call() { + return null; } @Override @@ -130,6 +133,6 @@ public String toString() { } }; - private ImmutableDAG.Builder actionGraphBuilder; + private ImmutableDAG.Builder> taskGraphBuilder; private ForkJoinPool fjp; } diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java similarity index 54% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java rename to test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java index 1f922f89b2724..bed56cc10b0b8 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ActionPipelineBuilderTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java @@ -32,6 +32,7 @@ import java.util.Comparator; import java.util.List; import java.util.Objects; +import java.util.concurrent.Callable; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.locks.LockSupport; import java.util.function.Consumer; @@ -41,9 +42,9 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -final class ActionPipelineBuilderTest { +final class TaskPipelineBuilderTest { - enum TestAction implements Consumer { + enum TestTask implements Consumer { A, B, C, @@ -58,83 +59,84 @@ public void accept(StringBuffer sb) { sb.append(name()); } - Runnable toRunnable(StringBuffer sb) { - return new Runnable () { + Callable toCallable(StringBuffer sb) { + return new Callable () { @Override - public void run() { + public Void call() { accept(sb); + return null; } @Override public String toString() { - return TestAction.this.toString(); + return TestTask.this.toString(); } }; } } - record ActionSpec(TestAction action, List dependencies, TestAction dependent) { + record TaskSpec(TestTask task, List dependencies, TestTask dependent) { } - private final static class ActionSpecBuilder { + private final static class TaskSpecBuilder { - ActionSpecBuilder(TestAction action) { - this.action = Objects.requireNonNull(action); + TaskSpecBuilder(TestTask task) { + this.task = Objects.requireNonNull(task); } - ActionSpecBuilder to(TestAction action) { - dependent = action; + TaskSpecBuilder to(TestTask task) { + dependent = task; return this; } - ActionSpecBuilder from(TestAction ... actions) { - dependencies.addAll(List.of(actions)); + TaskSpecBuilder from(TestTask ... tasks) { + dependencies.addAll(List.of(tasks)); return this; } - ActionSpec create() { - return new ActionSpec(action, dependencies, dependent); + TaskSpec create() { + return new TaskSpec(task, dependencies, dependent); } - private final TestAction action; - private final List dependencies = new ArrayList<>(); - private TestAction dependent; + private final TestTask task; + private final List dependencies = new ArrayList<>(); + private TestTask dependent; } @ParameterizedTest @MethodSource("testSequentialData") - public void testSequential(List actionSpecs, Object expectedString) { - testIt(new ForkJoinPool(1), actionSpecs, expectedString); + public void testSequential(List taskSpecs, Object expectedString) throws Exception { + testIt(new ForkJoinPool(1), taskSpecs, expectedString); } @ParameterizedTest @MethodSource("testParallelData") - public void testParallel(List actionSpecs, Object expectedString) { - testIt(new ForkJoinPool(4), actionSpecs, expectedString); + public void testParallel(List taskSpecs, Object expectedString) throws Exception { + testIt(new ForkJoinPool(4), taskSpecs, expectedString); } - private void testIt(ForkJoinPool fjp, List actionSpecs, Object expectedString) { - final var builder = new ActionPipelineBuilder(); + private void testIt(ForkJoinPool fjp, List taskSpecs, Object expectedString) throws Exception { + final var builder = new TaskPipelineBuilder(); builder.executor(fjp); final var sb = new StringBuffer(); - final var actionMap = Stream.of(TestAction.values()).collect(Collectors.toMap(x -> x, x -> { - return x.toRunnable(sb); + final var taskMap = Stream.of(TestTask.values()).collect(Collectors.toMap(x -> x, x -> { + return x.toCallable(sb); })); - actionSpecs.forEach(actionSpec -> { - builder.action(actionMap.get(actionSpec.action)) - .addDependencies(actionSpec.dependencies.stream().map(actionMap::get).toList()) - .dependent(actionMap.get(actionSpec.dependent)) + taskSpecs.forEach(taskSpec -> { + builder.task(taskMap.get(taskSpec.task)) + .addDependencies(taskSpec.dependencies.stream().map(taskMap::get).toList()) + .dependent(taskMap.get(taskSpec.dependent)) .add(); }); System.out.println(String.format("start for %s", expectedString)); - builder.create().run(); + builder.create().call(); final var actualString = sb.toString(); @@ -153,29 +155,29 @@ private static List testData(boolean sequential) { final List data = new ArrayList<>(); data.addAll(List.of( - new Object[] { List.of(action(A).create()), "A" }, - new Object[] { List.of(action(B).from(A).create()), "AB" }, + new Object[] { List.of(task(A).create()), "A" }, + new Object[] { List.of(task(B).from(A).create()), "AB" }, // D <- C <- B // ^ ^ // | | // +--- A ---+ - new Object[] { List.of(action(D).create(), action(C).from(B).to(D).create(), action(A).to(B).create(), action(A).to(D).create()), "ABCD" } + new Object[] { List.of(task(D).create(), task(C).from(B).to(D).create(), task(A).to(B).create(), task(A).to(D).create()), "ABCD" } )); - final var allValuesRegexp = Pattern.compile(String.format("[%s]{%d}", Stream.of(TestAction.values()).map(Enum::name).collect(joining()), TestAction.values().length)); + final var allValuesRegexp = Pattern.compile(String.format("[%s]{%d}", Stream.of(TestTask.values()).map(Enum::name).collect(joining()), TestTask.values().length)); data.addAll(List.of( - new Object[] { Stream.of(TestAction.values()) - .map(ActionPipelineBuilderTest::action) - .map(ActionSpecBuilder::create).toList(), - sequential ? Stream.of(TestAction.values()).map(Enum::name).collect(joining()) : allValuesRegexp }, + new Object[] { Stream.of(TestTask.values()) + .map(TaskPipelineBuilderTest::task) + .map(TaskSpecBuilder::create).toList(), + sequential ? Stream.of(TestTask.values()).map(Enum::name).collect(joining()) : allValuesRegexp }, - new Object[] { Stream.of(TestAction.values()) + new Object[] { Stream.of(TestTask.values()) .sorted(Comparator.reverseOrder()) - .map(ActionPipelineBuilderTest::action) - .map(ActionSpecBuilder::create).toList(), - sequential ? Stream.of(TestAction.values()).sorted(Comparator.reverseOrder()).map(Enum::name).collect(joining()) : allValuesRegexp } + .map(TaskPipelineBuilderTest::task) + .map(TaskSpecBuilder::create).toList(), + sequential ? Stream.of(TestTask.values()).sorted(Comparator.reverseOrder()).map(Enum::name).collect(joining()) : allValuesRegexp } )); // B -> A <- C @@ -183,7 +185,7 @@ private static List testData(boolean sequential) { // | | // +--- D ---+ data.add(new Object[] { - List.of(action(A).create(), action(B).from(D).to(A).create(), action(C).from(D).to(A).create()), + List.of(task(A).create(), task(B).from(D).to(A).create(), task(C).from(D).to(A).create()), sequential ? "DCBA" : Pattern.compile("D(BC|CB)A") }); @@ -198,14 +200,14 @@ private static List testParallelData() { return testData(false); } - private static ActionSpecBuilder action(TestAction action) { - return new ActionSpecBuilder(action); + private static TaskSpecBuilder task(TestTask task) { + return new TaskSpecBuilder(task); } - private final static TestAction A = TestAction.A; - private final static TestAction B = TestAction.B; - private final static TestAction C = TestAction.C; - private final static TestAction D = TestAction.D; - private final static TestAction K = TestAction.K; - private final static TestAction L = TestAction.L; + private final static TestTask A = TestTask.A; + private final static TestTask B = TestTask.B; + private final static TestTask C = TestTask.C; + private final static TestTask D = TestTask.D; + private final static TestTask K = TestTask.K; + private final static TestTask L = TestTask.L; } From d41365a0acf8074b9d9d5a0c2334407ee39d9c6c Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 28 Jan 2025 20:13:04 -0500 Subject: [PATCH 0257/1101] More unit tests added, better coverage --- .../internal/pipeline/BinaryMatrix.java | 17 +++ .../internal/pipeline/ImmutableDAG.java | 2 +- .../internal/pipeline/BinaryMatrixTest.java | 134 ++++++++++++++++++ .../internal/pipeline/DirectedEdgeTest.java | 58 ++++++++ 4 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java index 38b724d8dae0d..9193c4396a967 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java @@ -58,6 +58,23 @@ final class BinaryMatrix { this.values = Optional.ofNullable(values).orElseGet(() -> new BitSet(size)); } + @Override + public int hashCode() { + return Objects.hash(columns, rows, values); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + BinaryMatrix other = (BinaryMatrix) obj; + return columns == other.columns && rows == other.rows && Objects.equals(values, other.values); + } + interface Cursor { int row(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java index 589a3fc318dfa..a9cee11a9013a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java @@ -247,7 +247,7 @@ private static boolean isCyclic(BinaryMatrix edgeMatrix) { // Use Kahn's algorithm from https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm to find cyclic edges // Variable names picked from the algorithm pseudo-code. - // Set of all nodes with no incoming edge. + // Nodes with no incoming edges. final var S = getNoIncomingEdges(edgeMatrix).mapToObj(Integer::valueOf).collect(toCollection(ArrayList::new)); while (!S.isEmpty()) { diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java index 469f527eeacf8..5de201af4f134 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java @@ -24,16 +24,21 @@ package jdk.jpackage.internal.pipeline; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; import java.util.BitSet; import java.util.Iterator; import java.util.List; +import java.util.NoSuchElementException; import java.util.Spliterator; import java.util.function.Consumer; import java.util.stream.IntStream; import java.util.stream.Stream; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -156,6 +161,8 @@ void test() { final var split = getSpliterator(matrix); assertEquals(expected, readSelection(split::forEachRemaining)); + + assertThrows(NoSuchElementException.class, it::next); } } @@ -248,6 +255,133 @@ private static Stream testSelection() { ); } + record SetValueTest(MatrixSpec matrixSpec, int row, int column, Boolean expected) { + + static SetValueTest create(int rows, int columns, String encodedMatrixData, int row, int column, boolean expected) { + return new SetValueTest(new MatrixSpec(rows, columns, encodedMatrixData), row, column, expected); + } + + static SetValueTest create(int rows, int columns, int row, int column) { + return new SetValueTest(new MatrixSpec(rows, columns), row, column, null); + } + + void test() { + final var matrix = matrixSpec.createMatrix(); + final var matrixCopy = matrixSpec.createMatrix(); + if (expected == null) { + assertThrows(IndexOutOfBoundsException.class, () -> matrix.set(row, column)); + assertEquals(matrixCopy, matrix); + + assertThrows(IndexOutOfBoundsException.class, () -> matrix.set(row, column, true)); + assertEquals(matrixCopy, matrix); + + assertThrows(IndexOutOfBoundsException.class, () -> matrix.set(row, column, false)); + assertEquals(matrixCopy, matrix); + + assertThrows(IndexOutOfBoundsException.class, () -> matrix.unset(row, column)); + assertEquals(matrixCopy, matrix); + + assertThrows(IndexOutOfBoundsException.class, () -> matrix.isSet(row, column)); + assertEquals(matrixCopy, matrix); + } else { + assertEquals(expected, matrix.isSet(row, column)); + + matrix.set(row, column, expected); + assertEquals(expected, matrix.isSet(row, column)); + assertEquals(matrixCopy, matrix); + + if (expected) { + matrix.set(row, column); + } else { + matrix.unset(row, column); + } + assertEquals(expected, matrix.isSet(row, column)); + assertEquals(matrixCopy, matrix); + + matrix.set(row, column, !expected); + assertNotEquals(expected, matrix.isSet(row, column)); + assertNotEquals(matrixCopy, matrix); + + if (expected) { + matrix.set(row, column); + } else { + matrix.unset(row, column); + } + assertEquals(expected, matrix.isSet(row, column)); + assertEquals(matrixCopy, matrix); + } + } + } + + @ParameterizedTest + @MethodSource + public void testSetValue(SetValueTest testSpec) { + testSpec.test(); + } + + private static List testSetValue() { + final List data = new ArrayList<>(); + + data.addAll(List.of( + SetValueTest.create(1, 1, "0", 0, 0, false), + SetValueTest.create(1, 1, "1", 0, 0, true), + + SetValueTest.create(3, 2, -1, 0), + SetValueTest.create(3, 2, 3, 0), + SetValueTest.create(3, 2, 12, 0), + + SetValueTest.create(3, 2, 0, -1), + SetValueTest.create(3, 2, 0, 2), + SetValueTest.create(3, 2, 0, 12), + + SetValueTest.create(3, 2, 3, 2) + )); + + final var matrixData = new boolean[3][5]; + matrixData[0] = new boolean[] { false, true, false, true, true }; + matrixData[1] = new boolean[] { true, false, true, false, true }; + matrixData[2] = new boolean[] { false, false, true, false, false }; + + final var sb = new StringBuilder(); + for (int i = 0; i != 3; ++i) { + for (int j = 0; j != 5; ++j) { + sb.append(matrixData[i][j] ? '1' : '0'); + } + } + + final var encodedMatrixData = sb.toString(); + for (int i = 0; i != 3; ++i) { + for (int j = 0; j != 5; ++j) { + data.add(SetValueTest.create(3, 5, encodedMatrixData, i, j, matrixData[i][j])); + } + } + + return data; + } + + @Test + public void testEquals() { + final var matrixSpec = new MatrixSpec(2, 3, "001" + "101"); + + final var a = matrixSpec.createMatrix(); + final var b = matrixSpec.createMatrix(); + + assertTrue(a.equals(b)); + assertTrue(a.equals(a)); + assertFalse(a.equals(null)); + assertFalse(a.equals(matrixSpec)); + } + + @Test + public void testHashCode() { + final var matrixSpec2x3 = new MatrixSpec(2, 3); + + assertEquals(matrixSpec2x3.createMatrix().hashCode(), matrixSpec2x3.createMatrix().hashCode()); + + final var matrixSpec3x2 = new MatrixSpec(3, 2); + assertNotEquals(matrixSpec2x3.createMatrix().hashCode(), matrixSpec3x2.createMatrix().hashCode()); + } + private static List conv(int... values) { return IntStream.of(values).mapToObj(v -> v != 0).toList(); } diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java new file mode 100644 index 0000000000000..503a023e99cf4 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +final class DirectedEdgeTest { + + @ParameterizedTest + @MethodSource + public void testCtor(String tail, String head, Class expectedExceptionType) { + if (expectedExceptionType != null) { + assertThrows(expectedExceptionType, () -> DirectedEdge.create(tail, head)); + } else { + final var edge = DirectedEdge.create(tail, head); + assertTrue(tail == edge.tail()); + assertTrue(tail == edge.from()); + assertTrue(head == edge.head()); + assertTrue(head == edge.to()); + } + } + + private static List testCtor() { + return List.of( + new Object[] { "a", "b", null }, + new Object[] { "a", "a", IllegalArgumentException.class }, + new Object[] { "a", null, NullPointerException.class }, + new Object[] { null, "b", NullPointerException.class }, + new Object[] { null, null, NullPointerException.class } + ); + } +} From 45131072277e14f7314ea4d9a7620129be4c0067 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 28 Jan 2025 23:25:04 -0500 Subject: [PATCH 0258/1101] - Can't guarantee scheduling of tasks in predictable order in ForkJoinPool. so rework sequential execution to not use executor services at all. - Added a use case that fails. Some bug in TaskPipelineBuilder. Need to investigate --- .../pipeline/CountedCompleterBuilder.java | 8 +-- .../internal/pipeline/ImmutableDAG.java | 48 ++++++++++--- .../pipeline/TaskPipelineBuilder.java | 30 ++++++-- .../pipeline/TaskPipelineBuilderTest.java | 70 ++++++++++++++++--- 4 files changed, 128 insertions(+), 28 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java index c758341c4ae35..ae219d5a05767 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java @@ -45,7 +45,7 @@ final class CountedCompleterBuilder { CountedCompleterBuilder(ImmutableDAG> taskGraph) { this.taskGraph = Objects.requireNonNull(taskGraph); - runOnce = StreamSupport.stream(taskGraph.getNodes().spliterator(), false).filter(node -> { + runOnce = StreamSupport.stream(taskGraph.nodes().spliterator(), false).filter(node -> { return taskGraph.getHeadsOf(node).size() > 1; }).collect(toMap(x -> x, x -> new TaskCompleters())); } @@ -92,11 +92,7 @@ protected DependentComleter(CountedCompleter completer) { public void compute() { final var dependencyCompleters = dependencyCompleters(); setPendingCount(dependencyCompleters.size()); - - // ForkJoinPool will execute tasks in the reverse order of how they are scheduled. - // Reverse the order in which tasks are scheduled to get them executed in the order placed in the dependency list. - // Ordering works for sequential execution only. - dependencyCompleters.reversed().forEach(CountedCompleter::fork); + dependencyCompleters.forEach(CountedCompleter::fork); tryComplete(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java index a9cee11a9013a..c9dd7179bf163 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java @@ -27,10 +27,12 @@ import static java.util.stream.Collectors.toCollection; import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; +import java.util.function.Consumer; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -90,7 +92,7 @@ ImmutableDAG create() { edgeMatrix.set(row, column); } - if (isCyclic(edgeMatrix)) { + if (isCyclic(edgeMatrix, null)) { throw new UnsupportedOperationException("Cyclic edges not allowed"); } @@ -152,8 +154,19 @@ public Iterator iterator() { } } - Iterable getNodes() { - return nodes; + /** + * Returns topologically ordered nodes of this graph. + *

+ * For every directed edge ("tail", "head") from "tail" to "head", "tail" comes before "head". + * + * @return topologically ordered nodes of this graph + */ + List topologicalSort() { + final List result = new ArrayList<>(); + isCyclic(edgeMatrix, index -> { + result.add(nodes.get(index)); + }); + return result; } /** @@ -240,7 +253,7 @@ private static IntStream getNoOutgoingEdges(BinaryMatrix edgeMatrix) { }); } - private static boolean isCyclic(BinaryMatrix edgeMatrix) { + private static boolean isCyclic(BinaryMatrix edgeMatrix, Consumer topologicalOrderAccumulator) { final var edgeMatrixCopy = new BinaryMatrix(edgeMatrix); @@ -248,10 +261,14 @@ private static boolean isCyclic(BinaryMatrix edgeMatrix) { // Variable names picked from the algorithm pseudo-code. // Nodes with no incoming edges. - final var S = getNoIncomingEdges(edgeMatrix).mapToObj(Integer::valueOf).collect(toCollection(ArrayList::new)); + List S = getNoIncomingEdges(edgeMatrix).mapToObj(Integer::valueOf).collect(toCollection(ArrayList::new)); + + for (var i = 0; i != S.size(); ++i) { + final var n = S.get(i); - while (!S.isEmpty()) { - final var n = S.removeLast(); + if (topologicalOrderAccumulator != null) { + topologicalOrderAccumulator.accept(n); + } for (final var e : getOutgoingEdges(n, edgeMatrixCopy).toList()) { e.value(false); // remove the edge @@ -260,7 +277,22 @@ private static boolean isCyclic(BinaryMatrix edgeMatrix) { if (getIncomingEdges(m, edgeMatrixCopy).findAny().isEmpty()) { // No incoming edges to 'm' node. - S.add(m); + if (topologicalOrderAccumulator != null) { + if (i > 0) { + S = S.subList(i, S.size()); + i = 0; + } + + final var insertAtIndex = Math.abs((Collections.binarySearch(S, m) + 1)); + if (insertAtIndex == 0) { + S.set(0, m); + i = -1; + } else { + S.add(insertAtIndex, m); + } + } else { + S.add(m); + } } } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java index 8c0eb9642d00c..1d449ff41c093 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java @@ -27,6 +27,7 @@ import java.util.Collection; import java.util.LinkedHashSet; +import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -87,22 +88,41 @@ public TaskSpecBuilder task(Callable task) { } public TaskPipelineBuilder executor(ForkJoinPool v) { - Objects.requireNonNull(v); fjp = v; return this; } public TaskPipelineBuilder sequentialExecutor() { - fjp = new ForkJoinPool(1); + fjp = null; return this; } public Callable create() { final var taskGraph = taskGraphBuilder.create(); - final var rootCompleter = new CountedCompleterBuilder(taskGraph).create(); + if (fjp == null) { + return new SequentialWrapperTask(taskGraph.topologicalSort()); + } else { + final var rootCompleter = new CountedCompleterBuilder(taskGraph).create(); + + return new WrapperTask(rootCompleter, fjp); + } + } + + private record SequentialWrapperTask(List> tasks) implements Callable { + + SequentialWrapperTask { + Objects.requireNonNull(tasks); + } + + @Override + public Void call() throws Exception { + for (final var task : tasks) { + task.call(); + } + return null; + } - return new WrapperTask(rootCompleter, fjp); } private record WrapperTask(CountedCompleter rootCompleter, ForkJoinPool fjp) implements Callable { @@ -120,7 +140,7 @@ public Void call() { } - private static final Callable ROOT_ACTION = new Callable() { + private static final Callable ROOT_ACTION = new Callable<>() { @Override public Void call() { diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java index bed56cc10b0b8..818abf320f964 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java @@ -24,6 +24,7 @@ package jdk.jpackage.internal.pipeline; import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toMap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -37,7 +38,6 @@ import java.util.concurrent.locks.LockSupport; import java.util.function.Consumer; import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -50,17 +50,19 @@ enum TestTask implements Consumer { C, D, K, - L; + L, + M, + N; @Override public void accept(StringBuffer sb) { - LockSupport.parkNanos(Duration.ofMillis(10).toNanos()); + LockSupport.parkNanos(Duration.ofMillis(1).toNanos()); System.out.println(String.format("[%s] result before append: [%s]; append %s", Thread.currentThread(), sb, name())); sb.append(name()); } Callable toCallable(StringBuffer sb) { - return new Callable () { + return new Callable<> () { @Override public Void call() { @@ -108,7 +110,7 @@ TaskSpec create() { @ParameterizedTest @MethodSource("testSequentialData") public void testSequential(List taskSpecs, Object expectedString) throws Exception { - testIt(new ForkJoinPool(1), taskSpecs, expectedString); + testIt(null, taskSpecs, expectedString); } @ParameterizedTest @@ -123,7 +125,7 @@ private void testIt(ForkJoinPool fjp, List taskSpecs, Object expectedS final var sb = new StringBuffer(); - final var taskMap = Stream.of(TestTask.values()).collect(Collectors.toMap(x -> x, x -> { + final var taskMap = Stream.of(TestTask.values()).collect(toMap(x -> x, x -> { return x.toCallable(sb); })); @@ -162,10 +164,15 @@ private static List testData(boolean sequential) { // ^ ^ // | | // +--- A ---+ - new Object[] { List.of(task(D).create(), task(C).from(B).to(D).create(), task(A).to(B).create(), task(A).to(D).create()), "ABCD" } + new Object[] { List.of( + task(D).create(), + task(C).from(B).to(D).create(), + task(A).to(B).create(), + task(A).to(D).create()), "ABCD" } )); - final var allValuesRegexp = Pattern.compile(String.format("[%s]{%d}", Stream.of(TestTask.values()).map(Enum::name).collect(joining()), TestTask.values().length)); + final var allValuesRegexp = Pattern.compile(String.format("[%s]{%d}", + Stream.of(TestTask.values()).map(Enum::name).collect(joining()), TestTask.values().length)); data.addAll(List.of( new Object[] { Stream.of(TestTask.values()) @@ -185,9 +192,52 @@ private static List testData(boolean sequential) { // | | // +--- D ---+ data.add(new Object[] { - List.of(task(A).create(), task(B).from(D).to(A).create(), task(C).from(D).to(A).create()), + List.of(task(A).create(), + task(C).from(D).to(A).create(), + task(B).from(D).to(A).create()), sequential ? "DCBA" : Pattern.compile("D(BC|CB)A") }); + data.add(new Object[] { + List.of(task(A).create(), + task(B).from(D).to(A).create(), + task(C).from(D).to(A).create()), + sequential ? "DBCA" : Pattern.compile("D(BC|CB)A") + }); + + // B -> A <- C + // ^ ^ + // | | + // +--- D ---+ + // ^ + // | + // N + data.add(new Object[] { + List.of(task(A).create(), + task(C).from(D).to(A).create(), + task(N).to(D).create(), + task(B).from(D).to(A).create()), + sequential ? "NDCBA" : Pattern.compile("ND(BC|CB)A") + }); + + // B -> A <- C + // ^ ^ + // | | + // +--- D ---+ + // ^ + // | + // K -> N <- M + // ^ ^ + // | | + // +--- L ---+ + data.add(new Object[] { + List.of(task(A).create(), + task(C).from(D).to(A).create(), + task(N).to(D).create(), + task(B).from(D).to(A).create(), + task(K).from(L).to(N).create(), + task(M).from(L).to(N).create()), + sequential ? "LKMNDCBA" : Pattern.compile("L(KM|MK)ND(BC|CB)A") + }); return data; } @@ -210,4 +260,6 @@ private static TaskSpecBuilder task(TestTask task) { private final static TestTask D = TestTask.D; private final static TestTask K = TestTask.K; private final static TestTask L = TestTask.L; + private final static TestTask M = TestTask.M; + private final static TestTask N = TestTask.N; } From 39574caabeffb960e0e6969c927b6744f4fe1ada Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 29 Jan 2025 22:18:54 -0500 Subject: [PATCH 0259/1101] Finally made it work. Added unit tests for better coverage. --- .../pipeline/CountedCompleterBuilder.java | 187 ------- .../internal/pipeline/ImmutableDAG.java | 49 +- .../pipeline/TaskPipelineBuilder.java | 100 +++- .../internal/pipeline/ImmutableDAGTest.java | 162 ++++++- .../pipeline/TaskPipelineBuilderTest.java | 459 +++++++++++++----- 5 files changed, 623 insertions(+), 334 deletions(-) delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java deleted file mode 100644 index ae219d5a05767..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/CountedCompleterBuilder.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal.pipeline; - -import static java.util.stream.Collectors.toMap; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.Callable; -import java.util.concurrent.CountedCompleter; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.StreamSupport; - -/** - * Schedules execution of tasks in the given task graph. - */ -final class CountedCompleterBuilder { - - CountedCompleterBuilder(ImmutableDAG> taskGraph) { - this.taskGraph = Objects.requireNonNull(taskGraph); - - runOnce = StreamSupport.stream(taskGraph.nodes().spliterator(), false).filter(node -> { - return taskGraph.getHeadsOf(node).size() > 1; - }).collect(toMap(x -> x, x -> new TaskCompleters())); - } - - CountedCompleter create() { - final var rootCompleters = createRootCompleters(); - if (rootCompleters.size() == 1) { - return rootCompleters.get(0); - } else { - return new RootCompleter(rootCompleters); - } - } - - private List> createRootCompleters() { - final var rootNodes = taskGraph.getNoOutgoingEdges(); - - return rootNodes.stream().map(rootNode -> { - return new TaskCompleter(null, rootNode); - }).toList(); - } - - private Optional registerCompleter(Callable task, CountedCompleter completer) { - Objects.requireNonNull(completer); - final var dependentTasks = taskGraph.getHeadsOf(task); - if (dependentTasks.size() <= 1) { - return Optional.empty(); - } else { - var completers = runOnce.get(task); - completers.allCompleters().add(completer); - return Optional.of(completers); - } - } - - private abstract class DependentComleter extends CountedCompleter { - - protected DependentComleter() { - } - - protected DependentComleter(CountedCompleter completer) { - super(completer); - } - - @Override - public void compute() { - final var dependencyCompleters = dependencyCompleters(); - setPendingCount(dependencyCompleters.size()); - dependencyCompleters.forEach(CountedCompleter::fork); - - tryComplete(); - } - - protected abstract List> dependencyCompleters(); - - private static final long serialVersionUID = 1L; - } - - private final class TaskCompleter extends DependentComleter { - - TaskCompleter(CountedCompleter dependentCompleter, Callable task) { - super(dependentCompleter); - this.task = Objects.requireNonNull(task); - - dependencyCompleters = taskGraph.getTailsOf(task).stream().map(dependencyTask -> { - return new TaskCompleter(this, dependencyTask); - }).toList(); - - taskCompleters = registerCompleter(task, this); - } - - @Override - public void compute() { - if (taskCompleters.map(TaskCompleters::completer).map(ref -> ref.compareAndSet(null, this)).orElse(true)) { - super.compute(); - } - } - - @Override - public void onCompletion(CountedCompleter caller) { - if (taskCompleters.map(ac -> ac.isTaskCompleter(this)).orElse(true)) { - try { - task.call(); - } catch (Exception ex) { - completeExceptionally(ex); - } - taskCompleters.ifPresent(TaskCompleters::complete); - } - } - - @Override - protected List> dependencyCompleters() { - return dependencyCompleters; - } - - private final transient Callable task; - private final transient List> dependencyCompleters; - private final transient Optional taskCompleters; - - private static final long serialVersionUID = 1L; - } - - private final class RootCompleter extends DependentComleter { - - RootCompleter(List> dependencyCompleters) { - this.dependencyCompleters = dependencyCompleters; - } - - @Override - protected List> dependencyCompleters() { - return dependencyCompleters; - } - - private final transient List> dependencyCompleters; - - private static final long serialVersionUID = 1L; - } - - private record TaskCompleters(AtomicReference> completer, - List> allCompleters) { - - TaskCompleters() { - this(new AtomicReference<>(), new ArrayList<>()); - } - - boolean isTaskCompleter(CountedCompleter c) { - return c == completer.get(); - } - - void complete() { - allCompleters.forEach(c -> { - if (!isTaskCompleter(c)) { - c.complete(null); - } - }); - } - } - - private final ImmutableDAG> taskGraph; - private final Map, TaskCompleters> runOnce; -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java index c9dd7179bf163..efb3e5331216b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java @@ -32,7 +32,10 @@ import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -84,6 +87,10 @@ Builder canAddEdgeToUnknownNode(boolean v) { } ImmutableDAG create() { + if (nodes.isEmpty()) { + throw new UnsupportedOperationException("No edges"); + } + final var nodesAdapter = Nodes.ofList(this.nodes); final var edgeMatrix = new BinaryMatrix(nodes.size()); for (final var edge : edges) { @@ -169,6 +176,14 @@ List topologicalSort() { return result; } + List getAllHeadsOf(T node) { + return getAllNodesOf(node, true); + } + + List getAllTailsOf(T node) { + return getAllNodesOf(node, false); + } + /** * Gets the list of nodes that are heads of the edges sharing the same tail, * which is the given node. @@ -233,21 +248,44 @@ List getNoOutgoingEdges() { return getNoOutgoingEdges(edgeMatrix).mapToObj(nodes::get).toList(); } - private static Stream getOutgoingEdges(int node, BinaryMatrix edgeMatrix) { + private List getAllNodesOf(T node, boolean heads) { + final Set nodeIndexes = new TreeSet<>(); + traverseNodes(nodes.indexOf(node), edgeMatrix, heads, nodeIndex -> { + return nodeIndexes.add(nodeIndex); + }); + + return nodeIndexes.stream().map(nodes::get).toList(); + } + + static void traverseNodes(int nodeIndex, BinaryMatrix edgeMatrix, boolean heads, Function nodeAccumulator) { + final Stream nodes; + if (heads) { + nodes = getOutgoingEdges(nodeIndex, edgeMatrix).map(BinaryMatrix.Cursor::column); + } else { + nodes = getIncomingEdges(nodeIndex, edgeMatrix).map(BinaryMatrix.Cursor::row); + } + nodes.forEach(n -> { + if (nodeAccumulator.apply(n)) { + traverseNodes(n, edgeMatrix, heads, nodeAccumulator); + } + }); + } + + static Stream getOutgoingEdges(int node, BinaryMatrix edgeMatrix) { return edgeMatrix.getRowAsStream(node).filter(BinaryMatrix.Cursor::value); } - private static Stream getIncomingEdges(int node, BinaryMatrix edgeMatrix) { + static Stream getIncomingEdges(int node, BinaryMatrix edgeMatrix) { return edgeMatrix.getColumnAsStream(node).filter(BinaryMatrix.Cursor::value); } - private static IntStream getNoIncomingEdges(BinaryMatrix edgeMatrix) { + static IntStream getNoIncomingEdges(BinaryMatrix edgeMatrix) { return IntStream.range(0, edgeMatrix.getColumnCount()).filter(column -> { return getIncomingEdges(column, edgeMatrix).findAny().isEmpty(); }); } - private static IntStream getNoOutgoingEdges(BinaryMatrix edgeMatrix) { + static IntStream getNoOutgoingEdges(BinaryMatrix edgeMatrix) { return IntStream.range(0, edgeMatrix.getRowCount()).filter(row -> { return getOutgoingEdges(row, edgeMatrix).findAny().isEmpty(); }); @@ -290,6 +328,9 @@ private static boolean isCyclic(BinaryMatrix edgeMatrix, Consumer topol } else { S.add(insertAtIndex, m); } + } else if (i > 0) { + S.set(i, m); + i--; } else { S.add(m); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java index 1d449ff41c093..828b379abe550 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java @@ -32,8 +32,10 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.Callable; -import java.util.concurrent.CountedCompleter; -import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; public final class TaskPipelineBuilder { @@ -65,10 +67,10 @@ public TaskSpecBuilder addDependencies(Collection> v) { public TaskPipelineBuilder add() { if (taskGraphBuilder == null) { taskGraphBuilder = new ImmutableDAG.Builder<>(); - taskGraphBuilder.addEdge(task, ROOT_ACTION); + taskGraphBuilder.addEdge(task, ROOT_TASK); taskGraphBuilder.canAddEdgeToUnknownNode(false); } else { - taskGraphBuilder.addEdge(task, Optional.ofNullable(dependent).orElse(ROOT_ACTION)); + taskGraphBuilder.addEdge(task, Optional.ofNullable(dependent).orElse(ROOT_TASK)); } for (var dependency : dependencies) { @@ -87,25 +89,25 @@ public TaskSpecBuilder task(Callable task) { return new TaskSpecBuilder(task); } - public TaskPipelineBuilder executor(ForkJoinPool v) { - fjp = v; + public TaskPipelineBuilder executor(Executor v) { + executor = v; return this; } public TaskPipelineBuilder sequentialExecutor() { - fjp = null; + executor = null; return this; } public Callable create() { final var taskGraph = taskGraphBuilder.create(); - if (fjp == null) { - return new SequentialWrapperTask(taskGraph.topologicalSort()); + if (executor == null) { + final var tasks = taskGraph.topologicalSort(); + // Don't run the root task as it is NOP. + return new SequentialWrapperTask(tasks.subList(0, tasks.size() - 1)); } else { - final var rootCompleter = new CountedCompleterBuilder(taskGraph).create(); - - return new WrapperTask(rootCompleter, fjp); + return new ParallelWrapperTask(taskGraph, executor); } } @@ -125,34 +127,80 @@ public Void call() throws Exception { } - private record WrapperTask(CountedCompleter rootCompleter, ForkJoinPool fjp) implements Callable { + private record ParallelWrapperTask(ImmutableDAG> taskGraph, Executor executor) implements Callable { - WrapperTask { - Objects.requireNonNull(rootCompleter); - Objects.requireNonNull(fjp); + ParallelWrapperTask { + Objects.requireNonNull(taskGraph); + Objects.requireNonNull(executor); } @Override - public Void call() { - fjp.invoke(rootCompleter); + public Void call() throws Exception { + + final var taskFutures = new CompletableFuture[taskGraph.nodes().size()]; + + CompletableFuture lastFuture = null; + + // Schedule tasks in the order they should be executed: dependencies before dependents. + for (final var task : taskGraph.topologicalSort()) { + final var taskIndex = taskGraph.nodes().indexOf(task); + + final var dependencyTaskFutures = ImmutableDAG.getIncomingEdges(taskIndex, taskGraph.edgeMatrix()) + .map(BinaryMatrix.Cursor::row) + .map(dependencyTaskIndex -> { + return taskFutures[dependencyTaskIndex]; + }).toArray(CompletableFuture[]::new); + + if (dependencyTaskFutures.length == 0) { + lastFuture = CompletableFuture.runAsync(toRunnable(task), executor); + } else { + lastFuture = CompletableFuture.allOf(dependencyTaskFutures); + if (task != ROOT_TASK) { + lastFuture = lastFuture.thenRun(toRunnable(task)); + } + } + + taskFutures[taskIndex] = lastFuture; + } + + try { + lastFuture.get(); + } catch (ExecutionException ee) { + if (ee.getCause() instanceof Exception ex) { + throw ex; + } else { + throw ee; + } + } + return null; } + private static Runnable toRunnable(Callable callable) { + return () -> { + try { + callable.call(); + } catch (Error er) { + throw er; + } catch (RuntimeException ex) { + throw ex; + } catch (Throwable t) { + throw new CompletionException(t); + } + }; + } + } - private static final Callable ROOT_ACTION = new Callable<>() { + private static final Callable ROOT_TASK = new Callable<>() { @Override public Void call() { - return null; - } - - @Override - public String toString() { - return super.toString() + "(root)"; + // Should never get called. + throw new UnsupportedOperationException(); } }; private ImmutableDAG.Builder> taskGraphBuilder; - private ForkJoinPool fjp; + private Executor executor; } diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java index 8c9abe1af9714..1c7441881a59e 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java @@ -26,15 +26,50 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.NoSuchElementException; import java.util.stream.Stream; +import java.util.stream.StreamSupport; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; final class ImmutableDAGTest { + @Test + public void testInvalidCtorArgs() { + final var matrix1x2 = new BinaryMatrix(1, 2); + final var nodes = ImmutableDAG.Nodes.ofList(List.of(A, B)); + + assertThrows(IllegalArgumentException.class, () -> new ImmutableDAG(matrix1x2, nodes)); + + final var matrix3x3 = new BinaryMatrix(3, 3); + assertThrows(IllegalArgumentException.class, () -> new ImmutableDAG(matrix3x3, nodes)); + } + + @Test + public void testNodesToList() { + final var nodes = ImmutableDAG.Nodes.ofList(List.of(A, B)); + + assertEquals(2, nodes.size()); + + assertEquals(A, nodes.get(0)); + assertEquals(B, nodes.get(1)); + assertThrows(IndexOutOfBoundsException.class, () -> nodes.get(2)); + + assertEquals(0, nodes.indexOf(A)); + assertEquals(1, nodes.indexOf(B)); + assertThrows(NoSuchElementException.class, () -> nodes.indexOf(C)); + + final var copy = new ArrayList(); + for (var n : nodes) { + copy.add(n); + } + assertEquals(copy, List.of(A, B)); + } + @ParameterizedTest @MethodSource public void testCyclic(List> edges) { @@ -77,9 +112,9 @@ private static Stream testGetNoIncomingEdges() { new Object[] { List.of(edge(A, B), edge(C, D)), List.of(A, C) }, // A <- B - // | ^ + // ^ ^ // | | - // + <- D <- L + // + -- D <- L // | // + <- C new Object[] { List.of(edge(B, A), edge(D, B), edge(D, A), edge(C, D), edge(L, D)), List.of(C, L) }, @@ -181,6 +216,124 @@ public void testSome() { assertEquals(graph.getTailsOf(L), List.of(C)); } + @Test + public void testSome2() { + // B -> A <- C + // ^ ^ + // | | + // +--- D ---+ + // ^ + // | + // K -> N <- M <- P + // ^ ^ + // | O | + // | ^ | + // | | | + // +--- L ---+ + // + + final var graphBuilder = ImmutableDAG.build(); + + graphBuilder.addEdge(edge(B, A)); + graphBuilder.addEdge(edge(C, A)); + graphBuilder.addEdge(edge(D, B)); + graphBuilder.addEdge(edge(D, C)); + graphBuilder.addEdge(edge(N, D)); + graphBuilder.addEdge(edge(M, N)); + graphBuilder.addEdge(edge(K, N)); + graphBuilder.addEdge(edge(L, K)); + graphBuilder.addEdge(edge(L, M)); + graphBuilder.addEdge(edge(P, M)); + graphBuilder.addEdge(edge(L, O)); + + final var graph = graphBuilder.create(); + + assertEquals(graph.getNoIncomingEdges(), List.of(L, P)); + assertEquals(graph.getNoOutgoingEdges(), List.of(A, O)); + + assertEquals(graph.getHeadsOf(A), List.of()); + assertEquals(graph.getTailsOf(A), List.of(B, C)); + assertEquals(graph.getAllHeadsOf(A), List.of()); + assertEquals(graph.getAllTailsOf(A), List.of(B, C, D, N, M, K, L, P)); + + assertEquals(graph.getHeadsOf(B), List.of(A)); + assertEquals(graph.getTailsOf(B), List.of(D)); + assertEquals(graph.getAllHeadsOf(B), List.of(A)); + assertEquals(graph.getAllTailsOf(B), List.of(D, N, M, K, L, P)); + + assertEquals(graph.getHeadsOf(C), List.of(A)); + assertEquals(graph.getTailsOf(C), List.of(D)); + assertEquals(graph.getAllHeadsOf(C), List.of(A)); + assertEquals(graph.getAllTailsOf(C), List.of(D, N, M, K, L, P)); + + assertEquals(graph.getHeadsOf(D), List.of(B, C)); + assertEquals(graph.getTailsOf(D), List.of(N)); + assertEquals(graph.getAllHeadsOf(D), List.of(B, A, C)); + assertEquals(graph.getAllTailsOf(D), List.of(N, M, K, L, P)); + + assertEquals(graph.getHeadsOf(K), List.of(N)); + assertEquals(graph.getTailsOf(K), List.of(L)); + assertEquals(graph.getAllHeadsOf(K), List.of(B, A, C, D, N)); + assertEquals(graph.getAllTailsOf(K), List.of(L)); + + assertEquals(graph.getHeadsOf(L), List.of(M, K, O)); + assertEquals(graph.getTailsOf(L), List.of()); + assertEquals(graph.getAllHeadsOf(L), List.of(B, A, C, D, N, M, K, O)); + assertEquals(graph.getAllTailsOf(L), List.of()); + + assertEquals(graph.getHeadsOf(M), List.of(N)); + assertEquals(graph.getTailsOf(M), List.of(L, P)); + assertEquals(graph.getAllHeadsOf(M), List.of(B, A, C, D, N)); + assertEquals(graph.getAllTailsOf(M), List.of(L, P)); + + assertEquals(graph.getHeadsOf(N), List.of(D)); + assertEquals(graph.getTailsOf(N), List.of(M, K)); + assertEquals(graph.getAllHeadsOf(N), List.of(B, A, C, D)); + assertEquals(graph.getAllTailsOf(N), List.of(M, K, L, P)); + + assertEquals(graph.getHeadsOf(O), List.of()); + assertEquals(graph.getTailsOf(O), List.of(L)); + assertEquals(graph.getAllHeadsOf(O), List.of()); + assertEquals(graph.getAllTailsOf(O), List.of(L)); + + assertEquals(graph.getHeadsOf(P), List.of(M)); + assertEquals(graph.getTailsOf(P), List.of()); + assertEquals(graph.getAllHeadsOf(P), List.of(B, A, C, D, N, M)); + assertEquals(graph.getAllTailsOf(P), List.of()); + } + + @Test + public void testEmptyBuilder() { + assertThrows(UnsupportedOperationException.class, ImmutableDAG.build()::create); + } + + @Test + public void testBuilder() { + final var graphBuilder = ImmutableDAG.build(); + + graphBuilder.canAddEdgeToUnknownNode(false); + assertThrows(UnsupportedOperationException.class, () -> graphBuilder.addEdge(edge(A, B))); + assertThrows(UnsupportedOperationException.class, graphBuilder::create); + + graphBuilder.canAddEdgeToUnknownNode(true); + graphBuilder.addEdge(edge(A, B)); + assertNodesEquals(graphBuilder.create().nodes(), A, B); + + graphBuilder.canAddEdgeToUnknownNode(false); + graphBuilder.addEdge(edge(A, B)); + assertNodesEquals(graphBuilder.create().nodes(), A, B); + + graphBuilder.addEdge(edge(C, A)); + assertNodesEquals(graphBuilder.create().nodes(), A, B, C); + + assertThrows(UnsupportedOperationException.class, () -> graphBuilder.addEdge(edge(B, D))); + assertNodesEquals(graphBuilder.create().nodes(), A, B, C); + } + + private static void assertNodesEquals(ImmutableDAG.Nodes actual, String... expected) { + assertEquals(List.of(expected), StreamSupport.stream(actual.spliterator(), false).toList()); + } + private static ImmutableDAG create(Collection> edges) { final var graphBuilder = ImmutableDAG.build(); edges.forEach(graphBuilder::addEdge); @@ -195,5 +348,10 @@ private static DirectedEdge edge(String from, String to) { private final static String B = "B"; private final static String C = "C"; private final static String D = "D"; + private final static String K = "K"; private final static String L = "L"; + private final static String M = "M"; + private final static String N = "N"; + private final static String O = "O"; + private final static String P = "P"; } diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java index 818abf320f964..1ba61527239af 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java @@ -25,18 +25,25 @@ import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toMap; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.time.Duration; import java.util.ArrayList; import java.util.Comparator; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.locks.LockSupport; import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; @@ -44,7 +51,20 @@ final class TaskPipelineBuilderTest { - enum TestTask implements Consumer { + private static final class TestException extends Exception { + + TestException(TestTask sender) { + super(makeMessage(sender)); + } + + static String makeMessage(TestTask sender) { + return "Thrown by " + sender.name(); + } + + private static final long serialVersionUID = 1L; + } + + private enum TestTask implements Consumer { A, B, C, @@ -52,7 +72,16 @@ enum TestTask implements Consumer { K, L, M, - N; + N, + THROW_1(true); + + TestTask(boolean fail) { + this.fail = fail; + } + + TestTask() { + fail = false; + } @Override public void accept(StringBuffer sb) { @@ -65,7 +94,10 @@ Callable toCallable(StringBuffer sb) { return new Callable<> () { @Override - public Void call() { + public Void call() throws Exception { + if (isThrowing()) { + throw new TestException(TestTask.this); + } accept(sb); return null; } @@ -77,132 +109,250 @@ public String toString() { }; } - } - record TaskSpec(TestTask task, List dependencies, TestTask dependent) { + private boolean isThrowing() { + return fail; + } + + static Stream nonThrowingTasks() { + return Stream.of(values()).filter(Predicate.not(TestTask::isThrowing)); + } + + private final boolean fail; } - private final static class TaskSpecBuilder { + private record TaskSpec(TestTask task, List dependencies, TestTask dependent) { - TaskSpecBuilder(TestTask task) { - this.task = Objects.requireNonNull(task); + TaskSpec { + Objects.requireNonNull(task); + Objects.requireNonNull(dependencies); } - TaskSpecBuilder to(TestTask task) { - dependent = task; - return this; - } + final static class Builder { - TaskSpecBuilder from(TestTask ... tasks) { - dependencies.addAll(List.of(tasks)); - return this; - } + Builder(TestTask task) { + this.task = Objects.requireNonNull(task); + } - TaskSpec create() { - return new TaskSpec(task, dependencies, dependent); - } + Builder to(TestTask task) { + dependent = task; + return this; + } - private final TestTask task; - private final List dependencies = new ArrayList<>(); - private TestTask dependent; - } + Builder from(TestTask ... tasks) { + dependencies.addAll(List.of(tasks)); + return this; + } - @ParameterizedTest - @MethodSource("testSequentialData") - public void testSequential(List taskSpecs, Object expectedString) throws Exception { - testIt(null, taskSpecs, expectedString); + TaskSpec create() { + return new TaskSpec(task, dependencies, dependent); + } + + private final TestTask task; + private final List dependencies = new ArrayList<>(); + private TestTask dependent; + } } @ParameterizedTest - @MethodSource("testParallelData") - public void testParallel(List taskSpecs, Object expectedString) throws Exception { - testIt(new ForkJoinPool(4), taskSpecs, expectedString); + @MethodSource("testIt") + public void testIt(TestSpec testSpec) throws Exception { + testSpec.test(); } - private void testIt(ForkJoinPool fjp, List taskSpecs, Object expectedString) throws Exception { - final var builder = new TaskPipelineBuilder(); - builder.executor(fjp); + public record TestSpec(List taskSpecs, Object expectedString, Set expectedAnyFailures, Executor executor) { - final var sb = new StringBuffer(); + public TestSpec { + Objects.requireNonNull(taskSpecs); + Objects.requireNonNull(expectedString); + Objects.requireNonNull(expectedAnyFailures); + } - final var taskMap = Stream.of(TestTask.values()).collect(toMap(x -> x, x -> { - return x.toCallable(sb); - })); + final static class Builder { + + Builder taskSpecs(TaskSpec ...specs) { + taskSpecs.addAll(List.of(specs)); + return this; + } + + Builder expected(Pattern v) { + expectedRegexp = v; + return this; + } + + Builder expected(Predicate v) { + expectedPredicate = v; + return this; + } + + Builder expected(String v) { + expectedString = v; + return this; + } + + Builder expectedAnyFailure(TestTask... v) { + expectedAnyFailures.addAll(List.of(v)); + return this; + } + + Builder executor(Executor v) { + executor = v; + return this; + } + + TestSpec create() { + final Object expectedObject; + if (!isParallel()) { + expectedObject = expectedString; + } else if (expectedRegexp != null) { + expectedObject = expectedRegexp; + } else if (expectedPredicate != null) { + expectedObject = expectedPredicate; + } else { + expectedObject = expectedString; + } - taskSpecs.forEach(taskSpec -> { - builder.task(taskMap.get(taskSpec.task)) - .addDependencies(taskSpec.dependencies.stream().map(taskMap::get).toList()) - .dependent(taskMap.get(taskSpec.dependent)) - .add(); - }); + if (expectedPredicate != null && expectedRegexp != null) { + throw new IllegalStateException(); + } - System.out.println(String.format("start for %s", expectedString)); + return new TestSpec(taskSpecs, expectedObject, expectedAnyFailures, executor); + } - builder.create().call(); + private boolean isParallel() { + return executor != null; + } - final var actualString = sb.toString(); + private final List taskSpecs = new ArrayList<>(); + private String expectedString; + private Pattern expectedRegexp; + private Predicate expectedPredicate; + private Set expectedAnyFailures = new HashSet<>(); + private Executor executor; + } + + @SuppressWarnings("unchecked") + void test() { + final var builder = new TaskPipelineBuilder(); + builder.executor(executor); + + final var sb = new StringBuffer(); + + final var taskMap = Stream.of(TestTask.values()).collect(toMap(x -> x, x -> { + return x.toCallable(sb); + })); - if (expectedString instanceof Pattern expectedRegexp) { - assertTrue(expectedRegexp.matcher(actualString).matches(), () -> { - return String.format("Regexp %s doesn't match string %s", expectedRegexp, actualString); + taskSpecs.forEach(taskSpec -> { + builder.task(taskMap.get(taskSpec.task)) + .addDependencies(taskSpec.dependencies.stream().map(taskMap::get).toList()) + .dependent(taskMap.get(taskSpec.dependent)) + .add(); }); - } else { - assertEquals(expectedString.toString(), actualString); - } - System.out.println("end"); + if (expectedAnyFailures.isEmpty()) { + System.out.println(String.format("start for %s", expectedString)); + assertDoesNotThrow(builder.create()::call); + } else { + System.out.println(String.format("start for %s throws %s", expectedString, expectedAnyFailures)); + final var ex = assertThrows(TestException.class, builder.create()::call); + assertTrue(expectedAnyFailures.stream().map(TestException::makeMessage).anyMatch(Predicate.isEqual(ex.getMessage())), () -> { + return String.format("Exception message '%s' doesn't match any of failed tasks %s", ex.getMessage(), expectedAnyFailures); + }); + } + System.out.println("end"); + + final var actualString = sb.toString(); + + assertEquals(actualString.length(), actualString.chars().distinct().count()); + + if (expectedString instanceof Pattern expectedRegexp) { + assertTrue(expectedRegexp.matcher(actualString).matches(), () -> { + return String.format("Regexp %s doesn't match string %s", expectedRegexp, actualString); + }); + } else if (expectedString instanceof Predicate expectedPredicate) { + assertTrue(((Predicate)expectedPredicate).test(actualString), () -> { + return String.format("Predicate %s failed for string %s", expectedString, actualString); + }); + } else { + assertEquals(expectedString.toString(), actualString); + } + } } - private static List testData(boolean sequential) { - final List data = new ArrayList<>(); + private static List testIt() { + final List data = new ArrayList<>(); - data.addAll(List.of( - new Object[] { List.of(task(A).create()), "A" }, - new Object[] { List.of(task(B).from(A).create()), "AB" }, + data.add(test().taskSpecs(task(A).create()).expected("A").create()); - // D <- C <- B - // ^ ^ - // | | - // +--- A ---+ - new Object[] { List.of( - task(D).create(), - task(C).from(B).to(D).create(), - task(A).to(B).create(), - task(A).to(D).create()), "ABCD" } - )); + data.add(test().taskSpecs(task(B).from(A).create()).expected("AB").create()); - final var allValuesRegexp = Pattern.compile(String.format("[%s]{%d}", - Stream.of(TestTask.values()).map(Enum::name).collect(joining()), TestTask.values().length)); + // D <- C <- B + // ^ ^ + // | | + // +--- A ---+ + data.add(test().taskSpecs( + task(D).create(), + task(C).from(B).to(D).create(), + task(A).to(B).create(), + task(A).to(D).create() + ).expected("ABCD").create()); + + // A <- THROW_1 <- B + data.add(test().taskSpecs( + task(A).create(), + task(THROW_1).from(B).to(A).create() + ).expected("B").expectedAnyFailure(THROW_1).create()); + + data.addAll(testData(ForkJoinPool.commonPool())); + data.addAll(testData(Executors.newSingleThreadExecutor())); + data.addAll(testData(Executors.newFixedThreadPool(5))); + + data.addAll(testData(null)); - data.addAll(List.of( - new Object[] { Stream.of(TestTask.values()) - .map(TaskPipelineBuilderTest::task) - .map(TaskSpecBuilder::create).toList(), - sequential ? Stream.of(TestTask.values()).map(Enum::name).collect(joining()) : allValuesRegexp }, + return data; + } - new Object[] { Stream.of(TestTask.values()) - .sorted(Comparator.reverseOrder()) - .map(TaskPipelineBuilderTest::task) - .map(TaskSpecBuilder::create).toList(), - sequential ? Stream.of(TestTask.values()).sorted(Comparator.reverseOrder()).map(Enum::name).collect(joining()) : allValuesRegexp } - )); + private static List testData(Executor executor) { + final List data = new ArrayList<>(); + + final var allValuesRegexp = Pattern.compile(String.format("[%s]{%d}", + TestTask.nonThrowingTasks().map(Enum::name).collect(joining()), TestTask.nonThrowingTasks().count())); + + data.add(test().executor(executor).taskSpecs( + task(D).create(), + task(C).from(B).to(D).create(), + task(A).to(B).create(), + task(A).to(D).create() + ).expected("ABCD").create()); + + data.add(test().executor(executor).taskSpecs(TestTask.nonThrowingTasks() + .map(TaskPipelineBuilderTest::task) + .map(TaskSpec.Builder::create) + .toArray(TaskSpec[]::new) + ).expected(allValuesRegexp).expected(TestTask.nonThrowingTasks().map(Enum::name).collect(joining())).create()); + + data.add(test().executor(executor).taskSpecs(TestTask.nonThrowingTasks() + .sorted(Comparator.reverseOrder()) + .map(TaskPipelineBuilderTest::task) + .map(TaskSpec.Builder::create) + .toArray(TaskSpec[]::new) + ).expected(allValuesRegexp).expected(TestTask.nonThrowingTasks().sorted(Comparator.reverseOrder()).map(Enum::name).collect(joining())).create()); // B -> A <- C // ^ ^ // | | // +--- D ---+ - data.add(new Object[] { - List.of(task(A).create(), - task(C).from(D).to(A).create(), - task(B).from(D).to(A).create()), - sequential ? "DCBA" : Pattern.compile("D(BC|CB)A") - }); - data.add(new Object[] { - List.of(task(A).create(), - task(B).from(D).to(A).create(), - task(C).from(D).to(A).create()), - sequential ? "DBCA" : Pattern.compile("D(BC|CB)A") - }); + data.add(test().executor(executor).taskSpecs( + task(A).create(), + task(C).from(D).to(A).create(), + task(B).from(D).to(A).create() + ).expected(Pattern.compile("D(BC|CB)A")).expected("DCBA").create()); + + data.add(test().executor(executor).taskSpecs( + task(A).create(), + task(B).from(D).to(A).create(), + task(C).from(D).to(A).create() + ).expected(Pattern.compile("D(BC|CB)A")).expected("DBCA").create()); // B -> A <- C // ^ ^ @@ -211,13 +361,12 @@ private static List testData(boolean sequential) { // ^ // | // N - data.add(new Object[] { - List.of(task(A).create(), - task(C).from(D).to(A).create(), - task(N).to(D).create(), - task(B).from(D).to(A).create()), - sequential ? "NDCBA" : Pattern.compile("ND(BC|CB)A") - }); + data.add(test().executor(executor).taskSpecs( + task(A).create(), + task(C).from(D).to(A).create(), + task(N).to(D).create(), + task(B).from(D).to(A).create() + ).expected(Pattern.compile("ND(BC|CB)A")).expected("NDCBA").create()); // B -> A <- C // ^ ^ @@ -229,29 +378,108 @@ private static List testData(boolean sequential) { // ^ ^ // | | // +--- L ---+ - data.add(new Object[] { - List.of(task(A).create(), - task(C).from(D).to(A).create(), - task(N).to(D).create(), - task(B).from(D).to(A).create(), - task(K).from(L).to(N).create(), - task(M).from(L).to(N).create()), - sequential ? "LKMNDCBA" : Pattern.compile("L(KM|MK)ND(BC|CB)A") - }); + data.add(test().executor(executor).taskSpecs( + task(A).create(), + task(C).from(D).to(A).create(), + task(N).to(D).create(), + task(B).from(D).to(A).create(), + task(K).from(L).to(N).create(), + task(M).from(L).to(N).create() + ).expected(Pattern.compile("L(KM|MK)ND(BC|CB)A")).expected("LKMNDCBA").create()); + + // +-> A <-+ + // | | + // B THROW_1 <- D + // ^ ^ + // | | + // K C + data.add(test().executor(executor).taskSpecs( + task(A).create(), + task(B).from(K).to(A).create(), + task(THROW_1).from(D).to(A).create(), + task(C).to(THROW_1).create() + ).expected(c('K').before('B').and(onlyChars("KBDC"))).expected("KBDC").expectedAnyFailure(THROW_1).create()); + + // +--> A <--+ + // | ^ | + // | | | + // B C THROW_1 + data.add(test().executor(executor).taskSpecs( + task(A).create(), + task(B).to(A).create(), + task(C).to(A).create(), + task(THROW_1).to(A).create() + ).expected(onlyChars("BC")).expected("BC").expectedAnyFailure(THROW_1).create()); return data; } - private static List testSequentialData() { - return testData(true); + private static TaskSpec.Builder task(TestTask task) { + return new TaskSpec.Builder(task); + } + + private static TestSpec.Builder test() { + return new TestSpec.Builder(); + } + + private record PredicateWithDescritpion(Predicate predicate, String description) implements Predicate { + + PredicateWithDescritpion { + Objects.requireNonNull(predicate); + Objects.requireNonNull(description); + } + + @Override + public String toString() { + return String.format("(%s)", description); + } + + @Override + public Predicate and(Predicate other) { + return new PredicateWithDescritpion<>(predicate.and(other), String.format("%s and %s", toString(), other)); + } + + @Override + public Predicate or(Predicate other) { + return new PredicateWithDescritpion<>(predicate.or(other), String.format("%s or %s", toString(), other)); + } + + @Override + public Predicate negate() { + return new PredicateWithDescritpion<>(predicate, String.format("!%s", toString())); + } + + @Override + public boolean test(T t) { + return predicate.test(t); + } + } + + private record StringPredicateBuilder(char ch) { + Predicate before(char other) { + return new PredicateWithDescritpion<>(str -> { + return str.indexOf(ch) < str.indexOf(other); + }, String.format("%s before %s", ch, other)); + } + + Predicate after(char other) { + return new StringPredicateBuilder(other).before(ch); + } + } + + private static StringPredicateBuilder c(char ch) { + return new StringPredicateBuilder(ch); } - private static List testParallelData() { - return testData(false); + private static Predicate onlyChars(String chars) { + return onlyChars(chars.chars().mapToObj(v -> (char)v).toArray(Character[]::new)); } - private static TaskSpecBuilder task(TestTask task) { - return new TaskSpecBuilder(task); + private static Predicate onlyChars(Character... chars) { + return new PredicateWithDescritpion<>(str -> { + final Set set = Set.of(chars); + return str.chars().mapToObj(v -> (char)v).allMatch(set::contains); + }, String.format("only %s", List.of(chars))); } private final static TestTask A = TestTask.A; @@ -262,4 +490,5 @@ private static TaskSpecBuilder task(TestTask task) { private final static TestTask L = TestTask.L; private final static TestTask M = TestTask.M; private final static TestTask N = TestTask.N; + private final static TestTask THROW_1 = TestTask.THROW_1; } From 5bfb9d16bc4a91c56bdc654ef8913b03cb68c0b4 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 30 Jan 2025 00:32:24 -0500 Subject: [PATCH 0260/1101] More graph test cases added --- .../internal/pipeline/ImmutableDAG.java | 49 ++++++---- .../internal/pipeline/ImmutableDAGTest.java | 95 +++++++++++++++++-- 2 files changed, 117 insertions(+), 27 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java index efb3e5331216b..c96e5683ae71c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java @@ -27,6 +27,7 @@ import static java.util.stream.Collectors.toCollection; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -87,23 +88,7 @@ Builder canAddEdgeToUnknownNode(boolean v) { } ImmutableDAG create() { - if (nodes.isEmpty()) { - throw new UnsupportedOperationException("No edges"); - } - - final var nodesAdapter = Nodes.ofList(this.nodes); - final var edgeMatrix = new BinaryMatrix(nodes.size()); - for (final var edge : edges) { - final int row = nodes.indexOf(edge.tail()); - final int column = nodes.indexOf(edge.head()); - edgeMatrix.set(row, column); - } - - if (isCyclic(edgeMatrix, null)) { - throw new UnsupportedOperationException("Cyclic edges not allowed"); - } - - return new ImmutableDAG<>(edgeMatrix, nodesAdapter); + return ImmutableDAG.create(edges, nodes); } private boolean canAddEdgeToUnknownNode = true; @@ -116,7 +101,6 @@ interface Nodes extends Iterable { int indexOf(U node); U get(int index); - static Nodes ofList(List list) { return new Nodes<>() { @@ -161,6 +145,25 @@ public Iterator iterator() { } } + static ImmutableDAG create(Collection> edges, List nodes) { + return create(edges, Nodes.ofList(nodes)); + } + + static ImmutableDAG create(Collection> edges, Nodes nodes) { + final var edgeMatrix = new BinaryMatrix(nodes.size()); + for (final var edge : edges) { + final int row = nodes.indexOf(edge.tail()); + final int column = nodes.indexOf(edge.head()); + edgeMatrix.set(row, column); + } + + if (isCyclic(edgeMatrix, null)) { + throw new UnsupportedOperationException("Cyclic edges not allowed"); + } + + return new ImmutableDAG<>(edgeMatrix, nodes); + } + /** * Returns topologically ordered nodes of this graph. *

@@ -323,12 +326,16 @@ private static boolean isCyclic(BinaryMatrix edgeMatrix, Consumer topol final var insertAtIndex = Math.abs((Collections.binarySearch(S, m) + 1)); if (insertAtIndex == 0) { - S.set(0, m); - i = -1; + if (i == -1) { + S.add(0, m); + } else { + S.set(0, m); + i = -1; + } } else { S.add(insertAtIndex, m); } - } else if (i > 0) { + } else if (i >= 0) { S.set(i, m); i--; } else { diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java index 1c7441881a59e..fe75945af1d53 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java @@ -23,6 +23,7 @@ package jdk.jpackage.internal.pipeline; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -30,6 +31,7 @@ import java.util.Collection; import java.util.List; import java.util.NoSuchElementException; +import java.util.stream.IntStream; import java.util.stream.Stream; import java.util.stream.StreamSupport; import org.junit.jupiter.api.Test; @@ -43,10 +45,10 @@ public void testInvalidCtorArgs() { final var matrix1x2 = new BinaryMatrix(1, 2); final var nodes = ImmutableDAG.Nodes.ofList(List.of(A, B)); - assertThrows(IllegalArgumentException.class, () -> new ImmutableDAG(matrix1x2, nodes)); + assertThrows(IllegalArgumentException.class, () -> new ImmutableDAG<>(matrix1x2, nodes)); final var matrix3x3 = new BinaryMatrix(3, 3); - assertThrows(IllegalArgumentException.class, () -> new ImmutableDAG(matrix3x3, nodes)); + assertThrows(IllegalArgumentException.class, () -> new ImmutableDAG<>(matrix3x3, nodes)); } @Test @@ -302,9 +304,90 @@ public void testSome2() { assertEquals(graph.getAllTailsOf(P), List.of()); } + @ParameterizedTest + @MethodSource + public void testTopologicalSort(List> edges, int[] expectedNodes) { + + final var nodes = edges.stream().map(edge -> { + return Stream.of(edge.tail(), edge.head()); + }).flatMap(x -> x).sorted().distinct().toList(); + + System.out.println(String.format("%s", ImmutableDAG.create(edges, nodes).topologicalSort())); + assertArrayEquals(expectedNodes, ImmutableDAG.create(edges, nodes).topologicalSort().stream().mapToInt(x -> x).toArray()); + } + + private static List testTopologicalSort() { + return List.of( + new Object[] { List.of( + edge(11, 15), + edge(12, 16), + edge(13, 17), + edge(14, 15), + edge(14, 16), + edge(14, 17), + edge(14, 18)), IntStream.rangeClosed(11, 18).toArray() + }, + + new Object[] { List.of( + edge(5, 2), + edge(5, 0), + edge(4, 0), + edge(2, 3), + edge(3, 1)), new int[] {4, 5, 0, 2, 3, 1} + }, + + new Object[] { List.of( + edge(0, 1), + edge(0, 4), + edge(0, 7), + edge(0, 14), + edge(1, 5), + edge(2, 3), + edge(2, 5), + edge(2, 6), + edge(3, 10), + edge(4, 5), + edge(4, 8), + edge(5, 9), + edge(6, 10), + edge(7, 8), + edge(7, 11), + edge(10, 13), + edge(11, 12), + edge(13, 16), + edge(14, 15)), IntStream.rangeClosed(0, 16).toArray() + }, + + new Object[] { List.of( + edge(0, 2), + edge(0, 4), + edge(1, 4), + edge(1, 5), + edge(2, 5), + edge(3, 2)), new int[] {0, 1, 3, 2, 4, 5} + }, + + new Object[] { List.of( + edge(0, 1), + edge(0, 2), + edge(1, 3), + edge(2, 3), + edge(3, 4)), IntStream.rangeClosed(0, 4).toArray() + }, + + new Object[] { List.of( + edge(1, 2), + edge(1, 3), + edge(2, 4), + edge(3, 4), + edge(4, 5)), IntStream.rangeClosed(1, 5).toArray() + } + ); + } + @Test public void testEmptyBuilder() { - assertThrows(UnsupportedOperationException.class, ImmutableDAG.build()::create); + assertThrows(IllegalArgumentException.class, ImmutableDAG.build()::create); } @Test @@ -313,7 +396,7 @@ public void testBuilder() { graphBuilder.canAddEdgeToUnknownNode(false); assertThrows(UnsupportedOperationException.class, () -> graphBuilder.addEdge(edge(A, B))); - assertThrows(UnsupportedOperationException.class, graphBuilder::create); + assertThrows(IllegalArgumentException.class, graphBuilder::create); graphBuilder.canAddEdgeToUnknownNode(true); graphBuilder.addEdge(edge(A, B)); @@ -340,8 +423,8 @@ private static ImmutableDAG create(Collection> edge return graphBuilder.create(); } - private static DirectedEdge edge(String from, String to) { - return DirectedEdge.create(from, to); + private static DirectedEdge edge(T tail, T head) { + return DirectedEdge.create(tail, head); } private final static String A = "A"; From eade8b9044b8567c993339cccaef89f224fc8647 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 31 Jan 2025 14:43:06 -0500 Subject: [PATCH 0261/1101] Made DirectedEdge class public. Got rid of redundant ROOT_TASK. --- .../internal/pipeline/DirectedEdge.java | 10 +- .../internal/pipeline/ImmutableDAG.java | 32 ++----- .../pipeline/TaskPipelineBuilder.java | 91 +++++++++---------- .../internal/pipeline/TaskSpecBuilder.java | 88 ++++++++++++++++++ .../internal/pipeline/ImmutableDAGTest.java | 30 +++--- .../pipeline/TaskPipelineBuilderTest.java | 10 +- 6 files changed, 165 insertions(+), 96 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskSpecBuilder.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdge.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdge.java index dc47ccd16ee76..349696ebe268d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdge.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/DirectedEdge.java @@ -27,9 +27,9 @@ import java.util.Objects; -record DirectedEdge(T tail, T head) { +public record DirectedEdge(T tail, T head) { - DirectedEdge { + public DirectedEdge { Objects.requireNonNull(tail); Objects.requireNonNull(head); @@ -38,15 +38,15 @@ record DirectedEdge(T tail, T head) { } } - T from() { + public T from() { return tail; } - T to() { + public T to() { return head; } - static DirectedEdge create(U tail, U head) { + public static DirectedEdge create(U tail, U head) { return new DirectedEdge<>(tail, head); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java index c96e5683ae71c..293c34237f2fc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java @@ -57,41 +57,29 @@ static Builder build() { final static class Builder { + Builder addNode(U node) { + Objects.requireNonNull(node); + if (!nodes.contains(node)) { + nodes.add(node); + } + return this; + } + Builder addEdge(U tail, U head) { return addEdge(DirectedEdge.create(tail, head)); } Builder addEdge(DirectedEdge edge) { - - final var newTailNode = !nodes.contains(edge.tail()); - final var newHeadNode = !nodes.contains(edge.head()); - - if (newHeadNode && !canAddEdgeToUnknownNode) { - throw new UnsupportedOperationException("Can not add edge to unknown node"); - } - - if (newTailNode) { - nodes.add(edge.tail()); - } - - if (newHeadNode) { - nodes.add(edge.head()); - } - + addNode(edge.tail()); + addNode(edge.head()); edges.add(edge); return this; } - Builder canAddEdgeToUnknownNode(boolean v) { - canAddEdgeToUnknownNode = v; - return this; - } - ImmutableDAG create() { return ImmutableDAG.create(edges, nodes); } - private boolean canAddEdgeToUnknownNode = true; private final List nodes = new ArrayList<>(); private final List> edges = new ArrayList<>(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java index 828b379abe550..9f43ff2257873 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java @@ -26,11 +26,8 @@ package jdk.jpackage.internal.pipeline; import java.util.Collection; -import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; -import java.util.Optional; -import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; @@ -39,54 +36,49 @@ public final class TaskPipelineBuilder { - public final class TaskSpecBuilder { + public final class TaskBuilder extends TaskSpecBuilder> { - TaskSpecBuilder(Callable task) { - Objects.requireNonNull(task); - this.task = task; + TaskBuilder(Callable task) { + super(task); } - public TaskSpecBuilder dependent(Callable v) { - dependent = v; + @Override + public TaskBuilder addDependent(Callable v) { + super.addDependent(v); + return this; + } + + @Override + public TaskBuilder addDependency(Callable v) { + super.addDependency(v); return this; } - public TaskSpecBuilder addDependency(Callable v) { - Objects.requireNonNull(v); - dependencies.add(v); + @Override + public TaskBuilder addDependencies(Collection> v) { + super.addDependencies(v); return this; } - public TaskSpecBuilder addDependencies(Collection> v) { - Objects.requireNonNull(v); - v.forEach(Objects::requireNonNull); - dependencies.addAll(v); + @Override + public TaskBuilder addDependents(Collection> v) { + super.addDependents(v); return this; } public TaskPipelineBuilder add() { - if (taskGraphBuilder == null) { - taskGraphBuilder = new ImmutableDAG.Builder<>(); - taskGraphBuilder.addEdge(task, ROOT_TASK); - taskGraphBuilder.canAddEdgeToUnknownNode(false); + final var links = createLinks(); + if (links.isEmpty()) { + return addTask(task()); } else { - taskGraphBuilder.addEdge(task, Optional.ofNullable(dependent).orElse(ROOT_TASK)); - } - - for (var dependency : dependencies) { - taskGraphBuilder.addEdge(dependency, task); + links.forEach(TaskPipelineBuilder.this::linkTasks); + return TaskPipelineBuilder.this; } - - return TaskPipelineBuilder.this; } - - private Set> dependencies = new LinkedHashSet<>(); - private Callable dependent; - private final Callable task; } - public TaskSpecBuilder task(Callable task) { - return new TaskSpecBuilder(task); + public TaskBuilder task(Callable task) { + return new TaskBuilder(task); } public TaskPipelineBuilder executor(Executor v) { @@ -99,13 +91,25 @@ public TaskPipelineBuilder sequentialExecutor() { return this; } + public TaskPipelineBuilder addTask(Callable task) { + taskGraphBuilder.addNode(task); + return this; + } + + public TaskPipelineBuilder linkTasks(Callable tail, Callable head) { + return linkTasks(DirectedEdge.create(tail, head)); + } + + public TaskPipelineBuilder linkTasks(DirectedEdge> edge) { + taskGraphBuilder.addEdge(edge); + return this; + } + public Callable create() { final var taskGraph = taskGraphBuilder.create(); - if (executor == null) { final var tasks = taskGraph.topologicalSort(); - // Don't run the root task as it is NOP. - return new SequentialWrapperTask(tasks.subList(0, tasks.size() - 1)); + return new SequentialWrapperTask(tasks); } else { return new ParallelWrapperTask(taskGraph, executor); } @@ -155,9 +159,7 @@ public Void call() throws Exception { lastFuture = CompletableFuture.runAsync(toRunnable(task), executor); } else { lastFuture = CompletableFuture.allOf(dependencyTaskFutures); - if (task != ROOT_TASK) { - lastFuture = lastFuture.thenRun(toRunnable(task)); - } + lastFuture = lastFuture.thenRun(toRunnable(task)); } taskFutures[taskIndex] = lastFuture; @@ -192,15 +194,6 @@ private static Runnable toRunnable(Callable callable) { } - private static final Callable ROOT_TASK = new Callable<>() { - - @Override - public Void call() { - // Should never get called. - throw new UnsupportedOperationException(); - } - }; - - private ImmutableDAG.Builder> taskGraphBuilder; + private final ImmutableDAG.Builder> taskGraphBuilder = new ImmutableDAG.Builder<>(); private Executor executor; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskSpecBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskSpecBuilder.java new file mode 100644 index 0000000000000..e6b4457317f56 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskSpecBuilder.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +public class TaskSpecBuilder { + + public TaskSpecBuilder(T task) { + this.task = Objects.requireNonNull(task); + } + + public T task() { + return task; + } + + public TaskSpecBuilder addDependent(T v) { + Objects.requireNonNull(v); + dependents.add(v); + return this; + } + + public TaskSpecBuilder addDependency(T v) { + Objects.requireNonNull(v); + dependencies.add(v); + return this; + } + + public TaskSpecBuilder addDependencies(Collection v) { + Objects.requireNonNull(v); + v.forEach(Objects::requireNonNull); + dependencies.addAll(v); + return this; + } + + public TaskSpecBuilder addDependents(Collection v) { + Objects.requireNonNull(v); + v.forEach(Objects::requireNonNull); + dependents.addAll(v); + return this; + } + + public List> createLinks() { + List> edges = new ArrayList<>(); + + for (var dependency : dependencies) { + edges.add(DirectedEdge.create(dependency, task)); + } + + for (var dependent : dependents) { + edges.add(DirectedEdge.create(task, dependent)); + } + + return edges; + } + + private final Set dependencies = new LinkedHashSet<>(); + private final Set dependents = new LinkedHashSet<>(); + private final T task; +} diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java index fe75945af1d53..4707a4c471691 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java @@ -312,7 +312,6 @@ public void testTopologicalSort(List> edges, int[] expecte return Stream.of(edge.tail(), edge.head()); }).flatMap(x -> x).sorted().distinct().toList(); - System.out.println(String.format("%s", ImmutableDAG.create(edges, nodes).topologicalSort())); assertArrayEquals(expectedNodes, ImmutableDAG.create(edges, nodes).topologicalSort().stream().mapToInt(x -> x).toArray()); } @@ -391,26 +390,25 @@ public void testEmptyBuilder() { } @Test - public void testBuilder() { + public void testSingleNodeBuilder() { final var graphBuilder = ImmutableDAG.build(); + graphBuilder.addNode(A); + assertNodesEquals(graphBuilder.create().nodes(), A); + } - graphBuilder.canAddEdgeToUnknownNode(false); - assertThrows(UnsupportedOperationException.class, () -> graphBuilder.addEdge(edge(A, B))); - assertThrows(IllegalArgumentException.class, graphBuilder::create); - - graphBuilder.canAddEdgeToUnknownNode(true); - graphBuilder.addEdge(edge(A, B)); - assertNodesEquals(graphBuilder.create().nodes(), A, B); - - graphBuilder.canAddEdgeToUnknownNode(false); - graphBuilder.addEdge(edge(A, B)); + @Test + public void testIsolatedNodesBuilder() { + final var graphBuilder = ImmutableDAG.build(); + graphBuilder.addNode(A); + graphBuilder.addNode(B); assertNodesEquals(graphBuilder.create().nodes(), A, B); + assertEquals(graphBuilder.create().getNoOutgoingEdges(), List.of(A, B)); + assertEquals(graphBuilder.create().getNoIncomingEdges(), List.of(A, B)); - graphBuilder.addEdge(edge(C, A)); - assertNodesEquals(graphBuilder.create().nodes(), A, B, C); - - assertThrows(UnsupportedOperationException.class, () -> graphBuilder.addEdge(edge(B, D))); + graphBuilder.addEdge(edge(A, C)); assertNodesEquals(graphBuilder.create().nodes(), A, B, C); + assertEquals(graphBuilder.create().getNoOutgoingEdges(), List.of(B, C)); + assertEquals(graphBuilder.create().getNoIncomingEdges(), List.of(A, B)); } private static void assertNodesEquals(ImmutableDAG.Nodes actual, String... expected) { diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java index 1ba61527239af..0eb3189e7f4c2 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java @@ -243,10 +243,12 @@ void test() { })); taskSpecs.forEach(taskSpec -> { - builder.task(taskMap.get(taskSpec.task)) - .addDependencies(taskSpec.dependencies.stream().map(taskMap::get).toList()) - .dependent(taskMap.get(taskSpec.dependent)) - .add(); + final var taskBuilder = builder.task(taskMap.get(taskSpec.task)) + .addDependencies(taskSpec.dependencies.stream().map(taskMap::get).toList()); + if (taskSpec.dependent != null) { + taskBuilder.addDependent(taskMap.get(taskSpec.dependent)); + } + taskBuilder.add(); }); if (expectedAnyFailures.isEmpty()) { From a83310e9bb9345c58b2b11144fa1ffb1dd4f275a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 31 Jan 2025 17:52:36 -0500 Subject: [PATCH 0262/1101] Introduce PackagingPipeline. Converted windows packagers to use it. SimplePackageTest pass --- .../jdk/jpackage/internal/AppImageInfo.java | 56 +++ .../internal/ApplicationImageUtils.java | 147 ++++++ .../jpackage/internal/PackagingPipeline.java | 432 ++++++++++++++++++ .../jdk/jpackage/internal/WinAppBundler.java | 4 +- .../jdk/jpackage/internal/WinFromParams.java | 2 +- .../jdk/jpackage/internal/WinMsiBundler.java | 35 +- ...Builder.java => WinPackagingPipeline.java} | 31 +- 7 files changed, 667 insertions(+), 40 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageInfo.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java rename src/jdk.jpackage/windows/classes/jdk/jpackage/internal/{WinAppImageBuilder.java => WinPackagingPipeline.java} (78%) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageInfo.java new file mode 100644 index 0000000000000..419436c41aa14 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageInfo.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.ApplicationLayout; + +record AppImageInfo(AppImageLayout imageLayout, Path path) { + + AppImageInfo { + Objects.requireNonNull(imageLayout); + Objects.requireNonNull(path); + } + + AppImageLayout resolvedImagelayout() { + return imageLayout.resolveAt(path); + } + + Optional asResolvedApplicationLayout() { + return asApplicationLayout().map(v -> v.resolveAt(path)); + } + + Optional asApplicationLayout() { + if (imageLayout instanceof ApplicationLayout layout) { + return Optional.of(layout); + } else { + return Optional.empty(); + } + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java new file mode 100644 index 0000000000000..e313b102abbae --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.CustomLauncherIcon; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.PathUtils; + + +final class ApplicationImageUtils { + + static Optional createLauncherIconResource(Application app, + Launcher launcher, + Function resourceSupplier) { + final String defaultIconName = launcher.defaultIconResourceName(); + final String resourcePublicName = launcher.executableName() + PathUtils.getSuffix(Path.of(defaultIconName)); + + if (!launcher.hasIcon()) { + return Optional.empty(); + } + + OverridableResource resource = resourceSupplier.apply(defaultIconName) + .setCategory("icon") + .setPublicName(resourcePublicName); + + launcher.icon().flatMap(CustomLauncherIcon::fromLauncherIcon).map(CustomLauncherIcon::path).ifPresent(resource::setExternal); + + if (launcher.hasDefaultIcon() && app.mainLauncher().orElseThrow() != launcher) { + // No icon explicitly configured for this launcher. + // Dry-run resource creation to figure out its source. + final Path nullPath = null; + if (toSupplier(() -> resource.saveToFile(nullPath)).get() != OverridableResource.Source.ResourceDir) { + // No icon in resource dir for this launcher, inherit icon + // configured for the main launcher. + return createLauncherIconResource( + app, app.mainLauncher().orElseThrow(), + resourceSupplier + ).map(r -> r.setLogPublicName(resourcePublicName)); + } + } + + return Optional.of(resource); + } + + static PackagingPipeline.ApplicationImageTaskAction createWriteRuntimeAction() { + return (env, app, appLayout) -> { + app.runtimeBuilder().ifPresent(toConsumer(runtimeBuilder -> runtimeBuilder.createRuntime(appLayout))); + }; + } + + static PackagingPipeline.ApplicationImageTaskAction createWriteAppImageFileAction() { + return (env, app, appLayout) -> { + new AppImageFile(app).save(appLayout); + }; + } + + static PackagingPipeline.ApplicationImageTaskAction createCopyContentAction(Supplier> excludeCopyDirs) { + return (env, app, appLayout) -> { + var excludeCandidates = Stream.concat( + excludeCopyDirs.get().stream(), + Stream.of(env.buildRoot(), env.appImageDir()) + ).map(Path::toAbsolutePath).toList(); + + app.srcDir().ifPresent(toConsumer(srcDir -> { + copyRecursive(srcDir, appLayout.appDirectory(), excludeCandidates); + })); + + for (var srcDir : app.contentDirs()) { + copyRecursive(srcDir, + appLayout.contentDirectory().resolve(srcDir.getFileName()), + excludeCandidates); + } + }; + } + + static PackagingPipeline.ApplicationImageTaskAction createWriteLaunchersAction() { + return (env, app, appLayout) -> { + for (var launcher : app.launchers()) { + // Create corresponding .cfg file + new CfgFile(app, launcher).create(appLayout, appLayout); + + // Copy executable to launchers folder + Path executableFile = appLayout.launchersDirectory().resolve( + launcher.executableNameWithSuffix()); + try (var in = launcher.executableResource()) { + Files.createDirectories(executableFile.getParent()); + Files.copy(in, executableFile); + } + + executableFile.toFile().setExecutable(true); + } + }; + } + + private static void copyRecursive(Path srcDir, Path dstDir, List excludeDirs) throws IOException { + srcDir = srcDir.toAbsolutePath(); + + List excludes = new ArrayList<>(); + + for (var path : excludeDirs) { + if (Files.isDirectory(path)) { + if (path.startsWith(srcDir) && !Files.isSameFile(path, srcDir)) { + excludes.add(path); + } + } + } + + FileUtils.copyRecursive(srcDir, dstDir.toAbsolutePath(), excludes); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java new file mode 100644 index 0000000000000..9d78d8e7f7d6f --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import static java.util.stream.Collectors.toMap; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.Callable; +import java.util.function.Function; +import java.util.function.UnaryOperator; +import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.pipeline.DirectedEdge; +import jdk.jpackage.internal.pipeline.TaskPipelineBuilder; +import jdk.jpackage.internal.util.function.ExceptionBox; + + +final class PackagingPipeline { + + void execute(BuildEnv env, Application app) throws PackagerException { + execute(contextMapper.apply(createTaskContext(env, app))); + } + + void execute(BuildEnv env, Package pkg, Path outputDir) throws PackagerException { + execute(contextMapper.apply(createTaskContext(env, pkg, outputDir))); + } + + AppImageInfo analyzeAppImageDir(BuildEnv env, Package pkg) { + if (pkg.app().runtimeBuilder().isPresent()) { + // Runtime builder is present, return the path where app image will be created. + return new AppImageInfo(inputApplicationLayoutForPackaging.apply(pkg).orElseThrow(), env.appImageDir()); + } else { + return new AppImageInfo(pkg.app().imageLayout(), pkg.predefinedAppImage().orElseGet(() -> { + // No predefined app image and no runtime builder. + // This should be runtime packaging. + if (pkg.isRuntimeInstaller()) { + return env.appImageDir(); + } else { + // Can't create app image without runtime builder. + throw new UnsupportedOperationException(); + } + })); + } + } + + interface TaskAction { + } + + interface TaskID { + } + + interface AppImageTaskID extends TaskID { + static AppImageTaskID create(String label) { + record Impl(String label) implements AppImageTaskID { + Impl { + Objects.requireNonNull(label); + } + } + return new Impl(label); + } + + static final AppImageTaskID RUNTIME = create("RUNTIME"); + static final AppImageTaskID CONTENT = create("CONTENT"); + static final AppImageTaskID LAUNCHERS = create("LAUNCHERS"); + static final AppImageTaskID APP_IMAGE_FILE = create("APP_IMAGE_FILE"); + } + + interface PackageTaskID extends TaskID { + static PackageTaskID create(String label) { + record Impl(String label) implements PackageTaskID { + Impl { + Objects.requireNonNull(label); + } + } + return new Impl(label); + } + } + + enum TopLevelTaskID implements TaskID { + BUILD_APPLICATION_IMAGE, + COPY_APP_IMAGE, + PACKAGE + } + + interface TaskContext { + boolean test(TaskID taskID); + + void execute(TaskAction taskAction) throws IOException, PackagerException; + } + + @FunctionalInterface + interface ApplicationImageTaskAction extends TaskAction { + void execute(BuildEnv env, Application app, ApplicationLayout appLayout) throws IOException, PackagerException; + } + + @FunctionalInterface + interface CopyAppImageTaskAction extends TaskAction { + void execute(Package pkg, Path srcAppImageRoot, Path dstAppImageRoot) throws IOException, PackagerException; + } + + @FunctionalInterface + interface PackageTaskAction extends TaskAction { + void execute(BuildEnv env, Package pkg) throws IOException, PackagerException; + } + + @FunctionalInterface + interface NoArgTaskAction extends TaskAction { + void execute() throws IOException, PackagerException; + } + + record TaskConfig(TaskAction action) { + } + + static final class Builder { + + private Builder() { + } + + final class TaskBuilder { + + private TaskBuilder(TaskID id) { + this.id = Objects.requireNonNull(id); + } + + private TaskBuilder setAction(TaskAction v) { + action = v; + return this; + } + + TaskBuilder noaction() { + action = null; + return this; + } + + TaskBuilder action(ApplicationImageTaskAction action) { + return setAction(action); + } + + TaskBuilder copyAction(CopyAppImageTaskAction action) { + return setAction(action); + } + + TaskBuilder action(PackageTaskAction action) { + return setAction(action); + } + + TaskBuilder action(NoArgTaskAction action) { + return setAction(action); + } + + Builder add() { + final var config = new TaskConfig(action); + taskConfig.put(id, config); + return Builder.this; + } + + private final TaskID id; + private TaskAction action; + } + + Builder linkTasks(DirectedEdge edge) { + taskGraph.add(edge); + return this; + } + + Builder linkTasks(TaskID tail, TaskID head) { + return linkTasks(DirectedEdge.create(tail, head)); + } + + TaskBuilder task(TaskID id) { + return new TaskBuilder(id); + } + + Builder excludeDirFromCopying(Path path) { + Objects.requireNonNull(path); + excludeCopyDirs.add(path); + return this; + } + + Builder contextMapper(UnaryOperator v) { + contextMapper = v; + return this; + } + + Builder inputApplicationLayoutForPackaging(Function> v) { + inputApplicationLayoutForPackaging = v; + return this; + } + + PackagingPipeline create() { + return new PackagingPipeline(taskGraph, taskConfig, + Optional.ofNullable(contextMapper).orElse(UnaryOperator.identity()), + Optional.ofNullable(inputApplicationLayoutForPackaging).orElse(Package::asPackageApplicationLayout)); + } + + private final List> taskGraph = new ArrayList<>(); + private final List excludeCopyDirs = new ArrayList<>(); + private final Map taskConfig = new HashMap<>(); + private UnaryOperator contextMapper; + private Function> inputApplicationLayoutForPackaging; + } + + static Builder build() { + return new Builder(); + } + + static Builder buildStandard() { + final var builder = build(); + + configureApplicationTasks(builder); + configurePackageTasks(builder); + + return builder; + } + + static Builder configureApplicationTasks(Builder builder) { + builder.linkTasks(AppImageTaskID.RUNTIME, AppImageTaskID.CONTENT); + builder.linkTasks(AppImageTaskID.LAUNCHERS, AppImageTaskID.CONTENT); + builder.linkTasks(AppImageTaskID.CONTENT, AppImageTaskID.APP_IMAGE_FILE); + builder.linkTasks(AppImageTaskID.APP_IMAGE_FILE, TopLevelTaskID.BUILD_APPLICATION_IMAGE); + + builder.task(AppImageTaskID.RUNTIME).action(ApplicationImageUtils.createWriteRuntimeAction()).add(); + builder.task(AppImageTaskID.LAUNCHERS).action(ApplicationImageUtils.createWriteLaunchersAction()).add(); + builder.task(AppImageTaskID.APP_IMAGE_FILE).action(ApplicationImageUtils.createWriteAppImageFileAction()).add(); + builder.task(AppImageTaskID.CONTENT).action(ApplicationImageUtils.createCopyContentAction(() -> builder.excludeCopyDirs)).add(); + + return builder; + } + + static Builder configurePackageTasks(Builder builder) { + builder.linkTasks(TopLevelTaskID.BUILD_APPLICATION_IMAGE, TopLevelTaskID.PACKAGE); + builder.linkTasks(TopLevelTaskID.COPY_APP_IMAGE, TopLevelTaskID.PACKAGE); + + builder.task(TopLevelTaskID.COPY_APP_IMAGE).copyAction(createCopyAppImageAction()).add(); + builder.task(TopLevelTaskID.BUILD_APPLICATION_IMAGE).noaction().add(); + builder.task(TopLevelTaskID.PACKAGE).noaction().add(); + + return builder; + } + + static CopyAppImageTaskAction createCopyAppImageAction() { + return (pkg, srcAppImageRoot, dstAppImageRoot) -> { + final var srcLayout = pkg.appImageLayout().resolveAt(srcAppImageRoot); + final var srcLayoutPathGroup = AppImageLayout.toPathGroup(srcLayout); + + if (srcLayout instanceof ApplicationLayout appLayout) { + // Copy app layout omitting application image info file. + srcLayoutPathGroup.ghostPath(AppImageFile.getPathInAppImage(appLayout)); + } + + srcLayoutPathGroup.copy(AppImageLayout.toPathGroup(pkg.packageLayout().resolveAt(dstAppImageRoot))); + }; + } + + private PackagingPipeline(List> taskGraph, Map taskConfig, + UnaryOperator contextMapper, Function> inputApplicationLayoutForPackaging) { + this.taskGraph = Objects.requireNonNull(taskGraph); + this.taskConfig = Objects.requireNonNull(taskConfig); + this.contextMapper = Objects.requireNonNull(contextMapper); + this.inputApplicationLayoutForPackaging = Objects.requireNonNull(inputApplicationLayoutForPackaging); + } + + private TaskContext createTaskContext(BuildEnv env, Application app) { + final var appImageLayout = app.asApplicationLayout().map(layout -> layout.resolveAt(env.appImageDir())); + return new DefaultTaskContext(env, app, appImageLayout, Optional.empty()); + } + + private TaskContext createTaskContext(BuildEnv env, Package pkg, Path outputDir) { + final var pkgEnv = BuildEnv.withAppImageDir(env, env.buildRoot().resolve("image")); + final var appImageInfo = analyzeAppImageDir(env, pkg); + return new DefaultTaskContext(env, pkg.app(), appImageInfo.asResolvedApplicationLayout(), + Optional.of(new PackagingTaskContext(pkg, pkgEnv, appImageInfo.path(), outputDir))); + } + + private void execute(TaskContext context) throws PackagerException { + final Map> tasks = taskConfig.entrySet().stream().collect(toMap(Map.Entry::getKey, task -> { + return createTask(context, task.getKey(), task.getValue()); + })); + + final var builder = new TaskPipelineBuilder(); + + taskGraph.forEach(edge -> { + System.out.println(String.format("edge: %s", edge)); + builder.linkTasks(tasks.get(edge.tail()), tasks.get(edge.head())); + }); + + try { + builder.create().call(); + } catch (Exception ex) { + if (ex instanceof PackagerException pex) { + throw pex; + } else { + throw new PackagerException(ex); + } + } + } + + private static record PackagingTaskContext(Package pkg, BuildEnv env, Path srcAppImageDir, + Path outputDir) implements TaskContext { + + PackagingTaskContext { + Objects.requireNonNull(pkg); + Objects.requireNonNull(env); + Objects.requireNonNull(srcAppImageDir); + Objects.requireNonNull(outputDir); + } + + @Override + public boolean test(TaskID taskID) { + if (taskID == AppImageTaskID.APP_IMAGE_FILE) { + // Application image for packaging, skip adding application image info file. + return false; + } + + return true; + } + + @Override + public void execute(TaskAction taskAction) throws IOException, PackagerException { + if (taskAction instanceof PackageTaskAction pkgAction) { + pkgAction.execute(env, pkg); + } else if (taskAction instanceof CopyAppImageTaskAction copyAction) { + copyAction.execute(pkg, srcAppImageDir, env.appImageDir()); + } else { + throw new IllegalArgumentException(); + } + } + } + + private static record DefaultTaskContext(BuildEnv env, Application app, + Optional appLayout, Optional pkg) implements TaskContext { + + DefaultTaskContext { + Objects.requireNonNull(env); + Objects.requireNonNull(app); + Objects.requireNonNull(appLayout); + Objects.requireNonNull(pkg); + } + + @Override + public boolean test(TaskID taskID) { + if (pkg.isPresent() && !pkg.orElseThrow().test(taskID)) { + return false; + } else if (pkg.isEmpty() && taskID instanceof PackageTaskID) { + // Building application image, skip packaging tasks. + return false; + } else if (taskID instanceof AppImageTaskID) { + // Application image task. + if (app.isRuntime()) { + // Skip it as this is runtime app image. + return false; + } else { + // Accept the task only if configuration allows to build application image. + return canBuildAppImage(); + } + } + + return true; + } + + @Override + public void execute(TaskAction taskAction) throws IOException, PackagerException { + if (taskAction instanceof ApplicationImageTaskAction appImageAction) { + appImageAction.execute(env, app, appLayout.orElseThrow()); + } else if (taskAction instanceof NoArgTaskAction noArgAction) { + noArgAction.execute(); + } else { + pkg.orElseThrow().execute(taskAction); + } + } + + private boolean canBuildAppImage() { + // Build application image only when runtime builder is available. + return pkg.map(PackagingTaskContext::pkg).map(Package::app).orElse(app).runtimeBuilder().isPresent(); + } + + } + + private static Callable createTask(TaskContext context, TaskID id, TaskConfig config) { + Objects.requireNonNull(context); + Objects.requireNonNull(id); + return () -> { + if (config.action != null && context.test(id)) { + try { + context.execute(config.action); + } catch (ExceptionBox ex) { + throw ExceptionBox.rethrowUnchecked(ex); + } + } + return null; + }; + } + + private final List> taskGraph; + private final Map taskConfig; + private final Function> inputApplicationLayoutForPackaging; + private final UnaryOperator contextMapper; +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java index b97599b4c373c..06a34f9e52c0a 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java @@ -31,9 +31,9 @@ public WinAppBundler() { // Order is important! var app = WinFromParams.APPLICATION.fetchFrom(params); var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - WinAppImageBuilder.build() + WinPackagingPipeline.build() .excludeDirFromCopying(output.getParent()) - .create(app).execute(BuildEnv.withAppImageDir(env, output)); + .create().execute(BuildEnv.withAppImageDir(env, output), app); }); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java index 807ae316ea8a9..83c08a7e6a1a3 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java @@ -34,7 +34,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; -import static jdk.jpackage.internal.WinAppImageBuilder.APPLICATION_LAYOUT; +import static jdk.jpackage.internal.WinPackagingPipeline.APPLICATION_LAYOUT; import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; import static jdk.jpackage.internal.model.WinLauncherMixin.WinShortcut.WIN_SHORTCUT_DESKTOP; import static jdk.jpackage.internal.model.WinLauncherMixin.WinShortcut.WIN_SHORTCUT_START_MENU; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 309ea0d4ee225..807cbef77a983 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -25,9 +25,8 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.WinMsiPackage; +import static jdk.jpackage.internal.model.ConfigException.rethrowConfigException; + import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; @@ -55,11 +54,13 @@ import javax.xml.xpath.XPathFactory; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.RuntimeLayout; +import jdk.jpackage.internal.model.WinMsiPackage; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; -import static jdk.jpackage.internal.model.ConfigException.rethrowConfigException; /** * WinMsiBundler @@ -205,29 +206,11 @@ public boolean validate(Map params) private void prepareProto(WinMsiPackage pkg, BuildEnv env, Path msiOutputDir) throws PackagerException, IOException { - AppImageLayout appImageLayout; - - // we either have an application image or need to build one - if (pkg.app().runtimeBuilder().isPresent()) { - // Runtime builder is present, build app image. - WinAppImageBuilder.build() - .excludeDirFromCopying(msiOutputDir) - .create(pkg.app()).execute(env); - appImageLayout = pkg.appImageLayout().resolveAt(env.appImageDir()); - } else { - Path srcAppImageDir = pkg.predefinedAppImage().orElseGet(() -> { - // No predefined app image and no runtime builder. - // This should be runtime packaging. - if (pkg.isRuntimeInstaller()) { - return env.appImageDir(); - } else { - // Can't create app image without runtime builder. - throw new UnsupportedOperationException(); - } - }); + final var taskPipeline = WinPackagingPipeline.build().excludeDirFromCopying(msiOutputDir).create(); - appImageLayout = pkg.appImageLayout().resolveAt(srcAppImageDir); - } + taskPipeline.execute(env, pkg, msiOutputDir); + + final AppImageLayout appImageLayout = taskPipeline.analyzeAppImageDir(env, pkg).resolvedImagelayout(); // Configure installer icon if (appImageLayout instanceof RuntimeLayout runtimeLayout) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java similarity index 78% rename from src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java rename to src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java index e6933daece06f..2bca4f7ea50ad 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppImageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java @@ -24,22 +24,31 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.WinLauncher; -import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.WinApplication; +import static jdk.jpackage.internal.AppImageBuilder.createLauncherIconResource; + import java.io.IOException; import java.io.UncheckedIOException; -import jdk.jpackage.internal.AppImageBuilder.AppImageItemGroup; -import static jdk.jpackage.internal.AppImageBuilder.createLauncherIconResource; +import jdk.jpackage.internal.PackagingPipeline.AppImageTaskID; +import jdk.jpackage.internal.PackagingPipeline.TopLevelTaskID; +import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.WinApplication; +import jdk.jpackage.internal.model.WinLauncher; + +final class WinPackagingPipeline { -final class WinAppImageBuilder { + enum WinAppImageTaskID implements AppImageTaskID { + REBRAND_LAUNCHERS + } - static AppImageBuilder.Builder build() { - return AppImageBuilder.build() - .itemGroup(AppImageItemGroup.LAUNCHERS) - .addItem(WinAppImageBuilder::rebrandLaunchers); + static PackagingPipeline.Builder build() { + return PackagingPipeline.buildStandard() + .inputApplicationLayoutForPackaging(pkg -> pkg.app().asApplicationLayout()) + .linkTasks(WinAppImageTaskID.REBRAND_LAUNCHERS, TopLevelTaskID.BUILD_APPLICATION_IMAGE) + .linkTasks(AppImageTaskID.LAUNCHERS, WinAppImageTaskID.REBRAND_LAUNCHERS) + .task(TopLevelTaskID.COPY_APP_IMAGE).noaction().add() + .task(WinAppImageTaskID.REBRAND_LAUNCHERS).action(WinPackagingPipeline::rebrandLaunchers).add(); } private static void rebrandLaunchers(BuildEnv env, Application app, From af845e4e17e67ce4447df593d914934ed9d93d97 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 1 Feb 2025 00:33:17 -0500 Subject: [PATCH 0263/1101] Make ImmutableDAG public --- .../internal/pipeline/BinaryMatrix.java | 2 +- .../internal/pipeline/ImmutableDAG.java | 34 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java index 9193c4396a967..452cb24ce327c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java @@ -34,7 +34,7 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; -final class BinaryMatrix { +public final class BinaryMatrix { BinaryMatrix(BinaryMatrix other) { rows = other.rows; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java index 293c34237f2fc..76955474a8f3c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java @@ -49,15 +49,15 @@ * node container * @param nodes the node container */ -record ImmutableDAG(BinaryMatrix edgeMatrix, Nodes nodes) { +public record ImmutableDAG(BinaryMatrix edgeMatrix, Nodes nodes) { - static Builder build() { + public static Builder build() { return new Builder<>(); } - final static class Builder { + public final static class Builder { - Builder addNode(U node) { + public Builder addNode(U node) { Objects.requireNonNull(node); if (!nodes.contains(node)) { nodes.add(node); @@ -65,18 +65,18 @@ Builder addNode(U node) { return this; } - Builder addEdge(U tail, U head) { + public Builder addEdge(U tail, U head) { return addEdge(DirectedEdge.create(tail, head)); } - Builder addEdge(DirectedEdge edge) { + public Builder addEdge(DirectedEdge edge) { addNode(edge.tail()); addNode(edge.head()); edges.add(edge); return this; } - ImmutableDAG create() { + public ImmutableDAG create() { return ImmutableDAG.create(edges, nodes); } @@ -84,7 +84,7 @@ ImmutableDAG create() { private final List> edges = new ArrayList<>(); } - interface Nodes extends Iterable { + public interface Nodes extends Iterable { int size(); int indexOf(U node); U get(int index); @@ -120,7 +120,7 @@ public Iterator iterator() { } } - ImmutableDAG { + public ImmutableDAG { Objects.requireNonNull(nodes); Objects.requireNonNull(edgeMatrix); @@ -133,7 +133,7 @@ public Iterator iterator() { } } - static ImmutableDAG create(Collection> edges, List nodes) { + public static ImmutableDAG create(Collection> edges, List nodes) { return create(edges, Nodes.ofList(nodes)); } @@ -159,7 +159,7 @@ static ImmutableDAG create(Collection> edges, Nodes no * * @return topologically ordered nodes of this graph */ - List topologicalSort() { + public List topologicalSort() { final List result = new ArrayList<>(); isCyclic(edgeMatrix, index -> { result.add(nodes.get(index)); @@ -167,11 +167,11 @@ List topologicalSort() { return result; } - List getAllHeadsOf(T node) { + public List getAllHeadsOf(T node) { return getAllNodesOf(node, true); } - List getAllTailsOf(T node) { + public List getAllTailsOf(T node) { return getAllNodesOf(node, false); } @@ -188,7 +188,7 @@ List getAllTailsOf(T node) { * * @see Nodes */ - List getHeadsOf(T node) { + public List getHeadsOf(T node) { final int tail = nodes.indexOf(node); return getOutgoingEdges(tail, edgeMatrix).map(BinaryMatrix.Cursor::column).map(nodes::get).toList(); } @@ -206,7 +206,7 @@ List getHeadsOf(T node) { * * @see Nodes */ - List getTailsOf(T node) { + public List getTailsOf(T node) { final int head = nodes.indexOf(node); return getIncomingEdges(head, edgeMatrix).map(BinaryMatrix.Cursor::row).map(nodes::get).toList(); } @@ -221,7 +221,7 @@ List getTailsOf(T node) { * * @return the list of nodes without incoming edges */ - List getNoIncomingEdges() { + public List getNoIncomingEdges() { return getNoIncomingEdges(edgeMatrix).mapToObj(nodes::get).toList(); } @@ -235,7 +235,7 @@ List getNoIncomingEdges() { * * @return the list of nodes without outgoing edges */ - List getNoOutgoingEdges() { + public List getNoOutgoingEdges() { return getNoOutgoingEdges(edgeMatrix).mapToObj(nodes::get).toList(); } From d1e7d8ca4fdc3622c3de39bfeb8db524c08188a7 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 1 Feb 2025 00:56:02 -0500 Subject: [PATCH 0264/1101] Implemented PackagingPipeline on all platforms. All tests pass on Windows. SimplePackageTest pass on OSX. --- .../jpackage/internal/DesktopIntegration.java | 2 +- .../jpackage/internal/LinuxAppBundler.java | 4 +- .../jpackage/internal/LinuxFromParams.java | 2 +- .../internal/LinuxPackageBundler.java | 49 +-- ...ilder.java => LinuxPackagingPipeline.java} | 29 +- .../jdk/jpackage/internal/MacAppBundler.java | 18 +- .../jdk/jpackage/internal/MacFromParams.java | 2 +- ...uilder2.java => MacPackagingPipeline.java} | 162 ++++++--- .../jpackage/internal/AppImageBuilder.java | 319 ------------------ .../internal/ApplicationImageUtils.java | 2 +- .../jpackage/internal/PackagingPipeline.java | 212 ++++++++---- .../internal/WinPackagingPipeline.java | 16 +- 12 files changed, 313 insertions(+), 504 deletions(-) rename src/jdk.jpackage/linux/classes/jdk/jpackage/internal/{LinuxAppImageBuilder.java => LinuxPackagingPipeline.java} (75%) rename src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/{MacAppImageBuilder2.java => MacPackagingPipeline.java} (62%) delete mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 11b8185d9925b..7a1eaf9b5d09c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -45,7 +45,7 @@ import javax.imageio.ImageIO; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import static jdk.jpackage.internal.AppImageBuilder.createLauncherIconResource; +import static jdk.jpackage.internal.ApplicationImageUtils.createLauncherIconResource; import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.util.CompositeProxy; import jdk.jpackage.internal.util.PathUtils; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java index 2bca3fef0418f..4b385899b30c7 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java @@ -31,9 +31,9 @@ public LinuxAppBundler() { // Order is important! var app = LinuxFromParams.APPLICATION.fetchFrom(params); var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - LinuxAppImageBuilder.build() + LinuxPackagingPipeline.build() .excludeDirFromCopying(output.getParent()) - .create(app).execute(BuildEnv.withAppImageDir(env, output)); + .create().execute(BuildEnv.withAppImageDir(env, output), app); }); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java index 3fbf7d410e630..1c5b064a02724 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java @@ -29,7 +29,7 @@ import static jdk.jpackage.internal.FromParams.createApplicationBundlerParam; import static jdk.jpackage.internal.FromParams.createPackageBuilder; import static jdk.jpackage.internal.FromParams.createPackageBundlerParam; -import static jdk.jpackage.internal.LinuxAppImageBuilder.APPLICATION_LAYOUT; +import static jdk.jpackage.internal.LinuxPackagingPipeline.APPLICATION_LAYOUT; import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 6addb9a349c08..031da0a136e2c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -24,10 +24,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.LinuxPackage; -import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.ConfigException; import java.io.IOException; import java.nio.file.Path; import java.text.MessageFormat; @@ -36,11 +32,12 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Stream; -import jdk.jpackage.internal.model.AppImageLayout; -import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.PackagerException; abstract class LinuxPackageBundler extends AbstractBundler { @@ -103,43 +100,17 @@ public final Path execute(Map params, IOUtils.writableOutputDir(outputParentDir); // Order is important! - LinuxPackage pkg = pkgParam.fetchFrom(params); - var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + final LinuxPackage pkg = pkgParam.fetchFrom(params); + final var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); BuildEnv pkgEnv = BuildEnv.withAppImageDir(env, env.buildRoot().resolve("image")); - try { - // We either have an application image or need to build one. - if (pkg.app().runtimeBuilder().isPresent()) { - // Runtime builder is present, build app image. - LinuxAppImageBuilder.build() - .excludeDirFromCopying(outputParentDir) - .create(pkg).execute(pkgEnv); - } else { - Path srcAppImageDir = pkg.predefinedAppImage().orElseGet(() -> { - // No predefined app image and no runtime builder. - // This should be runtime packaging. - if (pkg.isRuntimeInstaller()) { - return env.appImageDir(); - } else { - // Can't create app image without runtime builder. - throw new UnsupportedOperationException(); - } - }); - - var srcLayout = pkg.appImageLayout().resolveAt(srcAppImageDir); - var srcLayoutPathGroup = AppImageLayout.toPathGroup(srcLayout); - - if (srcLayout instanceof ApplicationLayout appLayout) { - // Copy app layout omitting application image info file. - srcLayoutPathGroup.ghostPath(AppImageFile.getPathInAppImage(appLayout)); - } - - srcLayoutPathGroup.copy(AppImageLayout.toPathGroup( - pkg.packageLayout().resolveAt(pkgEnv.appImageDir()))); - } + LinuxPackagingPipeline.build() + .excludeDirFromCopying(outputParentDir) + .create().execute(env, pkg, outputParentDir); + try { for (var ca : customActions) { ca.init(pkgEnv, pkg); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java similarity index 75% rename from src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java rename to src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java index fd19434b8055c..58afec87cd48d 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java @@ -24,23 +24,34 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.Application; +import static jdk.jpackage.internal.ApplicationImageUtils.createLauncherIconResource; + import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; -import jdk.jpackage.internal.AppImageBuilder.AppImageItemGroup; -import static jdk.jpackage.internal.AppImageBuilder.createLauncherIconResource; +import jdk.jpackage.internal.PackagingPipeline.AppImageTaskID; +import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; +import jdk.jpackage.internal.PackagingPipeline.TaskID; +import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.resources.ResourceLocator; -final class LinuxAppImageBuilder { +final class LinuxPackagingPipeline { + + enum LinuxAppImageTaskID implements TaskID { + LAUNCHER_LIB, + LAUNCHER_ICONS + } - static AppImageBuilder.Builder build() { - return AppImageBuilder.build() - .itemGroup(AppImageItemGroup.LAUNCHERS) - .addItem(LinuxAppImageBuilder::writeLauncherLib) - .addItem(LinuxAppImageBuilder::writeLauncherIcons); + static PackagingPipeline.Builder build() { + return PackagingPipeline.buildStandard() + .task(LinuxAppImageTaskID.LAUNCHER_LIB) + .addDependent(PrimaryTaskID.BUILD_APPLICATION_IMAGE) + .action(LinuxPackagingPipeline::writeLauncherLib).add() + .task(LinuxAppImageTaskID.LAUNCHER_ICONS) + .addDependent(AppImageTaskID.CONTENT) + .action(LinuxPackagingPipeline::writeLauncherIcons).add(); } private static void writeLauncherLib(BuildEnv env, Application app, diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index 61d186266dc6b..7a12b3de69b66 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -43,20 +43,20 @@ public MacAppBundler() { // Order is important! final var app = MacFromParams.APPLICATION.fetchFrom(params); - final var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + final var env = BuildEnv.withAppImageDir(BuildEnvFromParams.BUILD_ENV.fetchFrom(params), output); - final var appImageBuilderBuilder = MacAppImageBuilder2.build().excludeDirFromCopying(output.getParent()); + final var taskPipeline = MacPackagingPipeline.build() + .excludeDirFromCopying(output.getParent()) + .inputApplicationLayoutForPackaging(pkg -> pkg.app().asApplicationLayout()) + .create(); if (isDependentTask()) { - final var pkg = Optional.of(MacFromParams.PACKAGE.fetchFrom(params)); - appImageBuilderBuilder.addItem((theEnv, theApp, appLayout) -> { - new PackageFile(pkg.orElseThrow().packageName()).save(appLayout); - }); + final var pkg = MacFromParams.PACKAGE.fetchFrom(params); + taskPipeline.execute(env, pkg, output); + } else { + taskPipeline.execute(env, app); } - final var appImageBuilder = appImageBuilderBuilder.create(app); - - appImageBuilder.execute(BuildEnv.withAppImageDir(env, output)); }); setParamsValidator(MacAppBundler::doValidate); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java index 3df92347a7615..cb21cfd04c567 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java @@ -31,7 +31,7 @@ import static jdk.jpackage.internal.FromParams.createApplicationBundlerParam; import static jdk.jpackage.internal.FromParams.createPackageBundlerParam; import static jdk.jpackage.internal.MacAppImageBuilder.APP_STORE; -import static jdk.jpackage.internal.MacAppImageBuilder2.APPLICATION_LAYOUT; +import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java similarity index 62% rename from src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java rename to src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index 71695df10cef2..dae2148e0683d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder2.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -43,33 +43,111 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Stream; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import jdk.jpackage.internal.AppImageBuilder.AppImageItem; -import jdk.jpackage.internal.AppImageBuilder.AppImageItemGroup; +import jdk.jpackage.internal.PackagingPipeline.AppImageTaskID; +import jdk.jpackage.internal.PackagingPipeline.ApplicationImageTaskAction; +import jdk.jpackage.internal.PackagingPipeline.CopyAppImageTaskAction; +import jdk.jpackage.internal.PackagingPipeline.TaskAction; +import jdk.jpackage.internal.PackagingPipeline.TaskContext; +import jdk.jpackage.internal.PackagingPipeline.TaskID; +import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; +import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.MacFileAssociation; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.SigningConfig; +import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; -final class MacAppImageBuilder2 { - - static AppImageBuilder.Builder build() { - return AppImageBuilder.build() - .itemGroup(AppImageItemGroup.RUNTIME) - .addItem(MacAppImageBuilder2::writeRuntimeInfoPlist) - .addItem(MacAppImageBuilder2::copyJliLib) - .itemGroup(AppImageItemGroup.BEGIN) - .addItem(new ApplicationIcon()) - .addItem(MacAppImageBuilder2::writePkgInfoFile) - .addItem(MacAppImageBuilder2::writeFileAssociationIcons) - .addItem(MacAppImageBuilder2::writeAppInfoPlist) - .itemGroup(AppImageItemGroup.END) - .addItem(MacAppImageBuilder2::sign); +final class MacPackagingPipeline { + + enum MacAppImageTaskID implements TaskID { + RUNTIME_INFO_PLIST, + COPY_JLILIB, + APP_ICON, + PKG_INFO_FILE, + PKG_FILE, + FA_ICONS, + APP_INFO_PLIST, + SIGN + } + + static PackagingPipeline.Builder build() { + final var builder = PackagingPipeline.buildStandard() + .pkgContextMapper(appContext -> { + return new TaskContext() { + + @Override + public boolean test(TaskID taskID) { + if (taskID == AppImageTaskID.APP_IMAGE_FILE) { + // Always create ".jpackage.xml" for compatibility with tests + // TODO: Don't create ".jpackage.xml" when doing bundling a package like on other platforms + return true; + } else { + return appContext.test(taskID); + } + } + + @Override + public void execute(TaskAction taskAction) throws IOException, PackagerException { + appContext.execute(taskAction); + } + + }; + }) + .task(PrimaryTaskID.COPY_APP_IMAGE) + .copyAction(MacPackagingPipeline::copyAppImage).add() + .task(MacAppImageTaskID.RUNTIME_INFO_PLIST) + .action(conv(MacPackagingPipeline::writeRuntimeInfoPlist)) + .addDependent(AppImageTaskID.CONTENT).add() + .task(MacAppImageTaskID.COPY_JLILIB) + .action(MacPackagingPipeline::copyJliLib) + .addDependent(AppImageTaskID.CONTENT).add() + .task(MacAppImageTaskID.APP_ICON) + .action(conv(new ApplicationIcon())) + .addDependent(AppImageTaskID.CONTENT).add() + .task(MacAppImageTaskID.PKG_INFO_FILE) + .action(MacPackagingPipeline::writePkgInfoFile) + .addDependent(AppImageTaskID.CONTENT).add() + .task(MacAppImageTaskID.PKG_FILE) + .action(MacPackagingPipeline::writePackageFile) + .addDependent(AppImageTaskID.CONTENT).add() + .task(MacAppImageTaskID.FA_ICONS) + .action(MacPackagingPipeline::writeFileAssociationIcons) + .addDependent(AppImageTaskID.CONTENT).add() + .task(MacAppImageTaskID.APP_INFO_PLIST) + .action(conv(MacPackagingPipeline::writeAppInfoPlist)) + .addDependent(AppImageTaskID.CONTENT).add(); + + builder.task(MacAppImageTaskID.SIGN) + .action(conv(MacPackagingPipeline::sign)) + .addDependencies(builder.taskGraphSnapshot().getAllTailsOf(PrimaryTaskID.BUILD_APPLICATION_IMAGE)) + .addDependent(PrimaryTaskID.BUILD_APPLICATION_IMAGE).add(); + + return builder; + } + + @FunctionalInterface + private interface MacApplicationImageTaskAction extends TaskAction { + void execute(BuildEnv env, MacApplication app, ApplicationLayout appLayout) throws IOException, PackagerException; + } + + private static ApplicationImageTaskAction conv(MacApplicationImageTaskAction v) { + return (env, app, appLayout) -> { + v.execute(env, (MacApplication)app, appLayout); + }; + } + + private static void copyAppImage(Package pkg, Path srcAppImageRoot, Path dstAppImageRoot) throws IOException { + FileUtils.copyRecursive(srcAppImageRoot, dstAppImageRoot); } private static void copyJliLib(BuildEnv env, Application app, @@ -89,16 +167,18 @@ private static void copyJliLib(BuildEnv env, Application app, } } - private static void writeRuntimeInfoPlist(BuildEnv env, Application app, - ApplicationLayout appLayout) throws IOException { + private static void writePackageFile(BuildEnv env, Package pkg) throws IOException { + new PackageFile(pkg.packageName()).save(pkg.asApplicationLayout().orElseThrow().resolveAt(env.appImageDir())); + } - final var macApp = ((MacApplication)app); + private static void writeRuntimeInfoPlist(BuildEnv env, MacApplication app, + ApplicationLayout appLayout) throws IOException { Map data = new HashMap<>(); - data.put("CF_BUNDLE_IDENTIFIER", macApp.bundleIdentifier()); - data.put("CF_BUNDLE_NAME", macApp.bundleName()); - data.put("CF_BUNDLE_VERSION", macApp.version()); - data.put("CF_BUNDLE_SHORT_VERSION_STRING", macApp.shortVersion().toString()); + data.put("CF_BUNDLE_IDENTIFIER", app.bundleIdentifier()); + data.put("CF_BUNDLE_NAME", app.bundleName()); + data.put("CF_BUNDLE_VERSION", app.version()); + data.put("CF_BUNDLE_SHORT_VERSION_STRING", app.shortVersion().toString()); env.createResource("Runtime-Info.plist.template") .setPublicName("Runtime-Info.plist") @@ -107,16 +187,14 @@ private static void writeRuntimeInfoPlist(BuildEnv env, Application app, .saveToFile(((MacApplicationLayout)appLayout).runtimeRootDirectory().resolve("Contents/Info.plist")); } - private static void writeAppInfoPlist(BuildEnv env, Application app, + private static void writeAppInfoPlist(BuildEnv env, MacApplication app, ApplicationLayout appLayout) throws IOException { - final var macApp = ((MacApplication)app); - final String faXml = toSupplier(() -> { var buf = new StringWriter(); var xml = XMLOutputFactory.newInstance().createXMLStreamWriter(buf); - writeCFBundleDocumentTypes(xml, macApp); - writeUTExportedTypeDeclarations(xml, macApp); + writeCFBundleDocumentTypes(xml, app); + writeUTExportedTypeDeclarations(xml, app); xml.flush(); xml.close(); return buf.toString(); @@ -126,11 +204,11 @@ private static void writeAppInfoPlist(BuildEnv env, Application app, data.put("DEPLOY_ICON_FILE", ApplicationIcon.getPath(app, appLayout).getFileName().toString()); data.put("DEPLOY_BUNDLE_COPYRIGHT", app.copyright()); data.put("DEPLOY_LAUNCHER_NAME", app.mainLauncher().orElseThrow().executableNameWithSuffix()); - data.put("DEPLOY_BUNDLE_SHORT_VERSION", macApp.shortVersion().toString()); + data.put("DEPLOY_BUNDLE_SHORT_VERSION", app.shortVersion().toString()); data.put("DEPLOY_BUNDLE_CFBUNDLE_VERSION", app.version()); - data.put("DEPLOY_BUNDLE_NAME", macApp.bundleName()); - data.put("DEPLOY_BUNDLE_IDENTIFIER", macApp.bundleIdentifier()); - data.put("DEPLOY_APP_CATEGORY", macApp.category()); + data.put("DEPLOY_BUNDLE_NAME", app.bundleName()); + data.put("DEPLOY_BUNDLE_IDENTIFIER", app.bundleIdentifier()); + data.put("DEPLOY_APP_CATEGORY", app.category()); data.put("DEPLOY_FILE_ASSOCIATIONS", faXml); env.createResource("Info-lite.plist.template") @@ -140,15 +218,13 @@ private static void writeAppInfoPlist(BuildEnv env, Application app, .saveToFile(appLayout.contentDirectory().resolve("Info.plist")); } - private static void sign(BuildEnv env, Application app, ApplicationLayout appLayout) throws IOException { - - final var macApp = ((MacApplication)app); + private static void sign(BuildEnv env, MacApplication app, ApplicationLayout appLayout) throws IOException { final var codesignConfigBuilder = CodesignConfig.build(); - macApp.signingConfig().ifPresent(codesignConfigBuilder::from); + app.signingConfig().ifPresent(codesignConfigBuilder::from); - if (macApp.sign() && macApp.signingConfig().flatMap(SigningConfig::entitlements).isEmpty()) { - final var entitlementsDefaultResource = macApp.signingConfig().map( + if (app.sign() && app.signingConfig().flatMap(SigningConfig::entitlements).isEmpty()) { + final var entitlementsDefaultResource = app.signingConfig().map( SigningConfig::entitlementsResourceName).orElseThrow(); final var entitlementsFile = env.configDir().resolve(app.name() + ".entitlements"); @@ -161,10 +237,10 @@ private static void sign(BuildEnv env, Application app, ApplicationLayout appLay } final Runnable signAction = () -> { - AppImageSigner.createSigner(macApp, codesignConfigBuilder.create()).accept(env.appImageDir()); + AppImageSigner.createSigner(app, codesignConfigBuilder.create()).accept(env.appImageDir()); }; - macApp.signingConfig().flatMap(SigningConfig::keyChain).ifPresentOrElse(keyChain -> { + app.signingConfig().flatMap(SigningConfig::keyChain).ifPresentOrElse(keyChain -> { toBiConsumer(TempKeychain::withKeychain).accept(keyChain, unused -> signAction.run()); }, signAction); } @@ -239,17 +315,17 @@ private static void addFaToUTExportedTypeDeclarations(XMLStreamWriter xml, })); } - private static class ApplicationIcon implements AppImageItem { + private static class ApplicationIcon implements MacApplicationImageTaskAction { static Path getPath(Application app, ApplicationLayout appLayout) { return appLayout.destktopIntegrationDirectory().resolve(app.name() + ".icns"); } @Override - public void write(BuildEnv env, Application app, ApplicationLayout appLayout) + public void execute(BuildEnv env, MacApplication app, ApplicationLayout appLayout) throws IOException { final var resource = env.createResource("JavaApp.icns").setCategory("icon"); - ((MacApplication)app).icon().ifPresent(resource::setExternal); + app.icon().ifPresent(resource::setExternal); resource.saveToFile(getPath(app, appLayout)); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java deleted file mode 100644 index 92e5e6def5a6a..0000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBuilder.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal; - -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Stream; -import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.ApplicationLayout; -import jdk.jpackage.internal.model.CustomLauncherIcon; -import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.util.FileUtils; -import jdk.jpackage.internal.util.PathUtils; -import jdk.jpackage.internal.util.function.ExceptionBox; - - -final class AppImageBuilder { - - static final class Builder { - - private Builder() { - } - - Builder addItem(AppImageItem v) { - return addItem(v, Scope.ALL); - } - - Builder addApplicationItem(AppImageItem v) { - return addItem(v, Scope.APPLICATION_ONLY); - } - - Builder addPackageItem(AppImageItem v) { - return addItem(v, Scope.PACKAGE_ONLY); - } - - Builder itemGroup(AppImageItemGroup v) { - Objects.requireNonNull(v); - curGroup = v; - return this; - } - - Builder excludeDirFromCopying(Path path) { - Objects.requireNonNull(path); - excludeCopyDirs.add(path); - return this; - } - - AppImageBuilder create(Application app) { - return new AppImageBuilder(app, excludeCopyDirs, customAppImageItemGroups); - } - - AppImageBuilder create(Package pkg) { - return new AppImageBuilder(pkg, excludeCopyDirs, customAppImageItemGroups); - } - - private Builder addItem(AppImageItem v, Set scope) { - Optional.ofNullable(customAppImageItemGroups.get(curGroup)).orElseGet(() -> { - List items = new ArrayList<>(); - customAppImageItemGroups.put(curGroup, items); - return items; - }).add(new ScopedAppImageItem(v, scope)); - return this; - } - - private List excludeCopyDirs = new ArrayList<>(); - private AppImageItemGroup curGroup = AppImageItemGroup.END; - private Map> customAppImageItemGroups = new HashMap<>(); - } - - static Builder build() { - return new Builder(); - } - - enum AppImageItemGroup { - BEGIN, - RUNTIME, - CONTENT, - LAUNCHERS, - APP_IMAGE_FILE, - END - } - - private enum Scope { - APPLICATION, - PACKAGE; - - final static Set APPLICATION_ONLY = Set.of(APPLICATION); - final static Set PACKAGE_ONLY = Set.of(PACKAGE); - final static Set ALL = EnumSet.allOf(Scope.class); - } - - private record ScopedAppImageItem(AppImageItem item, Set scope) { - ScopedAppImageItem { - Objects.requireNonNull(item); - Objects.requireNonNull(scope); - } - - boolean isInScope(Scope v) { - return scope.contains(v); - } - } - - @FunctionalInterface - interface AppImageItem { - void write(BuildEnv env, Application app, ApplicationLayout appLayout) throws IOException, PackagerException; - } - - private AppImageBuilder(Scope scope, Application app, ApplicationLayout appLayout, - List excludeCopyDirs, Map> customAppImageItemGroups) { - - this.app = Objects.requireNonNull(app); - this.appLayout = Objects.requireNonNull(appLayout); - - Objects.requireNonNull(scope); - Objects.requireNonNull(excludeCopyDirs); - Objects.requireNonNull(customAppImageItemGroups); - - appImageItemGroups = new HashMap<>(); - - appImageItemGroups.put(AppImageItemGroup.RUNTIME, List.of( - createRuntimeAppImageItem())); - appImageItemGroups.put(AppImageItemGroup.CONTENT, List.of( - createContentAppImageItem(excludeCopyDirs))); - appImageItemGroups.put(AppImageItemGroup.LAUNCHERS, List.of( - createLaunchersAppImageItem())); - - switch (scope) { - case APPLICATION -> { - appImageItemGroups.put(AppImageItemGroup.APP_IMAGE_FILE, List.of( - createAppImageFileAppImageItem())); - } - - default -> { - // NOP - } - } - - for (var e : customAppImageItemGroups.entrySet()) { - final var group = e.getKey(); - final var mutableItems = Optional.ofNullable(appImageItemGroups.get(group)).map(items -> { - return new ArrayList<>(items); - }).orElseGet(() -> { - return new ArrayList<>(); - }); - mutableItems.addAll(e.getValue().stream().filter(item -> { - return item.isInScope(scope); - }).map(ScopedAppImageItem::item).toList()); - if (!mutableItems.isEmpty()) { - appImageItemGroups.put(group, mutableItems); - } - } - } - - private AppImageBuilder(Application app, List excludeCopyDirs, - Map> customAppImageItemGroups) { - this(Scope.APPLICATION, app, app.asApplicationLayout().orElseThrow(), excludeCopyDirs, customAppImageItemGroups); - } - - private AppImageBuilder(Package pkg, List excludeCopyDirs, - Map> customAppImageItemGroups) { - this(Scope.PACKAGE, pkg.app(), pkg.asPackageApplicationLayout().orElseThrow(), excludeCopyDirs, customAppImageItemGroups); - } - - private static void copyRecursive(Path srcDir, Path dstDir, List excludeDirs) throws IOException { - srcDir = srcDir.toAbsolutePath(); - - List excludes = new ArrayList<>(); - - for (var path : excludeDirs) { - if (Files.isDirectory(path)) { - if (path.startsWith(srcDir) && !Files.isSameFile(path, srcDir)) { - excludes.add(path); - } - } - } - - FileUtils.copyRecursive(srcDir, dstDir.toAbsolutePath(), excludes); - } - - void execute(BuildEnv env) throws IOException, PackagerException { - var resolvedAppLayout = appLayout.resolveAt(env.appImageDir()); - try { - Stream.of(AppImageItemGroup.values()) - .map(appImageItemGroups::get) - .filter(Objects::nonNull) - .flatMap(List::stream) - .forEachOrdered(toConsumer(appImageItem -> { - appImageItem.write(env, app, resolvedAppLayout); - })); - } catch (ExceptionBox ex) { - throw ExceptionBox.rethrowUnchecked(ex); - } - } - - static Optional createLauncherIconResource(Application app, - Launcher launcher, - Function resourceSupplier) { - final String defaultIconName = launcher.defaultIconResourceName(); - final String resourcePublicName = launcher.executableName() + PathUtils.getSuffix(Path.of(defaultIconName)); - - if (!launcher.hasIcon()) { - return Optional.empty(); - } - - OverridableResource resource = resourceSupplier.apply(defaultIconName) - .setCategory("icon") - .setPublicName(resourcePublicName); - - launcher.icon().flatMap(CustomLauncherIcon::fromLauncherIcon).map(CustomLauncherIcon::path).ifPresent(resource::setExternal); - - if (launcher.hasDefaultIcon() && app.mainLauncher().orElseThrow() != launcher) { - // No icon explicitly configured for this launcher. - // Dry-run resource creation to figure out its source. - final Path nullPath = null; - if (toSupplier(() -> resource.saveToFile(nullPath)).get() != OverridableResource.Source.ResourceDir) { - // No icon in resource dir for this launcher, inherit icon - // configured for the main launcher. - return createLauncherIconResource( - app, app.mainLauncher().orElseThrow(), - resourceSupplier - ).map(r -> r.setLogPublicName(resourcePublicName)); - } - } - - return Optional.of(resource); - } - - private static AppImageItem createRuntimeAppImageItem() { - return (env, app, appLayout) -> { - app.runtimeBuilder().ifPresent(toConsumer(runtimeBuilder -> runtimeBuilder.createRuntime(appLayout))); - }; - } - - private static AppImageItem createAppImageFileAppImageItem() { - return (env, app, appLayout) -> { - new AppImageFile(app).save(appLayout); - }; - } - - private static AppImageItem createContentAppImageItem(List excludeCopyDirs) { - return (env, app, appLayout) -> { - var excludeCandidates = Stream.concat( - excludeCopyDirs.stream(), - Stream.of(env.buildRoot(), env.appImageDir()) - ).map(Path::toAbsolutePath).toList(); - - app.srcDir().ifPresent(toConsumer(srcDir -> { - copyRecursive(srcDir, appLayout.appDirectory(), excludeCandidates); - })); - - for (var srcDir : app.contentDirs()) { - copyRecursive(srcDir, - appLayout.contentDirectory().resolve(srcDir.getFileName()), - excludeCandidates); - } - }; - } - - private static AppImageItem createLaunchersAppImageItem() { - return (env, app, appLayout) -> { - for (var launcher : app.launchers()) { - // Create corresponding .cfg file - new CfgFile(app, launcher).create(appLayout, appLayout); - - // Copy executable to launchers folder - Path executableFile = appLayout.launchersDirectory().resolve( - launcher.executableNameWithSuffix()); - try (var in = launcher.executableResource()) { - Files.createDirectories(executableFile.getParent()); - Files.copy(in, executableFile); - } - - executableFile.toFile().setExecutable(true); - } - }; - } - - private final Application app; - private final ApplicationLayout appLayout; - private final Map> appImageItemGroups; -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java index e313b102abbae..bc41e985142bf 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java @@ -81,7 +81,7 @@ static Optional createLauncherIconResource(Application app, static PackagingPipeline.ApplicationImageTaskAction createWriteRuntimeAction() { return (env, app, appLayout) -> { - app.runtimeBuilder().ifPresent(toConsumer(runtimeBuilder -> runtimeBuilder.createRuntime(appLayout))); + app.runtimeBuilder().orElseThrow().createRuntime(appLayout); }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java index 9d78d8e7f7d6f..6280e1ffb2b28 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java @@ -30,6 +30,7 @@ import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -38,24 +39,27 @@ import java.util.concurrent.Callable; import java.util.function.Function; import java.util.function.UnaryOperator; +import java.util.stream.Stream; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.pipeline.ImmutableDAG; import jdk.jpackage.internal.pipeline.DirectedEdge; import jdk.jpackage.internal.pipeline.TaskPipelineBuilder; +import jdk.jpackage.internal.pipeline.TaskSpecBuilder; import jdk.jpackage.internal.util.function.ExceptionBox; final class PackagingPipeline { void execute(BuildEnv env, Application app) throws PackagerException { - execute(contextMapper.apply(createTaskContext(env, app))); + execute(appContextMapper.apply(createTaskContext(env, app))); } void execute(BuildEnv env, Package pkg, Path outputDir) throws PackagerException { - execute(contextMapper.apply(createTaskContext(env, pkg, outputDir))); + execute(pkgContextMapper.apply(createTaskContext(env, pkg, outputDir))); } AppImageInfo analyzeAppImageDir(BuildEnv env, Package pkg) { @@ -82,34 +86,14 @@ interface TaskAction { interface TaskID { } - interface AppImageTaskID extends TaskID { - static AppImageTaskID create(String label) { - record Impl(String label) implements AppImageTaskID { - Impl { - Objects.requireNonNull(label); - } - } - return new Impl(label); - } - - static final AppImageTaskID RUNTIME = create("RUNTIME"); - static final AppImageTaskID CONTENT = create("CONTENT"); - static final AppImageTaskID LAUNCHERS = create("LAUNCHERS"); - static final AppImageTaskID APP_IMAGE_FILE = create("APP_IMAGE_FILE"); - } - - interface PackageTaskID extends TaskID { - static PackageTaskID create(String label) { - record Impl(String label) implements PackageTaskID { - Impl { - Objects.requireNonNull(label); - } - } - return new Impl(label); - } + enum AppImageTaskID implements TaskID { + RUNTIME, + CONTENT, + LAUNCHERS, + APP_IMAGE_FILE } - enum TopLevelTaskID implements TaskID { + enum PrimaryTaskID implements TaskID { BUILD_APPLICATION_IMAGE, COPY_APP_IMAGE, PACKAGE @@ -149,10 +133,10 @@ static final class Builder { private Builder() { } - final class TaskBuilder { + final class TaskBuilder extends TaskSpecBuilder { private TaskBuilder(TaskID id) { - this.id = Objects.requireNonNull(id); + super(id); } private TaskBuilder setAction(TaskAction v) { @@ -181,18 +165,45 @@ TaskBuilder action(NoArgTaskAction action) { return setAction(action); } + @Override + public TaskBuilder addDependent(TaskID v) { + super.addDependent(v); + return this; + } + + @Override + public TaskBuilder addDependency(TaskID v) { + super.addDependency(v); + return this; + } + + @Override + public TaskBuilder addDependencies(Collection tasks) { + super.addDependencies(tasks); + return this; + } + + @Override + public TaskBuilder addDependents(Collection tasks) { + super.addDependents(tasks); + return this; + } + Builder add() { final var config = new TaskConfig(action); - taskConfig.put(id, config); + taskConfig.put(task(), config); + createLinks().forEach(Builder.this::linkTasks); return Builder.this; } - private final TaskID id; private TaskAction action; } Builder linkTasks(DirectedEdge edge) { taskGraph.add(edge); + if (taskGraphSnapshot != null) { + taskGraphSnapshot = null; + } return this; } @@ -211,7 +222,18 @@ Builder excludeDirFromCopying(Path path) { } Builder contextMapper(UnaryOperator v) { - contextMapper = v; + appContextMapper(v); + pkgContextMapper(v); + return this; + } + + Builder appContextMapper(UnaryOperator v) { + appContextMapper = v; + return this; + } + + Builder pkgContextMapper(UnaryOperator v) { + pkgContextMapper = v; return this; } @@ -220,17 +242,27 @@ Builder inputApplicationLayoutForPackaging(Function taskGraphSnapshot() { + if (taskGraphSnapshot == null) { + taskGraphSnapshot = createTaskGraph(taskGraph); + } + return taskGraphSnapshot; + } + PackagingPipeline create() { return new PackagingPipeline(taskGraph, taskConfig, - Optional.ofNullable(contextMapper).orElse(UnaryOperator.identity()), + Optional.ofNullable(appContextMapper).orElse(UnaryOperator.identity()), + Optional.ofNullable(pkgContextMapper).orElse(UnaryOperator.identity()), Optional.ofNullable(inputApplicationLayoutForPackaging).orElse(Package::asPackageApplicationLayout)); } private final List> taskGraph = new ArrayList<>(); private final List excludeCopyDirs = new ArrayList<>(); private final Map taskConfig = new HashMap<>(); - private UnaryOperator contextMapper; + private UnaryOperator appContextMapper; + private UnaryOperator pkgContextMapper; private Function> inputApplicationLayoutForPackaging; + private ImmutableDAG taskGraphSnapshot; } static Builder build() { @@ -247,26 +279,33 @@ static Builder buildStandard() { } static Builder configureApplicationTasks(Builder builder) { - builder.linkTasks(AppImageTaskID.RUNTIME, AppImageTaskID.CONTENT); - builder.linkTasks(AppImageTaskID.LAUNCHERS, AppImageTaskID.CONTENT); - builder.linkTasks(AppImageTaskID.CONTENT, AppImageTaskID.APP_IMAGE_FILE); - builder.linkTasks(AppImageTaskID.APP_IMAGE_FILE, TopLevelTaskID.BUILD_APPLICATION_IMAGE); + builder.task(AppImageTaskID.RUNTIME) + .addDependent(AppImageTaskID.CONTENT) + .action(ApplicationImageUtils.createWriteRuntimeAction()).add(); - builder.task(AppImageTaskID.RUNTIME).action(ApplicationImageUtils.createWriteRuntimeAction()).add(); - builder.task(AppImageTaskID.LAUNCHERS).action(ApplicationImageUtils.createWriteLaunchersAction()).add(); - builder.task(AppImageTaskID.APP_IMAGE_FILE).action(ApplicationImageUtils.createWriteAppImageFileAction()).add(); - builder.task(AppImageTaskID.CONTENT).action(ApplicationImageUtils.createCopyContentAction(() -> builder.excludeCopyDirs)).add(); + builder.task(AppImageTaskID.LAUNCHERS) + .addDependent(AppImageTaskID.CONTENT) + .action(ApplicationImageUtils.createWriteLaunchersAction()).add(); + + builder.task(AppImageTaskID.APP_IMAGE_FILE) + .addDependent(PrimaryTaskID.BUILD_APPLICATION_IMAGE) + .action(ApplicationImageUtils.createWriteAppImageFileAction()).add(); + + builder.task(AppImageTaskID.CONTENT) + .addDependent(AppImageTaskID.APP_IMAGE_FILE) + .action(ApplicationImageUtils.createCopyContentAction(() -> builder.excludeCopyDirs)).add(); return builder; } static Builder configurePackageTasks(Builder builder) { - builder.linkTasks(TopLevelTaskID.BUILD_APPLICATION_IMAGE, TopLevelTaskID.PACKAGE); - builder.linkTasks(TopLevelTaskID.COPY_APP_IMAGE, TopLevelTaskID.PACKAGE); + builder.task(PrimaryTaskID.COPY_APP_IMAGE).copyAction(createCopyAppImageAction()).add(); + + builder.task(PrimaryTaskID.BUILD_APPLICATION_IMAGE).noaction().add(); - builder.task(TopLevelTaskID.COPY_APP_IMAGE).copyAction(createCopyAppImageAction()).add(); - builder.task(TopLevelTaskID.BUILD_APPLICATION_IMAGE).noaction().add(); - builder.task(TopLevelTaskID.PACKAGE).noaction().add(); + builder.task(PrimaryTaskID.PACKAGE) + .addDependencies(List.of(PrimaryTaskID.BUILD_APPLICATION_IMAGE, PrimaryTaskID.COPY_APP_IMAGE)) + .noaction().add(); return builder; } @@ -286,23 +325,33 @@ static CopyAppImageTaskAction createCopyAppImageAction() { } private PackagingPipeline(List> taskGraph, Map taskConfig, - UnaryOperator contextMapper, Function> inputApplicationLayoutForPackaging) { + UnaryOperator appContextMapper, UnaryOperator pkgContextMapper, + Function> inputApplicationLayoutForPackaging) { this.taskGraph = Objects.requireNonNull(taskGraph); this.taskConfig = Objects.requireNonNull(taskConfig); - this.contextMapper = Objects.requireNonNull(contextMapper); + this.appContextMapper = Objects.requireNonNull(appContextMapper); + this.pkgContextMapper = Objects.requireNonNull(pkgContextMapper); this.inputApplicationLayoutForPackaging = Objects.requireNonNull(inputApplicationLayoutForPackaging); } private TaskContext createTaskContext(BuildEnv env, Application app) { final var appImageLayout = app.asApplicationLayout().map(layout -> layout.resolveAt(env.appImageDir())); - return new DefaultTaskContext(env, app, appImageLayout, Optional.empty()); + return new DefaultTaskContext(createTaskGraph(taskGraph), env, app, appImageLayout, Optional.empty()); } private TaskContext createTaskContext(BuildEnv env, Package pkg, Path outputDir) { - final var pkgEnv = BuildEnv.withAppImageDir(env, env.buildRoot().resolve("image")); + final BuildEnv pkgEnv; + if (pkg.app().runtimeBuilder().isPresent()) { + // Will build application image. Use the same build environment to package it. + pkgEnv = env; + } else { + // Use existing app image. Set up a new directory to copy the existing app image for packaging. + pkgEnv = BuildEnv.withAppImageDir(env, env.buildRoot().resolve("image")); + } + final var appImageInfo = analyzeAppImageDir(env, pkg); - return new DefaultTaskContext(env, pkg.app(), appImageInfo.asResolvedApplicationLayout(), + return new DefaultTaskContext(createTaskGraph(taskGraph), env, pkg.app(), + appImageInfo.asResolvedApplicationLayout(), Optional.of(new PackagingTaskContext(pkg, pkgEnv, appImageInfo.path(), outputDir))); } @@ -314,7 +363,6 @@ private void execute(TaskContext context) throws PackagerException { final var builder = new TaskPipelineBuilder(); taskGraph.forEach(edge -> { - System.out.println(String.format("edge: %s", edge)); builder.linkTasks(tasks.get(edge.tail()), tasks.get(edge.head())); }); @@ -361,10 +409,11 @@ public void execute(TaskAction taskAction) throws IOException, PackagerException } } - private static record DefaultTaskContext(BuildEnv env, Application app, + private static record DefaultTaskContext(ImmutableDAG taskGraph, BuildEnv env, Application app, Optional appLayout, Optional pkg) implements TaskContext { DefaultTaskContext { + Objects.requireNonNull(taskGraph); Objects.requireNonNull(env); Objects.requireNonNull(app); Objects.requireNonNull(appLayout); @@ -375,21 +424,18 @@ private static record DefaultTaskContext(BuildEnv env, Application app, public boolean test(TaskID taskID) { if (pkg.isPresent() && !pkg.orElseThrow().test(taskID)) { return false; - } else if (pkg.isEmpty() && taskID instanceof PackageTaskID) { + } else if (pkg.isEmpty() && isPackageTask(taskID)) { // Building application image, skip packaging tasks. return false; - } else if (taskID instanceof AppImageTaskID) { - // Application image task. - if (app.isRuntime()) { - // Skip it as this is runtime app image. - return false; - } else { - // Accept the task only if configuration allows to build application image. - return canBuildAppImage(); - } + } else if (app.runtimeBuilder().isEmpty() && isBuildApplicationImageTask(taskID)) { + // Runtime builder is not present, skip building application image tasks. + return false; + } else if (app.runtimeBuilder().isPresent() && isCopyAppImageTask(taskID)) { + // Runtime builder is present, skip copying app image tasks. + return false; + } else { + return true; } - - return true; } @Override @@ -403,11 +449,31 @@ public void execute(TaskAction taskAction) throws IOException, PackagerException } } - private boolean canBuildAppImage() { - // Build application image only when runtime builder is available. - return pkg.map(PackagingTaskContext::pkg).map(Package::app).orElse(app).runtimeBuilder().isPresent(); + private boolean isPackageTask(TaskID taskID) { + if (taskID == PrimaryTaskID.PACKAGE) { + return true; + } else { + return Stream.of(PrimaryTaskID.BUILD_APPLICATION_IMAGE, + PrimaryTaskID.COPY_APP_IMAGE).noneMatch(taskGraph.getAllHeadsOf(taskID)::contains); + } } + private boolean isBuildApplicationImageTask(TaskID taskID) { + return (taskID == PrimaryTaskID.BUILD_APPLICATION_IMAGE + || taskGraph.getAllHeadsOf(taskID).contains(PrimaryTaskID.BUILD_APPLICATION_IMAGE)); + } + + private boolean isCopyAppImageTask(TaskID taskID) { + return (taskID == PrimaryTaskID.COPY_APP_IMAGE + || taskGraph.getAllHeadsOf(taskID).contains(PrimaryTaskID.COPY_APP_IMAGE)); + } + + } + + private static ImmutableDAG createTaskGraph(List> taskGraph) { + final var builder = ImmutableDAG.build(); + taskGraph.forEach(builder::addEdge); + return builder.create(); } private static Callable createTask(TaskContext context, TaskID id, TaskConfig config) { @@ -416,6 +482,7 @@ private static Callable createTask(TaskContext context, TaskID id, TaskCon return () -> { if (config.action != null && context.test(id)) { try { + System.out.println("execute: " + id); context.execute(config.action); } catch (ExceptionBox ex) { throw ExceptionBox.rethrowUnchecked(ex); @@ -428,5 +495,6 @@ private static Callable createTask(TaskContext context, TaskID id, TaskCon private final List> taskGraph; private final Map taskConfig; private final Function> inputApplicationLayoutForPackaging; - private final UnaryOperator contextMapper; + private final UnaryOperator appContextMapper; + private final UnaryOperator pkgContextMapper; } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java index 2bca4f7ea50ad..114dd36278fcb 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java @@ -24,12 +24,13 @@ */ package jdk.jpackage.internal; -import static jdk.jpackage.internal.AppImageBuilder.createLauncherIconResource; +import static jdk.jpackage.internal.ApplicationImageUtils.createLauncherIconResource; import java.io.IOException; import java.io.UncheckedIOException; import jdk.jpackage.internal.PackagingPipeline.AppImageTaskID; -import jdk.jpackage.internal.PackagingPipeline.TopLevelTaskID; +import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; +import jdk.jpackage.internal.PackagingPipeline.TaskID; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.PackagerException; @@ -38,17 +39,18 @@ final class WinPackagingPipeline { - enum WinAppImageTaskID implements AppImageTaskID { + enum WinAppImageTaskID implements TaskID { REBRAND_LAUNCHERS } static PackagingPipeline.Builder build() { return PackagingPipeline.buildStandard() .inputApplicationLayoutForPackaging(pkg -> pkg.app().asApplicationLayout()) - .linkTasks(WinAppImageTaskID.REBRAND_LAUNCHERS, TopLevelTaskID.BUILD_APPLICATION_IMAGE) - .linkTasks(AppImageTaskID.LAUNCHERS, WinAppImageTaskID.REBRAND_LAUNCHERS) - .task(TopLevelTaskID.COPY_APP_IMAGE).noaction().add() - .task(WinAppImageTaskID.REBRAND_LAUNCHERS).action(WinPackagingPipeline::rebrandLaunchers).add(); + .task(PrimaryTaskID.COPY_APP_IMAGE).noaction().add() + .task(WinAppImageTaskID.REBRAND_LAUNCHERS) + .addDependency(AppImageTaskID.LAUNCHERS) + .addDependent(PrimaryTaskID.BUILD_APPLICATION_IMAGE) + .action(WinPackagingPipeline::rebrandLaunchers).add(); } private static void rebrandLaunchers(BuildEnv env, Application app, From 3d096acbfaad26f817af82600afb72cf91145a4d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 1 Feb 2025 06:52:17 -0500 Subject: [PATCH 0265/1101] Bugfix --- .../pipeline/TaskPipelineBuilder.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java index 9f43ff2257873..9c84815a8b26c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java @@ -143,8 +143,6 @@ public Void call() throws Exception { final var taskFutures = new CompletableFuture[taskGraph.nodes().size()]; - CompletableFuture lastFuture = null; - // Schedule tasks in the order they should be executed: dependencies before dependents. for (final var task : taskGraph.topologicalSort()) { final var taskIndex = taskGraph.nodes().indexOf(task); @@ -155,18 +153,29 @@ public Void call() throws Exception { return taskFutures[dependencyTaskIndex]; }).toArray(CompletableFuture[]::new); + final CompletableFuture f; if (dependencyTaskFutures.length == 0) { - lastFuture = CompletableFuture.runAsync(toRunnable(task), executor); + f = CompletableFuture.runAsync(toRunnable(task), executor); } else { - lastFuture = CompletableFuture.allOf(dependencyTaskFutures); - lastFuture = lastFuture.thenRun(toRunnable(task)); + f = CompletableFuture.allOf(dependencyTaskFutures).thenRun(toRunnable(task)); } - taskFutures[taskIndex] = lastFuture; + taskFutures[taskIndex] = f; + } + + final CompletableFuture [] rootFutures = taskGraph.getNoOutgoingEdges().stream().map(task -> { + return taskFutures[taskGraph.nodes().indexOf(task)]; + }).toArray(CompletableFuture []::new); + + final CompletableFuture rootFuture; + if (rootFutures.length == 1) { + rootFuture = rootFutures[0]; + } else { + rootFuture = CompletableFuture.allOf(rootFutures); } try { - lastFuture.get(); + rootFuture.get(); } catch (ExecutionException ee) { if (ee.getCause() instanceof Exception ex) { throw ex; From 145d922b618dc14f125af062af2e898b86f00225 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 1 Feb 2025 17:10:55 -0500 Subject: [PATCH 0266/1101] Better test code coverage --- .../jdk/jpackage/internal/pipeline/DirectedEdgeTest.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java index 503a023e99cf4..c7dedd4ae461e 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java @@ -23,8 +23,8 @@ package jdk.jpackage.internal.pipeline; +import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.List; import org.junit.jupiter.params.ParameterizedTest; @@ -39,10 +39,9 @@ public void testCtor(String tail, String head, Class expect assertThrows(expectedExceptionType, () -> DirectedEdge.create(tail, head)); } else { final var edge = DirectedEdge.create(tail, head); - assertTrue(tail == edge.tail()); - assertTrue(tail == edge.from()); - assertTrue(head == edge.head()); - assertTrue(head == edge.to()); + assertSame(tail, edge.from()); + assertSame(head, edge.head()); + assertSame(head, edge.to()); } } From 5fe9691159b46161e26521d99a18688f4c4e87d2 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 1 Feb 2025 17:15:42 -0500 Subject: [PATCH 0267/1101] Use static ImmutableDAG.getNoOutgoingEdges() to get the array of future indexes for joining --- .../internal/pipeline/TaskPipelineBuilder.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java index 9c84815a8b26c..b23dd107a75a7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java @@ -25,6 +25,9 @@ package jdk.jpackage.internal.pipeline; +import static jdk.jpackage.internal.pipeline.ImmutableDAG.getIncomingEdges; +import static jdk.jpackage.internal.pipeline.ImmutableDAG.getNoOutgoingEdges; + import java.util.Collection; import java.util.List; import java.util.Objects; @@ -147,7 +150,7 @@ public Void call() throws Exception { for (final var task : taskGraph.topologicalSort()) { final var taskIndex = taskGraph.nodes().indexOf(task); - final var dependencyTaskFutures = ImmutableDAG.getIncomingEdges(taskIndex, taskGraph.edgeMatrix()) + final var dependencyTaskFutures = getIncomingEdges(taskIndex, taskGraph.edgeMatrix()) .map(BinaryMatrix.Cursor::row) .map(dependencyTaskIndex -> { return taskFutures[dependencyTaskIndex]; @@ -163,9 +166,9 @@ public Void call() throws Exception { taskFutures[taskIndex] = f; } - final CompletableFuture [] rootFutures = taskGraph.getNoOutgoingEdges().stream().map(task -> { - return taskFutures[taskGraph.nodes().indexOf(task)]; - }).toArray(CompletableFuture []::new); + final var rootFutures = getNoOutgoingEdges(taskGraph.edgeMatrix()).mapToObj(taskIndex -> { + return taskFutures[taskIndex]; + }).toArray(CompletableFuture[]::new); final CompletableFuture rootFuture; if (rootFutures.length == 1) { From a30d6420780cd662faaf6e371b12d6bf9f76b330 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 2 Feb 2025 21:58:34 -0500 Subject: [PATCH 0268/1101] Remove redundant imports --- .../classes/jdk/jpackage/internal/MacAppImageBuilder.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java index 66a42d1fc6ab1..79458a014cf90 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -31,9 +31,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT; import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; import static jdk.jpackage.internal.StandardBundlerParam.createResource; -import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage; import java.io.ByteArrayOutputStream; import java.io.IOException; From 6159e1c6e5fc9ae91d3bbddbb513ee3086108992 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 2 Feb 2025 22:00:10 -0500 Subject: [PATCH 0269/1101] Remove confusing empty "if" branch --- .../jdk/jpackage/internal/FromParams.java | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java index e66e6da114769..379a6a744418a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -29,7 +29,6 @@ import static jdk.jpackage.internal.StandardBundlerParam.ADD_MODULES; import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.NAME; import static jdk.jpackage.internal.StandardBundlerParam.COPYRIGHT; import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; @@ -41,6 +40,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; import static jdk.jpackage.internal.StandardBundlerParam.LIMIT_MODULES; import static jdk.jpackage.internal.StandardBundlerParam.MODULE_PATH; +import static jdk.jpackage.internal.StandardBundlerParam.NAME; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.SOURCE_DIR; @@ -89,36 +89,34 @@ static ApplicationBuilder createApplicationBuilder(Map p appBuilder.appImageLayout(RuntimeLayout.DEFAULT); } else { appBuilder.appImageLayout(appLayout); - } - - if (isRuntimeInstaller) { - // NOP if building Java runtime installer - } else if (hasPredefinedAppImage(params)) { - final var appImageFile = PREDEFINED_APP_IMAGE_FILE.fetchFrom(params); - appBuilder.initFromAppImage(appImageFile, launcherInfo -> { - var launcherParams = mapLauncherInfo(launcherInfo); - return launcherMapper.apply(mergeParams(params, launcherParams)); - }); - } else { - final var launchers = createLaunchers(params, launcherMapper); - - final var runtimeBuilderBuilder = new RuntimeBuilderBuilder(); - - MODULE_PATH.copyInto(params, runtimeBuilderBuilder::modulePath); - - final var predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.findIn(params); - predefinedRuntimeImage.ifPresentOrElse(runtimeBuilderBuilder::forRuntime, () -> { - final var startupInfos = launchers.asList().stream() - .map(Launcher::startupInfo) - .map(Optional::orElseThrow).toList(); - final var jlinkOptionsBuilder = runtimeBuilderBuilder.forNewRuntime(startupInfos); - ADD_MODULES.copyInto(params, jlinkOptionsBuilder::addModules); - LIMIT_MODULES.copyInto(params, jlinkOptionsBuilder::limitModules); - JLINK_OPTIONS.copyInto(params, jlinkOptionsBuilder::options); - jlinkOptionsBuilder.appy(); - }); - appBuilder.launchers(launchers).runtimeBuilder(runtimeBuilderBuilder.create()); + if (hasPredefinedAppImage(params)) { + final var appImageFile = PREDEFINED_APP_IMAGE_FILE.fetchFrom(params); + appBuilder.initFromAppImage(appImageFile, launcherInfo -> { + var launcherParams = mapLauncherInfo(launcherInfo); + return launcherMapper.apply(mergeParams(params, launcherParams)); + }); + } else { + final var launchers = createLaunchers(params, launcherMapper); + + final var runtimeBuilderBuilder = new RuntimeBuilderBuilder(); + + MODULE_PATH.copyInto(params, runtimeBuilderBuilder::modulePath); + + final var predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.findIn(params); + predefinedRuntimeImage.ifPresentOrElse(runtimeBuilderBuilder::forRuntime, () -> { + final var startupInfos = launchers.asList().stream() + .map(Launcher::startupInfo) + .map(Optional::orElseThrow).toList(); + final var jlinkOptionsBuilder = runtimeBuilderBuilder.forNewRuntime(startupInfos); + ADD_MODULES.copyInto(params, jlinkOptionsBuilder::addModules); + LIMIT_MODULES.copyInto(params, jlinkOptionsBuilder::limitModules); + JLINK_OPTIONS.copyInto(params, jlinkOptionsBuilder::options); + jlinkOptionsBuilder.appy(); + }); + + appBuilder.launchers(launchers).runtimeBuilder(runtimeBuilderBuilder.create()); + } } return appBuilder; From 0f00847d7b730bdf573403fc061283c708a4b7d0 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 2 Feb 2025 22:00:48 -0500 Subject: [PATCH 0270/1101] More tests pass on osx --- .../internal/LinuxPackageBundler.java | 5 +- .../jdk/jpackage/internal/MacAppBundler.java | 12 +-- .../internal/MacApplicationBuilder.java | 16 +--- .../jdk/jpackage/internal/MacFromParams.java | 20 ++++- .../internal/MacPackagingPipeline.java | 85 ++++++++++--------- .../jdk/jpackage/internal/MacPkgBundler.java | 15 +--- .../jpackage/internal/PackagingPipeline.java | 52 +++++++----- 7 files changed, 112 insertions(+), 93 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 031da0a136e2c..fb45c2cb97c3b 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -103,11 +103,14 @@ public final Path execute(Map params, final LinuxPackage pkg = pkgParam.fetchFrom(params); final var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - BuildEnv pkgEnv = BuildEnv.withAppImageDir(env, + final BuildEnv pkgEnv = BuildEnv.withAppImageDir(env, env.buildRoot().resolve("image")); LinuxPackagingPipeline.build() .excludeDirFromCopying(outputParentDir) + .pkgBuildEnvFactory((e, p) -> { + return pkgEnv; + }) .create().execute(env, pkg, outputParentDir); try { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index 7a12b3de69b66..c52f0447f811f 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -45,16 +45,18 @@ public MacAppBundler() { final var app = MacFromParams.APPLICATION.fetchFrom(params); final var env = BuildEnv.withAppImageDir(BuildEnvFromParams.BUILD_ENV.fetchFrom(params), output); - final var taskPipeline = MacPackagingPipeline.build() + final var taskPipelineBuilder = MacPackagingPipeline.build() .excludeDirFromCopying(output.getParent()) - .inputApplicationLayoutForPackaging(pkg -> pkg.app().asApplicationLayout()) - .create(); + .inputApplicationLayoutForPackaging(pkg -> pkg.app().asApplicationLayout()); if (isDependentTask()) { final var pkg = MacFromParams.PACKAGE.fetchFrom(params); - taskPipeline.execute(env, pkg, output); + taskPipelineBuilder.pkgBuildEnvFactory((e, p) -> { + return BuildEnv.withAppImageDir(e, output); + }); + taskPipelineBuilder.create().execute(env, pkg, output); } else { - taskPipeline.execute(env, app); + taskPipelineBuilder.create().execute(env, app); } }); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java index 192ba494d48cd..9e65c7ab67712 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java @@ -24,8 +24,6 @@ */ package jdk.jpackage.internal; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; - import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Path; @@ -167,16 +165,10 @@ private String validatedBundleName() throws ConfigException { private String validatedBundleIdentifier() throws ConfigException { final var value = Optional.ofNullable(bundleIdentifier).orElseGet(() -> { - return toSupplier(() -> { - return app.mainLauncher() - .flatMap(Launcher::startupInfo) - .map(LauncherStartupInfo::simpleClassName) - .orElseThrow(() -> { - return I18N.buildConfigException("message.app-image-requires-identifier") - .advice("message.app-image-requires-identifier.advice") - .create(); - }); - }).get(); + return app.mainLauncher() + .flatMap(Launcher::startupInfo) + .map(LauncherStartupInfo::simpleClassName) + .orElseGet(app::name); }); if (!isValidBundleIdentifier(value)) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java index cb21cfd04c567..a6c22d3eb7768 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java @@ -31,15 +31,18 @@ import static jdk.jpackage.internal.FromParams.createApplicationBundlerParam; import static jdk.jpackage.internal.FromParams.createPackageBundlerParam; import static jdk.jpackage.internal.MacAppImageBuilder.APP_STORE; -import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; +import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import java.util.List; @@ -60,6 +63,8 @@ final class MacFromParams { private static MacApplication createMacApplication( Map params) throws ConfigException, IOException { + adjustRuntimeDir(params); + final var launcherFromParams = new LauncherFromParams(Optional.of(MacFromParams::createMacFa)); final var app = createApplicationBuilder(params, toFunction(launcherParams -> { @@ -69,6 +74,10 @@ private static MacApplication createMacApplication( final var appBuilder = new MacApplicationBuilder(app); + if (hasPredefinedAppImage(params)) { + appBuilder.externalInfoPlistFile(PREDEFINED_APP_IMAGE.fetchFrom(params).resolve("Contents/Info.plist")); + } + MAC_CF_BUNDLE_NAME.copyInto(params, appBuilder::bundleName); MAC_CF_BUNDLE_IDENTIFIER.copyInto(params, appBuilder::bundleIdentifier); APP_CATEGORY.copyInto(params, appBuilder::category); @@ -119,6 +128,15 @@ private static MacFileAssociation createMacFa(FileAssociation fa, Map params) { + PREDEFINED_RUNTIME_IMAGE.copyInto(params, runtimeRoot -> { + final var runtimeDir = runtimeRoot.resolve("Contents/Home"); + if (Files.isDirectory(runtimeDir)) { + params.put(PREDEFINED_RUNTIME_IMAGE.getID(), runtimeDir); + } + }); + } + static final BundlerParamInfo APPLICATION = createApplicationBundlerParam( MacFromParams::createMacApplication); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index dae2148e0683d..558c29f6feae9 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -43,19 +43,15 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.function.Predicate; -import java.util.stream.Stream; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import jdk.jpackage.internal.PackagingPipeline.AppImageTaskID; import jdk.jpackage.internal.PackagingPipeline.ApplicationImageTaskAction; -import jdk.jpackage.internal.PackagingPipeline.CopyAppImageTaskAction; +import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; import jdk.jpackage.internal.PackagingPipeline.TaskAction; import jdk.jpackage.internal.PackagingPipeline.TaskContext; import jdk.jpackage.internal.PackagingPipeline.TaskID; -import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; -import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.FileAssociation; @@ -82,26 +78,11 @@ enum MacAppImageTaskID implements TaskID { static PackagingPipeline.Builder build() { final var builder = PackagingPipeline.buildStandard() + .appContextMapper(appContext -> { + return new TaskContextProxy(appContext, true); + }) .pkgContextMapper(appContext -> { - return new TaskContext() { - - @Override - public boolean test(TaskID taskID) { - if (taskID == AppImageTaskID.APP_IMAGE_FILE) { - // Always create ".jpackage.xml" for compatibility with tests - // TODO: Don't create ".jpackage.xml" when doing bundling a package like on other platforms - return true; - } else { - return appContext.test(taskID); - } - } - - @Override - public void execute(TaskAction taskAction) throws IOException, PackagerException { - appContext.execute(taskAction); - } - - }; + return new TaskContextProxy(appContext, false); }) .task(PrimaryTaskID.COPY_APP_IMAGE) .copyAction(MacPackagingPipeline::copyAppImage).add() @@ -109,7 +90,8 @@ public void execute(TaskAction taskAction) throws IOException, PackagerException .action(conv(MacPackagingPipeline::writeRuntimeInfoPlist)) .addDependent(AppImageTaskID.CONTENT).add() .task(MacAppImageTaskID.COPY_JLILIB) - .action(MacPackagingPipeline::copyJliLib) + .action(conv(MacPackagingPipeline::copyJliLib)) + .addDependency(AppImageTaskID.RUNTIME) .addDependent(AppImageTaskID.CONTENT).add() .task(MacAppImageTaskID.APP_ICON) .action(conv(new ApplicationIcon())) @@ -137,23 +119,25 @@ public void execute(TaskAction taskAction) throws IOException, PackagerException @FunctionalInterface private interface MacApplicationImageTaskAction extends TaskAction { - void execute(BuildEnv env, MacApplication app, ApplicationLayout appLayout) throws IOException, PackagerException; + void execute(BuildEnv env, MacApplication app, MacApplicationLayout appLayout) + throws IOException, PackagerException; } private static ApplicationImageTaskAction conv(MacApplicationImageTaskAction v) { return (env, app, appLayout) -> { - v.execute(env, (MacApplication)app, appLayout); + v.execute(env, (MacApplication)app, (MacApplicationLayout)appLayout); }; } - private static void copyAppImage(Package pkg, Path srcAppImageRoot, Path dstAppImageRoot) throws IOException { + private static void copyAppImage(Package pkg, Path srcAppImageRoot, + Path dstAppImageRoot) throws IOException { FileUtils.copyRecursive(srcAppImageRoot, dstAppImageRoot); } - private static void copyJliLib(BuildEnv env, Application app, - ApplicationLayout appLayout) throws IOException { + private static void copyJliLib(BuildEnv env, MacApplication app, + MacApplicationLayout appLayout) throws IOException { - final var runtimeMacOSDir = ((MacApplicationLayout)appLayout).runtimeRootDirectory().resolve("Contents/MacOS"); + final var runtimeMacOSDir = appLayout.runtimeRootDirectory().resolve("Contents/MacOS"); final var jliName = Path.of("libjli.dylib"); @@ -171,6 +155,14 @@ private static void writePackageFile(BuildEnv env, Package pkg) throws IOExcepti new PackageFile(pkg.packageName()).save(pkg.asApplicationLayout().orElseThrow().resolveAt(env.appImageDir())); } + private static void writePkgInfoFile(BuildEnv env, Application app, + ApplicationLayout appLayout) throws IOException { + final var dir = appLayout.contentDirectory(); + Files.createDirectories(dir); + Files.write(dir.resolve("PkgInfo"), + "APPL????".getBytes(StandardCharsets.ISO_8859_1)); + } + private static void writeRuntimeInfoPlist(BuildEnv env, MacApplication app, ApplicationLayout appLayout) throws IOException { @@ -188,7 +180,7 @@ private static void writeRuntimeInfoPlist(BuildEnv env, MacApplication app, } private static void writeAppInfoPlist(BuildEnv env, MacApplication app, - ApplicationLayout appLayout) throws IOException { + MacApplicationLayout appLayout) throws IOException { final String faXml = toSupplier(() -> { var buf = new StringWriter(); @@ -218,7 +210,8 @@ private static void writeAppInfoPlist(BuildEnv env, MacApplication app, .saveToFile(appLayout.contentDirectory().resolve("Info.plist")); } - private static void sign(BuildEnv env, MacApplication app, ApplicationLayout appLayout) throws IOException { + private static void sign(BuildEnv env, MacApplication app, + MacApplicationLayout appLayout) throws IOException { final var codesignConfigBuilder = CodesignConfig.build(); app.signingConfig().ifPresent(codesignConfigBuilder::from); @@ -321,7 +314,7 @@ static Path getPath(Application app, ApplicationLayout appLayout) { } @Override - public void execute(BuildEnv env, MacApplication app, ApplicationLayout appLayout) + public void execute(BuildEnv env, MacApplication app, MacApplicationLayout appLayout) throws IOException { final var resource = env.createResource("JavaApp.icns").setCategory("icon"); @@ -341,10 +334,26 @@ private static void writeFileAssociationIcons(BuildEnv env, Application app, } } - private static void writePkgInfoFile(BuildEnv env, Application app, - ApplicationLayout appLayout) throws IOException { - Files.write(appLayout.contentDirectory().resolve("PkgInfo"), - "APPL????".getBytes(StandardCharsets.ISO_8859_1)); + private record TaskContextProxy(TaskContext delegate, boolean forApp) implements TaskContext { + + @Override + public boolean test(TaskID taskID) { + if (forApp && taskID == MacAppImageTaskID.PKG_FILE) { + // Don't create files relevant for package bundling when bundling app image + return false; + } else if (!forApp && taskID == AppImageTaskID.APP_IMAGE_FILE) { + // Always create ".jpackage.xml" for compatibility with tests + // TODO: Don't create ".jpackage.xml" when bundling a package like on other platforms + return true; + } else { + return delegate.test(taskID); + } + } + + @Override + public void execute(TaskAction taskAction) throws IOException, PackagerException { + delegate.execute(taskAction); + } } final static MacApplicationLayout APPLICATION_LAYOUT = MacApplicationLayout.create( diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 6d18d001b509c..76686900979c7 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -61,6 +61,7 @@ import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; import static jdk.jpackage.internal.StandardBundlerParam.createResource; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; +import static jdk.jpackage.internal.MacApplicationBuilder.isValidBundleIdentifier; import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.XmlUtils; @@ -691,20 +692,6 @@ public String getID() { return "pkg"; } - private static boolean isValidBundleIdentifier(String id) { - for (int i = 0; i < id.length(); i++) { - char a = id.charAt(i); - // We check for ASCII codes first which we accept. If check fails, - // check if it is acceptable extended ASCII or unicode character. - if ((a >= 'A' && a <= 'Z') || (a >= 'a' && a <= 'z') - || (a >= '0' && a <= '9') || (a == '-' || a == '.')) { - continue; - } - return false; - } - return true; - } - @Override public boolean validate(Map params) throws ConfigException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java index 6280e1ffb2b28..baf2a8574edba 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java @@ -37,6 +37,7 @@ import java.util.Objects; import java.util.Optional; import java.util.concurrent.Callable; +import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.UnaryOperator; import java.util.stream.Stream; @@ -45,8 +46,8 @@ import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.pipeline.ImmutableDAG; import jdk.jpackage.internal.pipeline.DirectedEdge; +import jdk.jpackage.internal.pipeline.ImmutableDAG; import jdk.jpackage.internal.pipeline.TaskPipelineBuilder; import jdk.jpackage.internal.pipeline.TaskSpecBuilder; import jdk.jpackage.internal.util.function.ExceptionBox; @@ -200,7 +201,7 @@ Builder add() { } Builder linkTasks(DirectedEdge edge) { - taskGraph.add(edge); + taskGraphBuilder.addEdge(edge); if (taskGraphSnapshot != null) { taskGraphSnapshot = null; } @@ -237,6 +238,11 @@ Builder pkgContextMapper(UnaryOperator v) { return this; } + Builder pkgBuildEnvFactory(BiFunction v) { + pkgBuildEnvFactory = v; + return this; + } + Builder inputApplicationLayoutForPackaging(Function> v) { inputApplicationLayoutForPackaging = v; return this; @@ -244,24 +250,28 @@ Builder inputApplicationLayoutForPackaging(Function taskGraphSnapshot() { if (taskGraphSnapshot == null) { - taskGraphSnapshot = createTaskGraph(taskGraph); + taskGraphSnapshot = taskGraphBuilder.create(); } return taskGraphSnapshot; } PackagingPipeline create() { - return new PackagingPipeline(taskGraph, taskConfig, + return new PackagingPipeline(taskGraphSnapshot(), taskConfig, Optional.ofNullable(appContextMapper).orElse(UnaryOperator.identity()), Optional.ofNullable(pkgContextMapper).orElse(UnaryOperator.identity()), - Optional.ofNullable(inputApplicationLayoutForPackaging).orElse(Package::asPackageApplicationLayout)); + Optional.ofNullable(inputApplicationLayoutForPackaging).orElse(Package::asPackageApplicationLayout), + Optional.ofNullable(pkgBuildEnvFactory).orElse((env, pkg) -> { + return BuildEnv.withAppImageDir(env, env.buildRoot().resolve("image")); + })); } - private final List> taskGraph = new ArrayList<>(); + private final ImmutableDAG.Builder taskGraphBuilder = ImmutableDAG.build(); private final List excludeCopyDirs = new ArrayList<>(); private final Map taskConfig = new HashMap<>(); private UnaryOperator appContextMapper; private UnaryOperator pkgContextMapper; private Function> inputApplicationLayoutForPackaging; + private BiFunction pkgBuildEnvFactory; private ImmutableDAG taskGraphSnapshot; } @@ -324,19 +334,21 @@ static CopyAppImageTaskAction createCopyAppImageAction() { }; } - private PackagingPipeline(List> taskGraph, Map taskConfig, + private PackagingPipeline(ImmutableDAG taskGraph, Map taskConfig, UnaryOperator appContextMapper, UnaryOperator pkgContextMapper, - Function> inputApplicationLayoutForPackaging) { + Function> inputApplicationLayoutForPackaging, + BiFunction pkgBuildEnvFactory) { this.taskGraph = Objects.requireNonNull(taskGraph); this.taskConfig = Objects.requireNonNull(taskConfig); this.appContextMapper = Objects.requireNonNull(appContextMapper); this.pkgContextMapper = Objects.requireNonNull(pkgContextMapper); this.inputApplicationLayoutForPackaging = Objects.requireNonNull(inputApplicationLayoutForPackaging); + this.pkgBuildEnvFactory = Objects.requireNonNull(pkgBuildEnvFactory); } private TaskContext createTaskContext(BuildEnv env, Application app) { final var appImageLayout = app.asApplicationLayout().map(layout -> layout.resolveAt(env.appImageDir())); - return new DefaultTaskContext(createTaskGraph(taskGraph), env, app, appImageLayout, Optional.empty()); + return new DefaultTaskContext(taskGraph, env, app, appImageLayout, Optional.empty()); } private TaskContext createTaskContext(BuildEnv env, Package pkg, Path outputDir) { @@ -346,11 +358,11 @@ private TaskContext createTaskContext(BuildEnv env, Package pkg, Path outputDir) pkgEnv = env; } else { // Use existing app image. Set up a new directory to copy the existing app image for packaging. - pkgEnv = BuildEnv.withAppImageDir(env, env.buildRoot().resolve("image")); + pkgEnv = pkgBuildEnvFactory.apply(env, pkg); } final var appImageInfo = analyzeAppImageDir(env, pkg); - return new DefaultTaskContext(createTaskGraph(taskGraph), env, pkg.app(), + return new DefaultTaskContext(taskGraph, env, pkg.app(), appImageInfo.asResolvedApplicationLayout(), Optional.of(new PackagingTaskContext(pkg, pkgEnv, appImageInfo.path(), outputDir))); } @@ -362,9 +374,11 @@ private void execute(TaskContext context) throws PackagerException { final var builder = new TaskPipelineBuilder(); - taskGraph.forEach(edge -> { - builder.linkTasks(tasks.get(edge.tail()), tasks.get(edge.head())); - }); + for (final var tail : taskGraph.nodes()) { + for (final var head : taskGraph.getHeadsOf(tail)) { + builder.linkTasks(tasks.get(tail), tasks.get(head)); + } + } try { builder.create().call(); @@ -470,19 +484,12 @@ private boolean isCopyAppImageTask(TaskID taskID) { } - private static ImmutableDAG createTaskGraph(List> taskGraph) { - final var builder = ImmutableDAG.build(); - taskGraph.forEach(builder::addEdge); - return builder.create(); - } - private static Callable createTask(TaskContext context, TaskID id, TaskConfig config) { Objects.requireNonNull(context); Objects.requireNonNull(id); return () -> { if (config.action != null && context.test(id)) { try { - System.out.println("execute: " + id); context.execute(config.action); } catch (ExceptionBox ex) { throw ExceptionBox.rethrowUnchecked(ex); @@ -492,9 +499,10 @@ private static Callable createTask(TaskContext context, TaskID id, TaskCon }; } - private final List> taskGraph; + private final ImmutableDAG taskGraph; private final Map taskConfig; private final Function> inputApplicationLayoutForPackaging; private final UnaryOperator appContextMapper; private final UnaryOperator pkgContextMapper; + private final BiFunction pkgBuildEnvFactory; } From a3f44370e4cc9ad4a5218fec86f9a01b581fb2d6 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 3 Feb 2025 12:17:16 -0500 Subject: [PATCH 0271/1101] Minor --- .../classes/jdk/jpackage/internal/WinPackagingPipeline.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java index 114dd36278fcb..40ed0c974f061 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java @@ -56,7 +56,7 @@ static PackagingPipeline.Builder build() { private static void rebrandLaunchers(BuildEnv env, Application app, ApplicationLayout appLayout) throws IOException, PackagerException { for (var launcher : app.launchers()) { - final var iconTarget = createLauncherIconResource(app, launcher, name -> env.createResource(name)).map(iconResource -> { + final var iconTarget = createLauncherIconResource(app, launcher, env::createResource).map(iconResource -> { var iconDir = env.buildRoot().resolve("icons"); var theIconTarget = iconDir.resolve(launcher.executableName() + ".ico"); try { @@ -74,7 +74,7 @@ private static void rebrandLaunchers(BuildEnv env, Application app, // Update branding of launcher executable new ExecutableRebrander((WinApplication) app, - (WinLauncher) launcher, name -> env.createResource(name)).execute( + (WinLauncher) launcher, env::createResource).execute( env, launcherExecutable, iconTarget); } } From 14d9fd6d3d80a9fa0e87510aba04e83eb5e2d12e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 3 Feb 2025 17:51:18 -0500 Subject: [PATCH 0272/1101] Bugfix of OSX packaging. All but ServiceTest tests pass --- .../macosx/classes/jdk/jpackage/internal/MacAppBundler.java | 2 ++ .../macosx/classes/jdk/jpackage/internal/MacFromParams.java | 2 ++ .../classes/jdk/jpackage/internal/MacPackagingPipeline.java | 2 +- .../share/classes/jdk/jpackage/internal/LauncherFromParams.java | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index c52f0447f811f..42cc08c3156f5 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -31,6 +31,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.MAIN_CLASS; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; +import static jdk.jpackage.internal.StandardBundlerParam.OUTPUT_DIR; import java.text.MessageFormat; import java.util.Map; @@ -47,6 +48,7 @@ public MacAppBundler() { final var taskPipelineBuilder = MacPackagingPipeline.build() .excludeDirFromCopying(output.getParent()) + .excludeDirFromCopying(OUTPUT_DIR.fetchFrom(params)) .inputApplicationLayoutForPackaging(pkg -> pkg.app().asApplicationLayout()); if (isDependentTask()) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java index a6c22d3eb7768..5b5e6c7c1bbfb 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java @@ -34,6 +34,7 @@ import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT; +import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; @@ -78,6 +79,7 @@ private static MacApplication createMacApplication( appBuilder.externalInfoPlistFile(PREDEFINED_APP_IMAGE.fetchFrom(params).resolve("Contents/Info.plist")); } + ICON.copyInto(params, appBuilder::icon); MAC_CF_BUNDLE_NAME.copyInto(params, appBuilder::bundleName); MAC_CF_BUNDLE_IDENTIFIER.copyInto(params, appBuilder::bundleIdentifier); APP_CATEGORY.copyInto(params, appBuilder::category); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index 558c29f6feae9..80f742a0f61db 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -284,7 +284,7 @@ private static void addFaToCFBundleDocumentTypes(XMLStreamWriter xml, fa.nsPersistentStoreTypeKey()); writeString(xml, "NSDocumentClass", fa.nsDocumentClass()); writeBoolean(xml, "LSIsAppleDefaultForType", true); - writeString(xml, "LSTypeIsPackage", fa.lsTypeIsPackage()); + writeBoolean(xml, "LSTypeIsPackage", fa.lsTypeIsPackage()); writeBoolean(xml, "LSSupportsOpeningDocumentsInPlace", fa.lsSupportsOpeningDocumentsInPlace()); writeBoolean(xml, "UISupportsDocumentBrowser", diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java index b79a2fe7be5f9..87723cf2655d7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java @@ -109,7 +109,7 @@ Launcher create(Map params) throws ConfigException { if (faExtension.isPresent()) { return new FileAssociationGroup(faGroup.items().stream().map(fa -> { - return faExtension.get().apply(fa, params); + return faExtension.get().apply(fa, faParams); }).toList()); } else { return faGroup; From dd6c1bc2671aacb28d0977b19359386bff76d0f3 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 4 Feb 2025 15:20:06 -0500 Subject: [PATCH 0273/1101] Added FromParams.getCurrentPackage() --- .../share/classes/jdk/jpackage/internal/FromParams.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java index 379a6a744418a..6f38f861df92e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -149,6 +149,11 @@ static BundlerParamInfo creat return BundlerParamInfo.createBundlerParam(jdk.jpackage.internal.model.Package.class, ctor); } + static Optional getCurrentPackage(Map params) { + return Optional.ofNullable((jdk.jpackage.internal.model.Package)params.get( + jdk.jpackage.internal.model.Package.class.getName())); + } + private static ApplicationLaunchers createLaunchers( Map params, Function, Launcher> launcherMapper) { From c85e05050b600d60b8517156b65d2808ec3f2fb7 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 4 Feb 2025 15:21:22 -0500 Subject: [PATCH 0274/1101] Simplify CfgFile.create() --- .../internal/ApplicationImageUtils.java | 2 +- .../jdk/jpackage/internal/CfgFile.java | 46 +++++++++++-------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java index bc41e985142bf..94d9e09da860c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java @@ -114,7 +114,7 @@ static PackagingPipeline.ApplicationImageTaskAction createWriteLaunchersAction() return (env, app, appLayout) -> { for (var launcher : app.launchers()) { // Create corresponding .cfg file - new CfgFile(app, launcher).create(appLayout, appLayout); + new CfgFile(app, launcher).create(appLayout); // Copy executable to launchers folder Path executableFile = appLayout.launchersDirectory().resolve( diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java index 528eb8d5abca7..11515ff787895 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java @@ -24,12 +24,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.LauncherStartupInfo; -import jdk.jpackage.internal.model.LauncherJarStartupInfo; -import jdk.jpackage.internal.model.LauncherModularStartupInfo; -import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -38,6 +32,12 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Stream; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.LauncherJarStartupInfo; +import jdk.jpackage.internal.model.LauncherModularStartupInfo; +import jdk.jpackage.internal.model.LauncherStartupInfo; /** @@ -50,10 +50,10 @@ final class CfgFile { version = app.version(); } - void create(ApplicationLayout unresolvedAppLayout, ApplicationLayout appLayout) throws IOException { + void create(ApplicationLayout appLayout) throws IOException { List> content = new ArrayList<>(); - ApplicationLayout appCfgLayout = createAppCfgLayout(unresolvedAppLayout); + final var refs = new Referencies(appLayout); content.add(Map.entry("[Application]", SECTION_TAG)); @@ -61,7 +61,7 @@ void create(ApplicationLayout unresolvedAppLayout, ApplicationLayout appLayout) content.add(Map.entry("app.mainmodule", modularStartupInfo.moduleName() + "/" + startupInfo.qualifiedClassName())); } else if (startupInfo instanceof LauncherJarStartupInfo jarStartupInfo) { - Path mainJarPath = appCfgLayout.appDirectory().resolve(jarStartupInfo.jarPath()); + Path mainJarPath = refs.appDirectory().resolve(jarStartupInfo.jarPath()); if (jarStartupInfo.isJarWithMainClass()) { content.add(Map.entry("app.mainjar", mainJarPath)); @@ -78,7 +78,7 @@ void create(ApplicationLayout unresolvedAppLayout, ApplicationLayout appLayout) for (var value : Optional.ofNullable(startupInfo.classPath()).orElseGet(List::of)) { content.add(Map.entry("app.classpath", - appCfgLayout.appDirectory().resolve(value).toString())); + refs.appDirectory().resolve(value).toString())); } content.add(Map.entry("[JavaOptions]", SECTION_TAG)); @@ -95,7 +95,7 @@ void create(ApplicationLayout unresolvedAppLayout, ApplicationLayout appLayout) // add module path if there is one if (Files.isDirectory(appLayout.appModsDirectory())) { content.add(Map.entry("java-options", "--module-path")); - content.add(Map.entry("java-options", appCfgLayout.appModsDirectory())); + content.add(Map.entry("java-options", refs.appModsDirectory())); } var arguments = Optional.ofNullable(startupInfo.defaultParameters()).orElseGet(List::of); @@ -123,15 +123,21 @@ void create(ApplicationLayout unresolvedAppLayout, ApplicationLayout appLayout) Files.write(cfgFile, (Iterable) lines::iterator); } - private ApplicationLayout createAppCfgLayout(ApplicationLayout appLayout) { - return ApplicationLayout - .buildFrom(appLayout.resolveAt(Path.of("$ROOTDIR"))) - .appDirectory("$APPDIR") - .appModsDirectory( - Path.of("$APPDIR").resolve( - appLayout.appDirectory().relativize( - appLayout.appModsDirectory()))) - .create(); + private record Referencies(Path appModsDirectory) { + + Referencies { + if (!appModsDirectory.getParent().equals(appDirectory())) { + throw new IllegalArgumentException(); + } + } + + Referencies(ApplicationLayout appLayout) { + this(Path.of("$APPDIR").resolve(appLayout.appModsDirectory().getFileName())); + } + + Path appDirectory() { + return Path.of("$APPDIR"); + } } private final LauncherStartupInfo startupInfo; From 56cebeef79bd463724082d775b7ff44dc200fc9a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 4 Feb 2025 15:22:01 -0500 Subject: [PATCH 0275/1101] Reorder imports --- .../classes/jdk/jpackage/internal/LinuxPackageBuilder.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index 7f5f1a116e644..795763765e9bb 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -24,11 +24,12 @@ */ package jdk.jpackage.internal; +import static jdk.jpackage.internal.I18N.buildConfigException; + import java.nio.file.Path; import java.util.Objects; import java.util.Optional; import java.util.regex.Pattern; -import static jdk.jpackage.internal.I18N.buildConfigException; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.ConfigException; @@ -36,8 +37,6 @@ import jdk.jpackage.internal.model.LinuxPackageMixin; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.StandardPackageType; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; final class LinuxPackageBuilder { From 99b6aa9a1451dbe83c5b153e5f129f581e147dad Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 4 Feb 2025 15:23:06 -0500 Subject: [PATCH 0276/1101] Use FromParams.getCurrentPackage() --- .../macosx/classes/jdk/jpackage/internal/MacAppBundler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index 42cc08c3156f5..f4d14d2248316 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -51,12 +51,12 @@ public MacAppBundler() { .excludeDirFromCopying(OUTPUT_DIR.fetchFrom(params)) .inputApplicationLayoutForPackaging(pkg -> pkg.app().asApplicationLayout()); - if (isDependentTask()) { - final var pkg = MacFromParams.PACKAGE.fetchFrom(params); + final var pkg = FromParams.getCurrentPackage(params); + if (pkg.isPresent()) { taskPipelineBuilder.pkgBuildEnvFactory((e, p) -> { return BuildEnv.withAppImageDir(e, output); }); - taskPipelineBuilder.create().execute(env, pkg, output); + taskPipelineBuilder.create().execute(env, pkg.orElseThrow(), output); } else { taskPipelineBuilder.create().execute(env, app); } From d97bf70fb8e7df6f9edd0d3cb81d581cd95f4471 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 4 Feb 2025 15:24:55 -0500 Subject: [PATCH 0277/1101] Add DMG and PKG model interfaces --- .../internal/MacDmgPackageBuilder.java | 67 +++++++++++++++++++ .../internal/MacPkgPackageBuilder.java | 42 ++++++++++++ .../internal/model/MacDmgPackage.java | 34 ++++++++++ .../internal/model/MacDmgPackageMixin.java | 46 +++++++++++++ .../internal/model/MacPkgPackage.java | 34 ++++++++++ 5 files changed, 223 insertions(+) create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackage.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java new file mode 100644 index 0000000000000..37954980c0856 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.MacDmgPackage; +import jdk.jpackage.internal.model.MacApplication; +import jdk.jpackage.internal.model.MacDmgPackageMixin; + +final class MacDmgPackageBuilder { + + MacDmgPackageBuilder(PackageBuilder pkgBuilder) { + this.pkgBuilder = Objects.requireNonNull(pkgBuilder); + } + + MacDmgPackageBuilder dmgContent(List v) { + dmgContent = v; + return this; + } + + MacDmgPackageBuilder icon(Path v) { + icon = v; + return this; + } + + List validatedDmgContent() { + return Optional.ofNullable(dmgContent).orElseGet(List::of); + } + + MacDmgPackage create() throws ConfigException { + final var pkg = pkgBuilder.create(); + + return MacDmgPackage.create(pkg, new MacDmgPackageMixin.Stub( + Optional.ofNullable(icon).or(((MacApplication)pkg.app())::icon), + validatedDmgContent())); + } + + private Path icon; + private List dmgContent; + private final PackageBuilder pkgBuilder; +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java new file mode 100644 index 0000000000000..94a78de5eca23 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.Objects; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.MacPkgPackage; + +final class MacPkgPackageBuilder { + + MacPkgPackageBuilder(PackageBuilder pkgBuilder) { + this.pkgBuilder = Objects.requireNonNull(pkgBuilder); + } + + MacPkgPackage create() throws ConfigException { + return MacPkgPackage.create(pkgBuilder.create()); + } + + private final PackageBuilder pkgBuilder; +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackage.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackage.java new file mode 100644 index 0000000000000..afb3eba1075c0 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackage.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import jdk.jpackage.internal.util.CompositeProxy; + +public interface MacDmgPackage extends Package, MacDmgPackageMixin { + + public static MacDmgPackage create(Package pkg, MacDmgPackageMixin mixin) { + return CompositeProxy.create(MacDmgPackage.class, pkg, mixin); + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java new file mode 100644 index 0000000000000..28d1703be316e --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; + +public interface MacDmgPackageMixin { + + Optional icon(); + + /** + * Returns additional top=level content for DMG package. + *

+ * Each item in the list can be a directory or a file. + * + * @return the additional top=level content for DMG package + */ + List content(); + + record Stub(Optional icon, List content) implements MacDmgPackageMixin { + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java new file mode 100644 index 0000000000000..0d4f973c1dc7c --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import jdk.jpackage.internal.util.CompositeProxy; + +public interface MacPkgPackage extends Package { + + public static MacPkgPackage create(Package pkg) { + return CompositeProxy.create(MacPkgPackage.class, pkg); + } +} From cb5e713346eee011da12b31180e16b77dda57d44 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 4 Feb 2025 16:02:26 -0500 Subject: [PATCH 0278/1101] All tests pass on all platforms --- .../internal/LinuxPackageBundler.java | 16 +++-- .../internal/MacAppImageFileExtras.java | 5 +- .../internal/MacApplicationBuilder.java | 19 +++++- .../internal/MacBaseInstallerBundler.java | 3 - .../jdk/jpackage/internal/MacDmgBundler.java | 11 ++- .../jdk/jpackage/internal/MacFromParams.java | 68 +++++++++++++------ .../internal/MacLaunchersAsServices.java | 12 ++-- .../jdk/jpackage/internal/MacPkgBundler.java | 4 ++ .../internal/model/MacApplication.java | 22 +++++- .../internal/model/MacApplicationMixin.java | 6 +- .../jpackage/internal/BuildEnvBuilder.java | 16 ++++- .../jpackage/internal/BuildEnvFromParams.java | 8 ++- .../jdk/jpackage/internal/PackageBuilder.java | 7 +- .../internal/StandardBundlerParam.java | 6 +- 14 files changed, 146 insertions(+), 57 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index fb45c2cb97c3b..c64c61eaf2c58 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -103,15 +103,19 @@ public final Path execute(Map params, final LinuxPackage pkg = pkgParam.fetchFrom(params); final var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - final BuildEnv pkgEnv = BuildEnv.withAppImageDir(env, - env.buildRoot().resolve("image")); + final BuildEnv pkgEnv; + + if (pkg.app().runtimeBuilder().isEmpty()) { + // Packaging external app image + pkgEnv = BuildEnv.withAppImageDir(env, BuildEnvBuilder.defaultAppImageDir(env.buildRoot())); + } else { + pkgEnv = env; + } LinuxPackagingPipeline.build() .excludeDirFromCopying(outputParentDir) - .pkgBuildEnvFactory((e, p) -> { - return pkgEnv; - }) - .create().execute(env, pkg, outputParentDir); + .pkgBuildEnvFactory((e, p) -> pkgEnv) + .create().execute(env, pkg, outputParentDir); try { for (var ca : customActions) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java index 4e8a1bdffafce..d44799e6807d8 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java @@ -28,9 +28,10 @@ import jdk.jpackage.internal.model.MacApplication.ExtraAppImageFileField; -record MacAppImageFileExtras(boolean signed) { +record MacAppImageFileExtras(boolean signed, boolean appStore) { MacAppImageFileExtras(AppImageFile appImageFile) { - this(getBooleanExtraFieldValue(ExtraAppImageFileField.SIGNED.fieldName(), appImageFile)); + this(getBooleanExtraFieldValue(ExtraAppImageFileField.SIGNED.fieldName(), appImageFile), + getBooleanExtraFieldValue(ExtraAppImageFileField.APP_STORE.fieldName(), appImageFile)); } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java index 9e65c7ab67712..7bb4c6d1a20df 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java @@ -32,7 +32,6 @@ import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.LauncherStartupInfo; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.MacApplicationMixin; import jdk.jpackage.internal.model.SigningConfig; @@ -49,6 +48,7 @@ private MacApplicationBuilder(MacApplicationBuilder other) { bundleName = other.bundleName; bundleIdentifier = other.bundleIdentifier; category = other.category; + appStore = other.appStore; externalInfoPlistFile = other.externalInfoPlistFile; } @@ -72,6 +72,11 @@ MacApplicationBuilder category(String v) { return this; } + MacApplicationBuilder appStore(boolean v) { + appStore = v; + return this; + } + MacApplicationBuilder externalInfoPlistFile(Path v) { externalInfoPlistFile = v; return this; @@ -88,7 +93,7 @@ MacApplication create() throws ConfigException { } final var mixin = new MacApplicationMixin.Stub(validatedIcon(), validatedBundleName(), - validatedBundleIdentifier(), validatedCategory(), createSigningConfig()); + validatedBundleIdentifier(), validatedCategory(), appStore, createSigningConfig()); return MacApplication.create(app, mixin); } @@ -167,7 +172,14 @@ private String validatedBundleIdentifier() throws ConfigException { final var value = Optional.ofNullable(bundleIdentifier).orElseGet(() -> { return app.mainLauncher() .flatMap(Launcher::startupInfo) - .map(LauncherStartupInfo::simpleClassName) + .map(li -> { + final var packageName = li.packageName(); + if (packageName.isEmpty()) { + return li.simpleClassName(); + } else { + return packageName; + } + }) .orElseGet(app::name); }); @@ -199,6 +211,7 @@ private record Defaults(String category) { private String bundleName; private String bundleIdentifier; private String category; + private boolean appStore; private Path externalInfoPlistFile; private SigningConfigBuilder signingBuilder; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index 2757d738a59b9..2eefc5e282a88 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -27,7 +27,6 @@ import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.ApplicationLayout; import java.io.IOException; import java.nio.file.Files; import java.nio.file.LinkOption; @@ -51,8 +50,6 @@ public abstract class MacBaseInstallerBundler extends AbstractBundler { "imagesRoot", Path.class, params -> { - // Order is important - MacFromParams.APPLICATION.fetchFrom(params); final var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); return env.buildRoot().resolve("images"); }, diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java index 8f71d6e9b58e8..3fa4f3e2259de 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java @@ -82,6 +82,8 @@ public Path bundle(Map params, IOUtils.writableOutputDir(outdir); + MacFromParams.DMG_PACKAGE.fetchFrom(params); + try { Path appLocation = prepareAppBundle(params); @@ -318,11 +320,12 @@ private Path buildDMG( Map params, Files.createDirectories(protoDMG.getParent()); Files.createDirectories(finalDMG.getParent()); + final var pkg = MacFromParams.DMG_PACKAGE.fetchFrom(params); + String hdiUtilVerbosityFlag = VERBOSE.fetchFrom(params) ? "-verbose" : "-quiet"; - List dmgContent = DMG_CONTENT.fetchFrom(params); - for (String content : dmgContent) { - Path path = Path.of(content); + List dmgContent = DMG_CONTENT.fetchFrom(params); + for (Path path : dmgContent) { FileUtils.copyRecursive(path, srcFolder.resolve(path.getFileName())); } // create temp image @@ -562,6 +565,8 @@ public boolean validate(Map params) try { Objects.requireNonNull(params); + MacFromParams.DMG_PACKAGE.fetchFrom(params); + //run basic validation to ensure requirements are met //we are not interested in return code, only possible exception validateAppImageAndBundeler(params); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java index 5b5e6c7c1bbfb..bf884e74318d3 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java @@ -29,17 +29,21 @@ import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import static jdk.jpackage.internal.FromParams.createApplicationBuilder; import static jdk.jpackage.internal.FromParams.createApplicationBundlerParam; +import static jdk.jpackage.internal.FromParams.createPackageBuilder; import static jdk.jpackage.internal.FromParams.createPackageBundlerParam; import static jdk.jpackage.internal.MacAppImageBuilder.APP_STORE; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT; +import static jdk.jpackage.internal.StandardBundlerParam.DMG_CONTENT; import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage; +import static jdk.jpackage.internal.model.StandardPackageType.MAC_DMG; +import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import java.io.IOException; @@ -54,9 +58,10 @@ import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.MacApplication; +import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.model.MacFileAssociation; import jdk.jpackage.internal.model.MacLauncher; -import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.MacPkgPackage; final class MacFromParams { @@ -85,14 +90,19 @@ private static MacApplication createMacApplication( APP_CATEGORY.copyInto(params, appBuilder::category); final boolean sign; + final boolean appStore; if (hasPredefinedAppImage(params)) { final var appImageFileExtras = new MacAppImageFileExtras(PREDEFINED_APP_IMAGE_FILE.fetchFrom(params)); sign = appImageFileExtras.signed(); + appStore = APP_STORE.findIn(params).orElse(false); } else { sign = SIGN_BUNDLE.findIn(params).orElse(false); + appStore = APP_STORE.findIn(params).orElse(false); } + appBuilder.appStore(appStore); + if (sign) { final var signingBuilder = new SigningConfigBuilder(); app.mainLauncher().flatMap(Launcher::startupInfo).ifPresent(signingBuilder::signingIdentifierPrefix); @@ -101,8 +111,6 @@ private static MacApplication createMacApplication( ENTITLEMENTS.copyInto(params, signingBuilder::entitlements); APP_IMAGE_SIGN_IDENTITY.copyInto(params, signingBuilder::signingIdentifier); - final boolean appStore = APP_STORE.findIn(params).orElse(false); - final var certificateNameFilter = appStore ? CertificateNameFilter.APP_STORE_APP_IMAGE : CertificateNameFilter.APP_IMAGE; signingBuilder.addCertificateNameFilters(certificateNameFilter.getFilters(SIGNING_KEY_USER.findIn(params))); @@ -113,6 +121,32 @@ private static MacApplication createMacApplication( return appBuilder.create(); } + private static MacDmgPackage createMacDmgPackage( + Map params) throws ConfigException, IOException { + + final var app = APPLICATION.fetchFrom(params); + + final var superPkgBuilder = createPackageBuilder(params, app, MAC_DMG); + + final var pkgBuilder = new MacDmgPackageBuilder(superPkgBuilder); + + DMG_CONTENT.copyInto(params, pkgBuilder::dmgContent); + + return pkgBuilder.create(); + } + + private static MacPkgPackage createMacPkgPackage( + Map params) throws ConfigException, IOException { + + final var app = APPLICATION.fetchFrom(params); + + final var superPkgBuilder = createPackageBuilder(params, app, MAC_PKG); + + final var pkgBuilder = new MacPkgPackageBuilder(superPkgBuilder); + + return pkgBuilder.create(); + } + private static MacFileAssociation createMacFa(FileAssociation fa, Map params) { final var builder = new MacFileAssociationBuilder(); @@ -142,33 +176,29 @@ private static void adjustRuntimeDir(Map params) { static final BundlerParamInfo APPLICATION = createApplicationBundlerParam( MacFromParams::createMacApplication); - // FIXME: This is just a stub. Replace with DMG and PKG packages - static final BundlerParamInfo PACKAGE = createPackageBundlerParam(params -> { - final var app = APPLICATION.fetchFrom(params); - final var builder = FromParams.createPackageBuilder(params, app, new PackageType () {}); - - builder.installDir(Path.of("/foo/bar")); + static final BundlerParamInfo DMG_PACKAGE = createPackageBundlerParam( + MacFromParams::createMacDmgPackage); - return builder.create(); - }); + static final BundlerParamInfo PKG_PACKAGE = createPackageBundlerParam( + MacFromParams::createMacPkgPackage); - public static final BundlerParamInfo MAC_CF_BUNDLE_NAME = createStringBundlerParam( + static final BundlerParamInfo MAC_CF_BUNDLE_NAME = createStringBundlerParam( Arguments.CLIOptions.MAC_BUNDLE_NAME.getId()); - public static final BundlerParamInfo APP_CATEGORY = createStringBundlerParam( + static final BundlerParamInfo APP_CATEGORY = createStringBundlerParam( Arguments.CLIOptions.MAC_CATEGORY.getId()); - public static final BundlerParamInfo ENTITLEMENTS = createPathBundlerParam( + static final BundlerParamInfo ENTITLEMENTS = createPathBundlerParam( Arguments.CLIOptions.MAC_ENTITLEMENTS.getId()); - public static final BundlerParamInfo MAC_CF_BUNDLE_IDENTIFIER = createStringBundlerParam( + static final BundlerParamInfo MAC_CF_BUNDLE_IDENTIFIER = createStringBundlerParam( Arguments.CLIOptions.MAC_BUNDLE_IDENTIFIER.getId()); - public static final BundlerParamInfo BUNDLE_ID_SIGNING_PREFIX = createStringBundlerParam( + static final BundlerParamInfo BUNDLE_ID_SIGNING_PREFIX = createStringBundlerParam( Arguments.CLIOptions.MAC_BUNDLE_SIGNING_PREFIX.getId()); - public static final BundlerParamInfo APP_IMAGE_SIGN_IDENTITY = createStringBundlerParam( + static final BundlerParamInfo APP_IMAGE_SIGN_IDENTITY = createStringBundlerParam( Arguments.CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getId()); private static final BundlerParamInfo FA_MAC_CFBUNDLETYPEROLE = createStringBundlerParam( @@ -197,7 +227,7 @@ private static void adjustRuntimeDir(Map params) { new BundlerParamInfo<>( Arguments.MAC_NSEXPORTABLETYPES, (Class>) (Object) List.class, - params -> null, + null, (s, p) -> Arrays.asList(s.split("(,|\\s)+")) ); @@ -206,7 +236,7 @@ private static void adjustRuntimeDir(Map params) { new BundlerParamInfo<>( Arguments.MAC_UTTYPECONFORMSTO, (Class>) (Object) List.class, - params -> null, + null, (s, p) -> Arrays.asList(s.split("(,|\\s)+")) ); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index 70d81f690bd33..5861dccfbe25c 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -26,6 +26,7 @@ import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.MacApplication; import java.io.IOException; import java.nio.file.Path; import java.util.List; @@ -48,9 +49,8 @@ private MacLaunchersAsServices(BuildEnv env, Package pkg) throws IOException { static ShellCustomAction create(Map params, Path outputDir) throws IOException { - // Order is important! - var pkg = MacFromParams.PACKAGE.fetchFrom(params); - var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + final var pkg = FromParams.getCurrentPackage(params).orElseThrow(); + final var env = BuildEnv.withAppImageDir(BuildEnvFromParams.BUILD_ENV.findIn(params).orElseThrow(), outputDir); if (pkg.isRuntimeInstaller()) { return null; @@ -59,10 +59,10 @@ static ShellCustomAction create(Map params, MacLaunchersAsServices::isEmpty)).orElse(null); } - public static Path getServicePListFileName(String packageName, + public static Path getServicePListFileName(String bundleIdentifier, String launcherName) { String baseName = launcherName.replaceAll("[\\s]", "_"); - return Path.of(packageName + "-" + baseName + ".plist"); + return Path.of(bundleIdentifier + "-" + baseName + ".plist"); } private static class MacLauncherAsService extends UnixLauncherAsService { @@ -71,7 +71,7 @@ private static class MacLauncherAsService extends UnixLauncherAsService { super(launcher, env.createResource("launchd.plist.template").setCategory(I18N .getString("resource.launchd-plist-file"))); - plistFilename = getServicePListFileName(pkg.packageName(), getName()); + plistFilename = getServicePListFileName(((MacApplication)pkg.app()).bundleIdentifier(), getName()); // It is recommended to set value of "label" property in launchd // .plist file equal to the name of this .plist file without the suffix. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 76686900979c7..e45e98551d61c 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -154,6 +154,8 @@ public Path bundle(Map params, IOUtils.writableOutputDir(outdir); + MacFromParams.PKG_PACKAGE.fetchFrom(params); + try { Path appImageDir = prepareAppBundle(params); @@ -698,6 +700,8 @@ public boolean validate(Map params) try { Objects.requireNonNull(params); + MacFromParams.PKG_PACKAGE.fetchFrom(params); + // run basic validation to ensure requirements are met // we are not interested in return code, only possible exception validateAppImageAndBundeler(params); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java index c8109ca8db2dd..4c2dee0e7245b 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java @@ -25,9 +25,13 @@ package jdk.jpackage.internal.model; import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toMap; +import java.nio.file.Path; import java.util.Map; +import java.util.function.Function; import java.util.stream.IntStream; +import java.util.stream.Stream; import jdk.jpackage.internal.util.CompositeProxy; public interface MacApplication extends Application, MacApplicationMixin { @@ -43,13 +47,18 @@ default DottedVersion shortVersion() { }).collect(joining("."))); } + @Override + default Path appImageDirName() { + return Path.of(Application.super.appImageDirName().toString() + ".app"); + } + default boolean sign() { return signingConfig().isPresent(); } @Override default Map extraAppImageFileData() { - return Map.of(ExtraAppImageFileField.SIGNED.fieldName(), Boolean.toString(sign())); + return Stream.of(ExtraAppImageFileField.values()).collect(toMap(ExtraAppImageFileField::fieldName, x -> x.asString(this))); } public static MacApplication create(Application app, MacApplicationMixin mixin) { @@ -57,16 +66,23 @@ public static MacApplication create(Application app, MacApplicationMixin mixin) } public enum ExtraAppImageFileField { - SIGNED("signed"); + SIGNED("signed", app -> Boolean.toString(app.sign())), + APP_STORE("app-store", app -> Boolean.toString(app.appStore())); - ExtraAppImageFileField(String fieldName) { + ExtraAppImageFileField(String fieldName, Function getter) { this.fieldName = fieldName; + this.getter = getter; } public String fieldName() { return fieldName; } + String asString(MacApplication app) { + return getter.apply(app); + } + private final String fieldName; + private final Function getter; } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java index db23b7f8a5b4d..31e2e6b44b4cb 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java @@ -37,9 +37,11 @@ public interface MacApplicationMixin { String category(); + boolean appStore(); + Optional signingConfig(); - record Stub(Optional icon, String bundleName, String bundleIdentifier, - String category, Optional signingConfig) implements MacApplicationMixin { + record Stub(Optional icon, String bundleName, String bundleIdentifier, String category, + boolean appStore, Optional signingConfig) implements MacApplicationMixin { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java index 3362b88313d96..d73dcb75784e8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java @@ -24,14 +24,15 @@ */ package jdk.jpackage.internal; +import static jdk.jpackage.internal.I18N.buildConfigException; + import java.io.IOException; import java.nio.file.Files; -import jdk.jpackage.internal.model.ConfigException; import java.nio.file.Path; import java.util.Objects; import java.util.Optional; -import static jdk.jpackage.internal.I18N.buildConfigException; import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.resources.ResourceLocator; final class BuildEnvBuilder { @@ -71,10 +72,19 @@ BuildEnvBuilder appImageDir(Path v) { } BuildEnvBuilder appImageDirFor(Application app) { - appImageDir = root.resolve("image").resolve(app.appImageDirName()); + appImageDir = defaultAppImageDir(root).resolve(app.appImageDirName()); return this; } + BuildEnvBuilder appImageDirForPackage() { + appImageDir = defaultAppImageDir(root); + return this; + } + + static Path defaultAppImageDir(Path root) { + return root.resolve("image"); + } + private Path appImageDir; private Path resourceDir; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java index 2de872f59fe73..11ec3d1cd8fb9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java @@ -36,15 +36,19 @@ final class BuildEnvFromParams { static BuildEnv create(Map params) throws ConfigException { - var builder = new BuildEnvBuilder(TEMP_ROOT.fetchFrom(params)) + final var builder = new BuildEnvBuilder(TEMP_ROOT.fetchFrom(params)) .resourceDir(RESOURCE_DIR.fetchFrom(params)); - var app = FromParams.APPLICATION.fetchFrom(params); + final var app = FromParams.APPLICATION.findIn(params).orElseThrow(); + + final var pkg = FromParams.getCurrentPackage(params); if (app.isRuntime()) { builder.appImageDir(PREDEFINED_RUNTIME_IMAGE.fetchFrom(params)); } else if (StandardBundlerParam.hasPredefinedAppImage(params)) { builder.appImageDir(StandardBundlerParam.getPredefinedAppImage(params)); + } else if (pkg.isPresent()) { + builder.appImageDirForPackage(); } else { builder.appImageDirFor(app); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index a1b446bcf7dc7..07ec5fed92946 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -184,13 +184,16 @@ private static Path defaultInstallDir(StandardPackageType pkgType, String pkgNam return Path.of("/opt").resolve(pkgName); } case MAC_DMG, MAC_PKG -> { - Path base; + final Path base; + final String dirName; if (app.isRuntime()) { + dirName = pkgName; base = Path.of("/Library/Java/JavaVirtualMachines"); } else { + dirName = pkgName + ".app"; base = Path.of("/Applications"); } - return base.resolve(pkgName); + return base.resolve(dirName); } default -> { throw new UnsupportedOperationException(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index 17b55ead23ad8..6291331f0d856 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -414,12 +414,12 @@ final class StandardBundlerParam { ); @SuppressWarnings("unchecked") - static final BundlerParamInfo> DMG_CONTENT = + static final BundlerParamInfo> DMG_CONTENT = new BundlerParamInfo<>( Arguments.CLIOptions.DMG_CONTENT.getId(), - (Class>) (Object)List.class, + (Class>) (Object)List.class, p -> Collections.emptyList(), - (s, p) -> Arrays.asList(s.split(",")) + (s, p) -> Stream.of(s.split(",")).map(Path::of).toList() ); @SuppressWarnings("unchecked") From 2b626aee4b1af7c9b71b51f13e2dbdf6a8f6f7ff Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 4 Feb 2025 17:53:08 -0500 Subject: [PATCH 0279/1101] Improve some tests --- .../jpackage/internal/util/PathGroupTest.java | 1 + .../macosx/MacAppStoreJlinkOptionsTest.java | 37 ++++++++++++------- .../macosx/MacAppStoreRuntimeTest.java | 16 ++++---- .../jpackage/share/RuntimeImageTest.java | 36 ++++++++++-------- 4 files changed, 54 insertions(+), 36 deletions(-) diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java index 4123b3abfac36..9819d4b76c1cc 100644 --- a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java +++ b/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java @@ -48,6 +48,7 @@ public class PathGroupTest { + @Test public void testNullId() { assertThrowsExactly(NullPointerException.class, () -> new PathGroup(Map.of()).getPath(null)); } diff --git a/test/jdk/tools/jpackage/macosx/MacAppStoreJlinkOptionsTest.java b/test/jdk/tools/jpackage/macosx/MacAppStoreJlinkOptionsTest.java index 1501fd15d8fdf..281793be02757 100644 --- a/test/jdk/tools/jpackage/macosx/MacAppStoreJlinkOptionsTest.java +++ b/test/jdk/tools/jpackage/macosx/MacAppStoreJlinkOptionsTest.java @@ -21,8 +21,14 @@ * questions. */ -import jdk.jpackage.test.JPackageCommand; +import static java.util.stream.Collectors.joining; + +import java.util.ArrayList; +import java.util.List; +import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageStringBundle; /** * Tests generation of app image with --mac-app-store and --jlink-options. jpackage should able @@ -43,20 +49,25 @@ public class MacAppStoreJLinkOptionsTest { @Test - public static void testWithStripNativeCommands() throws Exception { - JPackageCommand cmd = JPackageCommand.helloAppImage(); - cmd.addArguments("--mac-app-store", "--jlink-options", - "--strip-debug --no-man-pages --no-header-files --strip-native-commands"); + @Parameter("true") + @Parameter("false") + public static void testWithStripNativeCommands(boolean stripNativeCommands) throws Exception { - cmd.executeAndAssertHelloAppImageCreated(); - } + final var jlinkOptions = new ArrayList(List.of("--strip-debug --no-man-pages --no-header-files")); + if (stripNativeCommands) { + jlinkOptions.add("--strip-native-commands"); + } - @Test - public static void testWithoutStripNativeCommands() throws Exception { - JPackageCommand cmd = JPackageCommand.helloAppImage(); - cmd.addArguments("--mac-app-store", "--jlink-options", - "--strip-debug --no-man-pages --no-header-files"); + final var cmd = JPackageCommand.helloAppImage().ignoreDefaultRuntime(true); + + cmd.addArguments("--mac-app-store", "--jlink-options", jlinkOptions.stream().collect(joining(" "))); - cmd.execute(1); + if (stripNativeCommands) { + cmd.executeAndAssertHelloAppImageCreated(); + } else { + cmd.validateOutput(JPackageStringBundle.MAIN.cannedFormattedString( + "ERR_MissingJLinkOptMacAppStore", "--strip-native-commands")); + cmd.execute(1); + } } } diff --git a/test/jdk/tools/jpackage/macosx/MacAppStoreRuntimeTest.java b/test/jdk/tools/jpackage/macosx/MacAppStoreRuntimeTest.java index ab8b8590b33de..ba55a5d396deb 100644 --- a/test/jdk/tools/jpackage/macosx/MacAppStoreRuntimeTest.java +++ b/test/jdk/tools/jpackage/macosx/MacAppStoreRuntimeTest.java @@ -21,18 +21,18 @@ * questions. */ +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.io.IOException; import java.util.ArrayList; import java.util.List; - -import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Executor; -import jdk.jpackage.test.TKit; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageStringBundle; import jdk.jpackage.test.JavaTool; -import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.TKit; /** @@ -88,12 +88,14 @@ private static String getRuntimeImage(boolean stripNativeCommands) throws IOExce @Parameter("true") @Parameter("false") public static void test(boolean stripNativeCommands) throws Exception { - JPackageCommand cmd = JPackageCommand.helloAppImage(); + JPackageCommand cmd = JPackageCommand.helloAppImage().ignoreDefaultRuntime(true); cmd.addArguments("--mac-app-store", "--runtime-image", getRuntimeImage(stripNativeCommands)); if (stripNativeCommands) { cmd.executeAndAssertHelloAppImageCreated(); } else { + cmd.validateOutput(JPackageStringBundle.MAIN.cannedFormattedString( + "ERR_MacAppStoreRuntimeBinExists", Path.of(cmd.getArgumentValue("--runtime-image")).toAbsolutePath().toString())); cmd.execute(1); } } diff --git a/test/jdk/tools/jpackage/share/RuntimeImageTest.java b/test/jdk/tools/jpackage/share/RuntimeImageTest.java index a80018603bf4e..c4a588ca7a713 100644 --- a/test/jdk/tools/jpackage/share/RuntimeImageTest.java +++ b/test/jdk/tools/jpackage/share/RuntimeImageTest.java @@ -44,24 +44,28 @@ public class RuntimeImageTest { @Test public static void test() throws Exception { - final Path workDir = TKit.createTempDirectory("runtime").resolve("data"); - final Path jlinkOutputDir = workDir.resolve("temp.runtime"); - Files.createDirectories(jlinkOutputDir.getParent()); - new Executor() - .setToolProvider(JavaTool.JLINK) - .dumpOutput() - .addArguments( - "--output", jlinkOutputDir.toString(), - "--add-modules", "java.desktop", - "--strip-debug", - "--no-header-files", - "--no-man-pages", - "--strip-native-commands") - .execute(); + JPackageCommand cmd = JPackageCommand.helloAppImage(); - JPackageCommand cmd = JPackageCommand.helloAppImage() - .setArgumentValue("--runtime-image", jlinkOutputDir.toString()); + if (JPackageCommand.DEFAULT_RUNTIME_IMAGE == null) { + final Path workDir = TKit.createTempDirectory("runtime").resolve("data"); + final Path jlinkOutputDir = workDir.resolve("temp.runtime"); + Files.createDirectories(jlinkOutputDir.getParent()); + + new Executor() + .setToolProvider(JavaTool.JLINK) + .dumpOutput() + .addArguments( + "--output", jlinkOutputDir.toString(), + "--add-modules", "java.desktop", + "--strip-debug", + "--no-header-files", + "--no-man-pages", + "--strip-native-commands") + .execute(); + + cmd.setArgumentValue("--runtime-image", jlinkOutputDir.toString()); + } cmd.executeAndAssertHelloAppImageCreated(); } From 7918ec9ba2919fd4ad594ab78e173746e2e9aa33 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 4 Feb 2025 21:30:53 -0500 Subject: [PATCH 0280/1101] Accommodate junit tests --- test/jdk/tools/jpackage/junit/TEST.properties | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/jdk/tools/jpackage/junit/TEST.properties b/test/jdk/tools/jpackage/junit/TEST.properties index 12c38c2f5a5a1..fee08d9cc9620 100644 --- a/test/jdk/tools/jpackage/junit/TEST.properties +++ b/test/jdk/tools/jpackage/junit/TEST.properties @@ -1,2 +1,7 @@ JUnit.dirs = . -modules = jdk.jpackage + +modules=jdk.jpackage/jdk.jpackage.internal:+open \ + jdk.jpackage/jdk.jpackage.internal.model:+open \ + jdk.jpackage/jdk.jpackage.internal.pipeline:+open \ + jdk.jpackage/jdk.jpackage.internal.util:+open \ + jdk.jpackage/jdk.jpackage.internal.util.function:+open From 79719ee8dae1ccf52aa8cdcbf940f04cbd47bae8 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 7 Feb 2025 22:22:59 -0500 Subject: [PATCH 0281/1101] Convert helpers-test tests to junit format. It is easier to debug them in IDE this way. --- .../jpackage/helpers-test/TEST.properties | 7 +++ .../jdk/jpackage/test/AnnotationsTest.java | 12 +--- .../test/DirectoryContentVerifierTest.java | 49 ++++++--------- .../jdk/jpackage/test/JUnitAdapter.java | 45 +++++++++++++ .../jdk/jpackage/test/JavaAppDescTest.java | 15 ++--- .../jdk/jpackage/test/TKitTest.java | 33 ++++++---- .../jdk/jpackage/test/TestSuite.java | 63 ------------------- .../helpers/jdk/jpackage/test/Main.java | 7 ++- .../helpers/jdk/jpackage/test/TKit.java | 22 +++++++ .../jdk/jpackage/test/TestBuilder.java | 44 ++++++++++--- .../jdk/jpackage/test/TestInstance.java | 12 ++-- 11 files changed, 168 insertions(+), 141 deletions(-) create mode 100644 test/jdk/tools/jpackage/helpers-test/TEST.properties create mode 100644 test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java delete mode 100644 test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TestSuite.java diff --git a/test/jdk/tools/jpackage/helpers-test/TEST.properties b/test/jdk/tools/jpackage/helpers-test/TEST.properties new file mode 100644 index 0000000000000..bbb038c4ffa2f --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/TEST.properties @@ -0,0 +1,7 @@ +JUnit.dirs = . + +modules=jdk.jpackage/jdk.jpackage.internal:+open \ + jdk.jpackage/jdk.jpackage.internal.util:+open \ + jdk.jpackage/jdk.jpackage.internal.util.function:+open \ + java.base/jdk.internal.util \ + jdk.jlink/jdk.tools.jlink.internal diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java index d439452ffa0c6..d9daf317964af 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java @@ -41,16 +41,10 @@ import jdk.jpackage.test.Annotations.Test; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; -/* - * @test - * @summary Test jpackage test library's annotation processor - * @library /test/jdk/tools/jpackage/helpers - * @build jdk.jpackage.test.* - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.AnnotationsTest - */ -public class AnnotationsTest { +public class AnnotationsTest extends JUnitAdapter { - public static void main(String... args) { + @org.junit.jupiter.api.Test + public void test() { runTests(List.of(BasicTest.class, ParameterizedInstanceTest.class)); for (var os : OperatingSystem.values()) { try { diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/DirectoryContentVerifierTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/DirectoryContentVerifierTest.java index f74719880512f..ea69a525df929 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/DirectoryContentVerifierTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/DirectoryContentVerifierTest.java @@ -22,7 +22,11 @@ */ package jdk.jpackage.test; -import java.io.IOException; +import static java.util.stream.Collectors.toSet; +import static jdk.jpackage.test.DirectoryContentVerifierTest.AssertType.CONTAINS; +import static jdk.jpackage.test.DirectoryContentVerifierTest.AssertType.MATCH; +import static jdk.jpackage.test.TKit.assertAssert; + import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -30,16 +34,12 @@ import java.util.List; import java.util.Set; import java.util.function.BiConsumer; -import static java.util.stream.Collectors.toSet; import java.util.stream.Stream; -import jdk.jpackage.test.Annotations.Parameters; +import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; -import static jdk.jpackage.test.DirectoryContentVerifierTest.AssertType.CONTAINS; -import static jdk.jpackage.test.DirectoryContentVerifierTest.AssertType.MATCH; import jdk.jpackage.test.TKit.DirectoryContentVerifier; -import static jdk.jpackage.test.TKit.assertAssert; -public class DirectoryContentVerifierTest { +public class DirectoryContentVerifierTest extends JUnitAdapter { enum AssertType { MATCH(DirectoryContentVerifier::match), @@ -105,7 +105,6 @@ ArgsBuilder expectFail() { private boolean success = true; } - @Parameters public static Collection input() { List data = new ArrayList<>(); buildArgs().applyVariantsTo(data); @@ -127,35 +126,23 @@ public static Collection input() { return data; } - public DirectoryContentVerifierTest(String[] expectedPaths, String[] actualPaths, - AssertType assertOp, Boolean success) { - this.expectedPaths = conv(expectedPaths); - this.actualPaths = conv(actualPaths); - this.assertOp = assertOp; - this.success = success; - } - @Test - public void test() { - TKit.withTempDirectory("basedir", this::test); - } - - private void test(Path basedir) throws IOException { - for (var path : actualPaths) { - Files.createFile(basedir.resolve(path)); - } + @ParameterSupplier("input") + public void test(String[] expectedPaths, String[] actualPaths, AssertType assertOp, Boolean success) { + final var expectedPathsAsSet = conv(expectedPaths); + final var actualPathsAsSet = conv(actualPaths); + TKit.withTempDirectory("basedir", basedir -> { + for (var path : actualPathsAsSet) { + Files.createFile(basedir.resolve(path)); + } - var testee = TKit.assertDirectoryContent(basedir); + var testee = TKit.assertDirectoryContent(basedir); - assertAssert(success, () -> assertOp.assertFunc.accept(testee, expectedPaths)); + assertAssert(success, () -> assertOp.assertFunc.accept(testee, expectedPathsAsSet)); + }); } private static Set conv(String... paths) { return Stream.of(paths).map(Path::of).collect(toSet()); } - - private final Set expectedPaths; - private final Set actualPaths; - private final AssertType assertOp; - private final boolean success; } diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java new file mode 100644 index 0000000000000..47df38cd8c8f3 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import java.nio.file.Path; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +public class JUnitAdapter { + + JUnitAdapter() { + if (System.getProperty("test.src") == null) { + // Was called by somebody else but not by jtreg + System.setProperty("test.src", Path.of("@@openJdkDir@@/test/jdk/tools/jpackage").toString()); + } + } + + @Test + void runJPackageTests(@TempDir Path tempDir) throws Throwable { + Main.main(TestBuilder.build().workDirRoot(tempDir), new String [] { + "--jpt-before-run=jdk.jpackage.test.JPackageCommand.useToolProviderByDefault", + "--jpt-run=" + getClass().getName() + }); + } +} diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JavaAppDescTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JavaAppDescTest.java index a2cde44f00951..50f1992f79601 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JavaAppDescTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JavaAppDescTest.java @@ -26,18 +26,14 @@ import java.util.List; import java.util.function.UnaryOperator; import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Annotations.Parameters; -public class JavaAppDescTest { - - public JavaAppDescTest(JavaAppDesc expectedAppDesc, JavaAppDesc actualAppDesc) { - this.expectedAppDesc = expectedAppDesc; - this.actualAppDesc = actualAppDesc; - } +public class JavaAppDescTest extends JUnitAdapter { @Test - public void test() { + @ParameterSupplier("input") + public void test(JavaAppDesc expectedAppDesc, JavaAppDesc actualAppDesc) { TKit.assertEquals(expectedAppDesc.toString(), actualAppDesc.toString(), null); TKit.assertTrue(expectedAppDesc.equals(actualAppDesc), null); } @@ -53,7 +49,6 @@ public static void testClassFilePath(String... args) { appDesc).classFilePath().toString(), null); } - @Parameters public static List input() { return List.of(new Object[][] { createTestCase("", "hello.jar:Hello"), @@ -93,6 +88,4 @@ private static JavaAppDesc[] createTestCase(String appDesc, UnaryOperator assertTestsData() { List data = new ArrayList<>(); @@ -63,6 +63,12 @@ public static Collection assertTestsData() { data.addAll(List.of(assertFunc.args(7, 7).pass().expectLog("assertEquals(7)").createForMessage("Owl"))); data.addAll(List.of(assertFunc.args(7, 10).fail().expectLog("Expected [7]. Actual [10]").createForMessage("Owl"))); + assertFunc = MethodCallConfig.build("assertEquals", boolean.class, boolean.class, String.class); + data.addAll(List.of(assertFunc.args(true, true).pass().expectLog("assertEquals(true)").createForMessage("Emu"))); + data.addAll(List.of(assertFunc.args(false, false).pass().expectLog("assertEquals(false)").createForMessage("Emu"))); + data.addAll(List.of(assertFunc.args(true, false).fail().expectLog("Expected [true]. Actual [false]").createForMessage("Emu"))); + data.addAll(List.of(assertFunc.args(false, true).fail().expectLog("Expected [false]. Actual [true]").createForMessage("Emu"))); + assertFunc = MethodCallConfig.build("assertNotEquals", String.class, String.class, String.class); data.addAll(List.of(assertFunc.args("a", "b").pass().expectLog("assertNotEquals(a, b)").createForMessage("Tit"))); data.addAll(List.of(assertFunc.args("a", "a").fail().expectLog("Unexpected [a] value").createForMessage("Tit"))); @@ -71,6 +77,12 @@ public static Collection assertTestsData() { data.addAll(List.of(assertFunc.args(7, 10).pass().expectLog("assertNotEquals(7, 10)").createForMessage("Duck"))); data.addAll(List.of(assertFunc.args(7, 7).fail().expectLog("Unexpected [7] value").createForMessage("Duck"))); + assertFunc = MethodCallConfig.build("assertNotEquals", boolean.class, boolean.class, String.class); + data.addAll(List.of(assertFunc.args(true, false).pass().expectLog("assertNotEquals(true, false)").createForMessage("Sparrow"))); + data.addAll(List.of(assertFunc.args(false, true).pass().expectLog("assertNotEquals(false, true)").createForMessage("Sparrow"))); + data.addAll(List.of(assertFunc.args(true, true).fail().expectLog("Unexpected [true] value").createForMessage("Sparrow"))); + data.addAll(List.of(assertFunc.args(false, false).fail().expectLog("Unexpected [false] value").createForMessage("Sparrow"))); + assertFunc = MethodCallConfig.build("assertNull", Object.class, String.class); data.addAll(List.of(assertFunc.args((Object) null).pass().expectLog("assertNull()").createForMessage("Ibis"))); data.addAll(List.of(assertFunc.args("v").fail().expectLog("Unexpected not null value [v]").createForMessage("Ibis"))); @@ -191,12 +203,9 @@ Builder withAutoExpectLogPrefix(boolean v) { } } - public TKitTest(MethodCallConfig methodCall) { - this.methodCall = methodCall; - } - @Test - public void test() { + @ParameterSupplier("assertTestsData") + public void test(MethodCallConfig methodCall) { runAssertWithExpectedLogOutput(() -> { methodCall.method.invoke(null, methodCall.args); }, methodCall.expectFail, methodCall.expectLog); @@ -238,7 +247,5 @@ private static String concatMessages(String msg, String msg2) { return msg; } - private final MethodCallConfig methodCall; - private static final int LOG_MSG_TIMESTAMP_LENGTH = "[HH:mm:ss.SSS] ".length(); } diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TestSuite.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TestSuite.java deleted file mode 100644 index f9dda8514146d..0000000000000 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TestSuite.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.test; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; - -/* - * @test - * @summary Unit tests for jpackage test library - * @library /test/jdk/tools/jpackage/helpers - * @library /test/jdk/tools/jpackage/helpers-test - * @build jdk.jpackage.test.* - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.TestSuite - */ - -public final class TestSuite { - public static void main(String args[]) throws Throwable { - final var pkgName = TestSuite.class.getPackageName(); - final var javaSuffix = ".java"; - final var testSrcNameSuffix = "Test" + javaSuffix; - - final var unitTestDir = TKit.TEST_SRC_ROOT.resolve(Path.of("helpers-test", pkgName.split("\\."))); - - final List runTestArgs = new ArrayList<>(); - runTestArgs.addAll(List.of(args)); - - try (var javaSources = Files.list(unitTestDir)) { - runTestArgs.addAll(javaSources.filter(path -> { - return path.getFileName().toString().endsWith(testSrcNameSuffix); - }).map(path -> { - var filename = path.getFileName().toString(); - return String.join(".", pkgName, filename.substring(0, filename.length() - javaSuffix.length())); - }).map(testClassName -> { - return "--jpt-run=" + testClassName; - }).toList()); - } - - Main.main(runTestArgs.toArray(String[]::new)); - } -} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java index 5919d8361c432..439479a666ec0 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java @@ -38,10 +38,15 @@ public final class Main { + public static void main(String args[]) throws Throwable { + main(TestBuilder.build(), args); + } + + public static void main(TestBuilder.Builder builder, String args[]) throws Throwable { boolean listTests = false; List tests = new ArrayList<>(); - try (TestBuilder testBuilder = new TestBuilder(tests::add)) { + try (TestBuilder testBuilder = builder.testConsumer(tests::add).create()) { Deque argsAsList = new ArrayDeque<>(List.of(args)); while (!argsAsList.isEmpty()) { var arg = argsAsList.pop(); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index d3473952cf8d0..86ff061d5912e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -609,6 +609,28 @@ public static void assertNotEquals(long expected, long actual, String msg) { actual), msg)); } + public static void assertEquals(boolean expected, boolean actual, String msg) { + currentTest.notifyAssert(); + if (expected != actual) { + error(concatMessages(String.format( + "Expected [%s]. Actual [%s]", expected, actual), + msg)); + } + + traceAssert(concatMessages(String.format("assertEquals(%s)", expected), msg)); + } + + public static void assertNotEquals(boolean expected, boolean actual, String msg) { + currentTest.notifyAssert(); + if (expected == actual) { + error(concatMessages(String.format("Unexpected [%s] value", actual), + msg)); + } + + traceAssert(concatMessages(String.format("assertNotEquals(%s, %s)", expected, + actual), msg)); + } + public static void assertEquals(String expected, String actual, String msg) { currentTest.notifyAssert(); if ((actual != null && !actual.equals(expected)) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java index 195d1ea3936b9..17c0f131af377 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java @@ -23,9 +23,13 @@ package jdk.jpackage.test; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; +import static jdk.jpackage.test.TestMethodSupplier.MethodQuery.fromQualifiedMethodName; + import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Comparator; import java.util.HashSet; @@ -38,14 +42,12 @@ import java.util.function.UnaryOperator; import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.jpackage.internal.util.function.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingFunction; import jdk.jpackage.test.Annotations.AfterEach; import jdk.jpackage.test.Annotations.BeforeEach; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.internal.util.function.ThrowingConsumer; -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; -import jdk.jpackage.internal.util.function.ThrowingFunction; import jdk.jpackage.test.TestMethodSupplier.InvalidAnnotationException; -import static jdk.jpackage.test.TestMethodSupplier.MethodQuery.fromQualifiedMethodName; final class TestBuilder implements AutoCloseable { @@ -54,8 +56,35 @@ public void close() { flushTestGroup(); } - TestBuilder(Consumer testConsumer) { + static Builder build() { + return new Builder(); + } + + final static class Builder { + private Builder() { + } + + Builder testConsumer(Consumer v) { + testConsumer = v; + return this; + } + + Builder workDirRoot(Path v) { + workDirRoot = v; + return this; + } + + TestBuilder create() { + return new TestBuilder(testConsumer, workDirRoot); + } + + private Consumer testConsumer; + private Path workDirRoot = Path.of(""); + } + + private TestBuilder(Consumer testConsumer, Path workDirRoot) { this.testMethodSupplier = TestBuilderConfig.getDefault().createTestMethodSupplier(); + this.workDirRoot = Objects.requireNonNull(workDirRoot); argProcessors = Map.of( CMDLINE_ARG_PREFIX + "after-run", arg -> getJavaMethodsFromArg(arg).map( @@ -88,7 +117,7 @@ public void close() { CMDLINE_ARG_PREFIX + "dry-run", arg -> dryRun = true ); - this.testConsumer = testConsumer; + this.testConsumer = Objects.requireNonNull(testConsumer); clear(); } @@ -188,7 +217,7 @@ private void createTestInstance(MethodCall testBody) { } TestInstance test = new TestInstance(testBody, curBeforeActions, - curAfterActions, dryRun); + curAfterActions, dryRun, workDirRoot); if (includedTests == null) { trace(String.format("Create: %s", test.fullName())); } @@ -348,6 +377,7 @@ static void trace(String msg) { private final TestMethodSupplier testMethodSupplier; private final Map> argProcessors; private final Consumer testConsumer; + private final Path workDirRoot; private List testGroup; private List> beforeActions; private List> afterActions; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java index dd1e46eb09e4e..ca9523d576067 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java @@ -150,7 +150,7 @@ static TestDesc create(Method m, Object... args) { private String instanceArgs; } - TestInstance(ThrowingRunnable testBody) { + TestInstance(ThrowingRunnable testBody, Path workDirRoot) { assertCount = 0; this.testConstructor = (unused) -> null; this.testBody = (unused) -> testBody.run(); @@ -158,11 +158,11 @@ static TestDesc create(Method m, Object... args) { this.afterActions = Collections.emptyList(); this.testDesc = TestDesc.createBuilder().get(); this.dryRun = false; - this.workDir = createWorkDirName(testDesc); + this.workDir = workDirRoot.resolve(createWorkDirPath(testDesc)); } TestInstance(MethodCall testBody, List> beforeActions, - List> afterActions, boolean dryRun) { + List> afterActions, boolean dryRun, Path workDirRoot) { assertCount = 0; this.testConstructor = v -> ((MethodCall)v).newInstance(); this.testBody = testBody; @@ -170,7 +170,7 @@ static TestDesc create(Method m, Object... args) { this.afterActions = afterActions; this.testDesc = testBody.createDescription(); this.dryRun = dryRun; - this.workDir = createWorkDirName(testDesc); + this.workDir = workDirRoot.resolve(createWorkDirPath(testDesc)); } void notifyAssert() { @@ -276,8 +276,8 @@ private static boolean isCalledByJavatest() { return false; } - private static Path createWorkDirName(TestDesc testDesc) { - Path result = Path.of("."); + private static Path createWorkDirPath(TestDesc testDesc) { + Path result = Path.of(""); if (!isCalledByJavatest()) { result = result.resolve(testDesc.clazz.getSimpleName()); } From 115f4ef7899ca3e7c0a64730d68527955cb9744a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 12 Feb 2025 13:43:07 -0500 Subject: [PATCH 0282/1101] Make junit pass --- test/jdk/tools/jpackage/helpers-test/TEST.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/jdk/tools/jpackage/helpers-test/TEST.properties b/test/jdk/tools/jpackage/helpers-test/TEST.properties index bbb038c4ffa2f..1830ea05443bd 100644 --- a/test/jdk/tools/jpackage/helpers-test/TEST.properties +++ b/test/jdk/tools/jpackage/helpers-test/TEST.properties @@ -1,5 +1,7 @@ JUnit.dirs = . +lib.dirs = /test/jdk/tools/jpackage/helpers /test/jdk/tools/jpackage/helpers-test + modules=jdk.jpackage/jdk.jpackage.internal:+open \ jdk.jpackage/jdk.jpackage.internal.util:+open \ jdk.jpackage/jdk.jpackage.internal.util.function:+open \ From 2d929b1f394eb14bc2e11ffe251f29f7c8d7f719 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 08:24:05 -0500 Subject: [PATCH 0283/1101] Manual merge --- .../jdk/jpackage/test/AnnotationsTest.java | 38 ++++++++++------- .../jdk/jpackage/test/JUnitAdapter.java | 42 +++++++++++++++++-- .../jdk/jpackage/test/TKitTest.java | 24 +++-------- 3 files changed, 67 insertions(+), 37 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java index d9daf317964af..fe94720cba5d1 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java @@ -23,6 +23,9 @@ package jdk.jpackage.test; import static java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE; +import static java.util.stream.Collectors.toMap; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + import java.lang.reflect.Method; import java.nio.file.Path; import java.time.LocalDate; @@ -32,28 +35,33 @@ import java.util.List; import java.util.Optional; import java.util.Set; -import static java.util.stream.Collectors.toMap; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.ValueSource; public class AnnotationsTest extends JUnitAdapter { - @org.junit.jupiter.api.Test - public void test() { - runTests(List.of(BasicTest.class, ParameterizedInstanceTest.class)); - for (var os : OperatingSystem.values()) { - try { - TestBuilderConfig.setOperatingSystem(os); - TKit.log("Current operating system: " + os); - runTests(List.of(IfOSTest.class)); - } finally { - TestBuilderConfig.setDefaults(); - } + @ParameterizedTest + @ValueSource(classes = {BasicTest.class, ParameterizedInstanceTest.class}) + public void test(Class clazz) { + runTests(List.of(clazz)); + } + + @ParameterizedTest + @EnumSource(OperatingSystem.class) + public void testIfOSTest(OperatingSystem os) { + try { + TestBuilderConfig.setOperatingSystem(os); + TKit.log("Current operating system: " + os); + runTests(List.of(IfOSTest.class)); + } finally { + TestBuilderConfig.setDefaults(); } } @@ -308,12 +316,14 @@ private static void runTests(List> tests) return String.format("--jpt-run=%s", test.getName()); }).toArray(String[]::new); + final List log; try { - Main.main(args); + log = captureJPackageTestLog(() -> Main.main(args)); assertRecordedTestDescs(expectedTestDescs); } catch (Throwable t) { t.printStackTrace(System.err); System.exit(1); + return; } } diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java index 47df38cd8c8f3..c5c7783d50715 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java @@ -22,7 +22,19 @@ */ package jdk.jpackage.test; +import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Path; +import java.util.List; +import jdk.jpackage.internal.util.function.ThrowingRunnable; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -37,9 +49,31 @@ public class JUnitAdapter { @Test void runJPackageTests(@TempDir Path tempDir) throws Throwable { - Main.main(TestBuilder.build().workDirRoot(tempDir), new String [] { - "--jpt-before-run=jdk.jpackage.test.JPackageCommand.useToolProviderByDefault", - "--jpt-run=" + getClass().getName() - }); + if (!getClass().equals(JUnitAdapter.class)) { + Main.main(TestBuilder.build().workDirRoot(tempDir), new String [] { + "--jpt-before-run=jdk.jpackage.test.JPackageCommand.useToolProviderByDefault", + "--jpt-run=" + getClass().getName() + }); + } + } + + static List captureJPackageTestLog(ThrowingRunnable runnable) { + final var buf = new ByteArrayOutputStream(); + try (PrintStream ps = new PrintStream(buf, true, StandardCharsets.UTF_8)) { + TKit.withExtraLogStream(runnable, ps); + } + + try (final var in = new ByteArrayInputStream(buf.toByteArray()); + final var reader = new InputStreamReader(in, StandardCharsets.UTF_8); + final var bufReader = new BufferedReader(reader)) { + return bufReader.lines().map(line -> { + // Skip timestamp + return line.substring(LOG_MSG_TIMESTAMP_LENGTH); + }).toList(); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } } + + private static final int LOG_MSG_TIMESTAMP_LENGTH = "[HH:mm:ss.SSS] ".length(); } diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java index e025c9fe91de9..7952804d5cacd 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java @@ -220,23 +220,11 @@ private static void runAssertWithExpectedLogOutput(ThrowingRunnable action, private static void runWithExpectedLogOutput(ThrowingRunnable action, String... expectLogStrings) { - final var buf = new ByteArrayOutputStream(); - try (PrintStream ps = new PrintStream(buf, true, StandardCharsets.UTF_8)) { - TKit.withExtraLogStream(action, ps); - } finally { - toRunnable(() -> { - var output = new BufferedReader(new InputStreamReader( - new ByteArrayInputStream(buf.toByteArray()), - StandardCharsets.UTF_8)).lines().map(line -> { - // Skip timestamp - return line.substring(LOG_MSG_TIMESTAMP_LENGTH); - }).toList(); - if (output.size() == 1 && expectLogStrings.length == 1) { - TKit.assertEquals(expectLogStrings[0], output.get(0), null); - } else { - TKit.assertStringListEquals(List.of(expectLogStrings), output, null); - } - }).run(); + final var output = JUnitAdapter.captureJPackageTestLog(action); + if (output.size() == 1 && expectLogStrings.length == 1) { + TKit.assertEquals(expectLogStrings[0], output.get(0), null); + } else { + TKit.assertStringListEquals(List.of(expectLogStrings), output, null); } } @@ -246,6 +234,4 @@ private static String concatMessages(String msg, String msg2) { } return msg; } - - private static final int LOG_MSG_TIMESTAMP_LENGTH = "[HH:mm:ss.SSS] ".length(); } From c66c591544fef43e2a881ed919d120ce33f8a189 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 12 Feb 2025 16:22:27 -0500 Subject: [PATCH 0284/1101] Fix AnnotationsTest to create test work directory in temp directory supplied by JUnit --- .../jdk/jpackage/test/AnnotationsTest.java | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java index fe94720cba5d1..8bb12951f1348 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java @@ -41,6 +41,7 @@ import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.ValueSource; @@ -49,17 +50,17 @@ public class AnnotationsTest extends JUnitAdapter { @ParameterizedTest @ValueSource(classes = {BasicTest.class, ParameterizedInstanceTest.class}) - public void test(Class clazz) { - runTests(List.of(clazz)); + public void test(Class clazz, @TempDir Path workDir) { + runTest(clazz, workDir); } @ParameterizedTest @EnumSource(OperatingSystem.class) - public void testIfOSTest(OperatingSystem os) { + public void testIfOSTest(OperatingSystem os, @TempDir Path workDir) { try { TestBuilderConfig.setOperatingSystem(os); TKit.log("Current operating system: " + os); - runTests(List.of(IfOSTest.class)); + runTest(IfOSTest.class, workDir); } finally { TestBuilderConfig.setDefaults(); } @@ -302,23 +303,19 @@ public static Collection dateSupplier() { }); } - private static void runTests(List> tests) { + private static void runTest(Class test, Path workDir) { ACTUAL_TEST_DESCS.get().clear(); - var expectedTestDescs = tests.stream() - .map(AnnotationsTest::getExpectedTestDescs) - .flatMap(x -> x) + var expectedTestDescs = getExpectedTestDescs(test) // Collect in the map to check for collisions for free .collect(toMap(x -> x, x -> "")) .keySet(); - var args = tests.stream().map(test -> { - return String.format("--jpt-run=%s", test.getName()); - }).toArray(String[]::new); + var args = new String[] { String.format("--jpt-run=%s", test.getName()) }; final List log; try { - log = captureJPackageTestLog(() -> Main.main(args)); + log = captureJPackageTestLog(() -> Main.main(TestBuilder.build().workDirRoot(workDir), args)); assertRecordedTestDescs(expectedTestDescs); } catch (Throwable t) { t.printStackTrace(System.err); From 45a2ab57e2a9936a0ae27a526dd7e098e993caeb Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 08:36:04 -0500 Subject: [PATCH 0285/1101] Undo unrelated change --- .../helpers-test/jdk/jpackage/test/AnnotationsTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java index 8bb12951f1348..f6ec763ad4fbc 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java @@ -313,9 +313,8 @@ private static void runTest(Class test, Path wo var args = new String[] { String.format("--jpt-run=%s", test.getName()) }; - final List log; try { - log = captureJPackageTestLog(() -> Main.main(TestBuilder.build().workDirRoot(workDir), args)); + Main.main(TestBuilder.build().workDirRoot(workDir), args); assertRecordedTestDescs(expectedTestDescs); } catch (Throwable t) { t.printStackTrace(System.err); From c216296518b1f44232f126ce39c08be829f24eba Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 12 Feb 2025 16:22:44 -0500 Subject: [PATCH 0286/1101] Minor --- .../jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java index c5c7783d50715..7bf1f57a25494 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java @@ -48,9 +48,9 @@ public class JUnitAdapter { } @Test - void runJPackageTests(@TempDir Path tempDir) throws Throwable { + void runJPackageTests(@TempDir Path workDir) throws Throwable { if (!getClass().equals(JUnitAdapter.class)) { - Main.main(TestBuilder.build().workDirRoot(tempDir), new String [] { + Main.main(TestBuilder.build().workDirRoot(workDir), new String [] { "--jpt-before-run=jdk.jpackage.test.JPackageCommand.useToolProviderByDefault", "--jpt-run=" + getClass().getName() }); From d0c815d8dd4b4c91e46a75e276d9d5daaca7092f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 09:32:47 -0500 Subject: [PATCH 0287/1101] Remove TKit.assertEquals(boolean) and TKit.assertNotEquals(boolean). They belong to different branch --- .../jdk/jpackage/test/TKitTest.java | 18 --------------- .../helpers/jdk/jpackage/test/TKit.java | 22 ------------------- 2 files changed, 40 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java index 7952804d5cacd..4cddb1eb91249 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java @@ -25,13 +25,7 @@ import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStreamReader; -import java.io.PrintStream; import java.lang.reflect.Method; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -63,12 +57,6 @@ public static Collection assertTestsData() { data.addAll(List.of(assertFunc.args(7, 7).pass().expectLog("assertEquals(7)").createForMessage("Owl"))); data.addAll(List.of(assertFunc.args(7, 10).fail().expectLog("Expected [7]. Actual [10]").createForMessage("Owl"))); - assertFunc = MethodCallConfig.build("assertEquals", boolean.class, boolean.class, String.class); - data.addAll(List.of(assertFunc.args(true, true).pass().expectLog("assertEquals(true)").createForMessage("Emu"))); - data.addAll(List.of(assertFunc.args(false, false).pass().expectLog("assertEquals(false)").createForMessage("Emu"))); - data.addAll(List.of(assertFunc.args(true, false).fail().expectLog("Expected [true]. Actual [false]").createForMessage("Emu"))); - data.addAll(List.of(assertFunc.args(false, true).fail().expectLog("Expected [false]. Actual [true]").createForMessage("Emu"))); - assertFunc = MethodCallConfig.build("assertNotEquals", String.class, String.class, String.class); data.addAll(List.of(assertFunc.args("a", "b").pass().expectLog("assertNotEquals(a, b)").createForMessage("Tit"))); data.addAll(List.of(assertFunc.args("a", "a").fail().expectLog("Unexpected [a] value").createForMessage("Tit"))); @@ -77,12 +65,6 @@ public static Collection assertTestsData() { data.addAll(List.of(assertFunc.args(7, 10).pass().expectLog("assertNotEquals(7, 10)").createForMessage("Duck"))); data.addAll(List.of(assertFunc.args(7, 7).fail().expectLog("Unexpected [7] value").createForMessage("Duck"))); - assertFunc = MethodCallConfig.build("assertNotEquals", boolean.class, boolean.class, String.class); - data.addAll(List.of(assertFunc.args(true, false).pass().expectLog("assertNotEquals(true, false)").createForMessage("Sparrow"))); - data.addAll(List.of(assertFunc.args(false, true).pass().expectLog("assertNotEquals(false, true)").createForMessage("Sparrow"))); - data.addAll(List.of(assertFunc.args(true, true).fail().expectLog("Unexpected [true] value").createForMessage("Sparrow"))); - data.addAll(List.of(assertFunc.args(false, false).fail().expectLog("Unexpected [false] value").createForMessage("Sparrow"))); - assertFunc = MethodCallConfig.build("assertNull", Object.class, String.class); data.addAll(List.of(assertFunc.args((Object) null).pass().expectLog("assertNull()").createForMessage("Ibis"))); data.addAll(List.of(assertFunc.args("v").fail().expectLog("Unexpected not null value [v]").createForMessage("Ibis"))); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index 86ff061d5912e..d3473952cf8d0 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -609,28 +609,6 @@ public static void assertNotEquals(long expected, long actual, String msg) { actual), msg)); } - public static void assertEquals(boolean expected, boolean actual, String msg) { - currentTest.notifyAssert(); - if (expected != actual) { - error(concatMessages(String.format( - "Expected [%s]. Actual [%s]", expected, actual), - msg)); - } - - traceAssert(concatMessages(String.format("assertEquals(%s)", expected), msg)); - } - - public static void assertNotEquals(boolean expected, boolean actual, String msg) { - currentTest.notifyAssert(); - if (expected == actual) { - error(concatMessages(String.format("Unexpected [%s] value", actual), - msg)); - } - - traceAssert(concatMessages(String.format("assertNotEquals(%s, %s)", expected, - actual), msg)); - } - public static void assertEquals(String expected, String actual, String msg) { currentTest.notifyAssert(); if ((actual != null && !actual.equals(expected)) From 840ec5691c986120a7416e2a867fc83a63eb1d64 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 11:54:05 -0500 Subject: [PATCH 0288/1101] Local build tweaks --- .../macosx/classes/jdk/jpackage/internal/MacDmgBundler.java | 6 +++--- .../macosx/classes/jdk/jpackage/internal/MacPkgBundler.java | 6 +++--- test/jdk/tools/jpackage/share/BasicTest.java | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java index 3fa4f3e2259de..8643d8e4fb9fd 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java @@ -545,9 +545,9 @@ private Path buildDMG( Map params, } - ////////////////////////////////////////////////////////////////////////// - // Implement Bundler - ////////////////////////////////////////////////////////////////////////// + /* + * Implement Bundler + */ @Override public String getName() { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index e45e98551d61c..7c20e759b6cb7 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -680,9 +680,9 @@ private Path createPKG(Map params, } } - ////////////////////////////////////////////////////////////////////////// - // Implement Bundler - ////////////////////////////////////////////////////////////////////////// + /* + * Implement Bundler + */ @Override public String getName() { diff --git a/test/jdk/tools/jpackage/share/BasicTest.java b/test/jdk/tools/jpackage/share/BasicTest.java index d6ee40bd61d6d..967ce0ff67c55 100644 --- a/test/jdk/tools/jpackage/share/BasicTest.java +++ b/test/jdk/tools/jpackage/share/BasicTest.java @@ -78,7 +78,7 @@ public static Collection addModulesParams() { private static boolean isAllModulePathCapable() { Path jmods = Path.of(System.getProperty("java.home"), "jmods"); boolean noJmods = Files.notExists(jmods); - if (LinkableRuntimeImage.isLinkableRuntime() && noJmods) { + if (noJmods) { TKit.trace("ALL-MODULE-PATH test skipped for linkable run-time image"); return false; } From 5c6a8c0df75d363d13513fce84679d5a1423fcc2 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 11:54:33 -0500 Subject: [PATCH 0289/1101] Fix merge --- .../jpackage/internal/OSVersionCondition.java | 39 +++++++------------ .../jpackage/internal/WixFragmentBuilder.java | 20 ++++++++-- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/OSVersionCondition.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/OSVersionCondition.java index 80bb0c77625bc..16c399d70acf4 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/OSVersionCondition.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/OSVersionCondition.java @@ -24,8 +24,6 @@ */ package jdk.jpackage.internal; -import static jdk.jpackage.internal.WinMsiBundler.WIN_APP_IMAGE; - import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; @@ -38,8 +36,10 @@ import java.util.Comparator; import java.util.HexFormat; import java.util.List; -import java.util.Map; import java.util.Objects; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.WinMsiPackage; import jdk.jpackage.internal.util.XmlConsumer; @@ -48,17 +48,19 @@ */ record OSVersionCondition(WindowsVersion version) { - static OSVersionCondition createFromAppImage(ApplicationLayout appLayout, Map params) { - Objects.requireNonNull(appLayout); + static OSVersionCondition createFromAppImage(BuildEnv env, Application app) { + Objects.requireNonNull(env); + Objects.requireNonNull(app); final List executables = new ArrayList<>(); - if (!StandardBundlerParam.isRuntimeInstaller(params)) { - final var launcherName = StandardBundlerParam.APP_NAME.fetchFrom(params); - executables.add(appLayout.launchersDirectory().resolve(launcherName + ".exe")); - } + final var appImageLayout = app.imageLayout().resolveAt(env.appImageDir()); - executables.add(appLayout.runtimeDirectory().resolve("bin\\java.dll")); + app.mainLauncher().ifPresent(mainLauncher -> { + ((ApplicationLayout)appImageLayout).launchersDirectory().resolve(mainLauncher.executableNameWithSuffix()); + }); + + executables.add(appImageLayout.runtimeDirectory().resolve("bin\\java.dll")); final var lowestOsVersion = executables.stream() .filter(Files::isRegularFile) @@ -176,21 +178,10 @@ protected Collection getFragmentWriters() { } @Override - void initFromParams(Map params) { - super.initFromParams(params); - - final Path appImageRoot = WIN_APP_IMAGE.fetchFrom(params); - - ApplicationLayout appImageLayout; - if (StandardBundlerParam.isRuntimeInstaller(params)) { - appImageLayout = ApplicationLayout.javaRuntime(); - } else { - appImageLayout = ApplicationLayout.platformAppImage(); - } - - appImageLayout = appImageLayout.resolveAt(appImageRoot); + void initFromParams(BuildEnv env, WinMsiPackage pkg) { + super.initFromParams(env, pkg); - final var cond = OSVersionCondition.createFromAppImage(appImageLayout, params); + final var cond = OSVersionCondition.createFromAppImage(env, pkg.app()); setWixVariable("JpExecutableMajorOSVersion", String.valueOf(cond.version().majorOSVersion)); setWixVariable("JpExecutableMinorOSVersion", String.valueOf(cond.version().minorOSVersion)); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java index 32e32908e8890..7d86849b1662f 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,6 @@ import java.util.regex.Pattern; import javax.xml.stream.XMLStreamWriter; import jdk.jpackage.internal.util.XmlConsumer; -import jdk.jpackage.internal.OverridableResource.Source; import jdk.internal.util.Architecture; import jdk.jpackage.internal.WixSourceConverter.ResourceGroup; import jdk.jpackage.internal.WixToolset.WixToolsetType; @@ -62,11 +61,15 @@ final void setOutputFileName(String v) { outputFileName = v; } + final void setDefaultResourceName(String v) { + defaultResourceName = v; + } + void initFromParams(BuildEnv env, WinMsiPackage pkg) { wixVariables = null; additionalResources = null; configRoot = env.configDir(); - fragmentResource = env.createResource(outputFileName).setSourceOrder(Source.ResourceDir); + fragmentResource = env.createResource(defaultResourceName).setPublicName(outputFileName); } List getLoggableWixFeatures() { @@ -81,7 +84,10 @@ void configureWixPipeline(WixPipeline.Builder wixPipeline) { void addFilesToConfigRoot() throws IOException { Path fragmentPath = configRoot.resolve(outputFileName); - if (fragmentResource.saveToFile(fragmentPath) == null) { + final var src = fragmentResource.saveToStream(null); + if (src == null) { + // There is no predefined resource for the fragment. + // The fragment should be built in the format matching the version of the WiX Toolkit. createWixSource(fragmentPath, xml -> { for (var fragmentWriter : getFragmentWriters()) { xml.writeStartElement("Fragment"); @@ -89,6 +95,11 @@ void addFilesToConfigRoot() throws IOException { xml.writeEndElement(); // } }); + } else { + // Fragment is picked from the resource. May require conversion. + final var resourceGroup = new ResourceGroup(getWixType()); + resourceGroup.addResource(fragmentResource, fragmentPath); + resourceGroup.saveResources(); } if (additionalResources != null) { @@ -236,6 +247,7 @@ private String escape(CharSequence str) { private WixVariables wixVariables; private ResourceGroup additionalResources; private OverridableResource fragmentResource; + private String defaultResourceName; private String outputFileName; private Path configRoot; } From d99fa321c8a070d8a84c7b9824bfeb7fb760e03b Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Fri, 7 Feb 2025 19:58:51 +0000 Subject: [PATCH 0290/1101] 8349509: [macos] Clean up macOS dead code in jpackage Reviewed-by: asemenyuk --- .../jdk/jpackage/internal/MacDmgBundler.java | 14 ++++---------- .../jdk/jpackage/internal/MacPkgBundler.java | 10 +--------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java index 8643d8e4fb9fd..85776f7710ae8 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,13 +68,6 @@ public class MacDmgBundler extends MacBaseInstallerBundler { static final String DEFAULT_LICENSE_PLIST="lic_template.plist"; - public static final BundlerParamInfo INSTALLER_SUFFIX = - new BundlerParamInfo<> ( - "mac.dmg.installerName.suffix", - String.class, - params -> "", - (s, p) -> s); - public Path bundle(Map params, Path outdir) throws PackagerException { Log.verbose(MessageFormat.format(I18N.getString("message.building-dmg"), @@ -281,9 +274,10 @@ private Path buildDMG( Map params, Files.createDirectories(imagesRoot); } - Path protoDMG = imagesRoot.resolve(APP_NAME.fetchFrom(params) +"-tmp.dmg"); + Path protoDMG = imagesRoot.resolve(APP_NAME.fetchFrom(params) + + "-tmp.dmg"); Path finalDMG = outdir.resolve(MAC_INSTALLER_NAME.fetchFrom(params) - + INSTALLER_SUFFIX.fetchFrom(params) + ".dmg"); + + ".dmg"); Path srcFolder = appLocation.getParent(); if (StandardBundlerParam.isRuntimeInstaller(params)) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 7c20e759b6cb7..2794ea552d099 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -140,13 +140,6 @@ public class MacPkgBundler extends MacBaseInstallerBundler { }, (s, p) -> s); - public static final BundlerParamInfo INSTALLER_SUFFIX = - new BundlerParamInfo<> ( - "mac.pkg.installerName.suffix", - String.class, - params -> "", - (s, p) -> s); - public Path bundle(Map params, Path outdir) throws PackagerException { Log.verbose(MessageFormat.format(I18N.getString("message.building-pkg"), @@ -595,7 +588,6 @@ private Path createPKG(Map params, // build final package Path finalPKG = outdir.resolve(MAC_INSTALLER_NAME.fetchFrom(params) - + INSTALLER_SUFFIX.fetchFrom(params) + ".pkg"); Files.createDirectories(outdir); From 7948e2119eaffd2c6e7af6927c54c96c8c9a42bf Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 16:46:37 -0500 Subject: [PATCH 0291/1101] LocalizedExceptionBuilder: noFormat -> format --- .../internal/util/LocalizedExceptionBuilder.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java index d7b3404395cc6..0f7eca4832690 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java @@ -76,7 +76,7 @@ final public U create(BiFunction exc * @see #noformat() */ final public T format(boolean v) { - noFormat = !v; + format = v; return thiz(); } @@ -124,12 +124,12 @@ final public T cause(Throwable v) { * @return this */ final public T causeAndMessage(Throwable t) { - boolean oldNoFormat = noFormat; - return noformat().message(t.getMessage()).cause(t).format(oldNoFormat); + boolean oldformat = format; + return noformat().message(t.getMessage()).cause(t).format(oldformat); } final protected String formatString(String keyId, Object... args) { - if (!noFormat) { + if (format) { return i18n.format(keyId, args); } else if (args.length == 0) { return keyId; @@ -143,7 +143,7 @@ private T thiz() { return (T)this; } - private boolean noFormat; + private boolean format = true; private String msg; private Throwable cause; From 6d91d85d3327614644325bafa127cb5277f70715 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 16:47:04 -0500 Subject: [PATCH 0292/1101] Add BuildEnv.verbose() --- .../classes/jdk/jpackage/internal/BuildEnv.java | 14 +++++++++++++- .../jdk/jpackage/internal/BuildEnvBuilder.java | 9 ++++++++- .../jdk/jpackage/internal/BuildEnvFromParams.java | 8 +++++--- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java index 1297595ec7104..7f970ede59bcd 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java @@ -32,6 +32,8 @@ interface BuildEnv { Path buildRoot(); + boolean verbose(); + Optional resourceDir(); /** @@ -59,13 +61,18 @@ public Path appImageDir() { }; } - static BuildEnv create(Path buildRoot, Optional resourceDir, Class resourceLocator) { + static BuildEnv create(Path buildRoot, Optional resourceDir, boolean verbose, Class resourceLocator) { return new BuildEnv() { @Override public Path buildRoot() { return buildRoot; } + @Override + public boolean verbose() { + return verbose; + } + @Override public Optional resourceDir() { return resourceDir; @@ -95,6 +102,11 @@ final public Path buildRoot() { return target.buildRoot(); } + @Override + final public boolean verbose() { + return target.verbose(); + } + @Override final public Optional resourceDir() { return target.resourceDir(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java index d73dcb75784e8..2e7b3bd222356 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java @@ -58,7 +58,13 @@ BuildEnv create() throws ConfigException { } } - return BuildEnv.withAppImageDir(BuildEnv.create(root, Optional.ofNullable(resourceDir), ResourceLocator.class), appImageDir); + return BuildEnv.withAppImageDir(BuildEnv.create(root, Optional.ofNullable(resourceDir), + verbose, ResourceLocator.class), appImageDir); + } + + BuildEnvBuilder verbose(boolean v) { + verbose = v; + return this; } BuildEnvBuilder resourceDir(Path v) { @@ -87,6 +93,7 @@ static Path defaultAppImageDir(Path root) { private Path appImageDir; private Path resourceDir; + private boolean verbose; private final Path root; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java index 11ec3d1cd8fb9..6cfb8e7960a64 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java @@ -27,17 +27,19 @@ import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; +import static jdk.jpackage.internal.StandardBundlerParam.VERBOSE; import java.util.Map; - import jdk.jpackage.internal.model.ConfigException; final class BuildEnvFromParams { static BuildEnv create(Map params) throws ConfigException { - final var builder = new BuildEnvBuilder(TEMP_ROOT.fetchFrom(params)) - .resourceDir(RESOURCE_DIR.fetchFrom(params)); + final var builder = new BuildEnvBuilder(TEMP_ROOT.fetchFrom(params)); + + RESOURCE_DIR.copyInto(params, builder::resourceDir); + VERBOSE.copyInto(params, builder::verbose); final var app = FromParams.APPLICATION.findIn(params).orElseThrow(); From 0f3275ee118b2e44de13b43f93e7c44150c38e2c Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 16:47:35 -0500 Subject: [PATCH 0293/1101] Better formatting --- .../jdk/jpackage/internal/MacCertificateUtils.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java index 972db5810c01e..93346cd5ed5ed 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java @@ -51,9 +51,14 @@ public static Collection findCertificates(Optional keychain.map(PathUtils::normalizedAbsolutePathString).ifPresent(args::add); return toSupplier(() -> { - final byte[] pemCertificatesBuffer = Executor.of(args.toArray(String[]::new)) + final var output = Executor.of(args.toArray(String[]::new)) .setQuiet(true).saveOutput(true).executeExpectSuccess() - .getOutput().stream().reduce(new StringBuilder(), StringBuilder::append, StringBuilder::append).toString().getBytes(StandardCharsets.US_ASCII); + .getOutput(); + + final byte[] pemCertificatesBuffer = output.stream() + .reduce(new StringBuilder(), + StringBuilder::append, + StringBuilder::append).toString().getBytes(StandardCharsets.US_ASCII); try (var in = new ByteArrayInputStream(pemCertificatesBuffer)) { final var cf = CertificateFactory.getInstance("X.509"); @@ -63,6 +68,9 @@ public static Collection findCertificates(Optional } public static Collection filterX509Certificates(Collection certs) { - return certs.stream().filter(X509Certificate.class::isInstance).map(X509Certificate.class::cast).toList(); + return certs.stream() + .filter(X509Certificate.class::isInstance) + .map(X509Certificate.class::cast) + .toList(); } } From 126afd0763c33920d5343c2a0aaa4614a4e470b3 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 16:49:22 -0500 Subject: [PATCH 0294/1101] Add some validationss --- .../jdk/jpackage/internal/MacApplicationBuilder.java | 10 ++++++++++ .../jdk/jpackage/internal/SigningConfigBuilder.java | 6 ++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java index 7bb4c6d1a20df..1ec208de45470 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java @@ -92,6 +92,8 @@ MacApplication create() throws ConfigException { return createCopyForExternalInfoPlistFile().create(); } + validateAppVersion(app); + final var mixin = new MacApplicationMixin.Stub(validatedIcon(), validatedBundleName(), validatedBundleIdentifier(), validatedCategory(), appStore, createSigningConfig()); @@ -112,6 +114,14 @@ static boolean isValidBundleIdentifier(String id) { return true; } + private static void validateAppVersion(Application app) throws ConfigException { + try { + CFBundleVersion.of(app.version()); + } catch (IllegalArgumentException ex) { + throw I18N.buildConfigException(ex).advice("error.invalid-cfbundle-version.advice").create(); + } + } + private MacApplicationBuilder createCopyForExternalInfoPlistFile() throws ConfigException { try { final var plistFile = AppImageInfoPListFile.loadFromInfoPList(externalInfoPlistFile); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java index 2b1f793ec7e73..910e05b29a1f9 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java @@ -114,10 +114,12 @@ private Optional validatedSigningIdentifier() throws ConfigEx final var signingIdentifiers = signingIdentifierMap.get(certificateNameFilter); switch (signingIdentifiers.size()) { case 0 -> { - break; + throw I18N.buildConfigException("error.explicit-sign-no-cert") + .advice("error.explicit-sign-no-cert.advice").create(); } case 1 -> { - return Optional.of(new SigningIdentifierImpl(signingIdentifiers.get(0), Optional.ofNullable(signingIdentifierPrefix))); + return Optional.of(new SigningIdentifierImpl(signingIdentifiers.get(0), + Optional.ofNullable(signingIdentifierPrefix))); } default -> { // Multiple certificates matching the same criteria found From 95fd5d9ff25ff02e14aee2b8eac0dafcec344184 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 16:50:05 -0500 Subject: [PATCH 0295/1101] Get rid of params in DMG bundler --- .../internal/MacBaseInstallerBundler.java | 12 - .../jdk/jpackage/internal/MacDmgBundler.java | 205 ++++++++---------- 2 files changed, 96 insertions(+), 121 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index 2eefc5e282a88..915ad36d8299b 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -129,18 +129,6 @@ static String getInstallDir( return returnValue; } - // Returns display name of installation directory. Display name is used to - // show user installation location and for well known (default only) we will - // use "Applications" or "JavaVirtualMachines". - static String getInstallDirDisplayName( - Map params) { - if (StandardBundlerParam.isRuntimeInstaller(params)) { - return "JavaVirtualMachines"; - } else { - return "Applications"; - } - } - public MacBaseInstallerBundler() { appImageBundler = new MacAppBundler() .setDependentTask(true); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java index 85776f7710ae8..8ce0d4bcc77f1 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java @@ -25,9 +25,6 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.util.PathGroup; import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -40,24 +37,15 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.ResourceBundle; -import static jdk.jpackage.internal.MacAppImageBuilder.ICON_ICNS; -import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; -import static jdk.jpackage.internal.StandardBundlerParam.createResource; - -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT; -import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; -import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; -import static jdk.jpackage.internal.StandardBundlerParam.VERBOSE; -import static jdk.jpackage.internal.StandardBundlerParam.DMG_CONTENT; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.MacApplication; +import jdk.jpackage.internal.model.MacDmgPackage; +import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.PathGroup; public class MacDmgBundler extends MacBaseInstallerBundler { - private static final ResourceBundle I18N = ResourceBundle.getBundle( - "jdk.jpackage.internal.resources.MacResources"); - // Background image name in resources static final String DEFAULT_BACKGROUND_IMAGE = "background_dmg.tiff"; // Background image name and folder under which it will be stored in DMG @@ -70,25 +58,25 @@ public class MacDmgBundler extends MacBaseInstallerBundler { public Path bundle(Map params, Path outdir) throws PackagerException { + + final var pkg = MacFromParams.DMG_PACKAGE.fetchFrom(params); + var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + Log.verbose(MessageFormat.format(I18N.getString("message.building-dmg"), - APP_NAME.fetchFrom(params))); + pkg.app().name())); IOUtils.writableOutputDir(outdir); - MacFromParams.DMG_PACKAGE.fetchFrom(params); - try { - Path appLocation = prepareAppBundle(params); + env = BuildEnv.withAppImageDir(env, prepareAppBundle(params)); - if (appLocation != null && prepareConfigFiles(appLocation,params)) { - Path configScript = getConfig_Script(params); - if (IOUtils.exists(configScript)) { - IOUtils.run("bash", configScript); - } - - return buildDMG(params, appLocation, outdir); + prepareConfigFiles(pkg, env); + Path configScript = getConfig_Script(pkg, env); + if (IOUtils.exists(configScript)) { + IOUtils.run("bash", configScript); } - return null; + + return buildDMG(pkg, env, outdir); } catch (IOException | PackagerException ex) { Log.verbose(ex); throw new PackagerException(ex); @@ -97,9 +85,12 @@ public Path bundle(Map params, private static final String hdiutil = "/usr/bin/hdiutil"; - private void prepareDMGSetupScript(Path appLocation, - Map params) throws IOException { - Path dmgSetup = getConfig_VolumeScript(params); + private static Path imagesRoot(MacDmgPackage pkg, BuildEnv env) { + return env.buildRoot().resolve("dmg-images"); + } + + private void prepareDMGSetupScript(MacDmgPackage pkg, BuildEnv env) throws IOException { + Path dmgSetup = getConfig_VolumeScript(pkg, env); Log.verbose(MessageFormat.format( I18N.getString("message.preparing-dmg-setup"), dmgSetup.toAbsolutePath().toString())); @@ -107,17 +98,13 @@ private void prepareDMGSetupScript(Path appLocation, // We need to use URL for DMG to find it. We cannot use volume name, since // user might have open DMG with same volume name already. Url should end with // '/' and it should be real path (no symbolic links). - Path imageDir = IMAGES_ROOT.fetchFrom(params); - if (!Files.exists(imageDir)) { - // Create it, since it does not exist - Files.createDirectories(imageDir); - } - Path rootPath = Path.of(imageDir.toString()).toRealPath(); - Path volumePath = rootPath.resolve(APP_NAME.fetchFrom(params)); + Path imageDir = imagesRoot(pkg, env); + Path rootPath = imageDir.toRealPath(); + Path volumePath = rootPath.resolve(pkg.app().name()); String volumeUrl = volumePath.toUri().toString() + File.separator; // Provide full path to background image, so we can find it. - Path bgFile = Path.of(rootPath.toString(), APP_NAME.fetchFrom(params), + Path bgFile = Path.of(rootPath.toString(), pkg.app().name(), BACKGROUND_IMAGE_FOLDER, BACKGROUND_IMAGE); // Prepare DMG setup script @@ -125,94 +112,99 @@ private void prepareDMGSetupScript(Path appLocation, data.put("DEPLOY_VOLUME_URL", volumeUrl); data.put("DEPLOY_BG_FILE", bgFile.toString()); data.put("DEPLOY_VOLUME_PATH", volumePath.toString()); - data.put("DEPLOY_APPLICATION_NAME", APP_NAME.fetchFrom(params)); - String targetItem = (StandardBundlerParam.isRuntimeInstaller(params)) ? - APP_NAME.fetchFrom(params) : appLocation.getFileName().toString(); + data.put("DEPLOY_APPLICATION_NAME", pkg.app().name()); + String targetItem = pkg.isRuntimeInstaller() ? + pkg.app().name() : env.appImageDir().getFileName().toString(); data.put("DEPLOY_TARGET", targetItem); - data.put("DEPLOY_INSTALL_LOCATION", getInstallDir(params, true)); + data.put("DEPLOY_INSTALL_LOCATION", installRoot(pkg).toString()); data.put("DEPLOY_INSTALL_LOCATION_DISPLAY_NAME", - getInstallDirDisplayName(params)); + getInstallDirDisplayName(pkg)); - createResource(DEFAULT_DMG_SETUP_SCRIPT, params) + env.createResource(DEFAULT_DMG_SETUP_SCRIPT) .setCategory(I18N.getString("resource.dmg-setup-script")) .setSubstitutionData(data) .saveToFile(dmgSetup); } - private Path getConfig_VolumeScript(Map params) { - return CONFIG_ROOT.fetchFrom(params).resolve( - APP_NAME.fetchFrom(params) + "-dmg-setup.scpt"); + private static Path installRoot(MacDmgPackage pkg) { + if (pkg.isRuntimeInstaller()) { + return Path.of("/Library/Java/JavaVirtualMachines"); + } else { + return Path.of("/Applications"); + } + } + + // Returns display name of installation directory. Display name is used to + // show user installation location and for well known (default only) we will + // use "Applications" or "JavaVirtualMachines". + private static String getInstallDirDisplayName(MacDmgPackage pkg) { + return installRoot(pkg).getFileName().toString(); } - private Path getConfig_VolumeBackground( - Map params) { - return CONFIG_ROOT.fetchFrom(params).resolve( - APP_NAME.fetchFrom(params) + "-background.tiff"); + private Path getConfig_VolumeScript(MacDmgPackage pkg, BuildEnv env) { + return env.configDir().resolve(pkg.app().name() + "-dmg-setup.scpt"); } - private Path getConfig_VolumeIcon(Map params) { - return CONFIG_ROOT.fetchFrom(params).resolve( - APP_NAME.fetchFrom(params) + "-volume.icns"); + private Path getConfig_VolumeBackground(MacDmgPackage pkg, BuildEnv env) { + return env.configDir().resolve(pkg.app().name() + "-background.tiff"); } - private Path getConfig_LicenseFile(Map params) { - return CONFIG_ROOT.fetchFrom(params).resolve( - APP_NAME.fetchFrom(params) + "-license.plist"); + private Path getConfig_VolumeIcon(MacDmgPackage pkg, BuildEnv env) { + return env.configDir().resolve(pkg.app().name() + "-volume.icns"); } - private void prepareLicense(Map params) { + private Path getConfig_LicenseFile(MacDmgPackage pkg, BuildEnv env) { + return env.configDir().resolve(pkg.app().name() + "-license.plist"); + } + + private void prepareLicense(MacDmgPackage pkg, BuildEnv env) { try { - String licFileStr = LICENSE_FILE.fetchFrom(params); - if (licFileStr == null) { + final var licFile = pkg.licenseFile(); + if (licFile.isEmpty()) { return; } - Path licFile = Path.of(licFileStr); byte[] licenseContentOriginal = - Files.readAllBytes(licFile); + Files.readAllBytes(licFile.orElseThrow()); String licenseInBase64 = Base64.getEncoder().encodeToString(licenseContentOriginal); Map data = new HashMap<>(); data.put("APPLICATION_LICENSE_TEXT", licenseInBase64); - createResource(DEFAULT_LICENSE_PLIST, params) + env.createResource(DEFAULT_LICENSE_PLIST) .setCategory(I18N.getString("resource.license-setup")) .setSubstitutionData(data) - .saveToFile(getConfig_LicenseFile(params)); + .saveToFile(getConfig_LicenseFile(pkg, env)); } catch (IOException ex) { Log.verbose(ex); } } - private boolean prepareConfigFiles(Path appLocation, - Map params) throws IOException { + private void prepareConfigFiles(MacDmgPackage pkg, BuildEnv env) throws IOException { - createResource(DEFAULT_BACKGROUND_IMAGE, params) + env.createResource(DEFAULT_BACKGROUND_IMAGE) .setCategory(I18N.getString("resource.dmg-background")) - .saveToFile(getConfig_VolumeBackground(params)); + .saveToFile(getConfig_VolumeBackground(pkg, env)); - createResource(TEMPLATE_BUNDLE_ICON, params) + env.createResource(TEMPLATE_BUNDLE_ICON) .setCategory(I18N.getString("resource.volume-icon")) - .setExternal(ICON_ICNS.fetchFrom(params)) - .saveToFile(getConfig_VolumeIcon(params)); + .setExternal(pkg.icon().orElse(null)) + .saveToFile(getConfig_VolumeIcon(pkg, env)); - createResource(null, params) + env.createResource(null) .setCategory(I18N.getString("resource.post-install-script")) - .saveToFile(getConfig_Script(params)); - - prepareLicense(params); + .saveToFile(getConfig_Script(pkg, env)); - prepareDMGSetupScript(appLocation, params); + prepareLicense(pkg, env); - return true; + prepareDMGSetupScript(pkg, env); } // name of post-image script - private Path getConfig_Script(Map params) { - return CONFIG_ROOT.fetchFrom(params).resolve( - APP_NAME.fetchFrom(params) + "-post-image.sh"); + private Path getConfig_Script(MacDmgPackage pkg, BuildEnv env) { + return env.configDir().resolve(pkg.app().name() + "-post-image.sh"); } // Location of SetFile utility may be different depending on MacOS version @@ -266,32 +258,29 @@ private String findSetFileUtility() { return null; } - private Path buildDMG( Map params, - Path appLocation, Path outdir) throws IOException { + private Path buildDMG(MacDmgPackage pkg, BuildEnv env, Path outdir) throws IOException { boolean copyAppImage = false; - Path imagesRoot = IMAGES_ROOT.fetchFrom(params); + Path imagesRoot = imagesRoot(pkg, env); if (!Files.exists(imagesRoot)) { Files.createDirectories(imagesRoot); } - Path protoDMG = imagesRoot.resolve(APP_NAME.fetchFrom(params) + Path protoDMG = imagesRoot.resolve(pkg.app().name() + "-tmp.dmg"); - Path finalDMG = outdir.resolve(MAC_INSTALLER_NAME.fetchFrom(params) - + ".dmg"); + Path finalDMG = outdir.resolve(pkg.packageFileNameWithSuffix()); - Path srcFolder = appLocation.getParent(); - if (StandardBundlerParam.isRuntimeInstaller(params)) { - Path newRoot = Files.createTempDirectory(TEMP_ROOT.fetchFrom(params), + Path srcFolder = env.appImageDir().getParent(); + if (pkg.isRuntimeInstaller()) { + Path newRoot = Files.createTempDirectory(env.buildRoot(), "root-"); // first, is this already a runtime with // /Contents/Home - if so we need the Home dir - Path home = appLocation.resolve("Contents/Home"); - Path source = (Files.exists(home)) ? home : appLocation; + Path home = env.appImageDir().resolve("Contents/Home"); + Path source = (Files.exists(home)) ? home : env.appImageDir(); // Then we need to put back the /Content/Home - Path root = newRoot.resolve( - MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params)); + Path root = newRoot.resolve(((MacApplication)pkg.app()).bundleIdentifier()); Path dest = root.resolve("Contents/Home"); FileUtils.copyRecursive(source, dest); @@ -314,11 +303,9 @@ private Path buildDMG( Map params, Files.createDirectories(protoDMG.getParent()); Files.createDirectories(finalDMG.getParent()); - final var pkg = MacFromParams.DMG_PACKAGE.fetchFrom(params); - - String hdiUtilVerbosityFlag = VERBOSE.fetchFrom(params) ? + String hdiUtilVerbosityFlag = env.verbose() ? "-verbose" : "-quiet"; - List dmgContent = DMG_CONTENT.fetchFrom(params); + List dmgContent = pkg.content(); for (Path path : dmgContent) { FileUtils.copyRecursive(path, srcFolder.resolve(path.getFileName())); } @@ -328,7 +315,7 @@ private Path buildDMG( Map params, "create", hdiUtilVerbosityFlag, "-srcfolder", srcFolder.toAbsolutePath().toString(), - "-volname", APP_NAME.fetchFrom(params), + "-volname", pkg.app().name(), "-ov", protoDMG.toAbsolutePath().toString(), "-fs", "HFS+", "-format", "UDRW"); @@ -351,7 +338,7 @@ private Path buildDMG( Map params, "create", hdiUtilVerbosityFlag, "-size", String.valueOf(size), - "-volname", APP_NAME.fetchFrom(params), + "-volname", pkg.app().name(), "-ov", protoDMG.toAbsolutePath().toString(), "-fs", "HFS+"); new RetryExecutor() @@ -370,7 +357,7 @@ private Path buildDMG( Map params, "-mountroot", imagesRoot.toAbsolutePath().toString()); IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); - Path mountedRoot = imagesRoot.resolve(APP_NAME.fetchFrom(params)); + Path mountedRoot = imagesRoot.resolve(pkg.app().name()); // Copy app image, since we did not create DMG with it, but instead we created // empty one. @@ -392,7 +379,7 @@ private Path buildDMG( Map params, // background image Path bgdir = mountedRoot.resolve(BACKGROUND_IMAGE_FOLDER); Files.createDirectories(bgdir); - IOUtils.copyFile(getConfig_VolumeBackground(params), + IOUtils.copyFile(getConfig_VolumeBackground(pkg, env), bgdir.resolve(BACKGROUND_IMAGE)); // We will not consider setting background image and creating link @@ -400,7 +387,7 @@ private Path buildDMG( Map params, // headless environment. try { pb = new ProcessBuilder("/usr/bin/osascript", - getConfig_VolumeScript(params).toAbsolutePath().toString()); + getConfig_VolumeScript(pkg, env).toAbsolutePath().toString()); IOUtils.exec(pb, 180); // Wait 3 minutes. See JDK-8248248. } catch (IOException ex) { Log.verbose(ex); @@ -408,7 +395,7 @@ private Path buildDMG( Map params, // volume icon Path volumeIconFile = mountedRoot.resolve(".VolumeIcon.icns"); - IOUtils.copyFile(getConfig_VolumeIcon(params), + IOUtils.copyFile(getConfig_VolumeIcon(pkg, env), volumeIconFile); // Indicate that we want a custom icon @@ -497,7 +484,7 @@ private Path buildDMG( Map params, } catch (Exception ex) { // Convert might failed if something holds file. Try to convert copy. Path protoDMG2 = imagesRoot - .resolve(APP_NAME.fetchFrom(params) + "-tmp2.dmg"); + .resolve(pkg.app().name() + "-tmp2.dmg"); Files.copy(protoDMG, protoDMG2); try { pb = new ProcessBuilder( @@ -514,13 +501,13 @@ private Path buildDMG( Map params, } //add license if needed - if (Files.exists(getConfig_LicenseFile(params))) { + if (Files.exists(getConfig_LicenseFile(pkg, env))) { pb = new ProcessBuilder( hdiutil, "udifrez", finalDMG.toAbsolutePath().toString(), "-xml", - getConfig_LicenseFile(params).toAbsolutePath().toString() + getConfig_LicenseFile(pkg, env).toAbsolutePath().toString() ); new RetryExecutor() .setMaxAttemptsCount(10) @@ -533,7 +520,7 @@ private Path buildDMG( Map params, Log.verbose(MessageFormat.format(I18N.getString( "message.output-to-location"), - APP_NAME.fetchFrom(params), finalDMG.toAbsolutePath().toString())); + pkg.app().name(), finalDMG.toAbsolutePath().toString())); return finalDMG; } From 16704444687b73744b546e5c7aa87409eafac939 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 18:13:41 -0500 Subject: [PATCH 0296/1101] Bugfix --- .../macosx/classes/jdk/jpackage/internal/MacDmgBundler.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java index 8ce0d4bcc77f1..d101a72b5467e 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java @@ -99,6 +99,9 @@ private void prepareDMGSetupScript(MacDmgPackage pkg, BuildEnv env) throws IOExc // user might have open DMG with same volume name already. Url should end with // '/' and it should be real path (no symbolic links). Path imageDir = imagesRoot(pkg, env); + + Files.createDirectories(imageDir); + Path rootPath = imageDir.toRealPath(); Path volumePath = rootPath.resolve(pkg.app().name()); String volumeUrl = volumePath.toUri().toString() + File.separator; From 80d5152a166b6cf2a3af3cd227718012ae7d2d33 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 18:14:13 -0500 Subject: [PATCH 0297/1101] Remove dead code --- .../jdk/jpackage/internal/MacAppBundler.java | 7 - .../jpackage/internal/MacAppImageBuilder.java | 136 ------------------ 2 files changed, 143 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index f4d14d2248316..4eb6ded6f4131 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -104,13 +104,6 @@ public MacAppBundler() { params -> "", null); - public static final BundlerParamInfo BUNDLE_ID_SIGNING_PREFIX = - new BundlerParamInfo<>( - Arguments.CLIOptions.MAC_BUNDLE_SIGNING_PREFIX.getId(), - String.class, - params -> getIdentifier(params) + ".", - (s, p) -> s); - static String getIdentifier(Map params) { String s = MAIN_CLASS.fetchFrom(params); if (s == null) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java index 79458a014cf90..294e4842848a9 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -28,10 +28,7 @@ import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT; -import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.createResource; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -45,7 +42,6 @@ import java.util.EnumSet; import java.util.List; import java.util.Map; -import java.util.ResourceBundle; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -55,15 +51,9 @@ import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; -import jdk.internal.util.OSVersion; public class MacAppImageBuilder { - private static final ResourceBundle I18N = ResourceBundle.getBundle( - "jdk.jpackage.internal.resources.MacResources"); - - private static List keyChains; - static final BundlerParamInfo APP_STORE = new BundlerParamInfo<>( Arguments.CLIOptions.MAC_APP_STORE.getId(), @@ -76,20 +66,6 @@ public class MacAppImageBuilder { null : Boolean.valueOf(s) ); - public static final BundlerParamInfo MAC_CF_BUNDLE_NAME = - new BundlerParamInfo<>( - Arguments.CLIOptions.MAC_BUNDLE_NAME.getId(), - String.class, - params -> null, - (s, p) -> s); - - public static final BundlerParamInfo APP_CATEGORY = - new BundlerParamInfo<>( - Arguments.CLIOptions.MAC_CATEGORY.getId(), - String.class, - params -> "utilities", - (s, p) -> s); - public static final BundlerParamInfo MAC_CF_BUNDLE_IDENTIFIER = new BundlerParamInfo<>( Arguments.CLIOptions.MAC_BUNDLE_IDENTIFIER.getId(), @@ -108,118 +84,6 @@ public class MacAppImageBuilder { }, (s, p) -> s); - public static final BundlerParamInfo ICON_ICNS = - new BundlerParamInfo<>( - "icon.icns", - Path.class, - params -> { - Path f = ICON.fetchFrom(params); - if (f != null && f.getFileName() != null && !f.getFileName() - .toString().toLowerCase().endsWith(".icns")) { - Log.error(MessageFormat.format( - I18N.getString("message.icon-not-icns"), f)); - return null; - } - return f; - }, - (s, p) -> Path.of(s)); - - public static final BundlerParamInfo ENTITLEMENTS = - new BundlerParamInfo<>( - Arguments.CLIOptions.MAC_ENTITLEMENTS.getId(), - Path.class, - params -> { - try { - Path path = CONFIG_ROOT.fetchFrom(params).resolve( - APP_NAME.fetchFrom(params) + ".entitlements"); - String defPath = (APP_STORE.fetchFrom(params) ? - "sandbox.plist" : "entitlements.plist"); - createResource(defPath, params) - .setCategory(I18N.getString("resource.entitlements")) - .saveToFile(path); - return path; - } catch (IOException ioe) { - Log.verbose(ioe); - } - return null; - }, - (s, p) -> Path.of(s) - ); - - public static void addNewKeychain(Map params) - throws IOException, InterruptedException { - if (OSVersion.current().compareTo(new OSVersion(10, 12)) < 0) { - // we need this for OS X 10.12+ - return; - } - - String keyChain = SIGNING_KEYCHAIN.fetchFrom(params); - if (keyChain == null || keyChain.isEmpty()) { - return; - } - - // get current keychain list - String keyChainPath = Path.of(keyChain).toAbsolutePath().toString(); - List keychainList = new ArrayList<>(); - int ret = IOUtils.getProcessOutput( - keychainList, "security", "list-keychains"); - if (ret != 0) { - Log.error(I18N.getString("message.keychain.error")); - return; - } - boolean contains = keychainList.stream().anyMatch( - str -> str.trim().equals("\""+keyChainPath.trim()+"\"")); - if (contains) { - // keychain is already added in the search list - return; - } - - keyChains = new ArrayList<>(); - // remove " - keychainList.forEach((String s) -> { - String path = s.trim(); - if (path.startsWith("\"") && path.endsWith("\"")) { - path = path.substring(1, path.length()-1); - } - if (!keyChains.contains(path)) { - keyChains.add(path); - } - }); - - List args = new ArrayList<>(); - args.add("/usr/bin/security"); - args.add("list-keychains"); - args.add("-s"); - - args.addAll(keyChains); - args.add(keyChain); - - ProcessBuilder pb = new ProcessBuilder(args); - IOUtils.exec(pb); - } - - public static void restoreKeychainList(Map params) - throws IOException{ - if (OSVersion.current().compareTo(new OSVersion(10, 12)) < 0) { - // we need this for OS X 10.12+ - return; - } - - if (keyChains == null || keyChains.isEmpty()) { - return; - } - - List args = new ArrayList<>(); - args.add("/usr/bin/security"); - args.add("list-keychains"); - args.add("-s"); - - args.addAll(keyChains); - - ProcessBuilder pb = new ProcessBuilder(args); - IOUtils.exec(pb); - } - private static List getCodesignArgs( boolean force, Path path, String signingIdentity, String identifierPrefix, Path entitlements, String keyChain) { From a86d39dcf524ed4af7c642d9be6338cf6d02835b Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 20:27:56 -0500 Subject: [PATCH 0298/1101] Trailing whitespace removed --- .../share/classes/jdk/jpackage/internal/BuildEnvBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java index 2e7b3bd222356..2885715c5d23f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java @@ -58,10 +58,10 @@ BuildEnv create() throws ConfigException { } } - return BuildEnv.withAppImageDir(BuildEnv.create(root, Optional.ofNullable(resourceDir), + return BuildEnv.withAppImageDir(BuildEnv.create(root, Optional.ofNullable(resourceDir), verbose, ResourceLocator.class), appImageDir); } - + BuildEnvBuilder verbose(boolean v) { verbose = v; return this; From 6c5cc53e65744be64bbf07bdfb5e16d1bd2f2021 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 20:28:31 -0500 Subject: [PATCH 0299/1101] Trailing whitespace removed --- .../classes/jdk/jpackage/internal/SigningConfigBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java index 910e05b29a1f9..d00db3f74d6ba 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java @@ -118,7 +118,7 @@ private Optional validatedSigningIdentifier() throws ConfigEx .advice("error.explicit-sign-no-cert.advice").create(); } case 1 -> { - return Optional.of(new SigningIdentifierImpl(signingIdentifiers.get(0), + return Optional.of(new SigningIdentifierImpl(signingIdentifiers.get(0), Optional.ofNullable(signingIdentifierPrefix))); } default -> { From b83c5cea5799fcec342780e003d84cc5601060f9 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 20:31:04 -0500 Subject: [PATCH 0300/1101] Add signing config to mac pkg package. --- .../internal/MacPkgPackageBuilder.java | 20 ++++++++++- .../internal/model/MacPkgPackage.java | 10 ++++-- .../internal/model/MacPkgPackageMixin.java | 35 +++++++++++++++++++ 3 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackageMixin.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java index 94a78de5eca23..1e111e312c744 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java @@ -25,8 +25,11 @@ package jdk.jpackage.internal; import java.util.Objects; +import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.MacPkgPackage; +import jdk.jpackage.internal.model.MacPkgPackageMixin; +import jdk.jpackage.internal.model.SigningConfig; final class MacPkgPackageBuilder { @@ -34,9 +37,24 @@ final class MacPkgPackageBuilder { this.pkgBuilder = Objects.requireNonNull(pkgBuilder); } + MacPkgPackageBuilder signingBuilder(SigningConfigBuilder v) { + signingBuilder = v; + return this; + } + MacPkgPackage create() throws ConfigException { - return MacPkgPackage.create(pkgBuilder.create()); + return MacPkgPackage.create(pkgBuilder.create(), + new MacPkgPackageMixin.Stub(createSigningConfig())); + } + + private Optional createSigningConfig() throws ConfigException { + if (signingBuilder != null) { + return Optional.of(signingBuilder.create()); + } else { + return Optional.empty(); + } } private final PackageBuilder pkgBuilder; + private SigningConfigBuilder signingBuilder; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java index 0d4f973c1dc7c..1dd7bbf0e3cac 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java @@ -26,9 +26,13 @@ import jdk.jpackage.internal.util.CompositeProxy; -public interface MacPkgPackage extends Package { +public interface MacPkgPackage extends Package, MacPkgPackageMixin { - public static MacPkgPackage create(Package pkg) { - return CompositeProxy.create(MacPkgPackage.class, pkg); + default boolean sign() { + return signingConfig().flatMap(SigningConfig::identifier).isPresent(); + } + + public static MacPkgPackage create(Package pkg, MacPkgPackageMixin mixin) { + return CompositeProxy.create(MacPkgPackage.class, pkg, mixin); } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackageMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackageMixin.java new file mode 100644 index 0000000000000..2cc2ef32873dc --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackageMixin.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.util.Optional; + +public interface MacPkgPackageMixin { + + Optional signingConfig(); + + record Stub(Optional signingConfig) implements MacPkgPackageMixin { + } +} From 4fc540dcef3b4fd0433f5a1471ac03f0c8878276 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 20:32:06 -0500 Subject: [PATCH 0301/1101] Simplify UnixLauncherAsService. --- .../internal/LinuxLaunchersAsServices.java | 16 +++++++--------- .../internal/UnixLaunchersAsServices.java | 14 ++++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java index e7b03552e60bd..11e6e338c1c03 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java @@ -24,14 +24,14 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.Launcher; import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.Package; /** * Helper to install launchers as services using "systemd". @@ -39,7 +39,7 @@ public final class LinuxLaunchersAsServices extends UnixLaunchersAsServices { private LinuxLaunchersAsServices(BuildEnv env, Package pkg) throws IOException { - super(env, pkg.app(), REQUIRED_PACKAGES, launcher -> { + super(env.appImageDir(), pkg.app(), REQUIRED_PACKAGES, launcher -> { return new LauncherImpl(env, pkg, launcher); }); } @@ -70,20 +70,18 @@ public static Path getServiceUnitFileName(String packageName, String launcherNam return Path.of(packageName + "-" + baseName + ".service"); } - private static class LauncherImpl extends UnixLauncherAsService { + private static final class LauncherImpl extends UnixLauncherAsService { LauncherImpl(BuildEnv env, Package pkg, Launcher launcher) { - super(launcher, - env.createResource("unit-template.service").setCategory( - I18N.getString("resource.systemd-unit-file"))); + super(launcher, env.createResource("unit-template.service").setCategory( + I18N.getString("resource.systemd-unit-file"))); unitFilename = getServiceUnitFileName(pkg.packageName(), launcher.executableName()); getResource().setPublicName(unitFilename).addSubstitutionDataEntry( "APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo( - pkg.asInstalledPackageApplicationLayout().orElseThrow().resolveAt( - env.appImageDir()).launchersDirectory().resolve(getName()).toString())); + pkg.asInstalledPackageApplicationLayout().orElseThrow().launchersDirectory().resolve(getName()).toString())); } @Override diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java index 798124a34ca14..5f63165931839 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java @@ -32,6 +32,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -41,11 +42,12 @@ */ class UnixLaunchersAsServices extends ShellCustomAction { - UnixLaunchersAsServices(BuildEnv env, Application app, List requiredPackages, - Function factory) throws IOException { + UnixLaunchersAsServices(Path outputRoot, Application app, List requiredPackages, + Function factory) { - this.appImageDir = env.appImageDir(); - this.requiredPackages = requiredPackages; + Objects.requireNonNull(factory); + this.outputRoot = Objects.requireNonNull(outputRoot); + this.requiredPackages = Objects.requireNonNull(requiredPackages); // Read launchers information launchers = app.launchers().stream().filter(Launcher::isService).map(factory::apply).toList(); @@ -89,7 +91,7 @@ protected Map createImpl() throws IOException { data.put(COMMANDS_UNINSTALL, strigifier.apply("unregister_services")); for (var launcher : launchers) { - launcher.getResource().saveToFile(launcher.descriptorFilePath(appImageDir)); + launcher.getResource().saveToFile(launcher.descriptorFilePath(outputRoot)); } return data; @@ -108,7 +110,7 @@ abstract static class UnixLauncherAsService extends LauncherAsService { abstract Path descriptorFilePath(Path root); } - private final Path appImageDir; + private final Path outputRoot; private final List requiredPackages; private final List launchers; private final Enquoter enqouter = Enquoter.forShellLiterals(); From e037bff2c7fd7fa04901821afdd592a1454dbd96 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 20:33:03 -0500 Subject: [PATCH 0302/1101] Got rid of params (still need to clean validate()) in mac pkg bundler --- .../internal/MacLaunchersAsServices.java | 25 +- .../jdk/jpackage/internal/MacPkgBundler.java | 371 +++++++----------- 2 files changed, 162 insertions(+), 234 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index 5861dccfbe25c..bb233eeb99ec6 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -24,15 +24,14 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.MacApplication; import java.io.IOException; import java.nio.file.Path; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.function.Predicate; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.MacApplication; +import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.util.PathUtils; /** @@ -40,23 +39,19 @@ */ public final class MacLaunchersAsServices extends UnixLaunchersAsServices { - private MacLaunchersAsServices(BuildEnv env, Package pkg) throws IOException { - super(env, pkg.app(), List.of(), launcher -> { + private MacLaunchersAsServices(BuildEnv env, Package pkg) { + super(env.appImageDir(), pkg.app(), List.of(), launcher -> { return new MacLauncherAsService(env, pkg, launcher); }); } - static ShellCustomAction create(Map params, - Path outputDir) throws IOException { - - final var pkg = FromParams.getCurrentPackage(params).orElseThrow(); - final var env = BuildEnv.withAppImageDir(BuildEnvFromParams.BUILD_ENV.findIn(params).orElseThrow(), outputDir); - + static Optional create(BuildEnv env, Package pkg) { if (pkg.isRuntimeInstaller()) { - return null; + return Optional.empty(); + } else { + return Optional.of(new MacLaunchersAsServices(env, pkg)) + .filter(Predicate.not(MacLaunchersAsServices::isEmpty)); } - return Optional.of(new MacLaunchersAsServices(env, pkg)).filter(Predicate.not( - MacLaunchersAsServices::isEmpty)).orElse(null); } public static Path getServicePListFileName(String bundleIdentifier, diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 2794ea552d099..ae863081eb2b7 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -25,10 +25,10 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.PackagerException; -import jdk.internal.util.Architecture; -import jdk.internal.util.OSVersion; +import static jdk.jpackage.internal.MacAppImageBuilder.APP_STORE; +import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; +import static jdk.jpackage.internal.MacApplicationBuilder.isValidBundleIdentifier; +import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -49,19 +49,12 @@ import java.util.ResourceBundle; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; - -import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT; -import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; -import static jdk.jpackage.internal.MacAppBundler.APP_IMAGE_SIGN_IDENTITY; -import static jdk.jpackage.internal.MacAppImageBuilder.APP_STORE; -import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; -import static jdk.jpackage.internal.StandardBundlerParam.createResource; -import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; -import static jdk.jpackage.internal.MacApplicationBuilder.isValidBundleIdentifier; +import jdk.internal.util.Architecture; +import jdk.internal.util.OSVersion; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.MacApplication; +import jdk.jpackage.internal.model.MacPkgPackage; +import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.XmlUtils; @@ -73,39 +66,6 @@ public class MacPkgBundler extends MacBaseInstallerBundler { private static final String DEFAULT_BACKGROUND_IMAGE = "background_pkg.png"; private static final String DEFAULT_PDF = "product-def.plist"; - private static final BundlerParamInfo PACKAGES_ROOT = - new BundlerParamInfo<>( - "mac.pkg.packagesRoot", - Path.class, - params -> { - Path packagesRoot = - TEMP_ROOT.fetchFrom(params).resolve("packages"); - try { - Files.createDirectories(packagesRoot); - } catch (IOException ioe) { - return null; - } - return packagesRoot; - }, - (s, p) -> Path.of(s)); - - - protected final BundlerParamInfo SCRIPTS_DIR = - new BundlerParamInfo<>( - "mac.pkg.scriptsDir", - Path.class, - params -> { - Path scriptsDir = - CONFIG_ROOT.fetchFrom(params).resolve("scripts"); - try { - Files.createDirectories(scriptsDir); - } catch (IOException ioe) { - return null; - } - return scriptsDir; - }, - (s, p) -> Path.of(s)); - public static final BundlerParamInfo DEVELOPER_ID_INSTALLER_SIGNING_KEY = new BundlerParamInfo<>( @@ -142,94 +102,96 @@ public class MacPkgBundler extends MacBaseInstallerBundler { public Path bundle(Map params, Path outdir) throws PackagerException { + + final var pkg = MacFromParams.PKG_PACKAGE.fetchFrom(params); + var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + Log.verbose(MessageFormat.format(I18N.getString("message.building-pkg"), - APP_NAME.fetchFrom(params))); + pkg.app().name())); IOUtils.writableOutputDir(outdir); - MacFromParams.PKG_PACKAGE.fetchFrom(params); - try { - Path appImageDir = prepareAppBundle(params); - - if (appImageDir != null && prepareConfigFiles(params)) { + env = BuildEnv.withAppImageDir(env, prepareAppBundle(params)); - Path configScript = getConfig_Script(params); - if (IOUtils.exists(configScript)) { - IOUtils.run("bash", configScript); - } - - return createPKG(params, outdir, appImageDir); + prepareConfigFiles(pkg, env); + Path configScript = getConfig_Script(pkg, env); + if (IOUtils.exists(configScript)) { + IOUtils.run("bash", configScript); } - return null; - } catch (IOException ex) { + + return createPKG(pkg, env, outdir); + } catch (IOException | PackagerException ex) { Log.verbose(ex); throw new PackagerException(ex); } } - private Path getPackages_AppPackage(Map params) { - return PACKAGES_ROOT.fetchFrom(params).resolve( - APP_NAME.fetchFrom(params) + "-app.pkg"); + private Path packagesRoot(BuildEnv env) { + return env.buildRoot().resolve("packages"); } - private Path getPackages_ServicesPackage(Map params) { - return PACKAGES_ROOT.fetchFrom(params).resolve( - APP_NAME.fetchFrom(params) + "-services.pkg"); + private Path scriptsRoot(BuildEnv env) { + return env.configDir().resolve("scripts"); } - private Path getPackages_SupportPackage(Map params) { - return PACKAGES_ROOT.fetchFrom(params).resolve( - APP_NAME.fetchFrom(params) + "-support.pkg"); + private Path getPackages_AppPackage(MacPkgPackage pkg, BuildEnv env) { + return packagesRoot(env).resolve(pkg.app().name() + "-app.pkg"); } - private Path getConfig_DistributionXMLFile( - Map params) { - return CONFIG_ROOT.fetchFrom(params).resolve("distribution.dist"); + private Path getPackages_ServicesPackage(MacPkgPackage pkg, BuildEnv env) { + return packagesRoot(env).resolve(pkg.app().name() + "-services.pkg"); } - private Path getConfig_PDF(Map params) { - return CONFIG_ROOT.fetchFrom(params).resolve("product-def.plist"); + private Path getPackages_SupportPackage(MacPkgPackage pkg, BuildEnv env) { + return packagesRoot(env).resolve(pkg.app().name() + "-support.pkg"); } - private Path getConfig_BackgroundImage(Map params) { - return CONFIG_ROOT.fetchFrom(params).resolve( - APP_NAME.fetchFrom(params) + "-background.png"); + private Path getConfig_DistributionXMLFile(MacPkgPackage pkg, BuildEnv env) { + return env.configDir().resolve("distribution.dist"); } - private Path getConfig_BackgroundImageDarkAqua(Map params) { - return CONFIG_ROOT.fetchFrom(params).resolve( - APP_NAME.fetchFrom(params) + "-background-darkAqua.png"); + private Path getConfig_PDF(MacPkgPackage pkg, BuildEnv env) { + return env.configDir().resolve("product-def.plist"); } - private String getAppIdentifier(Map params) { - return MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params); + private Path getConfig_BackgroundImage(MacPkgPackage pkg, BuildEnv env) { + return env.configDir().resolve(pkg.app().name() + "-background.png"); } - private String getServicesIdentifier(Map params) { - return MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params) + ".services"; + private Path getConfig_BackgroundImageDarkAqua(MacPkgPackage pkg, BuildEnv env) { + return env.configDir().resolve(pkg.app().name() + "-background-darkAqua.png"); } - private String getSupportIdentifier(Map params) { - return MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params) + ".support"; + private String getAppIdentifier(MacPkgPackage pkg) { + return ((MacApplication)pkg.app()).bundleIdentifier(); } - private void preparePackageScripts(Map params) + private String getServicesIdentifier(MacPkgPackage pkg) { + return ((MacApplication)pkg.app()).bundleIdentifier() + ".services"; + } + + private String getSupportIdentifier(MacPkgPackage pkg) { + return ((MacApplication)pkg.app()).bundleIdentifier() + ".support"; + } + + private void preparePackageScripts(MacPkgPackage pkg, BuildEnv env) throws IOException { Log.verbose(I18N.getString("message.preparing-scripts")); + Files.createDirectories(scriptsRoot(env)); + Map data = new HashMap<>(); - Path appLocation = Path.of(getInstallDir(params, false), - APP_NAME.fetchFrom(params) + ".app", "Contents", "app"); + Path appLocation = pkg.asInstalledPackageApplicationLayout().orElseThrow().appDirectory(); - data.put("INSTALL_LOCATION", getInstallDir(params, false)); + data.put("INSTALL_LOCATION", Path.of("/").resolve(pkg.relativeInstallDir()).toString()); data.put("APP_LOCATION", appLocation.toString()); MacPkgInstallerScripts.createAppScripts() - .setResourceDir(RESOURCE_DIR.fetchFrom(params)) + .setResourceDir(env.resourceDir().orElse(null)) .setSubstitutionData(data) - .saveInFolder(SCRIPTS_DIR.fetchFrom(params)); + .saveInFolder(scriptsRoot(env)); } private void addPackageToInstallerGuiScript(XMLStreamWriter xml, @@ -257,9 +219,9 @@ private void addPackageToInstallerGuiScript(XMLStreamWriter xml, xml.writeEndElement(); // } - private void prepareDistributionXMLFile(Map params) + private void prepareDistributionXMLFile(MacPkgPackage pkg, BuildEnv env) throws IOException { - Path f = getConfig_DistributionXMLFile(params); + Path f = getConfig_DistributionXMLFile(pkg, env); Log.verbose(MessageFormat.format(I18N.getString( "message.preparing-distribution-dist"), f.toAbsolutePath().toString())); @@ -269,12 +231,12 @@ private void prepareDistributionXMLFile(Map params) xml.writeAttribute("minSpecVersion", "1"); xml.writeStartElement("title"); - xml.writeCharacters(APP_NAME.fetchFrom(params)); + xml.writeCharacters(pkg.app().name()); xml.writeEndElement(); xml.writeStartElement("background"); xml.writeAttribute("file", - getConfig_BackgroundImage(params).getFileName().toString()); + getConfig_BackgroundImage(pkg, env).getFileName().toString()); xml.writeAttribute("mime-type", "image/png"); xml.writeAttribute("alignment", "bottomleft"); xml.writeAttribute("scaling", "none"); @@ -282,17 +244,16 @@ private void prepareDistributionXMLFile(Map params) xml.writeStartElement("background-darkAqua"); xml.writeAttribute("file", - getConfig_BackgroundImageDarkAqua(params).getFileName().toString()); + getConfig_BackgroundImageDarkAqua(pkg, env).getFileName().toString()); xml.writeAttribute("mime-type", "image/png"); xml.writeAttribute("alignment", "bottomleft"); xml.writeAttribute("scaling", "none"); xml.writeEndElement(); - String licFileStr = LICENSE_FILE.fetchFrom(params); - if (licFileStr != null) { - Path licFile = Path.of(licFileStr); + final var licFile = pkg.licenseFile(); + if (licFile.isPresent()) { xml.writeStartElement("license"); - xml.writeAttribute("file", licFile.toAbsolutePath().toString()); + xml.writeAttribute("file", licFile.orElseThrow().toAbsolutePath().toString()); xml.writeAttribute("mime-type", "text/rtf"); xml.writeEndElement(); } @@ -304,18 +265,18 @@ private void prepareDistributionXMLFile(Map params) Map pkgs = new LinkedHashMap<>(); - pkgs.put(getAppIdentifier(params), getPackages_AppPackage(params)); - if (withServicesPkg(params)) { - pkgs.put(getServicesIdentifier(params), - getPackages_ServicesPackage(params)); - pkgs.put(getSupportIdentifier(params), - getPackages_SupportPackage(params)); + pkgs.put(getAppIdentifier(pkg), getPackages_AppPackage(pkg, env)); + if (withServicesPkg(pkg, env)) { + pkgs.put(getServicesIdentifier(pkg), + getPackages_ServicesPackage(pkg, env)); + pkgs.put(getSupportIdentifier(pkg), + getPackages_SupportPackage(pkg, env)); } - for (var pkg : pkgs.entrySet()) { - addPackageToInstallerGuiScript(xml, pkg.getKey(), - pkg.getValue().getFileName().toString(), - VERSION.fetchFrom(params)); + for (var p : pkgs.entrySet()) { + addPackageToInstallerGuiScript(xml, p.getKey(), + p.getValue().getFileName().toString(), + pkg.app().version()); } xml.writeStartElement("options"); @@ -342,34 +303,33 @@ private void prepareDistributionXMLFile(Map params) }); } - private boolean prepareConfigFiles(Map params) + private boolean prepareConfigFiles(MacPkgPackage pkg, BuildEnv env) throws IOException { - createResource(DEFAULT_BACKGROUND_IMAGE, params) + env.createResource(DEFAULT_BACKGROUND_IMAGE) .setCategory(I18N.getString("resource.pkg-background-image")) - .saveToFile(getConfig_BackgroundImage(params)); + .saveToFile(getConfig_BackgroundImage(pkg, env)); - createResource(DEFAULT_BACKGROUND_IMAGE, params) + env.createResource(DEFAULT_BACKGROUND_IMAGE) .setCategory(I18N.getString("resource.pkg-background-image")) - .saveToFile(getConfig_BackgroundImageDarkAqua(params)); + .saveToFile(getConfig_BackgroundImageDarkAqua(pkg, env)); - createResource(DEFAULT_PDF, params) + env.createResource(DEFAULT_PDF) .setCategory(I18N.getString("resource.pkg-pdf")) - .saveToFile(getConfig_PDF(params)); + .saveToFile(getConfig_PDF(pkg, env)); - prepareDistributionXMLFile(params); + prepareDistributionXMLFile(pkg, env); - createResource(null, params) + env.createResource(null) .setCategory(I18N.getString("resource.post-install-script")) - .saveToFile(getConfig_Script(params)); + .saveToFile(getConfig_Script(pkg, env)); return true; } // name of post-image script - private Path getConfig_Script(Map params) { - return CONFIG_ROOT.fetchFrom(params).resolve( - APP_NAME.fetchFrom(params) + "-post-image.sh"); + private Path getConfig_Script(MacPkgPackage pkg, BuildEnv env) { + return env.configDir().resolve(pkg.app().name() + "-post-image.sh"); } private void patchCPLFile(Path cpl) throws IOException { @@ -406,24 +366,22 @@ private void patchCPLFile(Path cpl) throws IOException { // based on doc "any .svn or CVS directories, and any .DS_Store files". // So easy approach will be to copy user provided app-image into temp folder // if root path contains other files. - private String getRoot(Map params, - Path appLocation) throws IOException { - Path rootDir = appLocation.getParent() == null ? - Path.of(".") : appLocation.getParent(); + private Path getRoot(MacPkgPackage pkg, BuildEnv env) throws IOException { + Path rootDir = env.appImageDir().getParent(); // Not needed for runtime installer and it might break runtime installer // if parent does not have any other files - if (!StandardBundlerParam.isRuntimeInstaller(params)) { + if (!pkg.isRuntimeInstaller()) { try (var fileList = Files.list(rootDir)) { Path[] list = fileList.toArray(Path[]::new); // We should only have app image and/or .DS_Store if (list.length == 1) { - return rootDir.toString(); + return rootDir; } else if (list.length == 2) { // Check case with app image and .DS_Store if (list[0].toString().toLowerCase().endsWith(".ds_store") || list[1].toString().toLowerCase().endsWith(".ds_store")) { - return rootDir.toString(); // Only app image and .DS_Store + return rootDir; // Only app image and .DS_Store } } } @@ -431,53 +389,47 @@ private String getRoot(Map params, // Copy to new root Path newRoot = Files.createTempDirectory( - TEMP_ROOT.fetchFrom(params), "root-"); + env.buildRoot(), "root-"); Path source, dest; - if (StandardBundlerParam.isRuntimeInstaller(params)) { + if (pkg.isRuntimeInstaller()) { // firs, is this already a runtime with // /Contents/Home - if so we need the Home dir - Path original = appLocation; + Path original = env.appImageDir(); Path home = original.resolve("Contents/Home"); source = (Files.exists(home)) ? home : original; // Then we need to put back the /Content/Home - dest = newRoot.resolve( - MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params) + "/Contents/Home"); + dest = newRoot.resolve(((MacApplication)pkg.app()).bundleIdentifier() + "/Contents/Home"); } else { - source = appLocation; - dest = newRoot.resolve(appLocation.getFileName()); + source = env.appImageDir(); + dest = newRoot.resolve(source.getFileName()); } FileUtils.copyRecursive(source, dest); - return newRoot.toString(); + return newRoot; } - private boolean withServicesPkg(Map params) { - try { - return !APP_STORE.fetchFrom(params) - && MacLaunchersAsServices.create(params, null) != null; - } catch (IOException ex) { - throw new RuntimeException(ex); - } + private boolean withServicesPkg(MacPkgPackage pkg, BuildEnv env) { + return MacLaunchersAsServices.create(env, pkg).isPresent(); } - private void createServicesPkg(Map params) throws + private void createServicesPkg(MacPkgPackage pkg, BuildEnv env) throws IOException { - Path root = TEMP_ROOT.fetchFrom(params).resolve("services"); + Path root = env.buildRoot().resolve("services"); Path srcRoot = root.resolve("src"); - var services = MacLaunchersAsServices.create(params, srcRoot); + var services = MacLaunchersAsServices.create(BuildEnv.withAppImageDir(env, srcRoot), pkg).orElseThrow(); Path scriptsDir = root.resolve("scripts"); var data = services.create(); - data.put("SERVICES_PACKAGE_ID", getServicesIdentifier(params)); + data.put("SERVICES_PACKAGE_ID", getServicesIdentifier(pkg)); MacPkgInstallerScripts.createServicesScripts() - .setResourceDir(RESOURCE_DIR.fetchFrom(params)) + .setResourceDir(env.resourceDir().orElse(null)) .setSubstitutionData(data) .saveInFolder(scriptsDir); @@ -489,34 +441,32 @@ private void createServicesPkg(Map params) throws "--scripts", scriptsDir.toString(), "--identifier", - getServicesIdentifier(params), - getPackages_ServicesPackage(params).toAbsolutePath().toString()); + getServicesIdentifier(pkg), + getPackages_ServicesPackage(pkg, env).toAbsolutePath().toString()); IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); - createSupportPkg(params, data); + createSupportPkg(pkg, env, data); } - private void createSupportPkg(Map params, + private void createSupportPkg(MacPkgPackage pkg, BuildEnv env, Map servicesSubstitutionData) throws IOException { - Path root = TEMP_ROOT.fetchFrom(params).resolve("support"); + Path root = env.buildRoot().resolve("support"); Path srcRoot = root.resolve("src"); var enqouter = Enquoter.forShellLiterals().setEnquotePredicate(str -> true); Map data = new HashMap<>(servicesSubstitutionData); - data.put("APP_INSTALLATION_FOLDER", enqouter.applyTo(Path.of( - getInstallDir(params, false), APP_NAME.fetchFrom(params) - + ".app").toString())); + data.put("APP_INSTALLATION_FOLDER", Path.of("/").resolve(pkg.relativeInstallDir()).toString()); data.put("SUPPORT_INSTALLATION_FOLDER", enqouter.applyTo(Path.of( - "/Library/Application Support", APP_NAME.fetchFrom(params)).toString())); + "/Library/Application Support", pkg.app().name()).toString())); new ShellScriptResource("uninstall.command") - .setResource(createResource("uninstall.command.template", params) + .setResource(env.createResource("uninstall.command.template") .setCategory(I18N.getString("resource.pkg-uninstall-script")) .setPublicName("uninstaller") .setSubstitutionData(data)) - .saveInFolder(srcRoot.resolve(APP_NAME.fetchFrom(params))); + .saveInFolder(srcRoot.resolve(pkg.app().name())); var pb = new ProcessBuilder("/usr/bin/pkgbuild", "--root", @@ -524,30 +474,31 @@ private void createSupportPkg(Map params, "--install-location", "/Library/Application Support", "--identifier", - getSupportIdentifier(params), - getPackages_SupportPackage(params).toAbsolutePath().toString()); + getSupportIdentifier(pkg), + getPackages_SupportPackage(pkg, env).toAbsolutePath().toString()); IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); } - private Path createPKG(Map params, - Path outdir, Path appLocation) { + private Path createPKG(MacPkgPackage pkg, BuildEnv env, Path outdir) { // generic find attempt try { - Path appPKG = getPackages_AppPackage(params); + Path appPKG = getPackages_AppPackage(pkg, env); - String root = getRoot(params, appLocation); + Path root = getRoot(pkg, env); - if (withServicesPkg(params)) { - createServicesPkg(params); + if (withServicesPkg(pkg, env)) { + createServicesPkg(pkg, env); } + final var installDir = Path.of("/").resolve(pkg.relativeInstallDir()).toString(); + // Generate default CPL file - Path cpl = CONFIG_ROOT.fetchFrom(params).resolve("cpl.plist"); + Path cpl = env.configDir().resolve("cpl.plist"); ProcessBuilder pb = new ProcessBuilder("/usr/bin/pkgbuild", "--root", - root, + root.toString(), "--install-location", - getInstallDir(params, false), + installDir, "--analyze", cpl.toAbsolutePath().toString()); @@ -556,95 +507,77 @@ private Path createPKG(Map params, patchCPLFile(cpl); // build application package - if (APP_STORE.fetchFrom(params)) { + if (((MacApplication)pkg.app()).appStore()) { pb = new ProcessBuilder("/usr/bin/pkgbuild", "--root", - root, + root.toString(), "--install-location", - getInstallDir(params, false), + installDir, "--component-plist", cpl.toAbsolutePath().toString(), "--identifier", - MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params), + ((MacApplication)pkg.app()).bundleIdentifier(), appPKG.toAbsolutePath().toString()); IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); } else { - preparePackageScripts(params); + preparePackageScripts(pkg, env); pb = new ProcessBuilder("/usr/bin/pkgbuild", "--root", - root, + root.toString(), "--install-location", - getInstallDir(params, false), + installDir, "--component-plist", cpl.toAbsolutePath().toString(), "--scripts", - SCRIPTS_DIR.fetchFrom(params) - .toAbsolutePath().toString(), + scriptsRoot(env).toAbsolutePath().toString(), "--identifier", - MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params), + ((MacApplication)pkg.app()).bundleIdentifier(), appPKG.toAbsolutePath().toString()); IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); } // build final package - Path finalPKG = outdir.resolve(MAC_INSTALLER_NAME.fetchFrom(params) - + ".pkg"); + Path finalPKG = outdir.resolve(pkg.packageFileNameWithSuffix()); Files.createDirectories(outdir); List commandLine = new ArrayList<>(); commandLine.add("/usr/bin/productbuild"); commandLine.add("--resources"); - commandLine.add(CONFIG_ROOT.fetchFrom(params).toAbsolutePath().toString()); + commandLine.add(env.configDir().toAbsolutePath().toString()); // maybe sign - if (Optional.ofNullable( - SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.TRUE)) { + if (pkg.sign()) { if (OSVersion.current().compareTo(new OSVersion(10, 12)) >= 0) { // we need this for OS X 10.12+ Log.verbose(I18N.getString("message.signing.pkg")); } - String signingIdentity = null; - // --mac-installer-sign-identity - if (!INSTALLER_SIGN_IDENTITY.getIsDefaultValue(params)) { - signingIdentity = INSTALLER_SIGN_IDENTITY.fetchFrom(params); - } else { - // Use --mac-signing-key-user-name if user did not request - // to sign just app image using --mac-app-image-sign-identity - if (APP_IMAGE_SIGN_IDENTITY.getIsDefaultValue(params)) { - // --mac-signing-key-user-name - signingIdentity = DEVELOPER_ID_INSTALLER_SIGNING_KEY.fetchFrom(params); - } - } + final var pkgSigningConfig = pkg.signingConfig().orElseThrow(); - if (signingIdentity != null) { - commandLine.add("--sign"); - commandLine.add(signingIdentity); - } + commandLine.add("--sign"); + commandLine.add(pkgSigningConfig.identifier().orElseThrow().name()); - String keychainName = SIGNING_KEYCHAIN.fetchFrom(params); - if (keychainName != null && !keychainName.isEmpty()) { + pkgSigningConfig.keyChain().ifPresent(keyChain -> { commandLine.add("--keychain"); - commandLine.add(keychainName); - } + commandLine.add(keyChain.toString()); + }); } - if (APP_STORE.fetchFrom(params)) { + if (((MacApplication)pkg.app()).appStore()) { commandLine.add("--product"); - commandLine.add(getConfig_PDF(params) + commandLine.add(getConfig_PDF(pkg, env) .toAbsolutePath().toString()); commandLine.add("--component"); - Path p = Path.of(root, APP_NAME.fetchFrom(params) + ".app"); + Path p = root.resolve(pkg.app().appImageDirName()); commandLine.add(p.toAbsolutePath().toString()); - commandLine.add(getInstallDir(params, false)); + commandLine.add(installDir); } else { commandLine.add("--distribution"); - commandLine.add(getConfig_DistributionXMLFile(params) + commandLine.add(getConfig_DistributionXMLFile(pkg, env) .toAbsolutePath().toString()); commandLine.add("--package-path"); - commandLine.add(PACKAGES_ROOT.fetchFrom(params) - .toAbsolutePath().toString()); + commandLine.add(packagesRoot(env).toAbsolutePath().toString()); } commandLine.add(finalPKG.toAbsolutePath().toString()); From ae5ddc790415761f7890c858b381f2264876ca69 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 20:37:17 -0500 Subject: [PATCH 0303/1101] Remove redundant "return" --- .../jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java index f6ec763ad4fbc..cd7914b917b05 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java @@ -319,7 +319,6 @@ private static void runTest(Class test, Path wo } catch (Throwable t) { t.printStackTrace(System.err); System.exit(1); - return; } } From 6db4c4f72f575c93748abe00b7026e0de492db9f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 14 Feb 2025 11:23:58 -0500 Subject: [PATCH 0304/1101] Fix bad merge --- test/jdk/tools/jpackage/share/BasicTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/tools/jpackage/share/BasicTest.java b/test/jdk/tools/jpackage/share/BasicTest.java index 967ce0ff67c55..2ce1c4aa7137f 100644 --- a/test/jdk/tools/jpackage/share/BasicTest.java +++ b/test/jdk/tools/jpackage/share/BasicTest.java @@ -60,7 +60,7 @@ public final class BasicTest { - public static Collection addModulesParams() { + public static Collection addModulesParams() { List params = new ArrayList<>(); params.add(new Object[][] { new String[] { "--add-modules", "ALL-DEFAULT" } }); params.add(new Object[][] { new String[] { "--add-modules", "java.desktop" } }); From 28ce46d6427e67b3f135b05a0b113cf62a96f938 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 14 Feb 2025 11:55:00 -0500 Subject: [PATCH 0305/1101] bugfix --- .../macosx/classes/jdk/jpackage/internal/MacPkgBundler.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index ae863081eb2b7..2f68946b4d67d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -484,6 +484,8 @@ private Path createPKG(MacPkgPackage pkg, BuildEnv env, Path outdir) { try { Path appPKG = getPackages_AppPackage(pkg, env); + Files.createDirectories(packagesRoot(env)); + Path root = getRoot(pkg, env); if (withServicesPkg(pkg, env)) { From ee3294485482b8290860db6ebcfb74fee66b1132 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 14 Feb 2025 15:48:19 -0500 Subject: [PATCH 0306/1101] Minor --- .../classes/jdk/jpackage/internal/ApplicationBuilder.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 2dfc421638ebb..94bfd7d8ed042 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -61,11 +61,10 @@ Application create() throws ConfigException { } else if (!launchersAsList.isEmpty()) { effectiveName = launchers.mainLauncher().name(); } else { - throw buildConfigException().message("error.no.name").advice("error.no.name.advice").create(); + throw buildConfigException("error.no.name").advice("error.no.name.advice").create(); } Objects.requireNonNull(launchersAsList); - Objects.requireNonNull(appImageLayout); return new Application.Stub( effectiveName, From b71ee1a405669fa5a87c6223ecc732635c6a0597 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 16 Feb 2025 13:12:35 -0500 Subject: [PATCH 0307/1101] Make JavaOptionsTest pass when fake runtime is used with tests --- test/jdk/tools/jpackage/share/JavaOptionsTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/jdk/tools/jpackage/share/JavaOptionsTest.java b/test/jdk/tools/jpackage/share/JavaOptionsTest.java index e15dc02eac6e6..014a9434cad5e 100644 --- a/test/jdk/tools/jpackage/share/JavaOptionsTest.java +++ b/test/jdk/tools/jpackage/share/JavaOptionsTest.java @@ -76,7 +76,7 @@ public static Collection input() { public JavaOptionsTest(String javaAppDesc, String[] jpackageArgs, String[] expectedParams) { - cmd = JPackageCommand.helloAppImage(javaAppDesc); + cmd = JPackageCommand.helloAppImage(javaAppDesc).ignoreFakeRuntime(); if (jpackageArgs != null) { cmd.addArguments(jpackageArgs); } @@ -90,7 +90,6 @@ public void test() { // 2.) run the launcher it generated List output = HelloApp.executeLauncher(cmd).getOutput(); - TKit.assertNotNull(output, "output is null"); for (String expect : expected) { TKit.assertTextStream(expect).apply(output.stream()); } From 0e37daf6e8ed68b8b1c9323d8666988c82e14cdc Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 16 Feb 2025 13:13:20 -0500 Subject: [PATCH 0308/1101] Follow up for moving junit tests in "junit/share" folder --- .../{AppImageInfo.java => AppImageDesc.java} | 12 ++++++------ .../internal/model/ApplicationLayoutTest.java | 0 .../jpackage/internal/model/DottedVersionTest.java | 0 .../jpackage/internal/pipeline/BinaryMatrixTest.java | 0 .../jpackage/internal/pipeline/DirectedEdgeTest.java | 0 .../jpackage/internal/pipeline/ImmutableDAGTest.java | 0 .../internal/pipeline/TaskPipelineBuilderTest.java | 0 .../jpackage/internal/util/CompositeProxyTest.java | 0 .../jdk/jpackage/internal/util/PathGroupTest.java | 0 9 files changed, 6 insertions(+), 6 deletions(-) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{AppImageInfo.java => AppImageDesc.java} (86%) rename test/jdk/tools/jpackage/junit/{ => share}/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java (100%) rename test/jdk/tools/jpackage/junit/{ => share}/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java (100%) rename test/jdk/tools/jpackage/junit/{ => share}/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java (100%) rename test/jdk/tools/jpackage/junit/{ => share}/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java (100%) rename test/jdk/tools/jpackage/junit/{ => share}/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java (100%) rename test/jdk/tools/jpackage/junit/{ => share}/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java (100%) rename test/jdk/tools/jpackage/junit/{ => share}/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java (100%) rename test/jdk/tools/jpackage/junit/{ => share}/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java (100%) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageDesc.java similarity index 86% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageInfo.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageDesc.java index 419436c41aa14..82fa541145828 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageDesc.java @@ -31,15 +31,15 @@ import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.ApplicationLayout; -record AppImageInfo(AppImageLayout imageLayout, Path path) { +record AppImageDesc(AppImageLayout appImageLyout, Path path) { - AppImageInfo { - Objects.requireNonNull(imageLayout); + AppImageDesc { + Objects.requireNonNull(appImageLyout); Objects.requireNonNull(path); } - AppImageLayout resolvedImagelayout() { - return imageLayout.resolveAt(path); + AppImageLayout resolvedAppImagelayout() { + return appImageLyout.resolveAt(path); } Optional asResolvedApplicationLayout() { @@ -47,7 +47,7 @@ Optional asResolvedApplicationLayout() { } Optional asApplicationLayout() { - if (imageLayout instanceof ApplicationLayout layout) { + if (appImageLyout instanceof ApplicationLayout layout) { return Optional.of(layout); } else { return Optional.empty(); diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java similarity index 100% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java rename to test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java similarity index 100% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java rename to test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java similarity index 100% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java rename to test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java similarity index 100% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java rename to test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java similarity index 100% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java rename to test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java similarity index 100% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java rename to test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java similarity index 100% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java rename to test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java diff --git a/test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java similarity index 100% rename from test/jdk/tools/jpackage/junit/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java rename to test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java From 85d99293006407a6c9fd1291215b1740842174aa Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 16 Feb 2025 13:15:20 -0500 Subject: [PATCH 0309/1101] Get rid of BuildEnv.Proxy --- .../jdk/jpackage/internal/BuildEnv.java | 63 ++++++------------- 1 file changed, 18 insertions(+), 45 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java index 7f970ede59bcd..de3907b290f1e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java @@ -53,29 +53,31 @@ default Path configDir() { OverridableResource createResource(String defaultName); static BuildEnv withAppImageDir(BuildEnv env, Path appImageDir) { - return new Proxy(env) { - @Override - public Path appImageDir() { - return appImageDir; - } - }; + return ((Internal.DefaultBuildEnv)env).copyWithAppImageDir(appImageDir); } static BuildEnv create(Path buildRoot, Optional resourceDir, boolean verbose, Class resourceLocator) { - return new BuildEnv() { - @Override - public Path buildRoot() { - return buildRoot; + return new Internal.DefaultBuildEnv(buildRoot, resourceDir, verbose, resourceLocator, Optional.empty()); + } + + static final class Internal { + private static record DefaultBuildEnv(Path buildRoot, Optional resourceDir, + boolean verbose, Class resourceLocator, Optional optAppImageDir) implements BuildEnv { + + DefaultBuildEnv { + Objects.requireNonNull(buildRoot); + Objects.requireNonNull(resourceDir); + Objects.requireNonNull(resourceLocator); + Objects.requireNonNull(optAppImageDir); } - @Override - public boolean verbose() { - return verbose; + DefaultBuildEnv copyWithAppImageDir(Path appImageDir) { + return new DefaultBuildEnv(buildRoot, resourceDir, verbose, resourceLocator, Optional.of(appImageDir)); } @Override - public Optional resourceDir() { - return resourceDir; + public Path appImageDir() { + return optAppImageDir.orElseGet(BuildEnv.super::appImageDir); } @Override @@ -86,37 +88,8 @@ public OverridableResource createResource(String defaultName) { } else { resource = new OverridableResource(); } - return resource.setResourceDir(resourceDir.orElse(null)); + return resourceDir.map(resource::setResourceDir).orElse(resource); } - }; - } - - static class Proxy implements BuildEnv { - - Proxy(BuildEnv target) { - this.target = Objects.requireNonNull(target); - } - - @Override - final public Path buildRoot() { - return target.buildRoot(); - } - - @Override - final public boolean verbose() { - return target.verbose(); } - - @Override - final public Optional resourceDir() { - return target.resourceDir(); - } - - @Override - final public OverridableResource createResource(String defaultName) { - return target.createResource(defaultName); - } - - private final BuildEnv target; } } From f13f0007cdd352bf6fa50ba2f5f50f3cbafd2c08 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 19 Feb 2025 11:54:53 -0500 Subject: [PATCH 0310/1101] Reworked to add support for java.nio.file.CopyOption --- .../jdk/jpackage/internal/util/PathGroup.java | 238 ++++++++++-------- 1 file changed, 139 insertions(+), 99 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java index 457db6abb28bd..ee4882190fc19 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java @@ -24,20 +24,23 @@ */ package jdk.jpackage.internal.util; +import static java.util.stream.Collectors.toMap; + import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.CopyOption; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Collection; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; -import java.util.function.BiFunction; -import java.util.stream.Collectors; +import java.util.function.Predicate; import java.util.stream.Stream; -import jdk.jpackage.internal.util.FileUtils; /** * Group of paths. Each path in the group is assigned a unique id. @@ -130,18 +133,39 @@ public List paths() { * @return unique root paths in this path group */ public List roots() { - // Sort by the number of path components in ascending order. - List> sorted = normalizedPaths().stream() - .sorted((a, b) -> a.getKey().getNameCount() - b.getKey().getNameCount()).toList(); - - // Returns `true` if `a` is a parent of `b` - BiFunction, Map.Entry, Boolean> isParentOrSelf = (a, b) -> { - return a == b || b.getKey().startsWith(a.getKey()); - }; - - return sorted.stream().filter( - v -> v == sorted.stream().sequential().filter(v2 -> isParentOrSelf.apply(v2, v)).findFirst().get()) - .map(v -> v.getValue()).toList(); + if (entries.isEmpty()) { + return List.of(); + } + + // Sort by the number of path components in descending order. + final var sorted = entries.entrySet().stream().map(e -> { + return Map.entry(e.getValue().normalize(), e.getValue()); + }).sorted(Comparator.comparingInt(e -> e.getValue().getNameCount() * -1)).distinct().toList(); + + final var shortestNormalizedPath = sorted.getLast().getKey(); + if (shortestNormalizedPath.getNameCount() == 1 && shortestNormalizedPath.getFileName().toString().isEmpty()) { + return List.of(sorted.getLast().getValue()); + } + + final List roots = new ArrayList<>(); + + for (int i = 0; i < sorted.size(); ++i) { + final var path = sorted.get(i).getKey(); + boolean pathIsRoot = true; + for (int j = i + 1; j < sorted.size(); ++j) { + final var maybeParent = sorted.get(j).getKey(); + if (path.getNameCount() > maybeParent.getNameCount() && path.startsWith(maybeParent)) { + pathIsRoot = false; + break; + } + } + + if (pathIsRoot) { + roots.add(sorted.get(i).getValue()); + } + } + + return roots; } /** @@ -155,9 +179,9 @@ public List roots() { */ public long sizeInBytes() throws IOException { long reply = 0; - for (Path dir : roots().stream().filter(f -> Files.isDirectory(f)).collect(Collectors.toList())) { + for (Path dir : roots().stream().filter(Files::isDirectory).toList()) { try (Stream stream = Files.walk(dir)) { - reply += stream.filter(p -> Files.isRegularFile(p)).mapToLong(f -> f.toFile().length()).sum(); + reply += stream.filter(Files::isRegularFile).mapToLong(f -> f.toFile().length()).sum(); } } return reply; @@ -175,7 +199,7 @@ public long sizeInBytes() throws IOException { public PathGroup resolveAt(Path root) { Objects.requireNonNull(root); return new PathGroup(entries.entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey(), e -> root.resolve(e.getValue())))); + .collect(toMap(Map.Entry::getKey, e -> root.resolve(e.getValue())))); } /** @@ -188,8 +212,8 @@ public PathGroup resolveAt(Path root) { * @param dst the destination path group * @throws IOException If an I/O error occurs */ - public void copy(PathGroup dst) throws IOException { - copy(this, dst, null, false); + public void copy(PathGroup dst, CopyOption ...options) throws IOException { + copy(this, dst, new Copy(false, options)); } /** @@ -199,8 +223,9 @@ public void copy(PathGroup dst) throws IOException { * @param dst the destination path group * @throws IOException If an I/O error occurs */ - public void move(PathGroup dst) throws IOException { - copy(this, dst, null, true); + public void move(PathGroup dst, CopyOption ...options) throws IOException { + copy(this, dst, new Copy(true, options)); + deleteEntries(); } /** @@ -212,8 +237,7 @@ public void move(PathGroup dst) throws IOException { * @throws IOException If an I/O error occurs */ public void transform(PathGroup dst, TransformHandler handler) throws IOException { - Objects.requireNonNull(handler); - copy(this, dst, handler, false); + copy(this, dst, handler); } /** @@ -250,102 +274,118 @@ default void createDirectory(Path dir) throws IOException { } } - private static void copy(PathGroup src, PathGroup dst, TransformHandler handler, boolean move) throws IOException { - List> copyItems = new ArrayList<>(); - List excludeItems = new ArrayList<>(); - - for (var id : src.entries.keySet()) { - Path srcPath = src.entries.get(id); - if (dst.entries.containsKey(id)) { - copyItems.add(Map.entry(srcPath, dst.entries.get(id))); + private void deleteEntries() throws IOException { + for (final var file : entries.values()) { + if (Files.isDirectory(file)) { + FileUtils.deleteRecursive(file); } else { - excludeItems.add(srcPath); + Files.deleteIfExists(file); } } - - copy(move, copyItems, excludeItems, handler); } - private static void copy(boolean move, List> entries, List excludePaths, - TransformHandler handler) throws IOException { - - if (handler == null) { - handler = new TransformHandler() { - @Override - public void copyFile(Path src, Path dst) throws IOException { - Files.createDirectories(dst.getParent()); - if (move) { - Files.move(src, dst); - } else { - Files.copy(src, dst); - } - } - - @Override - public void createDirectory(Path dir) throws IOException { - Files.createDirectories(dir); - } - }; + private record CopySpec(Path from, Path to, Path fromNormalized, Path toNormalized) { + CopySpec { + Objects.requireNonNull(from); + Objects.requireNonNull(fromNormalized); + Objects.requireNonNull(to); + Objects.requireNonNull(toNormalized); } - // destination -> source file mapping - Map actions = new HashMap<>(); - for (var action : entries) { - Path src = action.getKey(); - Path dst = action.getValue(); - if (Files.isDirectory(src)) { - try (Stream stream = Files.walk(src)) { - stream.sequential() - .forEach(path -> actions.put(dst.resolve(src.relativize(path)).normalize(), path)); - } - } else { - actions.put(dst.normalize(), src); - } + CopySpec(Path from, Path to) { + this(from, to, from.normalize(), to.normalize()); } + } - for (var action : actions.entrySet()) { - Path dst = action.getKey(); - Path src = action.getValue(); + private static void copy(PathGroup src, PathGroup dst, TransformHandler handler) throws IOException { + List copySpecs = new ArrayList<>(); + List excludePaths = new ArrayList<>(); - if (excludePaths.stream().anyMatch(src::startsWith)) { - continue; + for (final var e : src.entries.entrySet()) { + final var srcPath = e.getValue(); + final var dstPath = dst.entries.get(e.getKey()); + if (dstPath != null) { + copySpecs.add(new CopySpec(srcPath, dstPath)); + } else { + excludePaths.add(srcPath.normalize()); } + } - if (src.equals(dst) || !src.toFile().exists()) { - continue; - } + copy(copySpecs, excludePaths, handler); + } - if (Files.isDirectory(src)) { - handler.createDirectory(dst); + private record Copy(boolean move, CopyOption ... options) implements TransformHandler { + @Override + public void copyFile(Path src, Path dst) throws IOException { + Files.createDirectories(dst.getParent()); + if (move) { + Files.move(src, dst, options); } else { - handler.copyFile(src, dst); + Files.copy(src, dst, options); } } - if (move) { - // Delete source dirs. - for (var entry : entries) { - Path srcFile = entry.getKey(); - if (Files.isDirectory(srcFile)) { - FileUtils.deleteRecursive(srcFile); - } - } + @Override + public void createDirectory(Path dir) throws IOException { + Files.createDirectories(dir); } } - private static Map.Entry normalizedPath(Path v) { - final Path normalized; - if (!v.isAbsolute()) { - normalized = Path.of("./").resolve(v.normalize()); - } else { - normalized = v.normalize(); - } - - return Map.entry(normalized, v); + private static boolean match(Path what, List paths) { + return paths.stream().anyMatch(what::startsWith); } - private List> normalizedPaths() { - return entries.values().stream().map(PathGroup::normalizedPath).collect(Collectors.toList()); + private static void copy(List copySpecs, List excludePaths, + TransformHandler handler) throws IOException { + Objects.requireNonNull(excludePaths); + Objects.requireNonNull(handler); + + final var copySpecMap = copySpecs.stream().mapMulti((copySpec, consumer) -> { + final var src = copySpec.from; + + if (!Files.exists(src) || match(src, excludePaths)) { + return; + } + + if (Files.isDirectory(copySpec.from)) { + final var dst = copySpec.to; + try (final var files = Files.walk(src)) { + files.filter(file -> { + return !match(file, excludePaths); + }).map(file -> { + return new CopySpec(file, dst.resolve(src.relativize(file))); + }).toList().forEach(consumer::accept); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } else { + consumer.accept(copySpec); + } + }).collect(toMap(CopySpec::toNormalized, x -> x, (x, y) -> { + if (x.fromNormalized.equals(y.fromNormalized)) { + // Duplicated copy specs, accept. + return x; + } else { + throw new IllegalStateException(String.format( + "Duplicate source files [%s] and [%s] for [%s] destination file", x.from, y.from, x.to)); + } + })); + + try { + copySpecMap.values().stream().forEach(copySpec -> { + try { + if (Files.isDirectory(copySpec.from)) { + handler.createDirectory(copySpec.to); + } else { + handler.copyFile(copySpec.from, copySpec.to); + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); + } catch (UncheckedIOException ex) { + throw ex.getCause(); + } } private final Map entries; From 9f00466e47561a5a8e22cd1c5ee834e25b907d1e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 19 Feb 2025 11:56:43 -0500 Subject: [PATCH 0311/1101] Add ImmutableDAG.dump() to dump graph in mermaid diagram format for debugging. --- .../jdk/jpackage/internal/pipeline/ImmutableDAG.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java index 76955474a8f3c..60b2293e96468 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java @@ -39,6 +39,7 @@ import java.util.function.Function; import java.util.stream.IntStream; import java.util.stream.Stream; +import java.util.stream.StreamSupport; /** * Immutable directed acyclic graph (DAG). @@ -239,6 +240,17 @@ public List getNoOutgoingEdges() { return getNoOutgoingEdges(edgeMatrix).mapToObj(nodes::get).toList(); } + public void dumpToStdout() { + dump(System.out::println); + } + + public void dump(Consumer sink) { + sink.accept("graph LR;"); // mermaid "left-to-right" graph format + StreamSupport.stream(nodes.spliterator(), true).map(tail -> { + return getHeadsOf(tail).stream().map(head -> tail + "-->" + head); + }).flatMap(x -> x).toList().forEach(sink); + } + private List getAllNodesOf(T node, boolean heads) { final Set nodeIndexes = new TreeSet<>(); traverseNodes(nodes.indexOf(node), edgeMatrix, heads, nodeIndex -> { From 1117658794390e7e5655ab3b48d179f7b2b870b4 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 11:58:50 -0500 Subject: [PATCH 0312/1101] Minor --- .../windows/classes/jdk/jpackage/internal/WinFromParams.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java index 83c08a7e6a1a3..95f16d09575dd 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java @@ -44,7 +44,6 @@ import java.util.List; import java.util.Map; import java.util.UUID; - import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.WinApplication; import jdk.jpackage.internal.model.WinLauncher; From 2587c0bc44badd32bd0f126efdf28813725d79d7 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 11:59:17 -0500 Subject: [PATCH 0313/1101] Remove redundant imports --- .../share/classes/jdk/jpackage/internal/util/PathGroup.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java index ee4882190fc19..e1f2862273623 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java @@ -37,9 +37,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.Set; -import java.util.function.Predicate; import java.util.stream.Stream; /** From 640445b46daddfb8007c02a32fc4fe141dd5ba1f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 12:46:28 -0500 Subject: [PATCH 0314/1101] Use PathGroup to copy runtime --- .../internal/RuntimeBuilderBuilder.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java index 5f91c73fa9244..62f0cd5844126 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java @@ -24,24 +24,27 @@ */ package jdk.jpackage.internal; +import static jdk.jpackage.internal.I18N.buildConfigException; +import static jdk.jpackage.internal.model.RuntimeBuilder.getDefaultModulePath; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; -import static jdk.jpackage.internal.I18N.buildConfigException; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LauncherStartupInfo; import jdk.jpackage.internal.model.RuntimeBuilder; -import static jdk.jpackage.internal.model.RuntimeBuilder.getDefaultModulePath; import jdk.jpackage.internal.util.FileUtils; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; +import jdk.jpackage.internal.util.PathGroup; final class RuntimeBuilderBuilder { @@ -113,11 +116,15 @@ private static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, return appImageLayout -> { try { - // copy whole runtime, need to skip jmods and src.zip - final List excludes = List.of(Path.of("jmods"), Path.of("src.zip")); - FileUtils.copyRecursive(runtimeDir, - appImageLayout.runtimeDirectory(), - excludes, + // copy whole runtime, skipping jmods and src.zip + final var srcPathGroup = new PathGroup(Map.of("root", runtimeDir)); + // JDK8 + srcPathGroup.ghostPath(runtimeDir.resolve("src.zip")); + // Newer JDKs + srcPathGroup.ghostPath(runtimeDir.resolve("lib/src.zip")); + srcPathGroup.ghostPath(runtimeDir.resolve("jmods")); + + srcPathGroup.copy(new PathGroup(Map.of("root", appImageLayout.runtimeDirectory())), LinkOption.NOFOLLOW_LINKS); // if module-path given - copy modules to appDir/mods From a83c45a5d9612a1833b9b1b64b08b05733c7ee56 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 13:06:45 -0500 Subject: [PATCH 0315/1101] Create fake runtime in unique directory. --- .../jpackage/helpers/jdk/jpackage/test/JPackageCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 4b5ecc924a5b4..7613a99a8271d 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -274,7 +274,7 @@ public JPackageCommand setFakeRuntime() { }; addPrerequisiteAction(cmd -> { - Path fakeRuntimeDir = TKit.workDir().resolve("fake_runtime"); + Path fakeRuntimeDir = TKit.createTempDirectory("fake_runtime"); TKit.trace(String.format("Init fake runtime in [%s] directory", fakeRuntimeDir)); From 34ee7e12e7314545a58864a0a345a4217f7ccc3d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 15:27:41 -0500 Subject: [PATCH 0316/1101] Fix PathGroup to properly handle symbolic links copying --- .../jdk/jpackage/internal/util/PathGroup.java | 44 +++++++++++++++---- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java index e1f2862273623..06edb95f6abfe 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java @@ -29,7 +29,9 @@ import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.CopyOption; +import java.nio.file.FileVisitOption; import java.nio.file.Files; +import java.nio.file.LinkOption; import java.nio.file.Path; import java.util.ArrayList; import java.util.Comparator; @@ -211,7 +213,8 @@ public PathGroup resolveAt(Path root) { * @throws IOException If an I/O error occurs */ public void copy(PathGroup dst, CopyOption ...options) throws IOException { - copy(this, dst, new Copy(false, options)); + final var handler = new Copy(false, options); + copy(this, dst, handler, handler.followSymlinks()); } /** @@ -222,7 +225,8 @@ public void copy(PathGroup dst, CopyOption ...options) throws IOException { * @throws IOException If an I/O error occurs */ public void move(PathGroup dst, CopyOption ...options) throws IOException { - copy(this, dst, new Copy(true, options)); + final var handler = new Copy(true, options); + copy(this, dst, handler, handler.followSymlinks()); deleteEntries(); } @@ -235,7 +239,7 @@ public void move(PathGroup dst, CopyOption ...options) throws IOException { * @throws IOException If an I/O error occurs */ public void transform(PathGroup dst, TransformHandler handler) throws IOException { - copy(this, dst, handler); + copy(this, dst, handler, false); } /** @@ -270,6 +274,20 @@ default void copyFile(Path src, Path dst) throws IOException { default void createDirectory(Path dir) throws IOException { } + + /** + * Request to copy a symbolic link from the given source location into the given + * destination location. + * + * @implNote Default implementation calls {@link #copyFile}. + * + * @param src the source symbolic link location + * @param dst the destination symbolic link location + * @throws IOException If an I/O error occurs + */ + default void copySymbolicLink(Path src, Path dst) throws IOException { + copyFile(src, dst); + } } private void deleteEntries() throws IOException { @@ -295,7 +313,7 @@ private record CopySpec(Path from, Path to, Path fromNormalized, Path toNormaliz } } - private static void copy(PathGroup src, PathGroup dst, TransformHandler handler) throws IOException { + private static void copy(PathGroup src, PathGroup dst, TransformHandler handler, boolean followSymlinks) throws IOException { List copySpecs = new ArrayList<>(); List excludePaths = new ArrayList<>(); @@ -309,10 +327,15 @@ private static void copy(PathGroup src, PathGroup dst, TransformHandler handler) } } - copy(copySpecs, excludePaths, handler); + copy(copySpecs, excludePaths, handler, followSymlinks); } - private record Copy(boolean move, CopyOption ... options) implements TransformHandler { + private record Copy(boolean move, boolean followSymlinks, CopyOption ... options) implements TransformHandler { + + Copy(boolean move, CopyOption ... options) { + this(move, !Set.of(options).contains(LinkOption.NOFOLLOW_LINKS), options); + } + @Override public void copyFile(Path src, Path dst) throws IOException { Files.createDirectories(dst.getParent()); @@ -334,7 +357,7 @@ private static boolean match(Path what, List paths) { } private static void copy(List copySpecs, List excludePaths, - TransformHandler handler) throws IOException { + TransformHandler handler, boolean followSymlinks) throws IOException { Objects.requireNonNull(excludePaths); Objects.requireNonNull(handler); @@ -347,7 +370,8 @@ private static void copy(List copySpecs, List excludePaths, if (Files.isDirectory(copySpec.from)) { final var dst = copySpec.to; - try (final var files = Files.walk(src)) { + final var walkMode = followSymlinks ? new FileVisitOption[] { FileVisitOption.FOLLOW_LINKS } : new FileVisitOption[0]; + try (final var files = Files.walk(src, walkMode)) { files.filter(file -> { return !match(file, excludePaths); }).map(file -> { @@ -372,7 +396,9 @@ private static void copy(List copySpecs, List excludePaths, try { copySpecMap.values().stream().forEach(copySpec -> { try { - if (Files.isDirectory(copySpec.from)) { + if (Files.isSymbolicLink(copySpec.from)) { + handler.copySymbolicLink(copySpec.from, copySpec.to); + } else if (Files.isDirectory(copySpec.from)) { handler.createDirectory(copySpec.to); } else { handler.copyFile(copySpec.from, copySpec.to); From e169095ed29440eb828fbda6d7b063b28d292db7 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 16:13:33 -0500 Subject: [PATCH 0317/1101] Make JavaOptionsEqualsTest test work if the default runtime is fake --- test/jdk/tools/jpackage/share/JavaOptionsEqualsTest.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/jdk/tools/jpackage/share/JavaOptionsEqualsTest.java b/test/jdk/tools/jpackage/share/JavaOptionsEqualsTest.java index a4c2a26944a5a..67c78042e8258 100644 --- a/test/jdk/tools/jpackage/share/JavaOptionsEqualsTest.java +++ b/test/jdk/tools/jpackage/share/JavaOptionsEqualsTest.java @@ -75,17 +75,14 @@ public static Collection input() { } public JavaOptionsEqualsTest(String javaAppDesc, String[] jpackageArgs) { - cmd = JPackageCommand.helloAppImage(javaAppDesc); - if (jpackageArgs != null) { - cmd.addArguments(jpackageArgs); - } + cmd = JPackageCommand.helloAppImage(javaAppDesc).ignoreDefaultRuntime(true); + cmd.addArguments(jpackageArgs); } @Test public void test() { cmd.executeAndAssertHelloAppImageCreated(); List output = HelloApp.executeLauncher(cmd).getOutput(); - TKit.assertNotNull(output, "output is null"); TKit.assertTextStream(WARNING1).apply(output.stream()); TKit.assertTextStream(WARNING2).apply(output.stream()); } From 287c6d8be41c3b8f6657f9eee8a1d81d40da9756 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 16:14:48 -0500 Subject: [PATCH 0318/1101] Add RuntimeImageTest.testStrippedFiles() test to verify jmods and src.zip files are stripped from copied runtime --- .../jpackage/share/RuntimeImageTest.java | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/test/jdk/tools/jpackage/share/RuntimeImageTest.java b/test/jdk/tools/jpackage/share/RuntimeImageTest.java index a9bc11db333b9..0c795e7024813 100644 --- a/test/jdk/tools/jpackage/share/RuntimeImageTest.java +++ b/test/jdk/tools/jpackage/share/RuntimeImageTest.java @@ -21,13 +21,14 @@ * questions. */ +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import jdk.jpackage.test.TKit; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.Executor; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JavaTool; -import jdk.jpackage.test.Executor; +import jdk.jpackage.test.TKit; /* * @test @@ -43,7 +44,7 @@ public class RuntimeImageTest { @Test - public static void test() throws Exception { + public static void test() throws IOException { JPackageCommand cmd = JPackageCommand.helloAppImage(); @@ -70,4 +71,27 @@ public static void test() throws Exception { cmd.executeAndAssertHelloAppImageCreated(); } + @Test + public static void testStrippedFiles() throws IOException { + final var cmd = JPackageCommand.helloAppImage().setFakeRuntime(); + + final var runtimePath = Path.of(cmd.executePrerequisiteActions().getArgumentValue("--runtime-image")); + + Files.createDirectories(runtimePath.resolve("jmods")); + Files.createDirectories(runtimePath.resolve("lib")); + Files.createFile(runtimePath.resolve("lib/src.zip")); + Files.createFile(runtimePath.resolve("src.zip")); + + Files.createDirectories(runtimePath.resolve("foo/bar/src.zip")); + Files.createDirectories(runtimePath.resolve("custom/jmods")); + + (new JPackageCommand()).addArguments(cmd.getAllArguments()).executeAndAssertHelloAppImageCreated(); + + final var appRuntimeDir = cmd.appLayout().runtimeHomeDirectory(); + TKit.assertPathExists(appRuntimeDir.resolve("jmods"), false); + TKit.assertPathExists(appRuntimeDir.resolve("lib/src.zip"), false); + TKit.assertPathExists(appRuntimeDir.resolve("src.zip"), false); + TKit.assertDirectoryExists(appRuntimeDir.resolve("foo/bar/src.zip")); + TKit.assertDirectoryExists(appRuntimeDir.resolve("custom/jmods")); + } } From 1fd8040a142ae913b7c90265ff392de2e22443d2 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 16:16:56 -0500 Subject: [PATCH 0319/1101] Add MacPackage to the model --- .../internal/MacDmgPackageBuilder.java | 3 +- .../internal/MacPkgPackageBuilder.java | 3 +- .../jpackage/internal/model/MacPackage.java | 46 +++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java index 37954980c0856..af528dc595484 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java @@ -32,6 +32,7 @@ import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.MacDmgPackageMixin; +import jdk.jpackage.internal.model.MacPackage; final class MacDmgPackageBuilder { @@ -54,7 +55,7 @@ List validatedDmgContent() { } MacDmgPackage create() throws ConfigException { - final var pkg = pkgBuilder.create(); + final var pkg = MacPackage.create(pkgBuilder.create()); return MacDmgPackage.create(pkg, new MacDmgPackageMixin.Stub( Optional.ofNullable(icon).or(((MacApplication)pkg.app())::icon), diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java index 1e111e312c744..ec4f256520dc2 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java @@ -27,6 +27,7 @@ import java.util.Objects; import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.MacPackage; import jdk.jpackage.internal.model.MacPkgPackage; import jdk.jpackage.internal.model.MacPkgPackageMixin; import jdk.jpackage.internal.model.SigningConfig; @@ -43,7 +44,7 @@ MacPkgPackageBuilder signingBuilder(SigningConfigBuilder v) { } MacPkgPackage create() throws ConfigException { - return MacPkgPackage.create(pkgBuilder.create(), + return MacPkgPackage.create(MacPackage.create(pkgBuilder.create()), new MacPkgPackageMixin.Stub(createSigningConfig())); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java new file mode 100644 index 0000000000000..4901d5d8bf7ae --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.nio.file.Path; +import jdk.jpackage.internal.util.CompositeProxy; + +public interface MacPackage extends Package { + + @Override + default AppImageLayout appImageLayout() { + if (isRuntimeInstaller()) { + return RUNTIME_PACKAGE_LAYOUT; + } else { + return Package.super.appImageLayout(); + } + } + + public static MacPackage create(Package pkg) { + return CompositeProxy.create(MacPackage.class, pkg); + } + + public final static RuntimeLayout RUNTIME_PACKAGE_LAYOUT = RuntimeLayout.create(Path.of("Contents/Home")); +} From 6a39ea923fc2f0c7b55b869e1b1ae16ce5bce980 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 16:17:21 -0500 Subject: [PATCH 0320/1101] Minor --- .../share/classes/jdk/jpackage/internal/BuildEnvBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java index 2885715c5d23f..57872489a713c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java @@ -87,7 +87,7 @@ BuildEnvBuilder appImageDirForPackage() { return this; } - static Path defaultAppImageDir(Path root) { + private static Path defaultAppImageDir(Path root) { return root.resolve("image"); } From e5e84c61136a41acf71941bd01a1a05c3329214c Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 16:31:32 -0500 Subject: [PATCH 0321/1101] Add AppImageLayout.rootDirectory() --- .../internal/model/AppImageLayout.java | 16 ++++- .../internal/model/ApplicationLayout.java | 19 ++++- .../internal/model/RuntimeLayout.java | 28 ++++++-- .../internal/model/AppImageLayoutTest.java | 70 +++++++++++++++++++ 4 files changed, 123 insertions(+), 10 deletions(-) create mode 100644 test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/AppImageLayoutTest.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java index 0de3b6526ef12..e92eb19087a63 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java @@ -55,6 +55,14 @@ public interface AppImageLayout { */ Path runtimeDirectory(); + /** + * Root directory of this app image. + * It should normally be equal to Path.of("") for unresolved layout. + * + * @return the root directory of this app image + */ + Path rootDirectory(); + /** * Creates a copy of this app image resolved at the given root directory. * @@ -66,11 +74,11 @@ public interface AppImageLayout { /** * Default implementation of {@link AppImageLayout} interface. */ - record Stub(Path runtimeDirectory) implements AppImageLayout { + record Stub(Path rootDirectory, Path runtimeDirectory) implements AppImageLayout { @Override public AppImageLayout resolveAt(Path base) { - return new Stub(resolveNullablePath(base, runtimeDirectory)); + return new Stub(resolveNullablePath(base, rootDirectory), resolveNullablePath(base, runtimeDirectory)); } } @@ -79,7 +87,8 @@ public AppImageLayout resolveAt(Path base) { * instance. * * It will call every non-static accessible method without parameters and with - * {@link Path} return type of the given {@link AppImageLayout} instance. + * {@link Path} return type of the given {@link AppImageLayout} instance except + * {@link #rootDirectory()} method. *

* For every call, it will save the return value in the output {@link PathGroup} * object under the key equals the name of a function used in the call. @@ -98,6 +107,7 @@ public static PathGroup toPathGroup(AppImageLayout appImageLayout) { .map(Class::getMethods) .flatMap(Stream::of) .filter(m -> !Modifier.isStatic(m.getModifiers())) + .filter(m -> !"rootDirectory".equals(m.getName())) .filter(m -> { return m.getReturnType().isAssignableFrom(Path.class) && m.getParameterCount() == 0; }).>mapMulti((m, consumer) -> { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index a97850b04aa09..7f1c6603c2efa 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -24,10 +24,11 @@ */ package jdk.jpackage.internal.model; +import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; + import java.nio.file.Path; import java.util.Objects; import jdk.jpackage.internal.util.CompositeProxy; -import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; /** * Application app image layout. @@ -72,6 +73,7 @@ private Builder() { } private Builder(ApplicationLayout appLayout) { + rootDirectory = appLayout.rootDirectory(); launchersDirectory = appLayout.launchersDirectory(); appDirectory = appLayout.appDirectory(); runtimeDirectory = appLayout.runtimeDirectory(); @@ -82,6 +84,7 @@ private Builder(ApplicationLayout appLayout) { public ApplicationLayout create() { + Objects.requireNonNull(rootDirectory); Objects.requireNonNull(runtimeDirectory); Objects.requireNonNull(launchersDirectory); Objects.requireNonNull(appDirectory); @@ -90,7 +93,7 @@ public ApplicationLayout create() { Objects.requireNonNull(contentDirectory); return ApplicationLayout.create(new AppImageLayout.Stub( - runtimeDirectory), new ApplicationLayoutMixin.Stub( + rootDirectory, runtimeDirectory), new ApplicationLayoutMixin.Stub( launchersDirectory, appDirectory, appModsDirectory, destktopIntegrationDirectory, contentDirectory)); } @@ -100,6 +103,7 @@ public Builder setAll(String path) { } public Builder setAll(Path path) { + rootDirectory(path); launchersDirectory(path); appDirectory(path); runtimeDirectory(path); @@ -110,6 +114,7 @@ public Builder setAll(Path path) { } public Builder resolveAt(Path base) { + rootDirectory(resolveNullablePath(base, rootDirectory)); launchersDirectory(resolveNullablePath(base, launchersDirectory)); appDirectory(resolveNullablePath(base, appDirectory)); runtimeDirectory(resolveNullablePath(base, runtimeDirectory)); @@ -119,6 +124,15 @@ public Builder resolveAt(Path base) { return this; } + public Builder rootDirectory(String v) { + return rootDirectory(Path.of(v)); + } + + public Builder rootDirectory(Path v) { + rootDirectory = v; + return this; + } + public Builder launchersDirectory(String v) { return launchersDirectory(Path.of(v)); } @@ -173,6 +187,7 @@ public Builder contentDirectory(Path v) { return this; } + private Path rootDirectory = Path.of(""); private Path launchersDirectory; private Path appDirectory; private Path runtimeDirectory; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java index 23a250136ccbe..733fc7a74c303 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,20 +24,38 @@ */ package jdk.jpackage.internal.model; +import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; + import java.nio.file.Path; import jdk.jpackage.internal.util.CompositeProxy; -import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; /** * Java runtime app image layout. *

- * Use {@link #DEFAULT} to get the object implementing this interface. + * Use {@link #DEFAULT} field to get the default runtime app image layout or + * {@link #create(Path)} method to create custom runtime app image layout. */ public interface RuntimeLayout extends AppImageLayout { @Override default RuntimeLayout resolveAt(Path root) { - return create(new AppImageLayout.Stub(resolveNullablePath(root, runtimeDirectory()))); + return create(new AppImageLayout.Stub(resolveNullablePath(root, rootDirectory()), + resolveNullablePath(root, runtimeDirectory()))); + } + + /** + * Creates Java runtime app image layout. + *

+ * {@link #runtimeDirectory()} method + * called on the created object will return the value of the + * runtimeDirectory parameter. {@link #rootDirectory()} method + * called on the created object will return Path.of("") value. + * + * @param runtimeDirectory Java runtime directory + * @return Java runtime app image layout + */ + static RuntimeLayout create(Path runtimeDirectory) { + return create(new AppImageLayout.Stub(Path.of(""), runtimeDirectory)); } private static RuntimeLayout create(AppImageLayout layout) { @@ -51,5 +69,5 @@ private static RuntimeLayout create(AppImageLayout layout) { * the runtime directory is the same as the directory at which the layout is * resolved. */ - static final RuntimeLayout DEFAULT = create(new AppImageLayout.Stub(Path.of(""))); + static final RuntimeLayout DEFAULT = create(Path.of("")); } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/AppImageLayoutTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/AppImageLayoutTest.java new file mode 100644 index 0000000000000..1c863b653b12b --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/AppImageLayoutTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.model; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; + +import java.nio.file.Path; +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.Test; + + +public class AppImageLayoutTest { + + @Test + public void testStub() { + final var root = Path.of("root"); + final var runtime = Path.of("runtime"); + final var layout = new AppImageLayout.Stub(root, runtime); + + assertEquals(root, layout.rootDirectory()); + assertEquals(runtime, layout.runtimeDirectory()); + } + + @Test + public void testPathGroup() { + final var layout = new AppImageLayout.Stub(Path.of("root"), Path.of("runtime")); + + final var pathGroup = AppImageLayout.toPathGroup(layout); + + assertEquals(Set.of("runtimeDirectory"), pathGroup.keys()); + assertEquals(List.of(layout.runtimeDirectory()), pathGroup.paths()); + } + + @Test + public void testResolveAt() { + final var dir = Path.of("foo/bar"); + + final var layout = new AppImageLayout.Stub(Path.of(""), Path.of("runtime")); + + final var resolvedLayout = layout.resolveAt(dir); + + assertNotSame(layout, resolvedLayout); + + assertEquals(dir.resolve(layout.rootDirectory()), resolvedLayout.rootDirectory()); + assertEquals(dir.resolve(layout.runtimeDirectory()), resolvedLayout.runtimeDirectory()); + } +} From 3e7451bd81665e85a32817620c602e429b117360 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 16:33:19 -0500 Subject: [PATCH 0322/1101] Fix MacApplication.appImageDirName() --- .../classes/jdk/jpackage/internal/model/MacApplication.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java index 4c2dee0e7245b..8949cff7fa7f4 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java @@ -49,7 +49,11 @@ default DottedVersion shortVersion() { @Override default Path appImageDirName() { - return Path.of(Application.super.appImageDirName().toString() + ".app"); + if (isRuntime()) { + return Application.super.appImageDirName(); + } else { + return Path.of(Application.super.appImageDirName().toString() + ".app"); + } } default boolean sign() { From 10cfba4375d609922fed8c680c39cd9a91867fa6 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 16:34:35 -0500 Subject: [PATCH 0323/1101] Fix installation directory name for macos packages --- .../jdk/jpackage/internal/PackageBuilder.java | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index 07ec5fed92946..69794ecb3515e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -24,22 +24,17 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.Application; +import static jdk.jpackage.internal.I18N.buildConfigException; + import java.nio.file.Path; import java.util.Objects; import java.util.Optional; -import static jdk.jpackage.internal.I18N.buildConfigException; +import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.Package.Stub; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.StandardPackageType; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; -import static jdk.jpackage.internal.model.StandardPackageType.MAC_DMG; -import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG; -import static jdk.jpackage.internal.model.StandardPackageType.WIN_EXE; -import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; final class PackageBuilder { @@ -55,24 +50,23 @@ Package create() throws ConfigException { if (installDir != null) { var normalizedInstallDir = mapInstallDir(installDir, type); if (type instanceof StandardPackageType stdType) { - boolean addPackageName = true; + Optional installDirName = Optional.of(Path.of(effectiveName)); switch (stdType) { case LINUX_DEB, LINUX_RPM -> { switch (normalizedInstallDir.toString()) { case "/usr", "/usr/local" -> { - addPackageName = false; + installDirName = Optional.empty(); } } } case WIN_EXE, WIN_MSI -> { - addPackageName = false; + installDirName = Optional.empty(); } case MAC_DMG,MAC_PKG -> { + installDirName = Optional.of(app.appImageDirName()); } } - if (addPackageName) { - normalizedInstallDir = normalizedInstallDir.resolve(effectiveName); - } + normalizedInstallDir = installDirName.map(normalizedInstallDir::resolve).orElse(normalizedInstallDir); } relativeInstallDir = normalizedInstallDir; } else if (type instanceof StandardPackageType stdType) { @@ -82,7 +76,7 @@ Package create() throws ConfigException { } if (relativeInstallDir.isAbsolute()) { - relativeInstallDir = Path.of("/").relativize(relativeInstallDir); + relativeInstallDir = relativeInstallDir.getRoot().relativize(relativeInstallDir); } return new Stub( @@ -178,19 +172,17 @@ private static Path mapInstallDir(Path installDir, PackageType pkgType) private static Path defaultInstallDir(StandardPackageType pkgType, String pkgName, Application app) { switch (pkgType) { case WIN_EXE, WIN_MSI -> { - return Path.of(app.name()); + return app.appImageDirName(); } case LINUX_DEB, LINUX_RPM -> { return Path.of("/opt").resolve(pkgName); } case MAC_DMG, MAC_PKG -> { + final Path dirName = app.appImageDirName(); final Path base; - final String dirName; if (app.isRuntime()) { - dirName = pkgName; base = Path.of("/Library/Java/JavaVirtualMachines"); } else { - dirName = pkgName + ".app"; base = Path.of("/Applications"); } return base.resolve(dirName); From 83fe9ccc52528d77376cbc2b4e12608ed4d64e82 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 16:35:57 -0500 Subject: [PATCH 0324/1101] Tune FromParams.createApplicationBuilder() to work with macosx packages --- .../jdk/jpackage/internal/FromParams.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java index 6f38f861df92e..6ce387df692e0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -70,8 +70,14 @@ final class FromParams { static ApplicationBuilder createApplicationBuilder(Map params, - Function, Launcher> launcherMapper, ApplicationLayout appLayout) - throws ConfigException, IOException { + Function, Launcher> launcherMapper, + ApplicationLayout appLayout) throws ConfigException, IOException { + return createApplicationBuilder(params, launcherMapper, appLayout, Optional.of(RuntimeLayout.DEFAULT)); + } + + static ApplicationBuilder createApplicationBuilder(Map params, + Function, Launcher> launcherMapper, + ApplicationLayout appLayout, Optional predefinedRuntimeLayout) throws ConfigException, IOException { final var appBuilder = new ApplicationBuilder(); @@ -85,8 +91,13 @@ static ApplicationBuilder createApplicationBuilder(Map p final var isRuntimeInstaller = isRuntimeInstaller(params); + final var predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.findIn(params); + + final var predefinedRuntimeDirectory = predefinedRuntimeLayout.flatMap( + layout -> predefinedRuntimeImage.map(layout::resolveAt)).map(RuntimeLayout::runtimeDirectory); + if (isRuntimeInstaller) { - appBuilder.appImageLayout(RuntimeLayout.DEFAULT); + appBuilder.appImageLayout(predefinedRuntimeLayout.orElseThrow()); } else { appBuilder.appImageLayout(appLayout); @@ -103,8 +114,7 @@ static ApplicationBuilder createApplicationBuilder(Map p MODULE_PATH.copyInto(params, runtimeBuilderBuilder::modulePath); - final var predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.findIn(params); - predefinedRuntimeImage.ifPresentOrElse(runtimeBuilderBuilder::forRuntime, () -> { + predefinedRuntimeDirectory.ifPresentOrElse(runtimeBuilderBuilder::forRuntime, () -> { final var startupInfos = launchers.asList().stream() .map(Launcher::startupInfo) .map(Optional::orElseThrow).toList(); From 6edbf92b4a415070dd44a9ef91cf512e9c65869d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 16:38:49 -0500 Subject: [PATCH 0325/1101] Follow up for 1fd8040a142ae913b7c90265ff392de2e22443d2 commit --- .../classes/jdk/jpackage/internal/model/MacDmgPackage.java | 4 ++-- .../classes/jdk/jpackage/internal/model/MacPkgPackage.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackage.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackage.java index afb3eba1075c0..9efd4d818be87 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackage.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackage.java @@ -26,9 +26,9 @@ import jdk.jpackage.internal.util.CompositeProxy; -public interface MacDmgPackage extends Package, MacDmgPackageMixin { +public interface MacDmgPackage extends MacPackage, MacDmgPackageMixin { - public static MacDmgPackage create(Package pkg, MacDmgPackageMixin mixin) { + public static MacDmgPackage create(MacPackage pkg, MacDmgPackageMixin mixin) { return CompositeProxy.create(MacDmgPackage.class, pkg, mixin); } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java index 1dd7bbf0e3cac..dbeb40cb17938 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java @@ -26,13 +26,13 @@ import jdk.jpackage.internal.util.CompositeProxy; -public interface MacPkgPackage extends Package, MacPkgPackageMixin { +public interface MacPkgPackage extends MacPackage, MacPkgPackageMixin { default boolean sign() { return signingConfig().flatMap(SigningConfig::identifier).isPresent(); } - public static MacPkgPackage create(Package pkg, MacPkgPackageMixin mixin) { + public static MacPkgPackage create(MacPackage pkg, MacPkgPackageMixin mixin) { return CompositeProxy.create(MacPkgPackage.class, pkg, mixin); } } From 2a8c0ba6fd67cbfcd830fd6c20cc05b614f25a90 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 16:49:31 -0500 Subject: [PATCH 0326/1101] Got rid of `params` in DMG bundler. Enhanced PackagingPipeline to do native packaging. Changed Linux, Windows, and DMG bunders to work inside of the pipeline. All tests but PKG packaging pass. PKG bundler compiles but has not been tested. --- .../internal/LinuxPackageBundler.java | 59 +- .../internal/LinuxPackagingPipeline.java | 27 +- .../jdk/jpackage/internal/MacAppBundler.java | 15 +- .../internal/MacBaseInstallerBundler.java | 36 +- .../jdk/jpackage/internal/MacDmgBundler.java | 509 +---------------- .../jdk/jpackage/internal/MacDmgPackager.java | 531 ++++++++++++++++++ .../jdk/jpackage/internal/MacFromParams.java | 21 +- .../internal/MacPackagingPipeline.java | 209 ++++--- .../resources/MacResources.properties | 2 +- .../jpackage/internal/AppImageBundler.java | 18 +- .../internal/ApplicationImageUtils.java | 38 +- .../jpackage/internal/PackagerBuilder.java | 75 +++ .../jpackage/internal/PackagingPipeline.java | 334 +++++++---- .../jdk/jpackage/internal/WinMsiBundler.java | 54 +- .../internal/WinPackagingPipeline.java | 32 +- 15 files changed, 1078 insertions(+), 882 deletions(-) create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerBuilder.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index c64c61eaf2c58..2e1001daa1de7 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -34,6 +34,8 @@ import java.util.Objects; import java.util.function.Predicate; import java.util.stream.Stream; +import jdk.jpackage.internal.PackagingPipeline.PackageBuildEnv; +import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxPackage; import jdk.jpackage.internal.model.Package; @@ -103,48 +105,41 @@ public final Path execute(Map params, final LinuxPackage pkg = pkgParam.fetchFrom(params); final var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - final BuildEnv pkgEnv; - - if (pkg.app().runtimeBuilder().isEmpty()) { - // Packaging external app image - pkgEnv = BuildEnv.withAppImageDir(env, BuildEnvBuilder.defaultAppImageDir(env.buildRoot())); - } else { - pkgEnv = env; - } - LinuxPackagingPipeline.build() .excludeDirFromCopying(outputParentDir) - .pkgBuildEnvFactory((e, p) -> pkgEnv) + .task(PackagingPipeline.PackageTaskID.CREATE_PACKAGE_FILE) + .packageAction(this::buildPackage) + .add() + .task(PackagingPipeline.PackageTaskID.RUN_POST_IMAGE_USER_SCRIPT) + .noaction() // FIXME: implement post-app-image script execution on Linux + .add() .create().execute(env, pkg, outputParentDir); - try { - for (var ca : customActions) { - ca.init(pkgEnv, pkg); - } + return outputParentDir.resolve(pkg.packageFileNameWithSuffix()).toAbsolutePath(); + } - Map data = createDefaultReplacementData(pkgEnv, pkg); + private void buildPackage(PackageBuildEnv env) throws PackagerException, IOException { + for (var ca : customActions) { + ca.init(env.env(), env.pkg()); + } - for (var ca : customActions) { - ShellCustomAction.mergeReplacementData(data, ca.instance.create()); - } + Map data = createDefaultReplacementData(env.env(), env.pkg()); - data.putAll(createReplacementData(pkgEnv, pkg)); + for (var ca : customActions) { + ShellCustomAction.mergeReplacementData(data, ca.instance.create()); + } - Path packageBundle = buildPackageBundle(Collections.unmodifiableMap( - data), pkgEnv, pkg, outputParentDir); + data.putAll(createReplacementData(env.env(), env.pkg())); - verifyOutputBundle(pkgEnv, pkg, packageBundle).stream() - .filter(Objects::nonNull) - .forEachOrdered(ex -> { - Log.verbose(ex.getLocalizedMessage()); - Log.verbose(ex.getAdvice()); - }); + Path packageBundle = buildPackageBundle(Collections.unmodifiableMap( + data), env.env(), env.pkg(), env.outputDir()); - return packageBundle; - } catch (IOException ex) { - Log.verbose(ex); - throw new PackagerException(ex); - } + verifyOutputBundle(env.env(), env.pkg(), packageBundle).stream() + .filter(Objects::nonNull) + .forEachOrdered(ex -> { + Log.verbose(ex.getLocalizedMessage()); + Log.verbose(ex.getAdvice()); + }); } private List getListOfNeededPackages(BuildEnv env) throws IOException { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java index 58afec87cd48d..8c169b959b2d0 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java @@ -25,12 +25,13 @@ package jdk.jpackage.internal; import static jdk.jpackage.internal.ApplicationImageUtils.createLauncherIconResource; +import jdk.jpackage.internal.PackagingPipeline.AppImageBuildEnv; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; -import jdk.jpackage.internal.PackagingPipeline.AppImageTaskID; +import jdk.jpackage.internal.PackagingPipeline.BuildApplicationTaskID; import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; import jdk.jpackage.internal.PackagingPipeline.TaskID; import jdk.jpackage.internal.model.Application; @@ -48,27 +49,29 @@ static PackagingPipeline.Builder build() { return PackagingPipeline.buildStandard() .task(LinuxAppImageTaskID.LAUNCHER_LIB) .addDependent(PrimaryTaskID.BUILD_APPLICATION_IMAGE) - .action(LinuxPackagingPipeline::writeLauncherLib).add() + .applicationAction(LinuxPackagingPipeline::writeLauncherLib).add() .task(LinuxAppImageTaskID.LAUNCHER_ICONS) - .addDependent(AppImageTaskID.CONTENT) - .action(LinuxPackagingPipeline::writeLauncherIcons).add(); + .addDependent(BuildApplicationTaskID.CONTENT) + .applicationAction(LinuxPackagingPipeline::writeLauncherIcons).add(); } - private static void writeLauncherLib(BuildEnv env, Application app, - ApplicationLayout appLayout) throws IOException { - var launcherLib = ((LinuxApplicationLayout)appLayout).libAppLauncher(); + private static void writeLauncherLib( + AppImageBuildEnv env) throws IOException { + + final var launcherLib = env.resolvedLayout().libAppLauncher(); try (var in = ResourceLocator.class.getResourceAsStream("libjpackageapplauncheraux.so")) { Files.createDirectories(launcherLib.getParent()); Files.copy(in, launcherLib); } } - private static void writeLauncherIcons(BuildEnv env, Application app, - ApplicationLayout appLayout) throws IOException { - for (var launcher : app.launchers()) { - createLauncherIconResource(app, launcher, env::createResource).ifPresent(iconResource -> { + private static void writeLauncherIcons( + AppImageBuildEnv env) throws IOException { + + for (var launcher : env.app().launchers()) { + createLauncherIconResource(env.app(), launcher, env.env()::createResource).ifPresent(iconResource -> { String iconFileName = launcher.executableName() + ".png"; - Path iconTarget = appLayout.destktopIntegrationDirectory().resolve(iconFileName); + Path iconTarget = env.resolvedLayout().destktopIntegrationDirectory().resolve(iconFileName); try { iconResource.saveToFile(iconTarget); } catch (IOException ex) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index 4eb6ded6f4131..973970d6c02a1 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -46,20 +46,9 @@ public MacAppBundler() { final var app = MacFromParams.APPLICATION.fetchFrom(params); final var env = BuildEnv.withAppImageDir(BuildEnvFromParams.BUILD_ENV.fetchFrom(params), output); - final var taskPipelineBuilder = MacPackagingPipeline.build() + MacPackagingPipeline.build(Optional.empty()) .excludeDirFromCopying(output.getParent()) - .excludeDirFromCopying(OUTPUT_DIR.fetchFrom(params)) - .inputApplicationLayoutForPackaging(pkg -> pkg.app().asApplicationLayout()); - - final var pkg = FromParams.getCurrentPackage(params); - if (pkg.isPresent()) { - taskPipelineBuilder.pkgBuildEnvFactory((e, p) -> { - return BuildEnv.withAppImageDir(e, output); - }); - taskPipelineBuilder.create().execute(env, pkg.orElseThrow(), output); - } else { - taskPipelineBuilder.create().execute(env, app); - } + .excludeDirFromCopying(OUTPUT_DIR.fetchFrom(params)).create().execute(env, app); }); setParamsValidator(MacAppBundler::doValidate); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index 915ad36d8299b..6d48f18a311af 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -26,10 +26,8 @@ package jdk.jpackage.internal; import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.PackagerException; import java.io.IOException; import java.nio.file.Files; -import java.nio.file.LinkOption; import java.nio.file.Path; import java.text.MessageFormat; import java.util.Map; @@ -37,6 +35,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; +import static jdk.jpackage.internal.StandardBundlerParam.OUTPUT_DIR; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; @@ -130,8 +129,7 @@ static String getInstallDir( } public MacBaseInstallerBundler() { - appImageBundler = new MacAppBundler() - .setDependentTask(true); + appImageBundler = new MacAppBundler(); } protected void validateAppImageAndBundeler( @@ -177,36 +175,6 @@ protected void validateAppImageAndBundeler( } } - protected Path prepareAppBundle(Map params) - throws PackagerException, IOException { - Path appDir; - Path appImageRoot = APP_IMAGE_TEMP_ROOT.fetchFrom(params); - Path predefinedImage = - StandardBundlerParam.getPredefinedAppImage(params); - if (predefinedImage != null) { - appDir = appImageRoot.resolve(APP_NAME.fetchFrom(params) + ".app"); - FileUtils.copyRecursive(predefinedImage, appDir, - LinkOption.NOFOLLOW_LINKS); - - // Create PackageFile if predefined app image is not signed - if (!StandardBundlerParam.isRuntimeInstaller(params) && - !new MacAppImageFileExtras(PREDEFINED_APP_IMAGE_FILE.fetchFrom(params)).signed()) { - new PackageFile(APP_NAME.fetchFrom(params)).save( - ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT.resolveAt(appDir)); - // We need to re-sign app image after adding ".package" to it. - // We only do this if app image was not signed which means it is - // signed with ad-hoc signature. App bundles with ad-hoc - // signature are sealed, but without a signing identity, so we - // need to re-sign it after modification. - MacAppImageBuilder.signAppBundle(params, appDir, "-", null, null); - } - } else { - appDir = appImageBundler.execute(params, appImageRoot); - } - - return appDir; - } - @Override public String getBundleType() { return "INSTALLER"; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java index d101a72b5467e..5c9e7fdc3707c 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java @@ -25,514 +25,15 @@ package jdk.jpackage.internal; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.Base64; -import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Objects; import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.MacApplication; -import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.util.FileUtils; -import jdk.jpackage.internal.util.PathGroup; public class MacDmgBundler extends MacBaseInstallerBundler { - // Background image name in resources - static final String DEFAULT_BACKGROUND_IMAGE = "background_dmg.tiff"; - // Background image name and folder under which it will be stored in DMG - static final String BACKGROUND_IMAGE_FOLDER =".background"; - static final String BACKGROUND_IMAGE = "background.tiff"; - static final String DEFAULT_DMG_SETUP_SCRIPT = "DMGsetup.scpt"; - static final String TEMPLATE_BUNDLE_ICON = "JavaApp.icns"; - - static final String DEFAULT_LICENSE_PLIST="lic_template.plist"; - - public Path bundle(Map params, - Path outdir) throws PackagerException { - - final var pkg = MacFromParams.DMG_PACKAGE.fetchFrom(params); - var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - - Log.verbose(MessageFormat.format(I18N.getString("message.building-dmg"), - pkg.app().name())); - - IOUtils.writableOutputDir(outdir); - - try { - env = BuildEnv.withAppImageDir(env, prepareAppBundle(params)); - - prepareConfigFiles(pkg, env); - Path configScript = getConfig_Script(pkg, env); - if (IOUtils.exists(configScript)) { - IOUtils.run("bash", configScript); - } - - return buildDMG(pkg, env, outdir); - } catch (IOException | PackagerException ex) { - Log.verbose(ex); - throw new PackagerException(ex); - } - } - - private static final String hdiutil = "/usr/bin/hdiutil"; - - private static Path imagesRoot(MacDmgPackage pkg, BuildEnv env) { - return env.buildRoot().resolve("dmg-images"); - } - - private void prepareDMGSetupScript(MacDmgPackage pkg, BuildEnv env) throws IOException { - Path dmgSetup = getConfig_VolumeScript(pkg, env); - Log.verbose(MessageFormat.format( - I18N.getString("message.preparing-dmg-setup"), - dmgSetup.toAbsolutePath().toString())); - - // We need to use URL for DMG to find it. We cannot use volume name, since - // user might have open DMG with same volume name already. Url should end with - // '/' and it should be real path (no symbolic links). - Path imageDir = imagesRoot(pkg, env); - - Files.createDirectories(imageDir); - - Path rootPath = imageDir.toRealPath(); - Path volumePath = rootPath.resolve(pkg.app().name()); - String volumeUrl = volumePath.toUri().toString() + File.separator; - - // Provide full path to background image, so we can find it. - Path bgFile = Path.of(rootPath.toString(), pkg.app().name(), - BACKGROUND_IMAGE_FOLDER, BACKGROUND_IMAGE); - - // Prepare DMG setup script - Map data = new HashMap<>(); - data.put("DEPLOY_VOLUME_URL", volumeUrl); - data.put("DEPLOY_BG_FILE", bgFile.toString()); - data.put("DEPLOY_VOLUME_PATH", volumePath.toString()); - data.put("DEPLOY_APPLICATION_NAME", pkg.app().name()); - String targetItem = pkg.isRuntimeInstaller() ? - pkg.app().name() : env.appImageDir().getFileName().toString(); - data.put("DEPLOY_TARGET", targetItem); - data.put("DEPLOY_INSTALL_LOCATION", installRoot(pkg).toString()); - data.put("DEPLOY_INSTALL_LOCATION_DISPLAY_NAME", - getInstallDirDisplayName(pkg)); - - env.createResource(DEFAULT_DMG_SETUP_SCRIPT) - .setCategory(I18N.getString("resource.dmg-setup-script")) - .setSubstitutionData(data) - .saveToFile(dmgSetup); - } - - private static Path installRoot(MacDmgPackage pkg) { - if (pkg.isRuntimeInstaller()) { - return Path.of("/Library/Java/JavaVirtualMachines"); - } else { - return Path.of("/Applications"); - } - } - - // Returns display name of installation directory. Display name is used to - // show user installation location and for well known (default only) we will - // use "Applications" or "JavaVirtualMachines". - private static String getInstallDirDisplayName(MacDmgPackage pkg) { - return installRoot(pkg).getFileName().toString(); - } - - private Path getConfig_VolumeScript(MacDmgPackage pkg, BuildEnv env) { - return env.configDir().resolve(pkg.app().name() + "-dmg-setup.scpt"); - } - - private Path getConfig_VolumeBackground(MacDmgPackage pkg, BuildEnv env) { - return env.configDir().resolve(pkg.app().name() + "-background.tiff"); - } - - private Path getConfig_VolumeIcon(MacDmgPackage pkg, BuildEnv env) { - return env.configDir().resolve(pkg.app().name() + "-volume.icns"); - } - - private Path getConfig_LicenseFile(MacDmgPackage pkg, BuildEnv env) { - return env.configDir().resolve(pkg.app().name() + "-license.plist"); - } - - private void prepareLicense(MacDmgPackage pkg, BuildEnv env) { - try { - final var licFile = pkg.licenseFile(); - if (licFile.isEmpty()) { - return; - } - - byte[] licenseContentOriginal = - Files.readAllBytes(licFile.orElseThrow()); - String licenseInBase64 = - Base64.getEncoder().encodeToString(licenseContentOriginal); - - Map data = new HashMap<>(); - data.put("APPLICATION_LICENSE_TEXT", licenseInBase64); - - env.createResource(DEFAULT_LICENSE_PLIST) - .setCategory(I18N.getString("resource.license-setup")) - .setSubstitutionData(data) - .saveToFile(getConfig_LicenseFile(pkg, env)); - - } catch (IOException ex) { - Log.verbose(ex); - } - } - - private void prepareConfigFiles(MacDmgPackage pkg, BuildEnv env) throws IOException { - - env.createResource(DEFAULT_BACKGROUND_IMAGE) - .setCategory(I18N.getString("resource.dmg-background")) - .saveToFile(getConfig_VolumeBackground(pkg, env)); - - env.createResource(TEMPLATE_BUNDLE_ICON) - .setCategory(I18N.getString("resource.volume-icon")) - .setExternal(pkg.icon().orElse(null)) - .saveToFile(getConfig_VolumeIcon(pkg, env)); - - env.createResource(null) - .setCategory(I18N.getString("resource.post-install-script")) - .saveToFile(getConfig_Script(pkg, env)); - - prepareLicense(pkg, env); - - prepareDMGSetupScript(pkg, env); - } - - // name of post-image script - private Path getConfig_Script(MacDmgPackage pkg, BuildEnv env) { - return env.configDir().resolve(pkg.app().name() + "-post-image.sh"); - } - - // Location of SetFile utility may be different depending on MacOS version - // We look for several known places and if none of them work will - // try ot find it - private String findSetFileUtility() { - String typicalPaths[] = {"/Developer/Tools/SetFile", - "/usr/bin/SetFile", "/Developer/usr/bin/SetFile"}; - - String setFilePath = null; - for (String path : typicalPaths) { - Path f = Path.of(path); - if (Files.exists(f) && Files.isExecutable(f)) { - setFilePath = path; - break; - } - } - - // Validate SetFile, if Xcode is not installed it will run, but exit with error - // code - if (setFilePath != null) { - try { - ProcessBuilder pb = new ProcessBuilder(setFilePath, "-h"); - Process p = pb.start(); - int code = p.waitFor(); - if (code == 0) { - return setFilePath; - } - } catch (Exception ignored) {} - - // No need for generic find attempt. We found it, but it does not work. - // Probably due to missing xcode. - return null; - } - - // generic find attempt - try { - ProcessBuilder pb = new ProcessBuilder("/usr/bin/xcrun", "-find", "SetFile"); - Process p = pb.start(); - InputStreamReader isr = new InputStreamReader(p.getInputStream()); - BufferedReader br = new BufferedReader(isr); - String lineRead = br.readLine(); - if (lineRead != null) { - Path f = Path.of(lineRead); - if (Files.exists(f) && Files.isExecutable(f)) { - return f.toAbsolutePath().toString(); - } - } - } catch (IOException ignored) {} - - return null; - } - - private Path buildDMG(MacDmgPackage pkg, BuildEnv env, Path outdir) throws IOException { - boolean copyAppImage = false; - Path imagesRoot = imagesRoot(pkg, env); - if (!Files.exists(imagesRoot)) { - Files.createDirectories(imagesRoot); - } - - Path protoDMG = imagesRoot.resolve(pkg.app().name() - + "-tmp.dmg"); - Path finalDMG = outdir.resolve(pkg.packageFileNameWithSuffix()); - - Path srcFolder = env.appImageDir().getParent(); - if (pkg.isRuntimeInstaller()) { - Path newRoot = Files.createTempDirectory(env.buildRoot(), - "root-"); - - // first, is this already a runtime with - // /Contents/Home - if so we need the Home dir - Path home = env.appImageDir().resolve("Contents/Home"); - Path source = (Files.exists(home)) ? home : env.appImageDir(); - - // Then we need to put back the /Content/Home - Path root = newRoot.resolve(((MacApplication)pkg.app()).bundleIdentifier()); - Path dest = root.resolve("Contents/Home"); - - FileUtils.copyRecursive(source, dest); - - srcFolder = newRoot; - } - - Log.verbose(MessageFormat.format(I18N.getString( - "message.creating-dmg-file"), finalDMG.toAbsolutePath())); - - Files.deleteIfExists(protoDMG); - try { - Files.deleteIfExists(finalDMG); - } catch (IOException ex) { - throw new IOException(MessageFormat.format(I18N.getString( - "message.dmg-cannot-be-overwritten"), - finalDMG.toAbsolutePath())); - } - - Files.createDirectories(protoDMG.getParent()); - Files.createDirectories(finalDMG.getParent()); - - String hdiUtilVerbosityFlag = env.verbose() ? - "-verbose" : "-quiet"; - List dmgContent = pkg.content(); - for (Path path : dmgContent) { - FileUtils.copyRecursive(path, srcFolder.resolve(path.getFileName())); - } - // create temp image - ProcessBuilder pb = new ProcessBuilder( - hdiutil, - "create", - hdiUtilVerbosityFlag, - "-srcfolder", srcFolder.toAbsolutePath().toString(), - "-volname", pkg.app().name(), - "-ov", protoDMG.toAbsolutePath().toString(), - "-fs", "HFS+", - "-format", "UDRW"); - try { - IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); - } catch (IOException ex) { - Log.verbose(ex); // Log exception - - // Creating DMG from entire app image failed, so lets try to create empty - // DMG and copy files manually. See JDK-8248059. - copyAppImage = true; - - long size = new PathGroup(Map.of(new Object(), srcFolder)).sizeInBytes(); - size += 50 * 1024 * 1024; // Add extra 50 megabytes. Actually DMG size will - // not be bigger, but it will able to hold additional 50 megabytes of data. - // We need extra room for icons and background image. When we providing - // actual files to hdiutil, it will create DMG with ~50 megabytes extra room. - pb = new ProcessBuilder( - hdiutil, - "create", - hdiUtilVerbosityFlag, - "-size", String.valueOf(size), - "-volname", pkg.app().name(), - "-ov", protoDMG.toAbsolutePath().toString(), - "-fs", "HFS+"); - new RetryExecutor() - .setMaxAttemptsCount(10) - .setAttemptTimeoutMillis(3000) - .setWriteOutputToFile(true) - .execute(pb); - } - - // mount temp image - pb = new ProcessBuilder( - hdiutil, - "attach", - protoDMG.toAbsolutePath().toString(), - hdiUtilVerbosityFlag, - "-mountroot", imagesRoot.toAbsolutePath().toString()); - IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); - - Path mountedRoot = imagesRoot.resolve(pkg.app().name()); - - // Copy app image, since we did not create DMG with it, but instead we created - // empty one. - if (copyAppImage) { - // In case of predefine app image srcFolder will point to app bundle, so if - // we use it as is we will copy content of app bundle, but we need app bundle - // folder as well. - if (srcFolder.toString().toLowerCase().endsWith(".app")) { - Path destPath = mountedRoot - .resolve(srcFolder.getFileName()); - Files.createDirectory(destPath); - FileUtils.copyRecursive(srcFolder, destPath); - } else { - FileUtils.copyRecursive(srcFolder, mountedRoot); - } - } - - try { - // background image - Path bgdir = mountedRoot.resolve(BACKGROUND_IMAGE_FOLDER); - Files.createDirectories(bgdir); - IOUtils.copyFile(getConfig_VolumeBackground(pkg, env), - bgdir.resolve(BACKGROUND_IMAGE)); - - // We will not consider setting background image and creating link - // to install-dir in DMG as critical error, since it can fail in - // headless environment. - try { - pb = new ProcessBuilder("/usr/bin/osascript", - getConfig_VolumeScript(pkg, env).toAbsolutePath().toString()); - IOUtils.exec(pb, 180); // Wait 3 minutes. See JDK-8248248. - } catch (IOException ex) { - Log.verbose(ex); - } - - // volume icon - Path volumeIconFile = mountedRoot.resolve(".VolumeIcon.icns"); - IOUtils.copyFile(getConfig_VolumeIcon(pkg, env), - volumeIconFile); - - // Indicate that we want a custom icon - // NB: attributes of the root directory are ignored - // when creating the volume - // Therefore we have to do this after we mount image - String setFileUtility = findSetFileUtility(); - if (setFileUtility != null) { - //can not find utility => keep going without icon - try { - volumeIconFile.toFile().setWritable(true); - // The "creator" attribute on a file is a legacy attribute - // but it seems Finder excepts these bytes to be - // "icnC" for the volume icon - // (might not work on Mac 10.13 with old XCode) - pb = new ProcessBuilder( - setFileUtility, - "-c", "icnC", - volumeIconFile.toAbsolutePath().toString()); - IOUtils.exec(pb); - volumeIconFile.toFile().setReadOnly(); - - pb = new ProcessBuilder( - setFileUtility, - "-a", "C", - mountedRoot.toAbsolutePath().toString()); - IOUtils.exec(pb); - } catch (IOException ex) { - Log.error(ex.getMessage()); - Log.verbose("Cannot enable custom icon using SetFile utility"); - } - } else { - Log.verbose(I18N.getString("message.setfile.dmg")); - } - - } finally { - // Detach the temporary image - pb = new ProcessBuilder( - hdiutil, - "detach", - hdiUtilVerbosityFlag, - mountedRoot.toAbsolutePath().toString()); - // "hdiutil detach" might not work right away due to resource busy error, so - // repeat detach several times. - RetryExecutor retryExecutor = new RetryExecutor(); - // Image can get detach even if we got resource busy error, so stop - // trying to detach it if it is no longer attached. - retryExecutor.setExecutorInitializer(exec -> { - if (!Files.exists(mountedRoot)) { - retryExecutor.abort(); - } - }); - try { - // 10 times with 6 second delays. - retryExecutor.setMaxAttemptsCount(10).setAttemptTimeoutMillis(6000) - .execute(pb); - } catch (IOException ex) { - if (!retryExecutor.isAborted()) { - // Now force to detach if it still attached - if (Files.exists(mountedRoot)) { - pb = new ProcessBuilder( - hdiutil, - "detach", - "-force", - hdiUtilVerbosityFlag, - mountedRoot.toAbsolutePath().toString()); - IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); - } - } - } - } - - // Compress it to a new image - pb = new ProcessBuilder( - hdiutil, - "convert", - protoDMG.toAbsolutePath().toString(), - hdiUtilVerbosityFlag, - "-format", "UDZO", - "-o", finalDMG.toAbsolutePath().toString()); - try { - new RetryExecutor() - .setMaxAttemptsCount(10) - .setAttemptTimeoutMillis(3000) - .execute(pb); - } catch (Exception ex) { - // Convert might failed if something holds file. Try to convert copy. - Path protoDMG2 = imagesRoot - .resolve(pkg.app().name() + "-tmp2.dmg"); - Files.copy(protoDMG, protoDMG2); - try { - pb = new ProcessBuilder( - hdiutil, - "convert", - protoDMG2.toAbsolutePath().toString(), - hdiUtilVerbosityFlag, - "-format", "UDZO", - "-o", finalDMG.toAbsolutePath().toString()); - IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); - } finally { - Files.deleteIfExists(protoDMG2); - } - } - - //add license if needed - if (Files.exists(getConfig_LicenseFile(pkg, env))) { - pb = new ProcessBuilder( - hdiutil, - "udifrez", - finalDMG.toAbsolutePath().toString(), - "-xml", - getConfig_LicenseFile(pkg, env).toAbsolutePath().toString() - ); - new RetryExecutor() - .setMaxAttemptsCount(10) - .setAttemptTimeoutMillis(3000) - .execute(pb); - } - - //Delete the temporary image - Files.deleteIfExists(protoDMG); - - Log.verbose(MessageFormat.format(I18N.getString( - "message.output-to-location"), - pkg.app().name(), finalDMG.toAbsolutePath().toString())); - - return finalDMG; - } - - - /* - * Implement Bundler - */ - @Override public String getName() { return I18N.getString("dmg.bundler.name"); @@ -568,7 +69,15 @@ public boolean validate(Map params) @Override public Path execute(Map params, Path outputParentDir) throws PackagerException { - return bundle(params, outputParentDir); + + final var pkg = MacFromParams.DMG_PACKAGE.fetchFrom(params); + var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + + final var builder = MacDmgPackager.build().outputDir(outputParentDir).pkg(pkg).env(env); + + MacDmgPackager.findSetFileUtility().ifPresent(builder::setFileUtility); + + return builder.execute(); } @Override diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java new file mode 100644 index 0000000000000..0b015ee754550 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java @@ -0,0 +1,531 @@ +/* + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.text.MessageFormat; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Stream; +import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; +import jdk.jpackage.internal.PackagingPipeline.StartupParameters; +import jdk.jpackage.internal.PackagingPipeline.TaskID; +import jdk.jpackage.internal.model.MacDmgPackage; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.PathGroup; + +record MacDmgPackager(MacDmgPackage pkg, BuildEnv env, Path hdiutil, Path outputDir, Optional setFileUtility) { + + MacDmgPackager { + Objects.requireNonNull(pkg); + Objects.requireNonNull(env); + Objects.requireNonNull(hdiutil); + Objects.requireNonNull(outputDir); + Objects.requireNonNull(setFileUtility); + } + + static Builder build() { + return new Builder(); + } + + static final class Builder extends PackagerBuilder { + + Builder hdiutil(Path v) { + hdiutil = v; + return this; + } + + Builder setFileUtility(Path v) { + setFileUtility = v; + return this; + } + + Path execute() throws PackagerException { + Log.verbose(MessageFormat.format(I18N.getString("message.building-dmg"), + pkg.app().name())); + + IOUtils.writableOutputDir(outputDir); + + return execute(MacPackagingPipeline.build(Optional.of(pkg))); + } + + @Override + protected void configurePackagingPipeline(PackagingPipeline.Builder pipelineBuilder, + StartupParameters startupParameters) { + final var packager = new MacDmgPackager(pkg, startupParameters.packagingEnv(), + validatedHdiutil(), outputDir, Optional.ofNullable(setFileUtility)); + packager.applyToPipeline(pipelineBuilder); + } + + private Path validatedHdiutil() { + return Optional.ofNullable(hdiutil).orElse(HDIUTIL); + } + + private Path hdiutil; + private Path setFileUtility; + } + + // Location of SetFile utility may be different depending on MacOS version + // We look for several known places and if none of them work will + // try ot find it + static Optional findSetFileUtility() { + String typicalPaths[] = {"/Developer/Tools/SetFile", + "/usr/bin/SetFile", "/Developer/usr/bin/SetFile"}; + + final var setFilePath = Stream.of(typicalPaths).map(Path::of).filter(Files::isExecutable).findFirst(); + if (setFilePath.isPresent()) { + // Validate SetFile, if Xcode is not installed it will run, but exit with error + // code + try { + if (Executor.of(setFilePath.orElseThrow().toString(), "-h").setQuiet(true).execute() == 0) { + return setFilePath; + } + } catch (Exception ignored) { + // No need for generic find attempt. We found it, but it does not work. + // Probably due to missing xcode. + return Optional.empty(); + } + } + + // generic find attempt + try { + final var executor = Executor.of("/usr/bin/xcrun", "-find", "SetFile"); + final var code = executor.setQuiet(true).saveOutput(true).execute(); + if (code == 0 && executor.getOutput().isEmpty()) { + final var firstLine = executor.getOutput().getFirst(); + Path f = Path.of(firstLine); + if (Files.exists(f) && Files.isExecutable(f)) { + return Optional.of(f.toAbsolutePath()); + } + } + } catch (IOException ignored) {} + + return Optional.empty(); + } + + void applyToPipeline(PackagingPipeline.Builder pipelineBuilder) { + pipelineBuilder + .excludeDirFromCopying(outputDir) + .task(DmgPackageTaskID.COPY_DMG_CONTENT) + .action(this::copyDmgContent) + .addDependent(PackageTaskID.CREATE_PACKAGE_FILE) + .add() + .task(PackageTaskID.CREATE_CONFIG_FILES) + .action(this::prepareConfigFiles) + .add() + .task(PackageTaskID.CREATE_PACKAGE_FILE) + .action(this::buildDMG) + .add(); + } + + enum DmgPackageTaskID implements TaskID { + COPY_DMG_CONTENT + } + + Path volumePath() { + return dmgWorkdir(); + } + + String volumeName() { + return pkg.app().name(); + } + + String createVolumeUrlLocation() throws IOException { + Files.createDirectories(volumePath()); + // Url should end with '/' and it should be real path (no symbolic links). + return volumePath().toRealPath().resolve(volumeName()).toUri().toString() + File.separator; + } + + Path volumeScript() { + return env.configDir().resolve(pkg.app().name() + "-dmg-setup.scpt"); + } + + Path volumeBackground() { + return env.configDir().resolve(pkg.app().name() + "-background.tiff"); + } + + Path volumeIcon() { + return env.configDir().resolve(pkg.app().name() + "-volume.icns"); + } + + Path licenseFile() { + return env.configDir().resolve(pkg.app().name() + "-license.plist"); + } + + Path protoDmg() { + return dmgWorkdir().resolve("proto.dmg").toAbsolutePath(); + } + + Path protoCopyDmg() { + return dmgWorkdir().resolve("proto-copy.dmg").toAbsolutePath(); + } + + Path mountedProtoDmgPath() { + return dmgWorkdir().resolve(volumeName()); + } + + Path bgImageFileInMountedDmg() { + return mountedProtoDmgPath().resolve(".background/background.tiff"); + } + + private Path dmgWorkdir() { + return env.buildRoot().resolve("dmg-workdir"); + } + + private void copyDmgContent() throws IOException { + final var srcFolder = env.appImageDir(); + for (Path path : pkg.content()) { + FileUtils.copyRecursive(path, srcFolder.resolve(path.getFileName())); + } + } + + private void prepareDMGSetupScript() throws IOException { + Path dmgSetup = volumeScript(); + Log.verbose(MessageFormat.format( + I18N.getString("message.preparing-dmg-setup"), + dmgSetup.toAbsolutePath().toString())); + + // Prepare DMG setup script + Map data = new HashMap<>(); + + // We need to use URL for DMG to find it. We cannot use volume name, since + // user might have open DMG with same volume name already. + data.put("DEPLOY_VOLUME_URL", createVolumeUrlLocation()); + + // Full path to background image, so we can find it. + data.put("DEPLOY_BG_FILE", bgImageFileInMountedDmg().toString()); + + data.put("DEPLOY_VOLUME_PATH", volumePath().toString()); + data.put("DEPLOY_APPLICATION_NAME", pkg.app().name()); + String targetItem = pkg.relativeInstallDir().getFileName().toString(); + data.put("DEPLOY_TARGET", targetItem); + data.put("DEPLOY_INSTALL_LOCATION", installRoot(pkg).toString()); + data.put("DEPLOY_INSTALL_LOCATION_DISPLAY_NAME", + getInstallDirDisplayName()); + + env.createResource(DEFAULT_DMG_SETUP_SCRIPT) + .setCategory(I18N.getString("resource.dmg-setup-script")) + .setSubstitutionData(data) + .saveToFile(dmgSetup); + } + + private static Path installRoot(MacDmgPackage pkg) { + if (pkg.isRuntimeInstaller()) { + return Path.of("/Library/Java/JavaVirtualMachines"); + } else { + return Path.of("/Applications"); + } + } + + private void prepareLicense() throws IOException { + final var licFile = pkg.licenseFile(); + if (licFile.isEmpty()) { + return; + } + + byte[] licenseContentOriginal = + Files.readAllBytes(licFile.orElseThrow()); + String licenseInBase64 = + Base64.getEncoder().encodeToString(licenseContentOriginal); + + Map data = new HashMap<>(); + data.put("APPLICATION_LICENSE_TEXT", licenseInBase64); + + env.createResource(DEFAULT_LICENSE_PLIST) + .setCategory(I18N.getString("resource.license-setup")) + .setSubstitutionData(data) + .saveToFile(licenseFile()); + } + + private void prepareConfigFiles() throws IOException { + + env.createResource(DEFAULT_BACKGROUND_IMAGE) + .setCategory(I18N.getString("resource.dmg-background")) + .saveToFile(volumeBackground()); + + env.createResource(TEMPLATE_BUNDLE_ICON) + .setCategory(I18N.getString("resource.volume-icon")) + .setExternal(pkg.icon().orElse(null)) + .saveToFile(volumeIcon()); + + prepareLicense(); + + prepareDMGSetupScript(); + } + + // Returns display name of installation directory. Display name is used to + // show user installation location and for well known (default only) we will + // use "Applications" or "JavaVirtualMachines". + private String getInstallDirDisplayName() { + return installRoot(pkg).getFileName().toString(); + } + + private void buildDMG() throws IOException { + boolean copyAppImage = false; + + Path protoDMG = protoDmg(); + Path finalDMG = outputDir.resolve(pkg.packageFileNameWithSuffix()); + + Path srcFolder = env.appImageDir(); + + Log.verbose(MessageFormat.format(I18N.getString( + "message.creating-dmg-file"), finalDMG.toAbsolutePath())); + + try { + Files.deleteIfExists(finalDMG); + } catch (IOException ex) { + throw new IOException(MessageFormat.format(I18N.getString( + "message.dmg-cannot-be-overwritten"), + finalDMG.toAbsolutePath())); + } + + Files.createDirectories(protoDMG.getParent()); + Files.createDirectories(finalDMG.getParent()); + + String hdiUtilVerbosityFlag = env.verbose() ? + "-verbose" : "-quiet"; + + // create temp image + ProcessBuilder pb = new ProcessBuilder( + hdiutil.toString(), + "create", + hdiUtilVerbosityFlag, + "-srcfolder", srcFolder.toAbsolutePath().toString(), + "-volname", volumeName(), + "-ov", protoDMG.toString(), + "-fs", "HFS+", + "-format", "UDRW"); + try { + IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); + } catch (IOException ex) { + Log.verbose(ex); // Log exception + + // Creating DMG from entire app image failed, so lets try to create empty + // DMG and copy files manually. See JDK-8248059. + copyAppImage = true; + + long size = new PathGroup(Map.of(new Object(), srcFolder)).sizeInBytes(); + size += 50 * 1024 * 1024; // Add extra 50 megabytes. Actually DMG size will + // not be bigger, but it will able to hold additional 50 megabytes of data. + // We need extra room for icons and background image. When we providing + // actual files to hdiutil, it will create DMG with ~50 megabytes extra room. + pb = new ProcessBuilder( + hdiutil.toString(), + "create", + hdiUtilVerbosityFlag, + "-size", String.valueOf(size), + "-volname", volumeName(), + "-ov", protoDMG.toString(), + "-fs", "HFS+"); + new RetryExecutor() + .setMaxAttemptsCount(10) + .setAttemptTimeoutMillis(3000) + .setWriteOutputToFile(true) + .execute(pb); + } + + // mount temp image + pb = new ProcessBuilder( + hdiutil.toString(), + "attach", + protoDMG.toString(), + hdiUtilVerbosityFlag, + "-mountroot", protoDMG.getParent().toString()); + IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); + + final Path mountedRoot = mountedProtoDmgPath(); + + // Copy app image, since we did not create DMG with it, but instead we created + // empty one. + if (copyAppImage) { + FileUtils.copyRecursive(srcFolder, mountedRoot); + } + + try { + // background image + final var bgImageFile = bgImageFileInMountedDmg(); + Files.createDirectories(bgImageFile.getParent()); + IOUtils.copyFile(volumeBackground(), bgImageFile); + + // We will not consider setting background image and creating link + // to install-dir in DMG as critical error, since it can fail in + // headless environment. + try { + pb = new ProcessBuilder("/usr/bin/osascript", + volumeScript().toAbsolutePath().toString()); + IOUtils.exec(pb, 180); // Wait 3 minutes. See JDK-8248248. + } catch (IOException ex) { + Log.verbose(ex); + } + + // volume icon + Path volumeIconFile = mountedRoot.resolve(".VolumeIcon.icns"); + IOUtils.copyFile(volumeIcon(), volumeIconFile); + + // Indicate that we want a custom icon + // NB: attributes of the root directory are ignored + // when creating the volume + // Therefore we have to do this after we mount image + if (setFileUtility.isPresent()) { + //can not find utility => keep going without icon + try { + volumeIconFile.toFile().setWritable(true); + // The "creator" attribute on a file is a legacy attribute + // but it seems Finder excepts these bytes to be + // "icnC" for the volume icon + // (might not work on Mac 10.13 with old XCode) + pb = new ProcessBuilder( + setFileUtility.orElseThrow().toString(), + "-c", "icnC", + volumeIconFile.toAbsolutePath().toString()); + IOUtils.exec(pb); + volumeIconFile.toFile().setReadOnly(); + + pb = new ProcessBuilder( + setFileUtility.orElseThrow().toString(), + "-a", "C", + mountedRoot.toAbsolutePath().toString()); + IOUtils.exec(pb); + } catch (IOException ex) { + Log.error(ex.getMessage()); + Log.verbose("Cannot enable custom icon using SetFile utility"); + } + } else { + Log.verbose(I18N.getString("message.setfile.dmg")); + } + + } finally { + // Detach the temporary image + pb = new ProcessBuilder( + hdiutil.toString(), + "detach", + hdiUtilVerbosityFlag, + mountedRoot.toAbsolutePath().toString()); + // "hdiutil detach" might not work right away due to resource busy error, so + // repeat detach several times. + RetryExecutor retryExecutor = new RetryExecutor(); + // Image can get detach even if we got resource busy error, so stop + // trying to detach it if it is no longer attached. + retryExecutor.setExecutorInitializer(exec -> { + if (!Files.exists(mountedRoot)) { + retryExecutor.abort(); + } + }); + try { + // 10 times with 6 second delays. + retryExecutor.setMaxAttemptsCount(10).setAttemptTimeoutMillis(6000) + .execute(pb); + } catch (IOException ex) { + if (!retryExecutor.isAborted()) { + // Now force to detach if it still attached + if (Files.exists(mountedRoot)) { + pb = new ProcessBuilder( + hdiutil.toString(), + "detach", + "-force", + hdiUtilVerbosityFlag, + mountedRoot.toAbsolutePath().toString()); + IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); + } + } + } + } + + // Compress it to a new image + pb = new ProcessBuilder( + hdiutil.toString(), + "convert", + protoDMG.toAbsolutePath().toString(), + hdiUtilVerbosityFlag, + "-format", "UDZO", + "-o", finalDMG.toAbsolutePath().toString()); + try { + new RetryExecutor() + .setMaxAttemptsCount(10) + .setAttemptTimeoutMillis(3000) + .execute(pb); + } catch (Exception ex) { + // Convert might failed if something holds file. Try to convert copy. + Path protoCopyDMG = protoCopyDmg(); + Files.copy(protoDMG, protoCopyDMG); + try { + pb = new ProcessBuilder( + hdiutil.toString(), + "convert", + protoCopyDMG.toString(), + hdiUtilVerbosityFlag, + "-format", "UDZO", + "-o", finalDMG.toAbsolutePath().toString()); + IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); + } finally { + Files.deleteIfExists(protoCopyDMG); + } + } + + //add license if needed + if (pkg.licenseFile().isPresent()) { + pb = new ProcessBuilder( + hdiutil.toString(), + "udifrez", + finalDMG.toAbsolutePath().toString(), + "-xml", + licenseFile().toAbsolutePath().toString() + ); + new RetryExecutor() + .setMaxAttemptsCount(10) + .setAttemptTimeoutMillis(3000) + .execute(pb); + } + + try { + //Delete the temporary image + Files.deleteIfExists(protoDMG); + } catch (IOException ex) { + // Don't care if fails + } + + Log.verbose(MessageFormat.format(I18N.getString( + "message.output-to-location"), + pkg.app().name(), finalDMG.toAbsolutePath().toString())); + + } + + // Background image name in resources + private static final String DEFAULT_BACKGROUND_IMAGE = "background_dmg.tiff"; + private static final String DEFAULT_DMG_SETUP_SCRIPT = "DMGsetup.scpt"; + private static final String TEMPLATE_BUNDLE_ICON = "JavaApp.icns"; + + private static final String DEFAULT_LICENSE_PLIST="lic_template.plist"; + + private static final Path HDIUTIL = Path.of("/usr/bin/hdiutil"); +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java index bf884e74318d3..d81b492b4bb80 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java @@ -42,6 +42,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage; +import static jdk.jpackage.internal.model.MacPackage.RUNTIME_PACKAGE_LAYOUT; import static jdk.jpackage.internal.model.StandardPackageType.MAC_DMG; import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; @@ -62,6 +63,7 @@ import jdk.jpackage.internal.model.MacFileAssociation; import jdk.jpackage.internal.model.MacLauncher; import jdk.jpackage.internal.model.MacPkgPackage; +import jdk.jpackage.internal.model.RuntimeLayout; final class MacFromParams { @@ -69,14 +71,20 @@ final class MacFromParams { private static MacApplication createMacApplication( Map params) throws ConfigException, IOException { - adjustRuntimeDir(params); + final var predefinedRuntimeLayout = PREDEFINED_RUNTIME_IMAGE.findIn(params).map(predefinedRuntimeImage -> { + if (Files.isDirectory(RUNTIME_PACKAGE_LAYOUT.resolveAt(predefinedRuntimeImage).runtimeDirectory())) { + return RUNTIME_PACKAGE_LAYOUT; + } else { + return RuntimeLayout.DEFAULT; + } + }); final var launcherFromParams = new LauncherFromParams(Optional.of(MacFromParams::createMacFa)); final var app = createApplicationBuilder(params, toFunction(launcherParams -> { var launcher = launcherFromParams.create(launcherParams); return MacLauncher.create(launcher); - }), APPLICATION_LAYOUT).create(); + }), APPLICATION_LAYOUT, predefinedRuntimeLayout).create(); final var appBuilder = new MacApplicationBuilder(app); @@ -164,15 +172,6 @@ private static MacFileAssociation createMacFa(FileAssociation fa, Map params) { - PREDEFINED_RUNTIME_IMAGE.copyInto(params, runtimeRoot -> { - final var runtimeDir = runtimeRoot.resolve("Contents/Home"); - if (Files.isDirectory(runtimeDir)) { - params.put(PREDEFINED_RUNTIME_IMAGE.getID(), runtimeDir); - } - }); - } - static final BundlerParamInfo APPLICATION = createApplicationBundlerParam( MacFromParams::createMacApplication); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index 80f742a0f61db..6336d4d694ad1 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -46,12 +46,16 @@ import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import jdk.jpackage.internal.PackagingPipeline.AppImageTaskID; +import jdk.jpackage.internal.PackagingPipeline.AppImageBuildEnv; import jdk.jpackage.internal.PackagingPipeline.ApplicationImageTaskAction; +import jdk.jpackage.internal.PackagingPipeline.BuildApplicationTaskID; +import jdk.jpackage.internal.PackagingPipeline.CopyAppImageTaskID; +import jdk.jpackage.internal.PackagingPipeline.PackageBuildEnv; import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; import jdk.jpackage.internal.PackagingPipeline.TaskAction; import jdk.jpackage.internal.PackagingPipeline.TaskContext; import jdk.jpackage.internal.PackagingPipeline.TaskID; +import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.FileAssociation; @@ -60,88 +64,107 @@ import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.SigningConfig; -import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; final class MacPackagingPipeline { - enum MacAppImageTaskID implements TaskID { + enum MacBuildApplicationTaskID implements TaskID { RUNTIME_INFO_PLIST, COPY_JLILIB, APP_ICON, PKG_INFO_FILE, - PKG_FILE, FA_ICONS, APP_INFO_PLIST, + PACKAGE_FILE, SIGN } - static PackagingPipeline.Builder build() { + enum MacCopyAppImageTaskID implements TaskID { + COPY_PACKAGE_FILE, + COPY_SIGN + } + + static AppImageLayout packagingLayout(Package pkg) { + return pkg.appImageLayout().resolveAt(pkg.relativeInstallDir().getFileName()); + } + + static PackagingPipeline.Builder build(Optional pkg) { final var builder = PackagingPipeline.buildStandard() .appContextMapper(appContext -> { - return new TaskContextProxy(appContext, true); + return new TaskContextProxy(appContext, true, false); }) .pkgContextMapper(appContext -> { - return new TaskContextProxy(appContext, false); + final var isRuntimeInstaller = pkg.map(Package::isRuntimeInstaller).orElse(false); + final var withPredefinedAppImage = pkg.flatMap(Package::predefinedAppImage).isPresent(); + return new TaskContextProxy(appContext, false, isRuntimeInstaller || withPredefinedAppImage); }) - .task(PrimaryTaskID.COPY_APP_IMAGE) + .appImageLayoutForPackaging(MacPackagingPipeline::packagingLayout) + .task(CopyAppImageTaskID.COPY) .copyAction(MacPackagingPipeline::copyAppImage).add() - .task(MacAppImageTaskID.RUNTIME_INFO_PLIST) - .action(conv(MacPackagingPipeline::writeRuntimeInfoPlist)) - .addDependent(AppImageTaskID.CONTENT).add() - .task(MacAppImageTaskID.COPY_JLILIB) - .action(conv(MacPackagingPipeline::copyJliLib)) - .addDependency(AppImageTaskID.RUNTIME) - .addDependent(AppImageTaskID.CONTENT).add() - .task(MacAppImageTaskID.APP_ICON) - .action(conv(new ApplicationIcon())) - .addDependent(AppImageTaskID.CONTENT).add() - .task(MacAppImageTaskID.PKG_INFO_FILE) - .action(MacPackagingPipeline::writePkgInfoFile) - .addDependent(AppImageTaskID.CONTENT).add() - .task(MacAppImageTaskID.PKG_FILE) - .action(MacPackagingPipeline::writePackageFile) - .addDependent(AppImageTaskID.CONTENT).add() - .task(MacAppImageTaskID.FA_ICONS) - .action(MacPackagingPipeline::writeFileAssociationIcons) - .addDependent(AppImageTaskID.CONTENT).add() - .task(MacAppImageTaskID.APP_INFO_PLIST) - .action(conv(MacPackagingPipeline::writeAppInfoPlist)) - .addDependent(AppImageTaskID.CONTENT).add(); - - builder.task(MacAppImageTaskID.SIGN) - .action(conv(MacPackagingPipeline::sign)) + .task(MacBuildApplicationTaskID.RUNTIME_INFO_PLIST) + .applicationAction(MacPackagingPipeline::writeRuntimeInfoPlist) + .addDependent(BuildApplicationTaskID.CONTENT).add() + .task(MacBuildApplicationTaskID.COPY_JLILIB) + .applicationAction(MacPackagingPipeline::copyJliLib) + .addDependency(BuildApplicationTaskID.RUNTIME) + .addDependent(BuildApplicationTaskID.CONTENT).add() + .task(MacBuildApplicationTaskID.APP_ICON) + .applicationAction(new ApplicationIcon()) + .addDependent(BuildApplicationTaskID.CONTENT).add() + .task(MacBuildApplicationTaskID.PKG_INFO_FILE) + .applicationAction(MacPackagingPipeline::writePkgInfoFile) + .addDependent(BuildApplicationTaskID.CONTENT).add() + .task(MacBuildApplicationTaskID.PACKAGE_FILE) + .packageAction(MacPackagingPipeline::writePackageFile) + .addDependents(BuildApplicationTaskID.CONTENT).add() + .task(MacCopyAppImageTaskID.COPY_PACKAGE_FILE) + .packageAction(MacPackagingPipeline::writePackageFile) + .addDependencies(CopyAppImageTaskID.COPY) + .addDependents(PrimaryTaskID.COPY_APP_IMAGE).add() + .task(MacBuildApplicationTaskID.FA_ICONS) + .applicationAction(MacPackagingPipeline::writeFileAssociationIcons) + .addDependent(BuildApplicationTaskID.CONTENT).add() + .task(MacBuildApplicationTaskID.APP_INFO_PLIST) + .applicationAction(MacPackagingPipeline::writeAppInfoPlist) + .addDependent(BuildApplicationTaskID.CONTENT).add(); + + builder.task(MacBuildApplicationTaskID.SIGN) + .appImageAction(MacPackagingPipeline::sign) .addDependencies(builder.taskGraphSnapshot().getAllTailsOf(PrimaryTaskID.BUILD_APPLICATION_IMAGE)) - .addDependent(PrimaryTaskID.BUILD_APPLICATION_IMAGE).add(); + .addDependent(PrimaryTaskID.BUILD_APPLICATION_IMAGE) + .add(); + + builder.task(MacCopyAppImageTaskID.COPY_SIGN) + .appImageAction(MacPackagingPipeline::sign) + .addDependencies(builder.taskGraphSnapshot().getAllTailsOf(PrimaryTaskID.COPY_APP_IMAGE)) + .addDependent(PrimaryTaskID.COPY_APP_IMAGE) + .add(); + + pkg.ifPresent(p -> { + if (p.isRuntimeInstaller() || (p.predefinedAppImage().isPresent() && ((MacApplication)p.app()).sign())) { + // If this is a runtime package or a signed predefined app image, + // don't create ".package" file and don't sign it. + builder.task(MacCopyAppImageTaskID.COPY_PACKAGE_FILE).noaction().add(); + builder.task(MacCopyAppImageTaskID.COPY_SIGN).noaction().add(); + } + }); return builder; } - @FunctionalInterface - private interface MacApplicationImageTaskAction extends TaskAction { - void execute(BuildEnv env, MacApplication app, MacApplicationLayout appLayout) - throws IOException, PackagerException; + private static void copyAppImage(Package pkg, AppImageDesc srcAppImage, + AppImageDesc dstAppImage) throws IOException { + PackagingPipeline.copyAppImage(pkg, srcAppImage, dstAppImage, false/*!((MacApplication)pkg.app()).sign()*/); } - private static ApplicationImageTaskAction conv(MacApplicationImageTaskAction v) { - return (env, app, appLayout) -> { - v.execute(env, (MacApplication)app, (MacApplicationLayout)appLayout); - }; - } - - private static void copyAppImage(Package pkg, Path srcAppImageRoot, - Path dstAppImageRoot) throws IOException { - FileUtils.copyRecursive(srcAppImageRoot, dstAppImageRoot); - } + private static void copyJliLib( + AppImageBuildEnv env) throws IOException { - private static void copyJliLib(BuildEnv env, MacApplication app, - MacApplicationLayout appLayout) throws IOException { - - final var runtimeMacOSDir = appLayout.runtimeRootDirectory().resolve("Contents/MacOS"); + final var runtimeMacOSDir = env.resolvedLayout().runtimeRootDirectory().resolve("Contents/MacOS"); final var jliName = Path.of("libjli.dylib"); - try (var walk = Files.walk(appLayout.runtimeDirectory().resolve("lib"))) { + try (var walk = Files.walk(env.resolvedLayout().runtimeDirectory().resolve("lib"))) { final var jli = walk .filter(file -> file.getFileName().equals(jliName)) .findFirst() @@ -151,20 +174,23 @@ private static void copyJliLib(BuildEnv env, MacApplication app, } } - private static void writePackageFile(BuildEnv env, Package pkg) throws IOException { - new PackageFile(pkg.packageName()).save(pkg.asApplicationLayout().orElseThrow().resolveAt(env.appImageDir())); + private static void writePackageFile(PackageBuildEnv env) throws IOException { + new PackageFile(env.pkg().packageName()).save(env.resolvedLayout()); } - private static void writePkgInfoFile(BuildEnv env, Application app, - ApplicationLayout appLayout) throws IOException { - final var dir = appLayout.contentDirectory(); + private static void writePkgInfoFile( + AppImageBuildEnv env) throws IOException { + + final var dir = env.resolvedLayout().contentDirectory(); Files.createDirectories(dir); Files.write(dir.resolve("PkgInfo"), "APPL????".getBytes(StandardCharsets.ISO_8859_1)); } - private static void writeRuntimeInfoPlist(BuildEnv env, MacApplication app, - ApplicationLayout appLayout) throws IOException { + private static void writeRuntimeInfoPlist( + AppImageBuildEnv env) throws IOException { + + final var app = env.app(); Map data = new HashMap<>(); data.put("CF_BUNDLE_IDENTIFIER", app.bundleIdentifier()); @@ -172,15 +198,17 @@ private static void writeRuntimeInfoPlist(BuildEnv env, MacApplication app, data.put("CF_BUNDLE_VERSION", app.version()); data.put("CF_BUNDLE_SHORT_VERSION_STRING", app.shortVersion().toString()); - env.createResource("Runtime-Info.plist.template") + env.env().createResource("Runtime-Info.plist.template") .setPublicName("Runtime-Info.plist") .setCategory(I18N.getString("resource.runtime-info-plist")) .setSubstitutionData(data) - .saveToFile(((MacApplicationLayout)appLayout).runtimeRootDirectory().resolve("Contents/Info.plist")); + .saveToFile(env.resolvedLayout().runtimeRootDirectory().resolve("Contents/Info.plist")); } - private static void writeAppInfoPlist(BuildEnv env, MacApplication app, - MacApplicationLayout appLayout) throws IOException { + private static void writeAppInfoPlist( + AppImageBuildEnv env) throws IOException { + + final var app = env.app(); final String faXml = toSupplier(() -> { var buf = new StringWriter(); @@ -193,7 +221,7 @@ private static void writeAppInfoPlist(BuildEnv env, MacApplication app, }).get(); Map data = new HashMap<>(); - data.put("DEPLOY_ICON_FILE", ApplicationIcon.getPath(app, appLayout).getFileName().toString()); + data.put("DEPLOY_ICON_FILE", ApplicationIcon.getPath(app, env.resolvedLayout()).getFileName().toString()); data.put("DEPLOY_BUNDLE_COPYRIGHT", app.copyright()); data.put("DEPLOY_LAUNCHER_NAME", app.mainLauncher().orElseThrow().executableNameWithSuffix()); data.put("DEPLOY_BUNDLE_SHORT_VERSION", app.shortVersion().toString()); @@ -203,15 +231,16 @@ private static void writeAppInfoPlist(BuildEnv env, MacApplication app, data.put("DEPLOY_APP_CATEGORY", app.category()); data.put("DEPLOY_FILE_ASSOCIATIONS", faXml); - env.createResource("Info-lite.plist.template") + env.env().createResource("Info-lite.plist.template") .setCategory(I18N.getString("resource.app-info-plist")) .setSubstitutionData(data) .setPublicName("Info.plist") - .saveToFile(appLayout.contentDirectory().resolve("Info.plist")); + .saveToFile(env.resolvedLayout().contentDirectory().resolve("Info.plist")); } - private static void sign(BuildEnv env, MacApplication app, - MacApplicationLayout appLayout) throws IOException { + private static void sign(AppImageBuildEnv env) throws IOException { + + final var app = env.app(); final var codesignConfigBuilder = CodesignConfig.build(); app.signingConfig().ifPresent(codesignConfigBuilder::from); @@ -220,9 +249,9 @@ private static void sign(BuildEnv env, MacApplication app, final var entitlementsDefaultResource = app.signingConfig().map( SigningConfig::entitlementsResourceName).orElseThrow(); - final var entitlementsFile = env.configDir().resolve(app.name() + ".entitlements"); + final var entitlementsFile = env.env().configDir().resolve(app.name() + ".entitlements"); - env.createResource(entitlementsDefaultResource) + env.env().createResource(entitlementsDefaultResource) .setCategory(I18N.getString("resource.entitlements")) .saveToFile(entitlementsFile); @@ -230,7 +259,8 @@ private static void sign(BuildEnv env, MacApplication app, } final Runnable signAction = () -> { - AppImageSigner.createSigner(app, codesignConfigBuilder.create()).accept(env.appImageDir()); + final var appImageDir = env.resolvedLayout().rootDirectory(); + AppImageSigner.createSigner(app, codesignConfigBuilder.create()).accept(appImageDir); }; app.signingConfig().flatMap(SigningConfig::keyChain).ifPresentOrElse(keyChain -> { @@ -308,45 +338,48 @@ private static void addFaToUTExportedTypeDeclarations(XMLStreamWriter xml, })); } - private static class ApplicationIcon implements MacApplicationImageTaskAction { + private static class ApplicationIcon implements ApplicationImageTaskAction { static Path getPath(Application app, ApplicationLayout appLayout) { return appLayout.destktopIntegrationDirectory().resolve(app.name() + ".icns"); } @Override - public void execute(BuildEnv env, MacApplication app, MacApplicationLayout appLayout) + public void execute(AppImageBuildEnv env) throws IOException { - final var resource = env.createResource("JavaApp.icns").setCategory("icon"); + final var resource = env.env().createResource("JavaApp.icns").setCategory("icon"); - app.icon().ifPresent(resource::setExternal); + env.app().icon().ifPresent(resource::setExternal); - resource.saveToFile(getPath(app, appLayout)); + resource.saveToFile(getPath(env.app(), env.resolvedLayout())); } } - private static void writeFileAssociationIcons(BuildEnv env, Application app, - ApplicationLayout appLayout) throws IOException { - for (var faIcon : app.fileAssociations() + private static void writeFileAssociationIcons(AppImageBuildEnv env) throws IOException { + for (var faIcon : env.app().fileAssociations() .filter(FileAssociation::hasIcon) .map(FileAssociation::icon) .map(Optional::get).toList()) { - Files.copy(faIcon, appLayout.destktopIntegrationDirectory().resolve(faIcon.getFileName())); + Files.copy(faIcon, env.resolvedLayout().destktopIntegrationDirectory().resolve(faIcon.getFileName())); } } - private record TaskContextProxy(TaskContext delegate, boolean forApp) implements TaskContext { + private record TaskContextProxy(TaskContext delegate, boolean forApp, boolean copyAppImage) implements TaskContext { @Override public boolean test(TaskID taskID) { - if (forApp && taskID == MacAppImageTaskID.PKG_FILE) { - // Don't create files relevant for package bundling when bundling app image - return false; - } else if (!forApp && taskID == AppImageTaskID.APP_IMAGE_FILE) { - // Always create ".jpackage.xml" for compatibility with tests + if (!forApp && !copyAppImage && taskID == BuildApplicationTaskID.APP_IMAGE_FILE) { + // Always create ".jpackage.xml" if not copying predefined app image for compatibility with the tests // TODO: Don't create ".jpackage.xml" when bundling a package like on other platforms return true; + } + + if (!delegate.test(taskID)) { + return false; + } else if (taskID == MacBuildApplicationTaskID.PACKAGE_FILE) { + // Don't create files relevant for package bundling when bundling app image + return !forApp; } else { - return delegate.test(taskID); + return true; } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties index e0a555b369854..a922e8f19d887 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties @@ -51,7 +51,7 @@ resource.dmg-setup-script=DMG setup script resource.license-setup=License setup resource.dmg-background=dmg background resource.volume-icon=volume icon -resource.post-install-script=script to run after application image is populated +resource.post-app-image-script=script to run after application image is populated resource.pkg-preinstall-script=PKG preinstall script resource.pkg-postinstall-script=PKG postinstall script resource.pkg-services-preinstall-script=PKG preinstall script for services package diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java index 5892b128a23d7..f9e114118321f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java @@ -118,15 +118,6 @@ public final boolean isDefault() { return false; } - final AppImageBundler setDependentTask(boolean v) { - dependentTask = v; - return this; - } - - final boolean isDependentTask() { - return dependentTask; - } - @FunctionalInterface static interface AppImageSupplier { @@ -159,11 +150,9 @@ private Path createRoot(Map params, imageName = imageName + ".app"; } - if (!dependentTask) { - Log.verbose(MessageFormat.format( - I18N.getString("message.creating-app-bundle"), - imageName, outputDirectory.toAbsolutePath())); - } + Log.verbose(MessageFormat.format( + I18N.getString("message.creating-app-bundle"), + imageName, outputDirectory.toAbsolutePath())); // Create directory structure Path rootDirectory = outputDirectory.resolve(imageName); @@ -177,7 +166,6 @@ private Path createRoot(Map params, return rootDirectory; } - private boolean dependentTask; private ParamsValidator paramsValidator; private AppImageSupplier appImageSupplier; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java index 94d9e09da860c..f24f2fcf593a3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java @@ -37,7 +37,9 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; +import jdk.jpackage.internal.PackagingPipeline.ApplicationImageTaskAction; import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.CustomLauncherIcon; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.util.FileUtils; @@ -79,45 +81,45 @@ static Optional createLauncherIconResource(Application app, return Optional.of(resource); } - static PackagingPipeline.ApplicationImageTaskAction createWriteRuntimeAction() { - return (env, app, appLayout) -> { - app.runtimeBuilder().orElseThrow().createRuntime(appLayout); + static ApplicationImageTaskAction createWriteRuntimeAction() { + return env -> { + env.app().runtimeBuilder().orElseThrow().createRuntime(env.resolvedLayout()); }; } - static PackagingPipeline.ApplicationImageTaskAction createWriteAppImageFileAction() { - return (env, app, appLayout) -> { - new AppImageFile(app).save(appLayout); + static ApplicationImageTaskAction createWriteAppImageFileAction() { + return env -> { + new AppImageFile(env.app()).save(env.resolvedLayout()); }; } - static PackagingPipeline.ApplicationImageTaskAction createCopyContentAction(Supplier> excludeCopyDirs) { - return (env, app, appLayout) -> { + static ApplicationImageTaskAction createCopyContentAction(Supplier> excludeCopyDirs) { + return env -> { var excludeCandidates = Stream.concat( excludeCopyDirs.get().stream(), - Stream.of(env.buildRoot(), env.appImageDir()) + Stream.of(env.env().buildRoot(), env.env().appImageDir()) ).map(Path::toAbsolutePath).toList(); - app.srcDir().ifPresent(toConsumer(srcDir -> { - copyRecursive(srcDir, appLayout.appDirectory(), excludeCandidates); + env.app().srcDir().ifPresent(toConsumer(srcDir -> { + copyRecursive(srcDir, env.resolvedLayout().appDirectory(), excludeCandidates); })); - for (var srcDir : app.contentDirs()) { + for (var srcDir : env.app().contentDirs()) { copyRecursive(srcDir, - appLayout.contentDirectory().resolve(srcDir.getFileName()), + env.resolvedLayout().contentDirectory().resolve(srcDir.getFileName()), excludeCandidates); } }; } - static PackagingPipeline.ApplicationImageTaskAction createWriteLaunchersAction() { - return (env, app, appLayout) -> { - for (var launcher : app.launchers()) { + static ApplicationImageTaskAction createWriteLaunchersAction() { + return env -> { + for (var launcher : env.app().launchers()) { // Create corresponding .cfg file - new CfgFile(app, launcher).create(appLayout); + new CfgFile(env.app(), launcher).create(env.resolvedLayout()); // Copy executable to launchers folder - Path executableFile = appLayout.launchersDirectory().resolve( + Path executableFile = env.resolvedLayout().launchersDirectory().resolve( launcher.executableNameWithSuffix()); try (var in = launcher.executableResource()) { Files.createDirectories(executableFile.getParent()); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerBuilder.java new file mode 100644 index 0000000000000..c9f2c50b7f298 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerBuilder.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.Objects; +import jdk.jpackage.internal.PackagingPipeline.StartupParameters; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.PackagerException; + +abstract class PackagerBuilder> { + + U pkg(T v) { + pkg = v; + return thiz(); + } + + U env(BuildEnv v) { + env = v; + return thiz(); + } + + U outputDir(Path v) { + outputDir = v; + return thiz(); + } + + @SuppressWarnings("unchecked") + private U thiz() { + return (U)this; + } + + protected abstract void configurePackagingPipeline(PackagingPipeline.Builder pipelineBuilder, + StartupParameters startupParameters); + + Path execute(PackagingPipeline.Builder pipelineBuilder) throws PackagerException { + Objects.requireNonNull(pkg); + Objects.requireNonNull(env); + Objects.requireNonNull(outputDir); + + final var startupParameters = pipelineBuilder.createStartupParameters(env, pkg, outputDir); + + configurePackagingPipeline(pipelineBuilder, startupParameters); + + pipelineBuilder.create().execute(startupParameters); + + return outputDir.resolve(pkg.packageFileNameWithSuffix()); + } + + protected T pkg; + protected BuildEnv env; + protected Path outputDir; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java index baf2a8574edba..2b789c6fa592d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java @@ -28,6 +28,7 @@ import static java.util.stream.Collectors.toMap; import java.io.IOException; +import java.nio.file.LinkOption; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; @@ -37,10 +38,9 @@ import java.util.Objects; import java.util.Optional; import java.util.concurrent.Callable; -import java.util.function.BiFunction; import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.UnaryOperator; -import java.util.stream.Stream; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; @@ -60,25 +60,16 @@ void execute(BuildEnv env, Application app) throws PackagerException { } void execute(BuildEnv env, Package pkg, Path outputDir) throws PackagerException { - execute(pkgContextMapper.apply(createTaskContext(env, pkg, outputDir))); + execute((StartupParameters)createPackagingTaskContext(env, pkg, outputDir, + taskConfig, appImageLayoutForPackaging.apply(pkg))); } - AppImageInfo analyzeAppImageDir(BuildEnv env, Package pkg) { - if (pkg.app().runtimeBuilder().isPresent()) { - // Runtime builder is present, return the path where app image will be created. - return new AppImageInfo(inputApplicationLayoutForPackaging.apply(pkg).orElseThrow(), env.appImageDir()); - } else { - return new AppImageInfo(pkg.app().imageLayout(), pkg.predefinedAppImage().orElseGet(() -> { - // No predefined app image and no runtime builder. - // This should be runtime packaging. - if (pkg.isRuntimeInstaller()) { - return env.appImageDir(); - } else { - // Can't create app image without runtime builder. - throw new UnsupportedOperationException(); - } - })); - } + void execute(StartupParameters startupParameters) throws PackagerException { + execute(pkgContextMapper.apply(createTaskContext((PackagingTaskContext)startupParameters))); + } + + interface StartupParameters { + BuildEnv packagingEnv(); } interface TaskAction { @@ -87,38 +78,69 @@ interface TaskAction { interface TaskID { } - enum AppImageTaskID implements TaskID { + enum BuildApplicationTaskID implements TaskID { RUNTIME, CONTENT, LAUNCHERS, APP_IMAGE_FILE } + enum CopyAppImageTaskID implements TaskID { + COPY + } + enum PrimaryTaskID implements TaskID { BUILD_APPLICATION_IMAGE, COPY_APP_IMAGE, PACKAGE } - interface TaskContext { - boolean test(TaskID taskID); + enum PackageTaskID implements TaskID { + RUN_POST_IMAGE_USER_SCRIPT, + CREATE_CONFIG_FILES, + CREATE_PACKAGE_FILE + } + interface TaskContext extends Predicate { void execute(TaskAction taskAction) throws IOException, PackagerException; } + record AppImageBuildEnv(BuildEnv env, T app, U envLayout) { + @SuppressWarnings("unchecked") + U resolvedLayout() { + return (U)envLayout.resolveAt(env.appImageDir()); + } + } + + record PackageBuildEnv(BuildEnv env, T pkg, U envLayout, Path outputDir) { + @SuppressWarnings("unchecked") + U resolvedLayout() { + return (U)envLayout.resolveAt(env.appImageDir()); + } + + AppImageBuildEnv appImageBuildEnv() { + return new AppImageBuildEnv<>(env, pkg.app(), envLayout); + } + } + @FunctionalInterface - interface ApplicationImageTaskAction extends TaskAction { - void execute(BuildEnv env, Application app, ApplicationLayout appLayout) throws IOException, PackagerException; + interface ApplicationImageTaskAction extends TaskAction { + void execute(AppImageBuildEnv env) throws IOException, PackagerException; + } + + @FunctionalInterface + interface AppImageTaskAction extends TaskAction { + void execute(AppImageBuildEnv env) throws IOException, PackagerException; } @FunctionalInterface interface CopyAppImageTaskAction extends TaskAction { - void execute(Package pkg, Path srcAppImageRoot, Path dstAppImageRoot) throws IOException, PackagerException; + void execute(Package pkg, AppImageDesc srcAppImage, AppImageDesc dstAppImage) throws IOException, PackagerException; } @FunctionalInterface - interface PackageTaskAction extends TaskAction { - void execute(BuildEnv env, Package pkg) throws IOException, PackagerException; + interface PackageTaskAction extends TaskAction { + void execute(PackageBuildEnv env) throws IOException, PackagerException; } @FunctionalInterface @@ -126,7 +148,10 @@ interface NoArgTaskAction extends TaskAction { void execute() throws IOException, PackagerException; } - record TaskConfig(TaskAction action) { + record TaskConfig(Optional action) { + TaskConfig { + Objects.requireNonNull(action); + } } static final class Builder { @@ -150,7 +175,11 @@ TaskBuilder noaction() { return this; } - TaskBuilder action(ApplicationImageTaskAction action) { + TaskBuilder applicationAction(ApplicationImageTaskAction action) { + return setAction(action); + } + + TaskBuilder appImageAction(AppImageTaskAction action) { return setAction(action); } @@ -158,7 +187,7 @@ TaskBuilder copyAction(CopyAppImageTaskAction action) { return setAction(action); } - TaskBuilder action(PackageTaskAction action) { + TaskBuilder packageAction(PackageTaskAction action) { return setAction(action); } @@ -190,8 +219,16 @@ public TaskBuilder addDependents(Collection tasks) { return this; } + public TaskBuilder addDependencies(TaskID ... tasks) { + return addDependencies(List.of(tasks)); + } + + public TaskBuilder addDependents(TaskID ... tasks) { + return addDependents(List.of(tasks)); + } + Builder add() { - final var config = new TaskConfig(action); + final var config = new TaskConfig(Optional.ofNullable(action)); taskConfig.put(task(), config); createLinks().forEach(Builder.this::linkTasks); return Builder.this; @@ -238,13 +275,8 @@ Builder pkgContextMapper(UnaryOperator v) { return this; } - Builder pkgBuildEnvFactory(BiFunction v) { - pkgBuildEnvFactory = v; - return this; - } - - Builder inputApplicationLayoutForPackaging(Function> v) { - inputApplicationLayoutForPackaging = v; + Builder appImageLayoutForPackaging(Function v) { + appImageLayoutForPackaging = v; return this; } @@ -255,14 +287,20 @@ ImmutableDAG taskGraphSnapshot() { return taskGraphSnapshot; } + StartupParameters createStartupParameters(BuildEnv env, Package pkg, Path outputDir) { + return createPackagingTaskContext(env, pkg, outputDir, taskConfig, + validatedAppImageLayoutForPackaging().apply(pkg)); + } + + private Function validatedAppImageLayoutForPackaging() { + return Optional.ofNullable(appImageLayoutForPackaging).orElse(Package::packageLayout); + } + PackagingPipeline create() { return new PackagingPipeline(taskGraphSnapshot(), taskConfig, Optional.ofNullable(appContextMapper).orElse(UnaryOperator.identity()), Optional.ofNullable(pkgContextMapper).orElse(UnaryOperator.identity()), - Optional.ofNullable(inputApplicationLayoutForPackaging).orElse(Package::asPackageApplicationLayout), - Optional.ofNullable(pkgBuildEnvFactory).orElse((env, pkg) -> { - return BuildEnv.withAppImageDir(env, env.buildRoot().resolve("image")); - })); + validatedAppImageLayoutForPackaging()); } private final ImmutableDAG.Builder taskGraphBuilder = ImmutableDAG.build(); @@ -270,8 +308,7 @@ PackagingPipeline create() { private final Map taskConfig = new HashMap<>(); private UnaryOperator appContextMapper; private UnaryOperator pkgContextMapper; - private Function> inputApplicationLayoutForPackaging; - private BiFunction pkgBuildEnvFactory; + private Function appImageLayoutForPackaging; private ImmutableDAG taskGraphSnapshot; } @@ -289,82 +326,140 @@ static Builder buildStandard() { } static Builder configureApplicationTasks(Builder builder) { - builder.task(AppImageTaskID.RUNTIME) - .addDependent(AppImageTaskID.CONTENT) - .action(ApplicationImageUtils.createWriteRuntimeAction()).add(); + builder.task(BuildApplicationTaskID.RUNTIME) + .addDependent(BuildApplicationTaskID.CONTENT) + .applicationAction(ApplicationImageUtils.createWriteRuntimeAction()).add(); - builder.task(AppImageTaskID.LAUNCHERS) - .addDependent(AppImageTaskID.CONTENT) - .action(ApplicationImageUtils.createWriteLaunchersAction()).add(); + builder.task(BuildApplicationTaskID.LAUNCHERS) + .addDependent(BuildApplicationTaskID.CONTENT) + .applicationAction(ApplicationImageUtils.createWriteLaunchersAction()).add(); - builder.task(AppImageTaskID.APP_IMAGE_FILE) + builder.task(BuildApplicationTaskID.APP_IMAGE_FILE) .addDependent(PrimaryTaskID.BUILD_APPLICATION_IMAGE) - .action(ApplicationImageUtils.createWriteAppImageFileAction()).add(); + .applicationAction(ApplicationImageUtils.createWriteAppImageFileAction()).add(); - builder.task(AppImageTaskID.CONTENT) - .addDependent(AppImageTaskID.APP_IMAGE_FILE) - .action(ApplicationImageUtils.createCopyContentAction(() -> builder.excludeCopyDirs)).add(); + builder.task(BuildApplicationTaskID.CONTENT) + .addDependent(BuildApplicationTaskID.APP_IMAGE_FILE) + .applicationAction(ApplicationImageUtils.createCopyContentAction(() -> builder.excludeCopyDirs)).add(); return builder; } static Builder configurePackageTasks(Builder builder) { - builder.task(PrimaryTaskID.COPY_APP_IMAGE).copyAction(createCopyAppImageAction()).add(); + builder.task(CopyAppImageTaskID.COPY) + .copyAction(PackagingPipeline::copyAppImage) + .addDependent(PrimaryTaskID.COPY_APP_IMAGE) + .add(); + + builder.task(PrimaryTaskID.COPY_APP_IMAGE).add(); + + builder.task(PrimaryTaskID.BUILD_APPLICATION_IMAGE).add(); - builder.task(PrimaryTaskID.BUILD_APPLICATION_IMAGE).noaction().add(); + builder.task(PackageTaskID.RUN_POST_IMAGE_USER_SCRIPT) + .addDependencies(PrimaryTaskID.BUILD_APPLICATION_IMAGE, PrimaryTaskID.COPY_APP_IMAGE) + .addDependent(PackageTaskID.CREATE_PACKAGE_FILE) + .packageAction(PackagingPipeline::runPostAppImageUserScript).add(); - builder.task(PrimaryTaskID.PACKAGE) - .addDependencies(List.of(PrimaryTaskID.BUILD_APPLICATION_IMAGE, PrimaryTaskID.COPY_APP_IMAGE)) - .noaction().add(); + builder.task(PackageTaskID.CREATE_CONFIG_FILES) + .addDependent(PackageTaskID.CREATE_PACKAGE_FILE) + .add(); + + builder.task(PackageTaskID.CREATE_PACKAGE_FILE) + .addDependent(PrimaryTaskID.PACKAGE) + .add(); + + builder.task(PrimaryTaskID.PACKAGE).add(); return builder; } - static CopyAppImageTaskAction createCopyAppImageAction() { - return (pkg, srcAppImageRoot, dstAppImageRoot) -> { - final var srcLayout = pkg.appImageLayout().resolveAt(srcAppImageRoot); - final var srcLayoutPathGroup = AppImageLayout.toPathGroup(srcLayout); + static void copyAppImage(Package pkg, AppImageDesc srcAppImage, AppImageDesc dstAppImage) throws IOException { + copyAppImage(pkg, srcAppImage, dstAppImage, true); + } - if (srcLayout instanceof ApplicationLayout appLayout) { - // Copy app layout omitting application image info file. - srcLayoutPathGroup.ghostPath(AppImageFile.getPathInAppImage(appLayout)); - } + static void copyAppImage(Package pkg, AppImageDesc srcAppImage, AppImageDesc dstAppImage, + boolean removeAppImageFile) throws IOException { + final var srcLayout = srcAppImage.resolvedAppImagelayout(); + final var srcLayoutPathGroup = AppImageLayout.toPathGroup(srcLayout); - srcLayoutPathGroup.copy(AppImageLayout.toPathGroup(pkg.packageLayout().resolveAt(dstAppImageRoot))); - }; + if (removeAppImageFile && srcLayout instanceof ApplicationLayout appLayout) { + // Copy app layout omitting application image info file. + srcLayoutPathGroup.ghostPath(AppImageFile.getPathInAppImage(appLayout)); + } + + srcLayoutPathGroup.copy(AppImageLayout.toPathGroup(dstAppImage.resolvedAppImagelayout()), LinkOption.NOFOLLOW_LINKS); + } + + static void runPostAppImageUserScript(PackageBuildEnv env) throws IOException { + final var appImageDir = env.env().appImageDir(); + new ScriptRunner() + .setDirectory(appImageDir) + .setResourceCategoryId("resource.post-app-image-script") + .setScriptNameSuffix("post-image") + .setEnvironmentVariable("JpAppImageDir", appImageDir.toAbsolutePath().toString()) + .run(env.env(), env.pkg().packageName()); } private PackagingPipeline(ImmutableDAG taskGraph, Map taskConfig, UnaryOperator appContextMapper, UnaryOperator pkgContextMapper, - Function> inputApplicationLayoutForPackaging, - BiFunction pkgBuildEnvFactory) { + Function appImageLayoutForPackaging) { this.taskGraph = Objects.requireNonNull(taskGraph); this.taskConfig = Objects.requireNonNull(taskConfig); this.appContextMapper = Objects.requireNonNull(appContextMapper); this.pkgContextMapper = Objects.requireNonNull(pkgContextMapper); - this.inputApplicationLayoutForPackaging = Objects.requireNonNull(inputApplicationLayoutForPackaging); - this.pkgBuildEnvFactory = Objects.requireNonNull(pkgBuildEnvFactory); + this.appImageLayoutForPackaging = Objects.requireNonNull(appImageLayoutForPackaging); } private TaskContext createTaskContext(BuildEnv env, Application app) { - final var appImageLayout = app.asApplicationLayout().map(layout -> layout.resolveAt(env.appImageDir())); - return new DefaultTaskContext(taskGraph, env, app, appImageLayout, Optional.empty()); + return new DefaultTaskContext(taskGraph, env, app, app.asApplicationLayout(), Optional.empty()); + } + + private TaskContext createTaskContext(PackagingTaskContext packagingContext) { + final var pkgEnv = BuildEnv.withAppImageDir(packagingContext.env.env(), packagingContext.srcAppImage.path()); + return new DefaultTaskContext(taskGraph, pkgEnv, packagingContext.env.pkg.app(), + packagingContext.srcAppImage.asApplicationLayout(), Optional.of(packagingContext)); } - private TaskContext createTaskContext(BuildEnv env, Package pkg, Path outputDir) { - final BuildEnv pkgEnv; + private static PackagingTaskContext createPackagingTaskContext(BuildEnv env, Package pkg, + Path outputDir, Map taskConfig, AppImageLayout appImageLayoutForPackaging) { + + Objects.requireNonNull(env); + Objects.requireNonNull(outputDir); + Objects.requireNonNull(taskConfig); + Objects.requireNonNull(appImageLayoutForPackaging); + + final AppImageDesc srcAppImageDesc; + final AppImageDesc dstAppImageDesc; if (pkg.app().runtimeBuilder().isPresent()) { - // Will build application image. Use the same build environment to package it. - pkgEnv = env; + // Runtime builder is present, will build application image. + // appImageDir() should point to a directory where the application image will be created. + srcAppImageDesc = new AppImageDesc(appImageLayoutForPackaging, env.appImageDir()); + dstAppImageDesc = srcAppImageDesc; } else { - // Use existing app image. Set up a new directory to copy the existing app image for packaging. - pkgEnv = pkgBuildEnvFactory.apply(env, pkg); + srcAppImageDesc = new AppImageDesc(pkg.app().imageLayout(), pkg.predefinedAppImage().orElseGet(() -> { + // No predefined app image and no runtime builder. + // This should be runtime packaging. + if (pkg.isRuntimeInstaller()) { + return env.appImageDir(); + } else { + // Can't create app image without runtime builder. + throw new UnsupportedOperationException(); + } + })); + + if (taskConfig.get(CopyAppImageTaskID.COPY).action().isEmpty()) { + // "copy app image" task action is undefined indicating + // the package will use provided app image as-is. + dstAppImageDesc = srcAppImageDesc; + } else { + dstAppImageDesc = new AppImageDesc(appImageLayoutForPackaging, env.buildRoot().resolve("image")); + } } - final var appImageInfo = analyzeAppImageDir(env, pkg); - return new DefaultTaskContext(taskGraph, env, pkg.app(), - appImageInfo.asResolvedApplicationLayout(), - Optional.of(new PackagingTaskContext(pkg, pkgEnv, appImageInfo.path(), outputDir))); + final var pkgEnv = new PackageBuildEnv<>( + BuildEnv.withAppImageDir(env, dstAppImageDesc.path()), pkg, dstAppImageDesc.appImageLyout(), outputDir); + + return new PackagingTaskContext(pkgEnv, srcAppImageDesc); } private void execute(TaskContext context) throws PackagerException { @@ -391,19 +486,22 @@ private void execute(TaskContext context) throws PackagerException { } } - private static record PackagingTaskContext(Package pkg, BuildEnv env, Path srcAppImageDir, - Path outputDir) implements TaskContext { + private record PackagingTaskContext(PackageBuildEnv env, + AppImageDesc srcAppImage) implements TaskContext, StartupParameters { PackagingTaskContext { - Objects.requireNonNull(pkg); Objects.requireNonNull(env); - Objects.requireNonNull(srcAppImageDir); - Objects.requireNonNull(outputDir); + Objects.requireNonNull(srcAppImage); + } + + @Override + public BuildEnv packagingEnv() { + return env.env; } @Override public boolean test(TaskID taskID) { - if (taskID == AppImageTaskID.APP_IMAGE_FILE) { + if (taskID == BuildApplicationTaskID.APP_IMAGE_FILE) { // Application image for packaging, skip adding application image info file. return false; } @@ -411,19 +509,24 @@ public boolean test(TaskID taskID) { return true; } + @SuppressWarnings("unchecked") @Override public void execute(TaskAction taskAction) throws IOException, PackagerException { - if (taskAction instanceof PackageTaskAction pkgAction) { - pkgAction.execute(env, pkg); + if (taskAction instanceof PackageTaskAction) { + ((PackageTaskAction)taskAction).execute(env); } else if (taskAction instanceof CopyAppImageTaskAction copyAction) { - copyAction.execute(pkg, srcAppImageDir, env.appImageDir()); + copyAction.execute(env.pkg(), srcAppImage, new AppImageDesc(env.envLayout(), env.env().appImageDir())); } else { throw new IllegalArgumentException(); } } + + AppImageBuildEnv appImageBuildEnv() { + return env.appImageBuildEnv(); + } } - private static record DefaultTaskContext(ImmutableDAG taskGraph, BuildEnv env, Application app, + private record DefaultTaskContext(ImmutableDAG taskGraph, BuildEnv env, Application app, Optional appLayout, Optional pkg) implements TaskContext { DefaultTaskContext { @@ -436,15 +539,19 @@ private static record DefaultTaskContext(ImmutableDAG taskGraph, BuildEn @Override public boolean test(TaskID taskID) { + final var isBuildApplicationImageTask = isBuildApplicationImageTask(taskID); + final var isCopyAppImageTask = isCopyAppImageTask(taskID); + final var isPackageTask = !isBuildApplicationImageTask && !isCopyAppImageTask; + if (pkg.isPresent() && !pkg.orElseThrow().test(taskID)) { return false; - } else if (pkg.isEmpty() && isPackageTask(taskID)) { + } else if (pkg.isEmpty() && isPackageTask) { // Building application image, skip packaging tasks. return false; - } else if (app.runtimeBuilder().isEmpty() && isBuildApplicationImageTask(taskID)) { + } else if (app.runtimeBuilder().isEmpty() && isBuildApplicationImageTask && !isCopyAppImageTask) { // Runtime builder is not present, skip building application image tasks. return false; - } else if (app.runtimeBuilder().isPresent() && isCopyAppImageTask(taskID)) { + } else if (app.runtimeBuilder().isPresent() && isCopyAppImageTask && !isBuildApplicationImageTask) { // Runtime builder is present, skip copying app image tasks. return false; } else { @@ -452,10 +559,14 @@ public boolean test(TaskID taskID) { } } + @SuppressWarnings("unchecked") @Override public void execute(TaskAction taskAction) throws IOException, PackagerException { - if (taskAction instanceof ApplicationImageTaskAction appImageAction) { - appImageAction.execute(env, app, appLayout.orElseThrow()); + if (taskAction instanceof AppImageTaskAction) { + final var taskEnv = pkg.map(PackagingTaskContext::appImageBuildEnv).orElseGet(this::appBuildEnv); + ((AppImageTaskAction)taskAction).execute(taskEnv); + } else if (taskAction instanceof ApplicationImageTaskAction) { + ((ApplicationImageTaskAction)taskAction).execute(appBuildEnv()); } else if (taskAction instanceof NoArgTaskAction noArgAction) { noArgAction.execute(); } else { @@ -463,15 +574,6 @@ public void execute(TaskAction taskAction) throws IOException, PackagerException } } - private boolean isPackageTask(TaskID taskID) { - if (taskID == PrimaryTaskID.PACKAGE) { - return true; - } else { - return Stream.of(PrimaryTaskID.BUILD_APPLICATION_IMAGE, - PrimaryTaskID.COPY_APP_IMAGE).noneMatch(taskGraph.getAllHeadsOf(taskID)::contains); - } - } - private boolean isBuildApplicationImageTask(TaskID taskID) { return (taskID == PrimaryTaskID.BUILD_APPLICATION_IMAGE || taskGraph.getAllHeadsOf(taskID).contains(PrimaryTaskID.BUILD_APPLICATION_IMAGE)); @@ -482,15 +584,20 @@ private boolean isCopyAppImageTask(TaskID taskID) { || taskGraph.getAllHeadsOf(taskID).contains(PrimaryTaskID.COPY_APP_IMAGE)); } + @SuppressWarnings("unchecked") + private AppImageBuildEnv appBuildEnv() { + return new AppImageBuildEnv<>(env, app, (T)appLayout.orElseThrow()); + } } private static Callable createTask(TaskContext context, TaskID id, TaskConfig config) { Objects.requireNonNull(context); Objects.requireNonNull(id); + Objects.requireNonNull(config); return () -> { - if (config.action != null && context.test(id)) { + if (config.action.isPresent() && context.test(id)) { try { - context.execute(config.action); + context.execute(config.action.orElseThrow()); } catch (ExceptionBox ex) { throw ExceptionBox.rethrowUnchecked(ex); } @@ -501,8 +608,7 @@ private static Callable createTask(TaskContext context, TaskID id, TaskCon private final ImmutableDAG taskGraph; private final Map taskConfig; - private final Function> inputApplicationLayoutForPackaging; + private final Function appImageLayoutForPackaging; private final UnaryOperator appContextMapper; private final UnaryOperator pkgContextMapper; - private final BiFunction pkgBuildEnvFactory; } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 8b6a36786c785..ce81354082e13 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -52,9 +52,11 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; +import jdk.jpackage.internal.PackagingPipeline.PackageBuildEnv; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.RuntimeLayout; import jdk.jpackage.internal.model.WinMsiPackage; @@ -204,15 +206,9 @@ public boolean validate(Map params) } } - private void prepareProto(WinMsiPackage pkg, BuildEnv env, Path msiOutputDir) throws + private void prepareProto(Package pkg, BuildEnv env, AppImageLayout appImageLayout) throws PackagerException, IOException { - final var taskPipeline = WinPackagingPipeline.build().excludeDirFromCopying(msiOutputDir).create(); - - taskPipeline.execute(env, pkg, msiOutputDir); - - final AppImageLayout appImageLayout = taskPipeline.analyzeAppImageDir(env, pkg).resolvedImagelayout(); - // Configure installer icon if (appImageLayout instanceof RuntimeLayout runtimeLayout) { // Use icon from java launcher. @@ -251,33 +247,33 @@ public Path execute(Map params, var pkg = WinFromParams.MSI_PACKAGE.fetchFrom(params); var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - Path imageDir = env.appImageDir(); - try { - prepareProto(pkg, env, outputParentDir); - for (var wixFragment : wixFragments) { - wixFragment.initFromParams(env, pkg); - wixFragment.addFilesToConfigRoot(); - } - - Map wixVars = prepareMainProjectFile(env, pkg); + WinPackagingPipeline.build() + .excludeDirFromCopying(outputParentDir) + .task(PackagingPipeline.PackageTaskID.CREATE_PACKAGE_FILE) + .packageAction(this::buildPackage) + .add() + .create().execute(env, pkg, outputParentDir); - new ScriptRunner() - .setDirectory(imageDir) - .setResourceCategoryId("resource.post-app-image-script") - .setScriptNameSuffix("post-image") - .setEnvironmentVariable("JpAppImageDir", imageDir.toAbsolutePath().toString()) - .run(env, pkg.packageName()); + return outputParentDir.resolve(pkg.packageFileNameWithSuffix()).toAbsolutePath(); + } - return buildMSI(env, pkg, wixVars, outputParentDir); - } catch (IOException ex) { - Log.verbose(ex); - throw new PackagerException(ex); + private void buildPackage(PackageBuildEnv env) throws PackagerException, IOException { + prepareProto(env.pkg(), env.env(), env.resolvedLayout()); + for (var wixFragment : wixFragments) { + wixFragment.initFromParams(env.env(), env.pkg()); + wixFragment.addFilesToConfigRoot(); } + + Map wixVars = prepareMainProjectFile(env); + + buildMSI(env.env(), env.pkg(), wixVars, env.outputDir()); } - private Map prepareMainProjectFile(BuildEnv env, WinMsiPackage pkg) throws IOException { + private Map prepareMainProjectFile(PackageBuildEnv env) throws IOException { Map data = new HashMap<>(); + final var pkg = env.pkg(); + data.put("JpProductCode", pkg.productCode().toString()); data.put("JpProductUpgradeCode", pkg.upgradeCode().toString()); @@ -310,9 +306,9 @@ private Map prepareMainProjectFile(BuildEnv env, WinMsiPackage p }); data.put("JpAppSizeKb", Long.toString(AppImageLayout.toPathGroup( - pkg.packageLayout().resolveAt(env.appImageDir())).sizeInBytes() >> 10)); + env.resolvedLayout()).sizeInBytes() >> 10)); - data.put("JpConfigDir", env.configDir().toAbsolutePath().toString()); + data.put("JpConfigDir", env.env().configDir().toAbsolutePath().toString()); if (pkg.isSystemWideInstall()) { data.put("JpIsSystemWide", "yes"); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java index 40ed0c974f061..5729b3287d927 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java @@ -28,11 +28,13 @@ import java.io.IOException; import java.io.UncheckedIOException; -import jdk.jpackage.internal.PackagingPipeline.AppImageTaskID; +import jdk.jpackage.internal.PackagingPipeline.AppImageBuildEnv; +import jdk.jpackage.internal.PackagingPipeline.BuildApplicationTaskID; +import jdk.jpackage.internal.PackagingPipeline.CopyAppImageTaskID; import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; import jdk.jpackage.internal.PackagingPipeline.TaskID; -import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.WinApplication; import jdk.jpackage.internal.model.WinLauncher; @@ -45,19 +47,19 @@ enum WinAppImageTaskID implements TaskID { static PackagingPipeline.Builder build() { return PackagingPipeline.buildStandard() - .inputApplicationLayoutForPackaging(pkg -> pkg.app().asApplicationLayout()) - .task(PrimaryTaskID.COPY_APP_IMAGE).noaction().add() + .appImageLayoutForPackaging(Package::appImageLayout) + .task(CopyAppImageTaskID.COPY).noaction().add() .task(WinAppImageTaskID.REBRAND_LAUNCHERS) - .addDependency(AppImageTaskID.LAUNCHERS) + .addDependency(BuildApplicationTaskID.LAUNCHERS) .addDependent(PrimaryTaskID.BUILD_APPLICATION_IMAGE) - .action(WinPackagingPipeline::rebrandLaunchers).add(); + .applicationAction(WinPackagingPipeline::rebrandLaunchers).add(); } - private static void rebrandLaunchers(BuildEnv env, Application app, - ApplicationLayout appLayout) throws IOException, PackagerException { - for (var launcher : app.launchers()) { - final var iconTarget = createLauncherIconResource(app, launcher, env::createResource).map(iconResource -> { - var iconDir = env.buildRoot().resolve("icons"); + private static void rebrandLaunchers(AppImageBuildEnv env) + throws IOException, PackagerException { + for (var launcher : env.app().launchers()) { + final var iconTarget = createLauncherIconResource(env.app(), launcher, env.env()::createResource).map(iconResource -> { + var iconDir = env.env().buildRoot().resolve("icons"); var theIconTarget = iconDir.resolve(launcher.executableName() + ".ico"); try { if (null == iconResource.saveToFile(theIconTarget)) { @@ -69,13 +71,13 @@ private static void rebrandLaunchers(BuildEnv env, Application app, return theIconTarget; }); - var launcherExecutable = appLayout.launchersDirectory().resolve( + var launcherExecutable = env.resolvedLayout().launchersDirectory().resolve( launcher.executableNameWithSuffix()); // Update branding of launcher executable - new ExecutableRebrander((WinApplication) app, - (WinLauncher) launcher, env::createResource).execute( - env, launcherExecutable, iconTarget); + new ExecutableRebrander(env.app(), + (WinLauncher) launcher, env.env()::createResource).execute( + env.env(), launcherExecutable, iconTarget); } } From 855a6aa0b485f6f43e296efac4653303550c00b7 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 16:59:23 -0500 Subject: [PATCH 0327/1101] ImmutableDAG -> FixedDAG --- .../jpackage/internal/PackagingPipeline.java | 14 +++++----- .../{ImmutableDAG.java => FixedDAG.java} | 18 ++++++------ .../pipeline/TaskPipelineBuilder.java | 8 +++--- ...mmutableDAGTest.java => FixedDAGTest.java} | 28 +++++++++---------- 4 files changed, 35 insertions(+), 33 deletions(-) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/{ImmutableDAG.java => FixedDAG.java} (95%) rename test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/{ImmutableDAGTest.java => FixedDAGTest.java} (93%) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java index 2b789c6fa592d..19d8e08cda551 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java @@ -47,7 +47,7 @@ import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.pipeline.DirectedEdge; -import jdk.jpackage.internal.pipeline.ImmutableDAG; +import jdk.jpackage.internal.pipeline.FixedDAG; import jdk.jpackage.internal.pipeline.TaskPipelineBuilder; import jdk.jpackage.internal.pipeline.TaskSpecBuilder; import jdk.jpackage.internal.util.function.ExceptionBox; @@ -280,7 +280,7 @@ Builder appImageLayoutForPackaging(Function v) { return this; } - ImmutableDAG taskGraphSnapshot() { + FixedDAG taskGraphSnapshot() { if (taskGraphSnapshot == null) { taskGraphSnapshot = taskGraphBuilder.create(); } @@ -303,13 +303,13 @@ PackagingPipeline create() { validatedAppImageLayoutForPackaging()); } - private final ImmutableDAG.Builder taskGraphBuilder = ImmutableDAG.build(); + private final FixedDAG.Builder taskGraphBuilder = FixedDAG.build(); private final List excludeCopyDirs = new ArrayList<>(); private final Map taskConfig = new HashMap<>(); private UnaryOperator appContextMapper; private UnaryOperator pkgContextMapper; private Function appImageLayoutForPackaging; - private ImmutableDAG taskGraphSnapshot; + private FixedDAG taskGraphSnapshot; } static Builder build() { @@ -400,7 +400,7 @@ static void runPostAppImageUserScript(PackageBuildEnv e .run(env.env(), env.pkg().packageName()); } - private PackagingPipeline(ImmutableDAG taskGraph, Map taskConfig, + private PackagingPipeline(FixedDAG taskGraph, Map taskConfig, UnaryOperator appContextMapper, UnaryOperator pkgContextMapper, Function appImageLayoutForPackaging) { this.taskGraph = Objects.requireNonNull(taskGraph); @@ -526,7 +526,7 @@ AppImageBuildEnv appImageBuildEnv() { } } - private record DefaultTaskContext(ImmutableDAG taskGraph, BuildEnv env, Application app, + private record DefaultTaskContext(FixedDAG taskGraph, BuildEnv env, Application app, Optional appLayout, Optional pkg) implements TaskContext { DefaultTaskContext { @@ -606,7 +606,7 @@ private static Callable createTask(TaskContext context, TaskID id, TaskCon }; } - private final ImmutableDAG taskGraph; + private final FixedDAG taskGraph; private final Map taskConfig; private final Function appImageLayoutForPackaging; private final UnaryOperator appContextMapper; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/FixedDAG.java similarity index 95% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/FixedDAG.java index 60b2293e96468..2270a24e952c9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/ImmutableDAG.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/FixedDAG.java @@ -42,7 +42,9 @@ import java.util.stream.StreamSupport; /** - * Immutable directed acyclic graph (DAG). + * Fixed directed acyclic graph (DAG). + *

+ * Number of nodes is fixed, links between nodes can be added or removed. * * @param edgeMatrix the edge matrix. [i,j] addresses an edge, where 'i' is the * index of the head node of the edge in the node container @@ -50,7 +52,7 @@ * node container * @param nodes the node container */ -public record ImmutableDAG(BinaryMatrix edgeMatrix, Nodes nodes) { +public record FixedDAG(BinaryMatrix edgeMatrix, Nodes nodes) { public static Builder build() { return new Builder<>(); @@ -77,8 +79,8 @@ public Builder addEdge(DirectedEdge edge) { return this; } - public ImmutableDAG create() { - return ImmutableDAG.create(edges, nodes); + public FixedDAG create() { + return FixedDAG.create(edges, nodes); } private final List nodes = new ArrayList<>(); @@ -121,7 +123,7 @@ public Iterator iterator() { } } - public ImmutableDAG { + public FixedDAG { Objects.requireNonNull(nodes); Objects.requireNonNull(edgeMatrix); @@ -134,11 +136,11 @@ public Iterator iterator() { } } - public static ImmutableDAG create(Collection> edges, List nodes) { + public static FixedDAG create(Collection> edges, List nodes) { return create(edges, Nodes.ofList(nodes)); } - static ImmutableDAG create(Collection> edges, Nodes nodes) { + static FixedDAG create(Collection> edges, Nodes nodes) { final var edgeMatrix = new BinaryMatrix(nodes.size()); for (final var edge : edges) { final int row = nodes.indexOf(edge.tail()); @@ -150,7 +152,7 @@ static ImmutableDAG create(Collection> edges, Nodes no throw new UnsupportedOperationException("Cyclic edges not allowed"); } - return new ImmutableDAG<>(edgeMatrix, nodes); + return new FixedDAG<>(edgeMatrix, nodes); } /** diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java index b23dd107a75a7..1cb14bae1b78e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/TaskPipelineBuilder.java @@ -25,8 +25,8 @@ package jdk.jpackage.internal.pipeline; -import static jdk.jpackage.internal.pipeline.ImmutableDAG.getIncomingEdges; -import static jdk.jpackage.internal.pipeline.ImmutableDAG.getNoOutgoingEdges; +import static jdk.jpackage.internal.pipeline.FixedDAG.getIncomingEdges; +import static jdk.jpackage.internal.pipeline.FixedDAG.getNoOutgoingEdges; import java.util.Collection; import java.util.List; @@ -134,7 +134,7 @@ public Void call() throws Exception { } - private record ParallelWrapperTask(ImmutableDAG> taskGraph, Executor executor) implements Callable { + private record ParallelWrapperTask(FixedDAG> taskGraph, Executor executor) implements Callable { ParallelWrapperTask { Objects.requireNonNull(taskGraph); @@ -206,6 +206,6 @@ private static Runnable toRunnable(Callable callable) { } - private final ImmutableDAG.Builder> taskGraphBuilder = new ImmutableDAG.Builder<>(); + private final FixedDAG.Builder> taskGraphBuilder = new FixedDAG.Builder<>(); private Executor executor; } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/FixedDAGTest.java similarity index 93% rename from test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java rename to test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/FixedDAGTest.java index 4707a4c471691..e6763d6e556a3 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/ImmutableDAGTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/FixedDAGTest.java @@ -38,22 +38,22 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -final class ImmutableDAGTest { +final class FixedDAGTest { @Test public void testInvalidCtorArgs() { final var matrix1x2 = new BinaryMatrix(1, 2); - final var nodes = ImmutableDAG.Nodes.ofList(List.of(A, B)); + final var nodes = FixedDAG.Nodes.ofList(List.of(A, B)); - assertThrows(IllegalArgumentException.class, () -> new ImmutableDAG<>(matrix1x2, nodes)); + assertThrows(IllegalArgumentException.class, () -> new FixedDAG<>(matrix1x2, nodes)); final var matrix3x3 = new BinaryMatrix(3, 3); - assertThrows(IllegalArgumentException.class, () -> new ImmutableDAG<>(matrix3x3, nodes)); + assertThrows(IllegalArgumentException.class, () -> new FixedDAG<>(matrix3x3, nodes)); } @Test public void testNodesToList() { - final var nodes = ImmutableDAG.Nodes.ofList(List.of(A, B)); + final var nodes = FixedDAG.Nodes.ofList(List.of(A, B)); assertEquals(2, nodes.size()); @@ -187,7 +187,7 @@ public void testSome() { // | | | // +----+------+ - final var graphBuilder = ImmutableDAG.build(); + final var graphBuilder = FixedDAG.build(); graphBuilder.addEdge(edge(C, L)); graphBuilder.addEdge(edge(D, B)); @@ -234,7 +234,7 @@ public void testSome2() { // +--- L ---+ // - final var graphBuilder = ImmutableDAG.build(); + final var graphBuilder = FixedDAG.build(); graphBuilder.addEdge(edge(B, A)); graphBuilder.addEdge(edge(C, A)); @@ -312,7 +312,7 @@ public void testTopologicalSort(List> edges, int[] expecte return Stream.of(edge.tail(), edge.head()); }).flatMap(x -> x).sorted().distinct().toList(); - assertArrayEquals(expectedNodes, ImmutableDAG.create(edges, nodes).topologicalSort().stream().mapToInt(x -> x).toArray()); + assertArrayEquals(expectedNodes, FixedDAG.create(edges, nodes).topologicalSort().stream().mapToInt(x -> x).toArray()); } private static List testTopologicalSort() { @@ -386,19 +386,19 @@ private static List testTopologicalSort() { @Test public void testEmptyBuilder() { - assertThrows(IllegalArgumentException.class, ImmutableDAG.build()::create); + assertThrows(IllegalArgumentException.class, FixedDAG.build()::create); } @Test public void testSingleNodeBuilder() { - final var graphBuilder = ImmutableDAG.build(); + final var graphBuilder = FixedDAG.build(); graphBuilder.addNode(A); assertNodesEquals(graphBuilder.create().nodes(), A); } @Test public void testIsolatedNodesBuilder() { - final var graphBuilder = ImmutableDAG.build(); + final var graphBuilder = FixedDAG.build(); graphBuilder.addNode(A); graphBuilder.addNode(B); assertNodesEquals(graphBuilder.create().nodes(), A, B); @@ -411,12 +411,12 @@ public void testIsolatedNodesBuilder() { assertEquals(graphBuilder.create().getNoIncomingEdges(), List.of(A, B)); } - private static void assertNodesEquals(ImmutableDAG.Nodes actual, String... expected) { + private static void assertNodesEquals(FixedDAG.Nodes actual, String... expected) { assertEquals(List.of(expected), StreamSupport.stream(actual.spliterator(), false).toList()); } - private static ImmutableDAG create(Collection> edges) { - final var graphBuilder = ImmutableDAG.build(); + private static FixedDAG create(Collection> edges) { + final var graphBuilder = FixedDAG.build(); edges.forEach(graphBuilder::addEdge); return graphBuilder.create(); } From eb981ccd26ce92f7df85dd85cf8642788e606185 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 20 Feb 2025 17:13:38 -0500 Subject: [PATCH 0328/1101] Minor --- .../macosx/classes/jdk/jpackage/internal/MacDmgBundler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java index 5c9e7fdc3707c..56aacf6e44a73 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java @@ -73,11 +73,11 @@ public Path execute(Map params, final var pkg = MacFromParams.DMG_PACKAGE.fetchFrom(params); var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - final var builder = MacDmgPackager.build().outputDir(outputParentDir).pkg(pkg).env(env); + final var packager = MacDmgPackager.build().outputDir(outputParentDir).pkg(pkg).env(env); - MacDmgPackager.findSetFileUtility().ifPresent(builder::setFileUtility); + MacDmgPackager.findSetFileUtility().ifPresent(packager::setFileUtility); - return builder.execute(); + return packager.execute(); } @Override From 48ba237d02dcb029a05918807e30b49a8bdfef3f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 22 Feb 2025 00:53:15 -0500 Subject: [PATCH 0329/1101] Added tests for DMG install dir. Fixed DMG bundler to report warning only when custom install dir differs from the default install dir. --- .../internal/MacBaseInstallerBundler.java | 31 ++-- .../resources/MacResources.properties | 2 +- .../jdk/jpackage/test/JPackageCommand.java | 9 +- .../helpers/jdk/jpackage/test/MacHelper.java | 26 ++-- .../tools/jpackage/share/InstallDirTest.java | 134 ++++++++++++++++-- 5 files changed, 169 insertions(+), 33 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index 69ecce068e733..1a98e06dfa356 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -25,6 +25,13 @@ package jdk.jpackage.internal; +import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; +import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; +import static jdk.jpackage.internal.StandardBundlerParam.VERSION; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.LinkOption; @@ -32,12 +39,6 @@ import java.text.MessageFormat; import java.util.Map; import java.util.Optional; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import jdk.jpackage.internal.util.FileUtils; public abstract class MacBaseInstallerBundler extends AbstractBundler { @@ -102,16 +103,20 @@ public abstract class MacBaseInstallerBundler extends AbstractBundler { static String getInstallDir( Map params, boolean defaultOnly) { String returnValue = INSTALL_DIR.fetchFrom(params); - if (defaultOnly && returnValue != null) { - Log.info(I18N.getString("message.install-dir-ignored")); + + final String defaultInstallDir; + if (StandardBundlerParam.isRuntimeInstaller(params)) { + defaultInstallDir = "/Library/Java/JavaVirtualMachines"; + } else { + defaultInstallDir = "/Applications"; + } + + if (defaultOnly && returnValue != null && !Path.of(returnValue).equals(Path.of(defaultInstallDir))) { + Log.info(MessageFormat.format(I18N.getString("message.install-dir-ignored"), defaultInstallDir)); returnValue = null; } if (returnValue == null) { - if (StandardBundlerParam.isRuntimeInstaller(params)) { - returnValue = "/Library/Java/JavaVirtualMachines"; - } else { - returnValue = "/Applications"; - } + returnValue = defaultInstallDir; } return returnValue; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties index e0a555b369854..74f6c9267a73d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties @@ -91,7 +91,7 @@ message.preparing-scripts=Preparing package scripts. message.preparing-distribution-dist=Preparing distribution.dist: {0}. message.signing.pkg=Warning: For signing PKG, you might need to set "Always Trust" for your certificate using "Keychain Access" tool. message.setfile.dmg=Setting custom icon on DMG file skipped because 'SetFile' utility was not found. Installing Xcode with Command Line Tools should resolve this issue. -message.install-dir-ignored=Warning: "--install-dir" is not supported by DMG and will be default to /Applications. +message.install-dir-ignored=Warning: "--install-dir" is not supported by DMG and will be default to {0}. message.codesign.failed.reason.app.content="codesign" failed and additional application content was supplied via the "--app-content" parameter. Probably the additional content broke the integrity of the application bundle and caused the failure. Ensure content supplied via the "--app-content" parameter does not break the integrity of the application bundle, or add it in the post-processing step. message.codesign.failed.reason.xcode.tools=Possible reason for "codesign" failure is missing Xcode with command line developer tools. Install Xcode with command line developer tools to see if it resolves the problem. warning.unsigned.app.image=Warning: Using unsigned app-image to build signed {0}. diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 418d7377ec637..ee73e9e88a715 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -71,6 +71,7 @@ public JPackageCommand(JPackageCommand cmd) { ignoreDefaultRuntime = cmd.ignoreDefaultRuntime; ignoreDefaultVerbose = cmd.ignoreDefaultVerbose; immutable = cmd.immutable; + dmgInstallDir = cmd.dmgInstallDir; prerequisiteActions = new Actions(cmd.prerequisiteActions); verifyActions = new Actions(cmd.verifyActions); appLayoutAsserts = cmd.appLayoutAsserts; @@ -501,7 +502,11 @@ public Path appInstallationDirectory() { } if (TKit.isOSX()) { - return MacHelper.getInstallationDirectory(this); + if (packageType() == PackageType.MAC_DMG && dmgInstallDir != null) { + return dmgInstallDir; + } else { + return MacHelper.getInstallationDirectory(this); + } } throw TKit.throwUnknownPlatformError(); @@ -867,6 +872,7 @@ private static JPackageCommand convertFromRuntime(JPackageCommand cmd) { var copy = new JPackageCommand(cmd); copy.immutable = false; copy.removeArgumentWithValue("--runtime-image"); + copy.dmgInstallDir = cmd.appInstallationDirectory(); return copy; } @@ -1164,6 +1170,7 @@ public void run() { private boolean ignoreDefaultRuntime; private boolean ignoreDefaultVerbose; private boolean immutable; + private Path dmgInstallDir; private final Actions prerequisiteActions; private final Actions verifyActions; private Path executeInDirectory; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index 2256963999aec..72706129213e2 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -22,6 +22,8 @@ */ package jdk.jpackage.test; +import static java.util.stream.Collectors.toSet; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.lang.reflect.InvocationTargetException; @@ -29,13 +31,12 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.List; import java.util.ArrayList; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; -import static java.util.stream.Collectors.toSet; import java.util.stream.Stream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -43,13 +44,13 @@ import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; +import jdk.jpackage.internal.RetryExecutor; +import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.internal.util.function.ThrowingSupplier; import jdk.jpackage.test.PackageTest.PackageHandlers; -import jdk.jpackage.internal.RetryExecutor; -import jdk.jpackage.internal.util.PathUtils; -import org.xml.sax.SAXException; import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; public final class MacHelper { @@ -298,9 +299,18 @@ static String getBundleName(JPackageCommand cmd) { static Path getInstallationDirectory(JPackageCommand cmd) { cmd.verifyIsOfType(PackageType.MAC); - return Path.of(cmd.getArgumentValue("--install-dir", - () -> cmd.isRuntime() ? "/Library/Java/JavaVirtualMachines" : "/Applications")).resolve( - cmd.name() + (cmd.isRuntime() ? "" : ".app")); + + final var defaultInstallLocation = Path.of( + cmd.isRuntime() ? "/Library/Java/JavaVirtualMachines" : "/Applications"); + + final Path installLocation; + if (cmd.packageType() == PackageType.MAC_DMG) { + installLocation = defaultInstallLocation; + } else { + installLocation = cmd.getArgumentValue("--install-dir", () -> defaultInstallLocation, Path::of); + } + + return installLocation.resolve(cmd.name() + (cmd.isRuntime() ? "" : ".app")); } static Path getUninstallCommand(JPackageCommand cmd) { diff --git a/test/jdk/tools/jpackage/share/InstallDirTest.java b/test/jdk/tools/jpackage/share/InstallDirTest.java index 672a435d22054..604f66993f21a 100644 --- a/test/jdk/tools/jpackage/share/InstallDirTest.java +++ b/test/jdk/tools/jpackage/share/InstallDirTest.java @@ -22,12 +22,20 @@ */ import java.nio.file.Path; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; -import jdk.jpackage.test.TKit; -import jdk.jpackage.test.PackageTest; -import jdk.jpackage.test.PackageType; import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageStringBundle; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.PackageType; +import jdk.jpackage.test.RunnablePackageTest.Action; +import jdk.jpackage.test.TKit; +import jdk.jpackage.test.TKit.TextStreamVerifier; /** * Test --install-dir parameter. Output of the test should be @@ -92,11 +100,6 @@ public static void testCommon(Path installDir) { @Parameter("foo") @Parameter("/opt/foo/.././.") public static void testLinuxInvalid(String installDir) { - testLinuxBad(installDir, "Invalid installation directory"); - } - - private static void testLinuxBad(String installDir, - String errorMessageSubstring) { new PackageTest().configureHelloApp() .setExpectedExitCode(1) .forTypes(PackageType.LINUX) @@ -105,9 +108,120 @@ private static void testLinuxBad(String installDir, cmd.saveConsoleOutput(true); }) .addBundleVerifier((cmd, result) -> { - TKit.assertTextStream(errorMessageSubstring).apply( - result.getOutput().stream()); + cmd.validateOutput(JPackageStringBundle.MAIN.cannedFormattedString("error.invalid-install-dir")); }) .run(); } + + record DmgTestSpec(Path installDir, boolean installDirIgnored, boolean runtimeInstaller) { + + DmgTestSpec { + Objects.requireNonNull(installDir); + } + + static Builder build() { + return new Builder(); + } + + static final class Builder { + + Builder ignoredInstallDir(String v) { + installDir = Path.of(v); + installDirIgnored = true; + return this; + } + + Builder acceptedInstallDir(String v) { + installDir = Path.of(v); + installDirIgnored = false; + return this; + } + + Builder runtimeInstaller() { + runtimeInstaller = true; + return this; + } + + DmgTestSpec create() { + return new DmgTestSpec(installDir, installDirIgnored, runtimeInstaller); + } + + private Path installDir; + private boolean installDirIgnored; + private boolean runtimeInstaller; + } + + @Override + public String toString() { + final var sb = new StringBuilder(); + sb.append(installDir); + if (installDirIgnored) { + sb.append(", ignore"); + } + if (runtimeInstaller) { + sb.append(", runtime"); + } + return sb.toString(); + } + + void run() { + final var test = new PackageTest().forTypes(PackageType.MAC_DMG).ignoreBundleOutputDir(); + if (runtimeInstaller) { + test.addInitializer(cmd -> { + cmd.removeArgumentWithValue("--input"); + }); + } else { + test.configureHelloApp(); + } + + test.addInitializer(JPackageCommand::setFakeRuntime).addInitializer(cmd -> { + cmd.addArguments("--install-dir", installDir); + cmd.validateOutput(createInstallDirWarningVerifier()); + }).run(Action.CREATE_AND_UNPACK); + } + + private TextStreamVerifier createInstallDirWarningVerifier() { + final var verifier = TKit.assertTextStream( + JPackageStringBundle.MAIN.cannedFormattedString("message.install-dir-ignored", defaultDmgInstallDir()).getValue()); + if (installDirIgnored) { + return verifier; + } else { + return verifier.negate(); + } + } + + private String defaultDmgInstallDir() { + if (runtimeInstaller) { + return "/Library/Java/JavaVirtualMachines"; + } else { + return "/Applications"; + } + } + } + + @Test(ifOS = OperatingSystem.MACOS) + @ParameterSupplier + public static void testDmg(DmgTestSpec testSpec) { + testSpec.run(); + } + + public static List testDmg() { + return Stream.of( + DmgTestSpec.build().ignoredInstallDir("/foo"), + DmgTestSpec.build().ignoredInstallDir("/foo/bar"), + DmgTestSpec.build().ignoredInstallDir("/foo").runtimeInstaller(), + DmgTestSpec.build().ignoredInstallDir("/foo/bar").runtimeInstaller(), + + DmgTestSpec.build().ignoredInstallDir("/Library/Java/JavaVirtualMachines"), + DmgTestSpec.build().ignoredInstallDir("/Applications").runtimeInstaller(), + + DmgTestSpec.build().acceptedInstallDir("/Applications"), + DmgTestSpec.build().ignoredInstallDir("/Applications/foo/bar/buz"), + + DmgTestSpec.build().runtimeInstaller().acceptedInstallDir("/Library/Java/JavaVirtualMachines"), + DmgTestSpec.build().runtimeInstaller().ignoredInstallDir("/Library/Java/JavaVirtualMachines/foo/bar/buz") + ).map(DmgTestSpec.Builder::create).map(testSpec -> { + return new Object[] { testSpec }; + }).toList(); + } } From 68f9480ee65ba898a2948e76fa264348d8050d48 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 22 Feb 2025 11:41:32 -0500 Subject: [PATCH 0330/1101] Fix javadoc --- .../classes/jdk/jpackage/internal/model/Package.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java index 0905ebf1d64a1..0bf4e14d094c9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java @@ -66,15 +66,15 @@ * * * Linux - * bin/foo app/foo.jar - * opt/duke/bin/foo opt/duke/app/foo.jar - * /opt/duke/bin/foo /opt/duke/app/foo.jar + * bin/foo lib/app/foo.jar + * opt/duke/bin/foo opt/duke/lib/app/foo.jar + * /opt/duke/bin/foo /opt/duke/lib/app/foo.jar * * * OSX - * bin/foo app/foo.jar - * Applications/duke/bin/foo Applications/duke/app/foo.jar - * /Applications/duke/bin/foo /Applications/duke/app/foo.jar + * Contents/MacOS/foo Contents/app/foo.jar + * Applications/Duke.app/Contents/MacOS/foo Applications/Duke.app/Contents/app/foo.jar + * /Applications/Duke.app/Contents/MacOS/foo /Applications/Duke.app/Contents/app/foo.jar * * */ From 0c09eb65c1d1a58083764cacec80f4629a3dc8f6 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 22 Feb 2025 11:42:45 -0500 Subject: [PATCH 0331/1101] LinuxPackageBuilder.directName() -> LinuxPackageBuilder.literalName() --- .../classes/jdk/jpackage/internal/LinuxFromParams.java | 2 +- .../jdk/jpackage/internal/LinuxPackageBuilder.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java index 1c5b064a02724..deaa2f35303e4 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java @@ -74,7 +74,7 @@ private static LinuxPackageBuilder createLinuxPackageBuilder( LINUX_CATEGORY.copyInto(params, pkgBuilder::category); LINUX_MENU_GROUP.copyInto(params, pkgBuilder::menuGroupName); RELEASE.copyInto(params, pkgBuilder::release); - LINUX_PACKAGE_NAME.copyInto(params, pkgBuilder::directName); + LINUX_PACKAGE_NAME.copyInto(params, pkgBuilder::literalName); return pkgBuilder; } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index 795763765e9bb..0499810ad3e8d 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -45,8 +45,8 @@ final class LinuxPackageBuilder { } LinuxPackage create() throws ConfigException { - if (directName != null) { - pkgBuilder.name(directName); + if (literalName != null) { + pkgBuilder.name(literalName); } else { // Lower case and turn spaces/underscores into dashes pkgBuilder.name(pkgBuilder.create().packageName().toLowerCase().replaceAll("[ _]", "-")); @@ -77,8 +77,8 @@ private LinuxPackage create(Package pkg, AppImageLayout pkgLayout) throws Config pkg.asStandardPackageType().map(LinuxPackageArch::getValue).orElseThrow())); } - LinuxPackageBuilder directName(String v) { - directName = v; + LinuxPackageBuilder literalName(String v) { + literalName = v; return this; } @@ -161,7 +161,7 @@ private static void validatePackageName(String packageName, private record Defaults(String release, String menuGroupName, String category) { } - private String directName; + private String literalName; private String menuGroupName; private String category; private String additionalDependencies; From c0fb4529f05416d5c4995438f21f58d5d52e9660 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 22 Feb 2025 11:44:46 -0500 Subject: [PATCH 0332/1101] Allow to read properties configured on PackageBuilder. --- .../jdk/jpackage/internal/PackageBuilder.java | 64 +++++++++++++++---- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index 69794ecb3515e..d86690f86d184 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -44,13 +44,13 @@ final class PackageBuilder { } Package create() throws ConfigException { - final var effectiveName = Optional.ofNullable(name).orElseGet(app::name); + final var validatedName = validatedName(); Path relativeInstallDir; if (installDir != null) { var normalizedInstallDir = mapInstallDir(installDir, type); if (type instanceof StandardPackageType stdType) { - Optional installDirName = Optional.of(Path.of(effectiveName)); + Optional installDirName = Optional.of(Path.of(validatedName)); switch (stdType) { case LINUX_DEB, LINUX_RPM -> { switch (normalizedInstallDir.toString()) { @@ -69,10 +69,8 @@ Package create() throws ConfigException { normalizedInstallDir = installDirName.map(normalizedInstallDir::resolve).orElse(normalizedInstallDir); } relativeInstallDir = normalizedInstallDir; - } else if (type instanceof StandardPackageType stdType) { - relativeInstallDir = defaultInstallDir(stdType, effectiveName, app); } else { - throw new UnsupportedOperationException(); + relativeInstallDir = defaultInstallDir().orElseThrow(UnsupportedOperationException::new); } if (relativeInstallDir.isAbsolute()) { @@ -82,7 +80,7 @@ Package create() throws ConfigException { return new Stub( app, type, - effectiveName, + validatedName, Optional.ofNullable(description).orElseGet(app::description), version = Optional.ofNullable(version).orElseGet(app::version), Optional.ofNullable(aboutURL), @@ -95,42 +93,86 @@ PackageBuilder name(String v) { name = v; return this; } + + Optional name() { + return Optional.ofNullable(name); + } PackageBuilder fileName(Path v) { fileName = v; return this; } + + Optional fileName() { + return Optional.ofNullable(fileName); + } PackageBuilder description(String v) { description = v; return this; } + Optional description() { + return Optional.ofNullable(description); + } + PackageBuilder version(String v) { version = v; return this; } + Optional version() { + return Optional.ofNullable(version); + } + PackageBuilder aboutURL(String v) { aboutURL = v; return this; } + Optional aboutURL() { + return Optional.ofNullable(aboutURL); + } + PackageBuilder licenseFile(Path v) { licenseFile = v; return this; } + Optional licenseFile() { + return Optional.ofNullable(licenseFile); + } + PackageBuilder predefinedAppImage(Path v) { predefinedAppImage = v; return this; } + Optional predefinedAppImage() { + return Optional.ofNullable(predefinedAppImage); + } + PackageBuilder installDir(Path v) { installDir = v; return this; } + Optional installDir() { + return Optional.ofNullable(installDir); + } + + Optional defaultInstallDir() { + if (type instanceof StandardPackageType stdType) { + return defaultInstallDir(stdType, validatedName(), app); + } else { + return Optional.empty(); + } + } + + private String validatedName() { + return name().orElseGet(app::name); + } + private static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigException { var ex = buildConfigException("error.invalid-install-dir", installDir).create(); @@ -169,13 +211,13 @@ private static Path mapInstallDir(Path installDir, PackageType pkgType) return installDir; } - private static Path defaultInstallDir(StandardPackageType pkgType, String pkgName, Application app) { + private static Optional defaultInstallDir(StandardPackageType pkgType, String pkgName, Application app) { switch (pkgType) { case WIN_EXE, WIN_MSI -> { - return app.appImageDirName(); + return Optional.of(app.appImageDirName()); } case LINUX_DEB, LINUX_RPM -> { - return Path.of("/opt").resolve(pkgName); + return Optional.of(Path.of("/opt").resolve(pkgName)); } case MAC_DMG, MAC_PKG -> { final Path dirName = app.appImageDirName(); @@ -185,10 +227,10 @@ private static Path defaultInstallDir(StandardPackageType pkgType, String pkgNam } else { base = Path.of("/Applications"); } - return base.resolve(dirName); + return Optional.of(base.resolve(dirName)); } default -> { - throw new UnsupportedOperationException(); + return Optional.empty(); } } } From 642504bb6a471a619752323288fbd191e10cbf5e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 22 Feb 2025 11:45:04 -0500 Subject: [PATCH 0333/1101] Add logic to ignore non-default install dir for DMG packager --- .../jdk/jpackage/internal/MacDmgPackageBuilder.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java index af528dc595484..23c7eb658dd8e 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java @@ -29,8 +29,8 @@ import java.util.Objects; import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.model.MacApplication; +import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.model.MacDmgPackageMixin; import jdk.jpackage.internal.model.MacPackage; @@ -55,6 +55,14 @@ List validatedDmgContent() { } MacDmgPackage create() throws ConfigException { + pkgBuilder.installDir().ifPresent(installDir -> { + final var defaultInstallDirLocation = pkgBuilder.defaultInstallDir().map(Path::getParent).orElseThrow(); + if (!defaultInstallDirLocation.equals(installDir)) { + Log.info(I18N.format("message.install-dir-ignored", defaultInstallDirLocation)); + pkgBuilder.installDir(defaultInstallDirLocation); + } + }); + final var pkg = MacPackage.create(pkgBuilder.create()); return MacDmgPackage.create(pkg, new MacDmgPackageMixin.Stub( From 075511895b40c37eff81f54bc03e8c2dc4e80297 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 24 Feb 2025 10:48:04 -0500 Subject: [PATCH 0334/1101] Initial commit --- .../internal/MacBaseInstallerBundler.java | 87 +------------- .../jdk/jpackage/internal/MacPkgBundler.java | 112 ++++++++---------- 2 files changed, 53 insertions(+), 146 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index 6d48f18a311af..7dbcbc9f1e98b 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -25,53 +25,20 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; -import java.io.IOException; +import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; +import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; + import java.nio.file.Files; import java.nio.file.Path; import java.text.MessageFormat; import java.util.Map; import java.util.Optional; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.OUTPUT_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; -import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.model.ConfigException; public abstract class MacBaseInstallerBundler extends AbstractBundler { - static final BundlerParamInfo IMAGES_ROOT = - new BundlerParamInfo<>( - "imagesRoot", - Path.class, - params -> { - final var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - return env.buildRoot().resolve("images"); - }, - (s, p) -> null); - - private final BundlerParamInfo APP_IMAGE_TEMP_ROOT = - new BundlerParamInfo<>( - "mac.app.imageRoot", - Path.class, - params -> { - Path imageDir = IMAGES_ROOT.fetchFrom(params); - try { - if (!IOUtils.exists(imageDir)) { - Files.createDirectories(imageDir); - } - return Files.createTempDirectory( - imageDir, "image-"); - } catch (IOException e) { - return imageDir.resolve(getID()+ ".image"); - } - }, - (s, p) -> Path.of(s)); - public static final BundlerParamInfo SIGNING_KEY_USER = new BundlerParamInfo<>( Arguments.CLIOptions.MAC_SIGNING_KEY_NAME.getId(), @@ -86,48 +53,6 @@ public abstract class MacBaseInstallerBundler extends AbstractBundler { params -> "", null); - public static final BundlerParamInfo INSTALLER_SIGN_IDENTITY = - new BundlerParamInfo<>( - Arguments.CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getId(), - String.class, - params -> "", - null); - - public static final BundlerParamInfo MAC_INSTALLER_NAME = - new BundlerParamInfo<> ( - "mac.installerName", - String.class, - params -> { - String nm = INSTALLER_NAME.fetchFrom(params); - if (nm == null) return null; - - String version = VERSION.fetchFrom(params); - if (version == null) { - return nm; - } else { - return nm + "-" + version; - } - }, - (s, p) -> s); - - // Returns full path to installation directory - static String getInstallDir( - Map params, boolean defaultOnly) { - String returnValue = INSTALL_DIR.fetchFrom(params); - if (defaultOnly && returnValue != null) { - Log.info(I18N.getString("message.install-dir-ignored")); - returnValue = null; - } - if (returnValue == null) { - if (StandardBundlerParam.isRuntimeInstaller(params)) { - returnValue = "/Library/Java/JavaVirtualMachines"; - } else { - returnValue = "/Applications"; - } - } - return returnValue; - } - public MacBaseInstallerBundler() { appImageBundler = new MacAppBundler(); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 2f68946b4d67d..55ca5ccee9fea 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -30,9 +30,7 @@ import static jdk.jpackage.internal.MacApplicationBuilder.isValidBundleIdentifier; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.PrintStream; import java.io.PrintWriter; import java.net.URI; import java.net.URISyntaxException; @@ -51,8 +49,11 @@ import javax.xml.stream.XMLStreamWriter; import jdk.internal.util.Architecture; import jdk.internal.util.OSVersion; +import jdk.jpackage.internal.PackagingPipeline.PackageBuildEnv; +import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.MacApplication; +import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.model.MacPkgPackage; import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.util.FileUtils; @@ -100,6 +101,10 @@ public class MacPkgBundler extends MacBaseInstallerBundler { }, (s, p) -> s); + private static Path installLocation(MacPkgPackage pkg) { + return Path.of("/").resolve(pkg.relativeInstallDir()).getParent(); + } + public Path bundle(Map params, Path outdir) throws PackagerException { @@ -111,20 +116,25 @@ public Path bundle(Map params, IOUtils.writableOutputDir(outdir); - try { - env = BuildEnv.withAppImageDir(env, prepareAppBundle(params)); + MacPackagingPipeline.build(Optional.of(pkg)) + .excludeDirFromCopying(outdir) + .excludeDirFromCopying(StandardBundlerParam.OUTPUT_DIR.fetchFrom(params)) + .task(PackagingPipeline.PrimaryTaskID.PACKAGE) + .packageAction(this::buildPackage) + .add() + .create().execute(env, pkg, outdir); - prepareConfigFiles(pkg, env); - Path configScript = getConfig_Script(pkg, env); - if (IOUtils.exists(configScript)) { - IOUtils.run("bash", configScript); - } + return outdir.resolve(pkg.packageFileNameWithSuffix()).toAbsolutePath(); + } - return createPKG(pkg, env, outdir); - } catch (IOException | PackagerException ex) { - Log.verbose(ex); - throw new PackagerException(ex); + private void buildPackage(PackageBuildEnv env) throws PackagerException, IOException { + prepareConfigFiles(env.pkg(), env.env()); + Path configScript = getConfig_Script(env.pkg(), env.env()); + if (IOUtils.exists(configScript)) { + IOUtils.run("bash", configScript); } + + createPKG(env.pkg(), env.env(), env.outputDir()); } private Path packagesRoot(BuildEnv env) { @@ -366,49 +376,36 @@ private void patchCPLFile(Path cpl) throws IOException { // based on doc "any .svn or CVS directories, and any .DS_Store files". // So easy approach will be to copy user provided app-image into temp folder // if root path contains other files. - private Path getRoot(MacPkgPackage pkg, BuildEnv env) throws IOException { - Path rootDir = env.appImageDir().getParent(); - - // Not needed for runtime installer and it might break runtime installer + private BuildEnv prepareAppImage(MacPkgPackage pkg, BuildEnv env) throws IOException { + // Not needed for runtime installer and it might break runtime installer // if parent does not have any other files if (!pkg.isRuntimeInstaller()) { + final Path rootDir = env.appImageDir().getParent(); try (var fileList = Files.list(rootDir)) { Path[] list = fileList.toArray(Path[]::new); // We should only have app image and/or .DS_Store if (list.length == 1) { - return rootDir; + return env; } else if (list.length == 2) { // Check case with app image and .DS_Store if (list[0].toString().toLowerCase().endsWith(".ds_store") || list[1].toString().toLowerCase().endsWith(".ds_store")) { - return rootDir; // Only app image and .DS_Store + return env; // Only app image and .DS_Store } } } - } - - // Copy to new root - Path newRoot = Files.createTempDirectory( - env.buildRoot(), "root-"); - Path source, dest; + // Copy to new root + Path newRoot = Files.createTempDirectory(env.buildRoot(), "root-"); + Path source = env.appImageDir(); + Path dest = newRoot.resolve(source.getFileName()); - if (pkg.isRuntimeInstaller()) { - // firs, is this already a runtime with - // /Contents/Home - if so we need the Home dir - Path original = env.appImageDir(); - Path home = original.resolve("Contents/Home"); - source = (Files.exists(home)) ? home : original; + FileUtils.copyRecursive(source, dest); - // Then we need to put back the /Content/Home - dest = newRoot.resolve(((MacApplication)pkg.app()).bundleIdentifier() + "/Contents/Home"); - } else { - source = env.appImageDir(); - dest = newRoot.resolve(source.getFileName()); + return BuildEnv.withAppImageDir(env, dest); } - FileUtils.copyRecursive(source, dest); - return newRoot; + return env; } private boolean withServicesPkg(MacPkgPackage pkg, BuildEnv env) { @@ -486,21 +483,21 @@ private Path createPKG(MacPkgPackage pkg, BuildEnv env, Path outdir) { Files.createDirectories(packagesRoot(env)); - Path root = getRoot(pkg, env); + env = prepareAppImage(pkg, env); if (withServicesPkg(pkg, env)) { createServicesPkg(pkg, env); } - final var installDir = Path.of("/").resolve(pkg.relativeInstallDir()).toString(); + final var installLocation = installLocation(pkg).toString(); // Generate default CPL file Path cpl = env.configDir().resolve("cpl.plist"); ProcessBuilder pb = new ProcessBuilder("/usr/bin/pkgbuild", "--root", - root.toString(), + env.appImageDir().toString(), "--install-location", - installDir, + installLocation, "--analyze", cpl.toAbsolutePath().toString()); @@ -512,22 +509,21 @@ private Path createPKG(MacPkgPackage pkg, BuildEnv env, Path outdir) { if (((MacApplication)pkg.app()).appStore()) { pb = new ProcessBuilder("/usr/bin/pkgbuild", "--root", - root.toString(), + env.appImageDir().toString(), "--install-location", - installDir, + installLocation, "--component-plist", cpl.toAbsolutePath().toString(), "--identifier", ((MacApplication)pkg.app()).bundleIdentifier(), appPKG.toAbsolutePath().toString()); - IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); } else { preparePackageScripts(pkg, env); pb = new ProcessBuilder("/usr/bin/pkgbuild", "--root", - root.toString(), + env.appImageDir().toString(), "--install-location", - installDir, + installLocation, "--component-plist", cpl.toAbsolutePath().toString(), "--scripts", @@ -535,8 +531,8 @@ private Path createPKG(MacPkgPackage pkg, BuildEnv env, Path outdir) { "--identifier", ((MacApplication)pkg.app()).bundleIdentifier(), appPKG.toAbsolutePath().toString()); - IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); } + IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); // build final package Path finalPKG = outdir.resolve(pkg.packageFileNameWithSuffix()); @@ -571,9 +567,9 @@ private Path createPKG(MacPkgPackage pkg, BuildEnv env, Path outdir) { commandLine.add(getConfig_PDF(pkg, env) .toAbsolutePath().toString()); commandLine.add("--component"); - Path p = root.resolve(pkg.app().appImageDirName()); + Path p = env.appImageDir().resolve(pkg.app().appImageDirName()); commandLine.add(p.toAbsolutePath().toString()); - commandLine.add(installDir); + commandLine.add(installLocation); } else { commandLine.add("--distribution"); commandLine.add(getConfig_DistributionXMLFile(pkg, env) @@ -584,21 +580,7 @@ private Path createPKG(MacPkgPackage pkg, BuildEnv env, Path outdir) { commandLine.add(finalPKG.toAbsolutePath().toString()); pb = new ProcessBuilder(commandLine); - - try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos)) { - try { - IOUtils.exec(pb, false, ps, true, Executor.INFINITE_TIMEOUT); - } catch (IOException ioe) { - // Log output of "productbuild" in case of - // error. It should help user to diagnose - // issue when using --mac-installer-sign-identity - Log.info(MessageFormat.format(I18N.getString( - "error.tool.failed.with.output"), "productbuild")); - Log.info(baos.toString().strip()); - throw ioe; - } - } + IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); return finalPKG; } catch (Exception ignored) { From 17e4c982adac060cc4a46e8dca3b92805fa3d786 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Feb 2025 10:39:41 -0500 Subject: [PATCH 0335/1101] Move PKG packaging in MacPkgPackager.java --- .../jdk/jpackage/internal/MacPkgBundler.java | 527 +---------------- .../jdk/jpackage/internal/MacPkgPackager.java | 557 ++++++++++++++++++ 2 files changed, 564 insertions(+), 520 deletions(-) create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 55ca5ccee9fea..0ff54517663b0 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -30,43 +30,16 @@ import static jdk.jpackage.internal.MacApplicationBuilder.isValidBundleIdentifier; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; -import java.io.IOException; -import java.io.PrintWriter; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.file.Files; import java.nio.file.Path; import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.ResourceBundle; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; -import jdk.internal.util.Architecture; -import jdk.internal.util.OSVersion; -import jdk.jpackage.internal.PackagingPipeline.PackageBuildEnv; -import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.MacApplication; -import jdk.jpackage.internal.model.MacDmgPackage; -import jdk.jpackage.internal.model.MacPkgPackage; import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.util.FileUtils; -import jdk.jpackage.internal.util.XmlUtils; public class MacPkgBundler extends MacBaseInstallerBundler { - private static final ResourceBundle I18N = ResourceBundle.getBundle( - "jdk.jpackage.internal.resources.MacResources"); - - private static final String DEFAULT_BACKGROUND_IMAGE = "background_pkg.png"; - private static final String DEFAULT_PDF = "product-def.plist"; - public static final BundlerParamInfo DEVELOPER_ID_INSTALLER_SIGNING_KEY = new BundlerParamInfo<>( @@ -101,498 +74,6 @@ public class MacPkgBundler extends MacBaseInstallerBundler { }, (s, p) -> s); - private static Path installLocation(MacPkgPackage pkg) { - return Path.of("/").resolve(pkg.relativeInstallDir()).getParent(); - } - - public Path bundle(Map params, - Path outdir) throws PackagerException { - - final var pkg = MacFromParams.PKG_PACKAGE.fetchFrom(params); - var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - - Log.verbose(MessageFormat.format(I18N.getString("message.building-pkg"), - pkg.app().name())); - - IOUtils.writableOutputDir(outdir); - - MacPackagingPipeline.build(Optional.of(pkg)) - .excludeDirFromCopying(outdir) - .excludeDirFromCopying(StandardBundlerParam.OUTPUT_DIR.fetchFrom(params)) - .task(PackagingPipeline.PrimaryTaskID.PACKAGE) - .packageAction(this::buildPackage) - .add() - .create().execute(env, pkg, outdir); - - return outdir.resolve(pkg.packageFileNameWithSuffix()).toAbsolutePath(); - } - - private void buildPackage(PackageBuildEnv env) throws PackagerException, IOException { - prepareConfigFiles(env.pkg(), env.env()); - Path configScript = getConfig_Script(env.pkg(), env.env()); - if (IOUtils.exists(configScript)) { - IOUtils.run("bash", configScript); - } - - createPKG(env.pkg(), env.env(), env.outputDir()); - } - - private Path packagesRoot(BuildEnv env) { - return env.buildRoot().resolve("packages"); - } - - private Path scriptsRoot(BuildEnv env) { - return env.configDir().resolve("scripts"); - } - - private Path getPackages_AppPackage(MacPkgPackage pkg, BuildEnv env) { - return packagesRoot(env).resolve(pkg.app().name() + "-app.pkg"); - } - - private Path getPackages_ServicesPackage(MacPkgPackage pkg, BuildEnv env) { - return packagesRoot(env).resolve(pkg.app().name() + "-services.pkg"); - } - - private Path getPackages_SupportPackage(MacPkgPackage pkg, BuildEnv env) { - return packagesRoot(env).resolve(pkg.app().name() + "-support.pkg"); - } - - private Path getConfig_DistributionXMLFile(MacPkgPackage pkg, BuildEnv env) { - return env.configDir().resolve("distribution.dist"); - } - - private Path getConfig_PDF(MacPkgPackage pkg, BuildEnv env) { - return env.configDir().resolve("product-def.plist"); - } - - private Path getConfig_BackgroundImage(MacPkgPackage pkg, BuildEnv env) { - return env.configDir().resolve(pkg.app().name() + "-background.png"); - } - - private Path getConfig_BackgroundImageDarkAqua(MacPkgPackage pkg, BuildEnv env) { - return env.configDir().resolve(pkg.app().name() + "-background-darkAqua.png"); - } - - private String getAppIdentifier(MacPkgPackage pkg) { - return ((MacApplication)pkg.app()).bundleIdentifier(); - } - - private String getServicesIdentifier(MacPkgPackage pkg) { - return ((MacApplication)pkg.app()).bundleIdentifier() + ".services"; - } - - private String getSupportIdentifier(MacPkgPackage pkg) { - return ((MacApplication)pkg.app()).bundleIdentifier() + ".support"; - } - - private void preparePackageScripts(MacPkgPackage pkg, BuildEnv env) - throws IOException { - Log.verbose(I18N.getString("message.preparing-scripts")); - - Files.createDirectories(scriptsRoot(env)); - - Map data = new HashMap<>(); - - Path appLocation = pkg.asInstalledPackageApplicationLayout().orElseThrow().appDirectory(); - - data.put("INSTALL_LOCATION", Path.of("/").resolve(pkg.relativeInstallDir()).toString()); - data.put("APP_LOCATION", appLocation.toString()); - - MacPkgInstallerScripts.createAppScripts() - .setResourceDir(env.resourceDir().orElse(null)) - .setSubstitutionData(data) - .saveInFolder(scriptsRoot(env)); - } - - private void addPackageToInstallerGuiScript(XMLStreamWriter xml, - String pkgId, String pkgName, String pkgVersion) throws IOException, - XMLStreamException { - xml.writeStartElement("pkg-ref"); - xml.writeAttribute("id", pkgId); - xml.writeEndElement(); // - xml.writeStartElement("choice"); - xml.writeAttribute("id", pkgId); - xml.writeAttribute("visible", "false"); - xml.writeStartElement("pkg-ref"); - xml.writeAttribute("id", pkgId); - xml.writeEndElement(); // - xml.writeEndElement(); // - xml.writeStartElement("pkg-ref"); - xml.writeAttribute("id", pkgId); - xml.writeAttribute("version", pkgVersion); - xml.writeAttribute("onConclusion", "none"); - try { - xml.writeCharacters(new URI(null, null, pkgName, null).toASCIIString()); - } catch (URISyntaxException ex) { - throw new RuntimeException(ex); - } - xml.writeEndElement(); // - } - - private void prepareDistributionXMLFile(MacPkgPackage pkg, BuildEnv env) - throws IOException { - Path f = getConfig_DistributionXMLFile(pkg, env); - - Log.verbose(MessageFormat.format(I18N.getString( - "message.preparing-distribution-dist"), f.toAbsolutePath().toString())); - - XmlUtils.createXml(f, xml -> { - xml.writeStartElement("installer-gui-script"); - xml.writeAttribute("minSpecVersion", "1"); - - xml.writeStartElement("title"); - xml.writeCharacters(pkg.app().name()); - xml.writeEndElement(); - - xml.writeStartElement("background"); - xml.writeAttribute("file", - getConfig_BackgroundImage(pkg, env).getFileName().toString()); - xml.writeAttribute("mime-type", "image/png"); - xml.writeAttribute("alignment", "bottomleft"); - xml.writeAttribute("scaling", "none"); - xml.writeEndElement(); - - xml.writeStartElement("background-darkAqua"); - xml.writeAttribute("file", - getConfig_BackgroundImageDarkAqua(pkg, env).getFileName().toString()); - xml.writeAttribute("mime-type", "image/png"); - xml.writeAttribute("alignment", "bottomleft"); - xml.writeAttribute("scaling", "none"); - xml.writeEndElement(); - - final var licFile = pkg.licenseFile(); - if (licFile.isPresent()) { - xml.writeStartElement("license"); - xml.writeAttribute("file", licFile.orElseThrow().toAbsolutePath().toString()); - xml.writeAttribute("mime-type", "text/rtf"); - xml.writeEndElement(); - } - - /* - * Note that the content of the distribution file - * below is generated by productbuild --synthesize - */ - - Map pkgs = new LinkedHashMap<>(); - - pkgs.put(getAppIdentifier(pkg), getPackages_AppPackage(pkg, env)); - if (withServicesPkg(pkg, env)) { - pkgs.put(getServicesIdentifier(pkg), - getPackages_ServicesPackage(pkg, env)); - pkgs.put(getSupportIdentifier(pkg), - getPackages_SupportPackage(pkg, env)); - } - - for (var p : pkgs.entrySet()) { - addPackageToInstallerGuiScript(xml, p.getKey(), - p.getValue().getFileName().toString(), - pkg.app().version()); - } - - xml.writeStartElement("options"); - xml.writeAttribute("customize", "never"); - xml.writeAttribute("require-scripts", "false"); - xml.writeAttribute("hostArchitectures", - Architecture.isAARCH64() ? "arm64" : "x86_64"); - xml.writeEndElement(); // - xml.writeStartElement("choices-outline"); - xml.writeStartElement("line"); - xml.writeAttribute("choice", "default"); - for (var pkgId : pkgs.keySet()) { - xml.writeStartElement("line"); - xml.writeAttribute("choice", pkgId); - xml.writeEndElement(); // - } - xml.writeEndElement(); // - xml.writeEndElement(); // - xml.writeStartElement("choice"); - xml.writeAttribute("id", "default"); - xml.writeEndElement(); // - - xml.writeEndElement(); // - }); - } - - private boolean prepareConfigFiles(MacPkgPackage pkg, BuildEnv env) - throws IOException { - - env.createResource(DEFAULT_BACKGROUND_IMAGE) - .setCategory(I18N.getString("resource.pkg-background-image")) - .saveToFile(getConfig_BackgroundImage(pkg, env)); - - env.createResource(DEFAULT_BACKGROUND_IMAGE) - .setCategory(I18N.getString("resource.pkg-background-image")) - .saveToFile(getConfig_BackgroundImageDarkAqua(pkg, env)); - - env.createResource(DEFAULT_PDF) - .setCategory(I18N.getString("resource.pkg-pdf")) - .saveToFile(getConfig_PDF(pkg, env)); - - prepareDistributionXMLFile(pkg, env); - - env.createResource(null) - .setCategory(I18N.getString("resource.post-install-script")) - .saveToFile(getConfig_Script(pkg, env)); - - return true; - } - - // name of post-image script - private Path getConfig_Script(MacPkgPackage pkg, BuildEnv env) { - return env.configDir().resolve(pkg.app().name() + "-post-image.sh"); - } - - private void patchCPLFile(Path cpl) throws IOException { - String cplData = Files.readString(cpl); - String[] lines = cplData.split("\n"); - try (PrintWriter out = new PrintWriter(Files.newBufferedWriter(cpl))) { - int skip = 0; - // Used to skip Java.runtime bundle, since - // pkgbuild with --root will find two bundles app and Java runtime. - // We cannot generate component proprty list when using - // --component argument. - for (int i = 0; i < lines.length; i++) { - if (lines[i].trim().equals("BundleIsRelocatable")) { - out.println(lines[i]); - out.println(""); - i++; - } else if (lines[i].trim().equals("ChildBundles")) { - ++skip; - } else if ((skip > 0) && lines[i].trim().equals("")) { - --skip; - } else { - if (skip == 0) { - out.println(lines[i]); - } - } - } - } - } - - // pkgbuild includes all components from "--root" and subfolders, - // so if we have app image in folder which contains other images, then they - // will be included as well. It does have "--filter" option which use regex - // to exclude files/folder, but it will overwrite default one which excludes - // based on doc "any .svn or CVS directories, and any .DS_Store files". - // So easy approach will be to copy user provided app-image into temp folder - // if root path contains other files. - private BuildEnv prepareAppImage(MacPkgPackage pkg, BuildEnv env) throws IOException { - // Not needed for runtime installer and it might break runtime installer - // if parent does not have any other files - if (!pkg.isRuntimeInstaller()) { - final Path rootDir = env.appImageDir().getParent(); - try (var fileList = Files.list(rootDir)) { - Path[] list = fileList.toArray(Path[]::new); - // We should only have app image and/or .DS_Store - if (list.length == 1) { - return env; - } else if (list.length == 2) { - // Check case with app image and .DS_Store - if (list[0].toString().toLowerCase().endsWith(".ds_store") || - list[1].toString().toLowerCase().endsWith(".ds_store")) { - return env; // Only app image and .DS_Store - } - } - } - - // Copy to new root - Path newRoot = Files.createTempDirectory(env.buildRoot(), "root-"); - Path source = env.appImageDir(); - Path dest = newRoot.resolve(source.getFileName()); - - FileUtils.copyRecursive(source, dest); - - return BuildEnv.withAppImageDir(env, dest); - } - - return env; - } - - private boolean withServicesPkg(MacPkgPackage pkg, BuildEnv env) { - return MacLaunchersAsServices.create(env, pkg).isPresent(); - } - - private void createServicesPkg(MacPkgPackage pkg, BuildEnv env) throws - IOException { - Path root = env.buildRoot().resolve("services"); - - Path srcRoot = root.resolve("src"); - - var services = MacLaunchersAsServices.create(BuildEnv.withAppImageDir(env, srcRoot), pkg).orElseThrow(); - - Path scriptsDir = root.resolve("scripts"); - - var data = services.create(); - data.put("SERVICES_PACKAGE_ID", getServicesIdentifier(pkg)); - - MacPkgInstallerScripts.createServicesScripts() - .setResourceDir(env.resourceDir().orElse(null)) - .setSubstitutionData(data) - .saveInFolder(scriptsDir); - - var pb = new ProcessBuilder("/usr/bin/pkgbuild", - "--root", - srcRoot.toString(), - "--install-location", - "/", - "--scripts", - scriptsDir.toString(), - "--identifier", - getServicesIdentifier(pkg), - getPackages_ServicesPackage(pkg, env).toAbsolutePath().toString()); - IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); - - createSupportPkg(pkg, env, data); - } - - private void createSupportPkg(MacPkgPackage pkg, BuildEnv env, - Map servicesSubstitutionData) throws IOException { - Path root = env.buildRoot().resolve("support"); - - Path srcRoot = root.resolve("src"); - - var enqouter = Enquoter.forShellLiterals().setEnquotePredicate(str -> true); - - Map data = new HashMap<>(servicesSubstitutionData); - data.put("APP_INSTALLATION_FOLDER", Path.of("/").resolve(pkg.relativeInstallDir()).toString()); - data.put("SUPPORT_INSTALLATION_FOLDER", enqouter.applyTo(Path.of( - "/Library/Application Support", pkg.app().name()).toString())); - - new ShellScriptResource("uninstall.command") - .setResource(env.createResource("uninstall.command.template") - .setCategory(I18N.getString("resource.pkg-uninstall-script")) - .setPublicName("uninstaller") - .setSubstitutionData(data)) - .saveInFolder(srcRoot.resolve(pkg.app().name())); - - var pb = new ProcessBuilder("/usr/bin/pkgbuild", - "--root", - srcRoot.toString(), - "--install-location", - "/Library/Application Support", - "--identifier", - getSupportIdentifier(pkg), - getPackages_SupportPackage(pkg, env).toAbsolutePath().toString()); - IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); - } - - private Path createPKG(MacPkgPackage pkg, BuildEnv env, Path outdir) { - // generic find attempt - try { - Path appPKG = getPackages_AppPackage(pkg, env); - - Files.createDirectories(packagesRoot(env)); - - env = prepareAppImage(pkg, env); - - if (withServicesPkg(pkg, env)) { - createServicesPkg(pkg, env); - } - - final var installLocation = installLocation(pkg).toString(); - - // Generate default CPL file - Path cpl = env.configDir().resolve("cpl.plist"); - ProcessBuilder pb = new ProcessBuilder("/usr/bin/pkgbuild", - "--root", - env.appImageDir().toString(), - "--install-location", - installLocation, - "--analyze", - cpl.toAbsolutePath().toString()); - - IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); - - patchCPLFile(cpl); - - // build application package - if (((MacApplication)pkg.app()).appStore()) { - pb = new ProcessBuilder("/usr/bin/pkgbuild", - "--root", - env.appImageDir().toString(), - "--install-location", - installLocation, - "--component-plist", - cpl.toAbsolutePath().toString(), - "--identifier", - ((MacApplication)pkg.app()).bundleIdentifier(), - appPKG.toAbsolutePath().toString()); - } else { - preparePackageScripts(pkg, env); - pb = new ProcessBuilder("/usr/bin/pkgbuild", - "--root", - env.appImageDir().toString(), - "--install-location", - installLocation, - "--component-plist", - cpl.toAbsolutePath().toString(), - "--scripts", - scriptsRoot(env).toAbsolutePath().toString(), - "--identifier", - ((MacApplication)pkg.app()).bundleIdentifier(), - appPKG.toAbsolutePath().toString()); - } - IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); - - // build final package - Path finalPKG = outdir.resolve(pkg.packageFileNameWithSuffix()); - Files.createDirectories(outdir); - - List commandLine = new ArrayList<>(); - commandLine.add("/usr/bin/productbuild"); - - commandLine.add("--resources"); - commandLine.add(env.configDir().toAbsolutePath().toString()); - - // maybe sign - if (pkg.sign()) { - if (OSVersion.current().compareTo(new OSVersion(10, 12)) >= 0) { - // we need this for OS X 10.12+ - Log.verbose(I18N.getString("message.signing.pkg")); - } - - final var pkgSigningConfig = pkg.signingConfig().orElseThrow(); - - commandLine.add("--sign"); - commandLine.add(pkgSigningConfig.identifier().orElseThrow().name()); - - pkgSigningConfig.keyChain().ifPresent(keyChain -> { - commandLine.add("--keychain"); - commandLine.add(keyChain.toString()); - }); - } - - if (((MacApplication)pkg.app()).appStore()) { - commandLine.add("--product"); - commandLine.add(getConfig_PDF(pkg, env) - .toAbsolutePath().toString()); - commandLine.add("--component"); - Path p = env.appImageDir().resolve(pkg.app().appImageDirName()); - commandLine.add(p.toAbsolutePath().toString()); - commandLine.add(installLocation); - } else { - commandLine.add("--distribution"); - commandLine.add(getConfig_DistributionXMLFile(pkg, env) - .toAbsolutePath().toString()); - commandLine.add("--package-path"); - commandLine.add(packagesRoot(env).toAbsolutePath().toString()); - } - commandLine.add(finalPKG.toAbsolutePath().toString()); - - pb = new ProcessBuilder(commandLine); - IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); - - return finalPKG; - } catch (Exception ignored) { - Log.verbose(ignored); - return null; - } - } - - /* - * Implement Bundler - */ - @Override public String getName() { return I18N.getString("pkg.bundler.name"); @@ -663,7 +144,13 @@ public boolean validate(Map params) @Override public Path execute(Map params, Path outputParentDir) throws PackagerException { - return bundle(params, outputParentDir); + + final var pkg = MacFromParams.PKG_PACKAGE.fetchFrom(params); + var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + + final var packager = MacPkgPackager.build().outputDir(outputParentDir).pkg(pkg).env(env); + + return packager.execute(); } @Override diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java new file mode 100644 index 0000000000000..0994b2acbf6d2 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java @@ -0,0 +1,557 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.util.PathUtils.normalizedAbsolutePathString; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.UncheckedIOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Stream; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import jdk.internal.util.Architecture; +import jdk.internal.util.OSVersion; +import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; +import jdk.jpackage.internal.PackagingPipeline.StartupParameters; +import jdk.jpackage.internal.PackagingPipeline.TaskID; +import jdk.jpackage.internal.model.MacApplication; +import jdk.jpackage.internal.model.MacPkgPackage; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.util.XmlUtils; + +record MacPkgPackager(MacPkgPackage pkg, BuildEnv env, Optional services, Path outputDir) { + + enum PkgPackageTaskID implements TaskID { + PREPARE_MAIN_SCRIPTS, + CREATE_DISTRIBUTION_XML_FILE, + CREATE_COMPONENT_PLIST_FILE, + PREPARE_SERVICES + } + + static Builder build() { + return new Builder(); + } + + static final class Builder extends PackagerBuilder { + + Path execute() throws PackagerException { + Log.verbose(MessageFormat.format(I18N.getString("message.building-pkg"), + pkg.app().name())); + + IOUtils.writableOutputDir(outputDir); + + return execute(MacPackagingPipeline.build(Optional.of(pkg))); + } + + @Override + protected void configurePackagingPipeline(PackagingPipeline.Builder pipelineBuilder, + StartupParameters startupParameters) { + final var packager = new MacPkgPackager(pkg, startupParameters.packagingEnv(), createServices(), outputDir); + packager.applyToPipeline(pipelineBuilder); + } + + private Optional createServices() { + return Optional.empty(); + } + } + + record InternalPackage(Path srcRoot, String identifier, Path path, List otherPkgbuildArgs) { + + InternalPackage { + Objects.requireNonNull(srcRoot); + Objects.requireNonNull(identifier); + Objects.requireNonNull(path); + Objects.requireNonNull(otherPkgbuildArgs); + } + + private List allPkgbuildArgs() { + final List args = new ArrayList<>(); + args.add("-root"); + args.add(normalizedAbsolutePathString(srcRoot)); + args.addAll(otherPkgbuildArgs); + args.add("--identifier"); + args.add(identifier); + args.add(normalizedAbsolutePathString(path)); + return args; + } + + void build() { + final List cmdline = new ArrayList<>(); + cmdline.add("/usr/bin/pkgbuild"); + cmdline.addAll(allPkgbuildArgs()); + try { + IOUtils.exec(new ProcessBuilder(cmdline), false, null, true, Executor.INFINITE_TIMEOUT); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + } + + record Services(InternalPackage servicesPkg, Path servicesScriptsDir, InternalPackage supportPkg) { + + Services { + Objects.requireNonNull(servicesPkg); + Objects.requireNonNull(servicesScriptsDir); + Objects.requireNonNull(supportPkg); + } + + static Services create(MacPkgPackage pkg, BuildEnv env) { + final var servicesRoot = env.buildRoot().resolve("services"); + final var supportRoot = env.buildRoot().resolve("support"); + + final var servicesScriptsDir = servicesRoot.resolve("scripts"); + + final var servicesPkg = InternalPackageType.SERVICES.createInternalPackage( + servicesRoot.resolve("src"), pkg, env, List.of( + "--install-location", "/", + "--scripts", normalizedAbsolutePathString(servicesScriptsDir))); + + final var supportPkg = InternalPackageType.SUPPORT.createInternalPackage( + supportRoot, pkg, env, List.of( + "--install-location", "/Library/Application Support")); + + return new Services(servicesPkg, servicesScriptsDir, supportPkg); + } + + Stream asStream() { + return Stream.of(servicesPkg, supportPkg); + } + + void prepareForPkgbuild(MacPkgPackage pkg, BuildEnv env) throws IOException { + prepareSupportForPkgbuild(pkg, env, prepareServicesForPkgbuild(pkg, env)); + } + + private Map prepareServicesForPkgbuild(MacPkgPackage pkg, BuildEnv env) throws IOException { + final var services = new MacLaunchersAsServices(BuildEnv.withAppImageDir(env, servicesPkg.srcRoot()), pkg); + + final var data = services.create(); + data.put("SERVICES_PACKAGE_ID", servicesPkg.identifier()); + + MacPkgInstallerScripts.createServicesScripts() + .setResourceDir(env.resourceDir().orElse(null)) + .setSubstitutionData(data) + .saveInFolder(servicesScriptsDir); + + return data; + } + + private void prepareSupportForPkgbuild(MacPkgPackage pkg, BuildEnv env, + Map servicesSubstitutionData) throws IOException { + final var enqouter = Enquoter.forShellLiterals().setEnquotePredicate(str -> true); + + final var mainInstallDir = Path.of("/").resolve(pkg.relativeInstallDir()); + final var supportInstallDir = Path.of("/Library/Application Support").resolve(mainInstallDir.getFileName()); + + Map data = new HashMap<>(servicesSubstitutionData); + data.put("APP_INSTALLATION_FOLDER", mainInstallDir.toString()); + data.put("SUPPORT_INSTALLATION_FOLDER", enqouter.applyTo(supportInstallDir.toString())); + + new ShellScriptResource("uninstall.command") + .setResource(env.createResource("uninstall.command.template") + .setCategory(I18N.getString("resource.pkg-uninstall-script")) + .setPublicName("uninstaller") + .setSubstitutionData(data)) + .saveInFolder(supportPkg.srcRoot().resolve(pkg.app().name())); + } + } + + private enum InternalPackageType implements TaskID { + MAIN, + SERVICES("services"), + SUPPORT("support"); + + InternalPackage createInternalPackage(Path srcRoot, MacPkgPackage pkg, BuildEnv env, List otherPkgbuildArgs) { + return new InternalPackage(srcRoot, identifier(pkg), env.buildRoot().resolve("packages").resolve(filename(pkg)), otherPkgbuildArgs); + } + + private InternalPackageType(String nameSuffix) { + this.nameSuffix = Optional.of(nameSuffix); + } + + private InternalPackageType() { + this.nameSuffix = Optional.empty(); + } + + private String identifier(Package pkg) { + final var baseIdentifier = ((MacApplication)pkg.app()).bundleIdentifier(); + return nameSuffix.map(v -> baseIdentifier + "." + v).orElse(baseIdentifier); + } + + private String filename(Package pkg) { + return String.format("%s-%s.pkg", pkg.app().name(), nameSuffix.orElse("app")); + } + + private final Optional nameSuffix; + } + + private void applyToPipeline(PackagingPipeline.Builder pipelineBuilder) { + pipelineBuilder + .excludeDirFromCopying(outputDir) + .task(PkgPackageTaskID.PREPARE_MAIN_SCRIPTS) + .action(this::prepareMainScripts) + .add() + .task(PkgPackageTaskID.CREATE_DISTRIBUTION_XML_FILE) + .action(this::prepareDistributionXMLFile) + .add() + .task(PkgPackageTaskID.CREATE_COMPONENT_PLIST_FILE) + .action(this::createComponentPlistFile) + .add() + .task(PackageTaskID.CREATE_CONFIG_FILES) + .action(this::prepareConfigFiles) + .add() + .task(PackageTaskID.CREATE_PACKAGE_FILE) + .action(this::productbuild) + .addDependencies(InternalPackageType.values()) + .addDependencies(PkgPackageTaskID.CREATE_DISTRIBUTION_XML_FILE, PkgPackageTaskID.CREATE_COMPONENT_PLIST_FILE) + .add() + .task(PkgPackageTaskID.PREPARE_SERVICES) + .action(this::prepareServicesForBkgbuild) + .add() + .task(InternalPackageType.SERVICES) + .addDependencies(PkgPackageTaskID.PREPARE_SERVICES) + .action(this::buildServicesPKG) + .add() + .task(InternalPackageType.SUPPORT) + .addDependencies(PkgPackageTaskID.PREPARE_SERVICES) + .action(this::buildSupportPKG) + .add() + .task(InternalPackageType.MAIN) + .action(this::buildMainPKG) + .addDependencies(PkgPackageTaskID.PREPARE_MAIN_SCRIPTS) + .add(); + + if (pkg.app().isService()) { + for (var taskID : List.of(PkgPackageTaskID.PREPARE_SERVICES, InternalPackageType.SERVICES, InternalPackageType.SUPPORT)) { + pipelineBuilder.task(taskID).noaction().add(); + } + } + } + + List internalPackages() { + return Stream.concat(Stream.of(mainPkg()), + services.map(Services::asStream).orElseGet(Stream::of)).toList(); + } + + InternalPackage mainPkg() { + final List args = new ArrayList<>(); + args.add("--install-location"); + args.add(normalizedAbsolutePathString(installLocation())); + args.add("--component-plist"); + args.add(normalizedAbsolutePathString(componentPlistFile())); + + if (!app().appStore()) { + args.add("--scripts"); + args.add(normalizedAbsolutePathString(scriptsRoot())); + } + + return InternalPackageType.MAIN.createInternalPackage(env.appImageDir(), pkg, env, List.of( + "--install-location", normalizedAbsolutePathString(installLocation()), + "--component-plist", normalizedAbsolutePathString(componentPlistFile()))); + } + + MacApplication app() { + return (MacApplication)pkg.app(); + } + + Path scriptsRoot() { + return env.configDir().resolve("scripts"); + } + + Path componentPlistFile() { + return env.configDir().resolve("cpl.plist"); + } + + Path installLocation() { + return Path.of("/").resolve(pkg.relativeInstallDir()).getParent(); + } + + Path distributionXmlFile() { + return env.configDir().resolve("distribution.dist"); + } + + Path appStoreProductFile() { + return env.configDir().resolve("product-def.plist"); + } + + Path backgroundImage() { + return env.configDir().resolve(pkg.app().name() + "-background.png"); + } + + Path backgroundImageDarkAqua() { + return env.configDir().resolve(pkg.app().name() + "-background-darkAqua.png"); + } + + private void addInternalPackageToInstallerGuiScript(InternalPackage internalPkg, + XMLStreamWriter xml) throws IOException, XMLStreamException { + xml.writeStartElement("pkg-ref"); + xml.writeAttribute("id", internalPkg.identifier()); + xml.writeEndElement(); // + xml.writeStartElement("choice"); + xml.writeAttribute("id", internalPkg.identifier()); + xml.writeAttribute("visible", "false"); + xml.writeStartElement("pkg-ref"); + xml.writeAttribute("id", internalPkg.identifier()); + xml.writeEndElement(); // + xml.writeEndElement(); // + xml.writeStartElement("pkg-ref"); + xml.writeAttribute("id", internalPkg.identifier()); + xml.writeAttribute("version", pkg.version()); + xml.writeAttribute("onConclusion", "none"); + try { + xml.writeCharacters(new URI(null, null, internalPkg.path().getFileName().toString(), null).toASCIIString()); + } catch (URISyntaxException ex) { + throw new RuntimeException(ex); + } + xml.writeEndElement(); // + } + + private void prepareMainScripts() throws IOException { + Log.verbose(I18N.getString("message.preparing-scripts")); + + Files.createDirectories(scriptsRoot()); + + Map data = new HashMap<>(); + + final var appLocation = pkg.asInstalledPackageApplicationLayout().orElseThrow().appDirectory(); + + data.put("INSTALL_LOCATION", Path.of("/").resolve(pkg.relativeInstallDir()).toString()); + data.put("APP_LOCATION", appLocation.toString()); + + MacPkgInstallerScripts.createAppScripts() + .setResourceDir(env.resourceDir().orElse(null)) + .setSubstitutionData(data) + .saveInFolder(scriptsRoot()); + } + + private void prepareDistributionXMLFile() throws IOException { + final var f = distributionXmlFile(); + + Log.verbose(MessageFormat.format(I18N.getString( + "message.preparing-distribution-dist"), f.toAbsolutePath().toString())); + + XmlUtils.createXml(f, xml -> { + xml.writeStartElement("installer-gui-script"); + xml.writeAttribute("minSpecVersion", "1"); + + xml.writeStartElement("title"); + xml.writeCharacters(pkg.app().name()); + xml.writeEndElement(); + + xml.writeStartElement("background"); + xml.writeAttribute("file", backgroundImage().getFileName().toString()); + xml.writeAttribute("mime-type", "image/png"); + xml.writeAttribute("alignment", "bottomleft"); + xml.writeAttribute("scaling", "none"); + xml.writeEndElement(); + + xml.writeStartElement("background-darkAqua"); + xml.writeAttribute("file", backgroundImageDarkAqua().getFileName().toString()); + xml.writeAttribute("mime-type", "image/png"); + xml.writeAttribute("alignment", "bottomleft"); + xml.writeAttribute("scaling", "none"); + xml.writeEndElement(); + + final var licFile = pkg.licenseFile(); + if (licFile.isPresent()) { + xml.writeStartElement("license"); + xml.writeAttribute("file", licFile.orElseThrow().toAbsolutePath().toString()); + xml.writeAttribute("mime-type", "text/rtf"); + xml.writeEndElement(); + } + + /* + * Note that the content of the distribution file + * below is generated by productbuild --synthesize + */ + + for (final var p : internalPackages()) { + addInternalPackageToInstallerGuiScript(p, xml); + } + + xml.writeStartElement("options"); + xml.writeAttribute("customize", "never"); + xml.writeAttribute("require-scripts", "false"); + xml.writeAttribute("hostArchitectures", Architecture.isAARCH64() ? "arm64" : "x86_64"); + xml.writeEndElement(); // + xml.writeStartElement("choices-outline"); + xml.writeStartElement("line"); + xml.writeAttribute("choice", "default"); + for (final var p : internalPackages()) { + xml.writeStartElement("line"); + xml.writeAttribute("choice", p.identifier()); + xml.writeEndElement(); // + } + xml.writeEndElement(); // + xml.writeEndElement(); // + xml.writeStartElement("choice"); + xml.writeAttribute("id", "default"); + xml.writeEndElement(); // + + xml.writeEndElement(); // + }); + } + + private void prepareConfigFiles() throws IOException { + env.createResource(DEFAULT_BACKGROUND_IMAGE) + .setCategory(I18N.getString("resource.pkg-background-image")) + .saveToFile(backgroundImage()); + + env.createResource(DEFAULT_BACKGROUND_IMAGE) + .setCategory(I18N.getString("resource.pkg-background-image")) + .saveToFile(backgroundImageDarkAqua()); + + if (app().appStore()) { + env.createResource(DEFAULT_PDF) + .setCategory(I18N.getString("resource.pkg-pdf")) + .saveToFile(appStoreProductFile()); + } + } + + private void patchCPLFile(Path cpl) throws IOException { + String cplData = Files.readString(cpl); + String[] lines = cplData.split("\n"); + try (PrintWriter out = new PrintWriter(Files.newBufferedWriter(cpl))) { + int skip = 0; + // Used to skip Java.runtime bundle, since + // pkgbuild with --root will find two bundles app and Java runtime. + // We cannot generate component proprty list when using + // --component argument. + for (int i = 0; i < lines.length; i++) { + if (lines[i].trim().equals("BundleIsRelocatable")) { + out.println(lines[i]); + out.println(""); + i++; + } else if (lines[i].trim().equals("ChildBundles")) { + ++skip; + } else if ((skip > 0) && lines[i].trim().equals("")) { + --skip; + } else { + if (skip == 0) { + out.println(lines[i]); + } + } + } + } + } + + private void prepareServicesForBkgbuild() throws IOException { + services.orElseThrow().prepareForPkgbuild(pkg, env); + } + + private void buildServicesPKG() { + services.orElseThrow().servicesPkg().build(); + } + + private void buildSupportPKG() { + services.orElseThrow().supportPkg().build(); + } + + private void buildMainPKG() throws IOException { + mainPkg().build(); + } + + private void createComponentPlistFile() throws IOException { + final var cpl = componentPlistFile(); + + Files.createDirectories(cpl.getParent()); + + final var pb = new ProcessBuilder("/usr/bin/pkgbuild", + "--root", + normalizedAbsolutePathString(env.appImageDir()), + "--install-location", + normalizedAbsolutePathString(installLocation()), + "--analyze", + normalizedAbsolutePathString(cpl)); + + IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); + + patchCPLFile(cpl); + } + + private void productbuild() throws IOException { + final var finalPkg = outputDir.resolve(pkg.packageFileNameWithSuffix()); + Files.createDirectories(finalPkg.getParent()); + + List commandLine = new ArrayList<>(); + commandLine.add("/usr/bin/productbuild"); + + commandLine.add("--resources"); + commandLine.add(normalizedAbsolutePathString(env.configDir())); + + // maybe sign + if (pkg.sign()) { + if (OSVersion.current().compareTo(new OSVersion(10, 12)) >= 0) { + // we need this for OS X 10.12+ + Log.verbose(I18N.getString("message.signing.pkg")); + } + + final var pkgSigningConfig = pkg.signingConfig().orElseThrow(); + + commandLine.add("--sign"); + commandLine.add(pkgSigningConfig.identifier().orElseThrow().name()); + + pkgSigningConfig.keyChain().ifPresent(keyChain -> { + commandLine.add("--keychain"); + commandLine.add(keyChain.toString()); + }); + } + + if (app().appStore()) { + commandLine.add("--product"); + commandLine.add(normalizedAbsolutePathString(appStoreProductFile())); + commandLine.add("--component"); + Path p = env.appImageDir().resolve(pkg.app().appImageDirName()); + commandLine.add(p.toAbsolutePath().toString()); + commandLine.add(normalizedAbsolutePathString(installLocation())); + } else { + commandLine.add("--distribution"); + commandLine.add(normalizedAbsolutePathString(distributionXmlFile())); + commandLine.add("--package-path"); + // Assume all internal .pkg files reside in the same directory. + commandLine.add(normalizedAbsolutePathString(mainPkg().path().getParent())); + } + commandLine.add(normalizedAbsolutePathString(finalPkg)); + + final var pb = new ProcessBuilder(commandLine); + IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); + } + + private static final String DEFAULT_BACKGROUND_IMAGE = "background_pkg.png"; + private static final String DEFAULT_PDF = "product-def.plist"; +} From 101769212af7cf571be18c8ce60bd500f6f8e7da Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Feb 2025 10:41:17 -0500 Subject: [PATCH 0336/1101] Make MacDmgPackager.applyToPipeline(). It is internal and is supposed to be used by MacDmgPackager.Builder. --- .../macosx/classes/jdk/jpackage/internal/MacDmgPackager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java index 0b015ee754550..270e873524169 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java @@ -133,7 +133,7 @@ static Optional findSetFileUtility() { return Optional.empty(); } - void applyToPipeline(PackagingPipeline.Builder pipelineBuilder) { + private void applyToPipeline(PackagingPipeline.Builder pipelineBuilder) { pipelineBuilder .excludeDirFromCopying(outputDir) .task(DmgPackageTaskID.COPY_DMG_CONTENT) From 9249a28a186c1214ab76953e804f89cef4cbbcf3 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Feb 2025 10:42:00 -0500 Subject: [PATCH 0337/1101] Simplify MacLaunchersAsServices --- .../jpackage/internal/MacLaunchersAsServices.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index bb233eeb99ec6..859d4da0c9ab5 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -24,11 +24,8 @@ */ package jdk.jpackage.internal; -import java.io.IOException; import java.nio.file.Path; import java.util.List; -import java.util.Optional; -import java.util.function.Predicate; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.Package; @@ -39,21 +36,12 @@ */ public final class MacLaunchersAsServices extends UnixLaunchersAsServices { - private MacLaunchersAsServices(BuildEnv env, Package pkg) { + MacLaunchersAsServices(BuildEnv env, Package pkg) { super(env.appImageDir(), pkg.app(), List.of(), launcher -> { return new MacLauncherAsService(env, pkg, launcher); }); } - static Optional create(BuildEnv env, Package pkg) { - if (pkg.isRuntimeInstaller()) { - return Optional.empty(); - } else { - return Optional.of(new MacLaunchersAsServices(env, pkg)) - .filter(Predicate.not(MacLaunchersAsServices::isEmpty)); - } - } - public static Path getServicePListFileName(String bundleIdentifier, String launcherName) { String baseName = launcherName.replaceAll("[\\s]", "_"); From 32103d4dd34274bb821b24c02820fe676591c01d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Feb 2025 12:43:25 -0500 Subject: [PATCH 0338/1101] Fix compilation errors --- .../macosx/classes/jdk/jpackage/internal/MacPkgBundler.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 2f68946b4d67d..ac038b42c27fa 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -112,7 +112,6 @@ public Path bundle(Map params, IOUtils.writableOutputDir(outdir); try { - env = BuildEnv.withAppImageDir(env, prepareAppBundle(params)); prepareConfigFiles(pkg, env); Path configScript = getConfig_Script(pkg, env); @@ -121,7 +120,7 @@ public Path bundle(Map params, } return createPKG(pkg, env, outdir); - } catch (IOException | PackagerException ex) { + } catch (IOException ex) { Log.verbose(ex); throw new PackagerException(ex); } From 730221cae5b7dcf0ee91db02a2e66da755a68460 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Feb 2025 15:17:44 -0500 Subject: [PATCH 0339/1101] Fix DMG packaging: it didn't display destination directory when a dialog with copying DMG contents popped up. --- .../jdk/jpackage/internal/MacDmgPackager.java | 91 +++++++++---------- .../jpackage/internal/model/MacPackage.java | 4 + 2 files changed, 49 insertions(+), 46 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java index 270e873524169..777c0460a804b 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java @@ -25,6 +25,8 @@ package jdk.jpackage.internal; +import static jdk.jpackage.internal.util.PathUtils.normalizedAbsolutePathString; + import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -153,7 +155,7 @@ enum DmgPackageTaskID implements TaskID { } Path volumePath() { - return dmgWorkdir(); + return dmgWorkdir().resolve(volumeName()); } String volumeName() { @@ -161,9 +163,10 @@ String volumeName() { } String createVolumeUrlLocation() throws IOException { - Files.createDirectories(volumePath()); + final var volumeParentDir = volumePath().getParent(); + Files.createDirectories(volumeParentDir); // Url should end with '/' and it should be real path (no symbolic links). - return volumePath().toRealPath().resolve(volumeName()).toUri().toString() + File.separator; + return volumeParentDir.toRealPath().resolve(volumePath().getFileName()).toUri().toString() + File.separator; } Path volumeScript() { @@ -183,19 +186,15 @@ Path licenseFile() { } Path protoDmg() { - return dmgWorkdir().resolve("proto.dmg").toAbsolutePath(); + return dmgWorkdir().resolve("proto.dmg"); } Path protoCopyDmg() { - return dmgWorkdir().resolve("proto-copy.dmg").toAbsolutePath(); - } - - Path mountedProtoDmgPath() { - return dmgWorkdir().resolve(volumeName()); + return dmgWorkdir().resolve("proto-copy.dmg"); } Path bgImageFileInMountedDmg() { - return mountedProtoDmgPath().resolve(".background/background.tiff"); + return volumePath().resolve(".background/background.tiff"); } private Path dmgWorkdir() { @@ -227,11 +226,16 @@ private void prepareDMGSetupScript() throws IOException { data.put("DEPLOY_VOLUME_PATH", volumePath().toString()); data.put("DEPLOY_APPLICATION_NAME", pkg.app().name()); + String targetItem = pkg.relativeInstallDir().getFileName().toString(); data.put("DEPLOY_TARGET", targetItem); - data.put("DEPLOY_INSTALL_LOCATION", installRoot(pkg).toString()); - data.put("DEPLOY_INSTALL_LOCATION_DISPLAY_NAME", - getInstallDirDisplayName()); + + data.put("DEPLOY_INSTALL_LOCATION", pkg.installDir().getParent().toString()); + + // "DEPLOY_INSTALL_LOCATION_DISPLAY_NAME" is the label for the default destination directory + // for DMG bundle on the right side from the "copy" arrow in the dialog + // that pops up when user clicks on a .dmg file. + data.put("DEPLOY_INSTALL_LOCATION_DISPLAY_NAME", getInstallDirDisplayName()); env.createResource(DEFAULT_DMG_SETUP_SCRIPT) .setCategory(I18N.getString("resource.dmg-setup-script")) @@ -239,14 +243,6 @@ private void prepareDMGSetupScript() throws IOException { .saveToFile(dmgSetup); } - private static Path installRoot(MacDmgPackage pkg) { - if (pkg.isRuntimeInstaller()) { - return Path.of("/Library/Java/JavaVirtualMachines"); - } else { - return Path.of("/Applications"); - } - } - private void prepareLicense() throws IOException { final var licFile = pkg.licenseFile(); if (licFile.isEmpty()) { @@ -283,11 +279,14 @@ private void prepareConfigFiles() throws IOException { prepareDMGSetupScript(); } - // Returns display name of installation directory. Display name is used to - // show user installation location and for well known (default only) we will - // use "Applications" or "JavaVirtualMachines". private String getInstallDirDisplayName() { - return installRoot(pkg).getFileName().toString(); + final var defaultInstallDir = new PackageBuilder(pkg.app(), pkg.type()).defaultInstallDir().orElseThrow(); + if (defaultInstallDir.equals(pkg.installDir())) { + // Return "Applications" for "/Applications/foo.app" + return defaultInstallDir.getParent().getFileName().toString(); + } else { + return pkg.installDir().getParent().toString(); + } } private void buildDMG() throws IOException { @@ -320,9 +319,9 @@ private void buildDMG() throws IOException { hdiutil.toString(), "create", hdiUtilVerbosityFlag, - "-srcfolder", srcFolder.toAbsolutePath().toString(), + "-srcfolder", normalizedAbsolutePathString(srcFolder), "-volname", volumeName(), - "-ov", protoDMG.toString(), + "-ov", normalizedAbsolutePathString(protoDMG), "-fs", "HFS+", "-format", "UDRW"); try { @@ -345,7 +344,7 @@ private void buildDMG() throws IOException { hdiUtilVerbosityFlag, "-size", String.valueOf(size), "-volname", volumeName(), - "-ov", protoDMG.toString(), + "-ov", normalizedAbsolutePathString(protoDMG), "-fs", "HFS+"); new RetryExecutor() .setMaxAttemptsCount(10) @@ -358,17 +357,17 @@ private void buildDMG() throws IOException { pb = new ProcessBuilder( hdiutil.toString(), "attach", - protoDMG.toString(), + normalizedAbsolutePathString(protoDMG), hdiUtilVerbosityFlag, "-mountroot", protoDMG.getParent().toString()); IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); - final Path mountedRoot = mountedProtoDmgPath(); + final Path mountedVolume = volumePath(); // Copy app image, since we did not create DMG with it, but instead we created // empty one. if (copyAppImage) { - FileUtils.copyRecursive(srcFolder, mountedRoot); + FileUtils.copyRecursive(srcFolder, mountedVolume); } try { @@ -382,14 +381,14 @@ private void buildDMG() throws IOException { // headless environment. try { pb = new ProcessBuilder("/usr/bin/osascript", - volumeScript().toAbsolutePath().toString()); + normalizedAbsolutePathString(volumeScript())); IOUtils.exec(pb, 180); // Wait 3 minutes. See JDK-8248248. } catch (IOException ex) { Log.verbose(ex); } // volume icon - Path volumeIconFile = mountedRoot.resolve(".VolumeIcon.icns"); + Path volumeIconFile = mountedVolume.resolve(".VolumeIcon.icns"); IOUtils.copyFile(volumeIcon(), volumeIconFile); // Indicate that we want a custom icon @@ -407,14 +406,14 @@ private void buildDMG() throws IOException { pb = new ProcessBuilder( setFileUtility.orElseThrow().toString(), "-c", "icnC", - volumeIconFile.toAbsolutePath().toString()); + normalizedAbsolutePathString(volumeIconFile)); IOUtils.exec(pb); volumeIconFile.toFile().setReadOnly(); pb = new ProcessBuilder( setFileUtility.orElseThrow().toString(), "-a", "C", - mountedRoot.toAbsolutePath().toString()); + normalizedAbsolutePathString(mountedVolume)); IOUtils.exec(pb); } catch (IOException ex) { Log.error(ex.getMessage()); @@ -430,14 +429,14 @@ private void buildDMG() throws IOException { hdiutil.toString(), "detach", hdiUtilVerbosityFlag, - mountedRoot.toAbsolutePath().toString()); + normalizedAbsolutePathString(mountedVolume)); // "hdiutil detach" might not work right away due to resource busy error, so // repeat detach several times. RetryExecutor retryExecutor = new RetryExecutor(); // Image can get detach even if we got resource busy error, so stop // trying to detach it if it is no longer attached. retryExecutor.setExecutorInitializer(exec -> { - if (!Files.exists(mountedRoot)) { + if (!Files.exists(mountedVolume)) { retryExecutor.abort(); } }); @@ -448,13 +447,13 @@ private void buildDMG() throws IOException { } catch (IOException ex) { if (!retryExecutor.isAborted()) { // Now force to detach if it still attached - if (Files.exists(mountedRoot)) { + if (Files.exists(mountedVolume)) { pb = new ProcessBuilder( hdiutil.toString(), "detach", "-force", hdiUtilVerbosityFlag, - mountedRoot.toAbsolutePath().toString()); + normalizedAbsolutePathString(mountedVolume)); IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); } } @@ -465,10 +464,10 @@ private void buildDMG() throws IOException { pb = new ProcessBuilder( hdiutil.toString(), "convert", - protoDMG.toAbsolutePath().toString(), + normalizedAbsolutePathString(protoDMG), hdiUtilVerbosityFlag, "-format", "UDZO", - "-o", finalDMG.toAbsolutePath().toString()); + "-o", normalizedAbsolutePathString(finalDMG)); try { new RetryExecutor() .setMaxAttemptsCount(10) @@ -482,10 +481,10 @@ private void buildDMG() throws IOException { pb = new ProcessBuilder( hdiutil.toString(), "convert", - protoCopyDMG.toString(), + normalizedAbsolutePathString(protoCopyDMG), hdiUtilVerbosityFlag, "-format", "UDZO", - "-o", finalDMG.toAbsolutePath().toString()); + "-o", normalizedAbsolutePathString(finalDMG)); IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); } finally { Files.deleteIfExists(protoCopyDMG); @@ -497,9 +496,9 @@ private void buildDMG() throws IOException { pb = new ProcessBuilder( hdiutil.toString(), "udifrez", - finalDMG.toAbsolutePath().toString(), + normalizedAbsolutePathString(finalDMG), "-xml", - licenseFile().toAbsolutePath().toString() + normalizedAbsolutePathString(licenseFile()) ); new RetryExecutor() .setMaxAttemptsCount(10) @@ -516,7 +515,7 @@ private void buildDMG() throws IOException { Log.verbose(MessageFormat.format(I18N.getString( "message.output-to-location"), - pkg.app().name(), finalDMG.toAbsolutePath().toString())); + pkg.app().name(), normalizedAbsolutePathString(finalDMG))); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java index 4901d5d8bf7ae..3acf2b425c0d1 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java @@ -38,6 +38,10 @@ default AppImageLayout appImageLayout() { } } + default Path installDir() { + return Path.of("/").resolve(relativeInstallDir()); + } + public static MacPackage create(Package pkg) { return CompositeProxy.create(MacPackage.class, pkg); } From d0eb8b7af6625012132c6e7e220d1a9202bad783 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Feb 2025 15:18:10 -0500 Subject: [PATCH 0340/1101] Formatting --- .../classes/jdk/jpackage/internal/model/LinuxDebPackage.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java index 96563c5681099..6f8061e740b6f 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java @@ -70,8 +70,7 @@ default String versionWithRelease() { default Optional relativeCopyrightFilePath() { if (isRuntimeInstaller()) { return Optional.empty(); - } else if (isInstallDirInUsrTree() || Path.of("/").resolve(relativeInstallDir()).startsWith( - "/usr/")) { + } else if (isInstallDirInUsrTree() || Path.of("/").resolve(relativeInstallDir()).startsWith("/usr/")) { return Optional.of(Path.of("/usr/share/doc/", packageName(), "copyright")); } else { return Optional.of(relativeInstallDir().resolve("share/doc/copyright")); From 1707c34d6f55ab9ba0c7780cbc02d064dfcf1430 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Feb 2025 16:04:38 -0500 Subject: [PATCH 0341/1101] Basic tests pass with PKG packager --- .../jdk/jpackage/internal/MacPkgPackager.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java index 0994b2acbf6d2..bb48ba2dbebd7 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java @@ -87,7 +87,11 @@ protected void configurePackagingPipeline(PackagingPipeline.Builder pipelineBuil } private Optional createServices() { - return Optional.empty(); + if (pkg.app().isService()) { + return Optional.of(Services.create(pkg, env)); + } else { + return Optional.empty(); + } } } @@ -102,7 +106,7 @@ record InternalPackage(Path srcRoot, String identifier, Path path, List private List allPkgbuildArgs() { final List args = new ArrayList<>(); - args.add("-root"); + args.add("--root"); args.add(normalizedAbsolutePathString(srcRoot)); args.addAll(otherPkgbuildArgs); args.add("--identifier"); @@ -116,6 +120,7 @@ void build() { cmdline.add("/usr/bin/pkgbuild"); cmdline.addAll(allPkgbuildArgs()); try { + Files.createDirectories(path.getParent()); IOUtils.exec(new ProcessBuilder(cmdline), false, null, true, Executor.INFINITE_TIMEOUT); } catch (IOException ex) { throw new UncheckedIOException(ex); @@ -256,10 +261,18 @@ private void applyToPipeline(PackagingPipeline.Builder pipelineBuilder) { .addDependencies(PkgPackageTaskID.PREPARE_MAIN_SCRIPTS) .add(); - if (pkg.app().isService()) { - for (var taskID : List.of(PkgPackageTaskID.PREPARE_SERVICES, InternalPackageType.SERVICES, InternalPackageType.SUPPORT)) { - pipelineBuilder.task(taskID).noaction().add(); - } + final List disabledTasks = new ArrayList<>(); + + if (!pkg.app().isService()) { + disabledTasks.addAll(List.of(PkgPackageTaskID.PREPARE_SERVICES, InternalPackageType.SERVICES, InternalPackageType.SUPPORT)); + } + + if (pkg.isRuntimeInstaller()) { + disabledTasks.add(PkgPackageTaskID.PREPARE_MAIN_SCRIPTS); + } + + for (final var taskID : disabledTasks) { + pipelineBuilder.task(taskID).noaction().add(); } } @@ -543,7 +556,7 @@ private void productbuild() throws IOException { commandLine.add("--distribution"); commandLine.add(normalizedAbsolutePathString(distributionXmlFile())); commandLine.add("--package-path"); - // Assume all internal .pkg files reside in the same directory. + // Assume all internal .pkg files reside in the same directory. commandLine.add(normalizedAbsolutePathString(mainPkg().path().getParent())); } commandLine.add(normalizedAbsolutePathString(finalPkg)); From 6cddb4ccd30a908bf0fe23cbec7c091fbc072e1a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Feb 2025 17:42:59 -0500 Subject: [PATCH 0342/1101] Use XSLT to transform component .plist file --- .../jdk/jpackage/internal/MacPkgPackager.java | 37 +++++-------- .../resources/adjust-component-plist.xsl | 55 +++++++++++++++++++ 2 files changed, 68 insertions(+), 24 deletions(-) create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/adjust-component-plist.xsl diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java index bb48ba2dbebd7..46ed47d7853a2 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java @@ -27,8 +27,8 @@ import static jdk.jpackage.internal.util.PathUtils.normalizedAbsolutePathString; +import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.PrintWriter; import java.io.UncheckedIOException; import java.net.URI; import java.net.URISyntaxException; @@ -44,6 +44,10 @@ import java.util.stream.Stream; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; import jdk.internal.util.Architecture; import jdk.internal.util.OSVersion; import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; @@ -53,6 +57,7 @@ import jdk.jpackage.internal.model.MacPkgPackage; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.resources.ResourceLocator; import jdk.jpackage.internal.util.XmlUtils; record MacPkgPackager(MacPkgPackage pkg, BuildEnv env, Optional services, Path outputDir) { @@ -457,29 +462,13 @@ private void prepareConfigFiles() throws IOException { } private void patchCPLFile(Path cpl) throws IOException { - String cplData = Files.readString(cpl); - String[] lines = cplData.split("\n"); - try (PrintWriter out = new PrintWriter(Files.newBufferedWriter(cpl))) { - int skip = 0; - // Used to skip Java.runtime bundle, since - // pkgbuild with --root will find two bundles app and Java runtime. - // We cannot generate component proprty list when using - // --component argument. - for (int i = 0; i < lines.length; i++) { - if (lines[i].trim().equals("BundleIsRelocatable")) { - out.println(lines[i]); - out.println(""); - i++; - } else if (lines[i].trim().equals("ChildBundles")) { - ++skip; - } else if ((skip > 0) && lines[i].trim().equals("")) { - --skip; - } else { - if (skip == 0) { - out.println(lines[i]); - } - } - } + try (final var xsltResource = ResourceLocator.class.getResourceAsStream("adjust-component-plist.xsl")) { + final var srcXml = new StreamSource(new ByteArrayInputStream(Files.readAllBytes(cpl))); + final var dstXml = new StreamResult(cpl.toFile()); + final var xslt = TransformerFactory.newInstance().newTransformer(new StreamSource(xsltResource)); + xslt.transform(srcXml, dstXml); + } catch (TransformerException ex) { + throw new RuntimeException(ex); } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/adjust-component-plist.xsl b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/adjust-component-plist.xsl new file mode 100644 index 0000000000000..94b8a93dc1fb8 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/adjust-component-plist.xsl @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + From 9c7f4a758bdc862db7f4537d5c3e6d2f23564b69 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 26 Feb 2025 09:52:07 -0500 Subject: [PATCH 0343/1101] Parse xml without downloading external entities --- .../classes/jdk/jpackage/internal/MacPkgPackager.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java index 46ed47d7853a2..e269fe598e00a 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java @@ -46,6 +46,7 @@ import javax.xml.stream.XMLStreamWriter; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import jdk.internal.util.Architecture; @@ -59,6 +60,7 @@ import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.resources.ResourceLocator; import jdk.jpackage.internal.util.XmlUtils; +import org.xml.sax.SAXException; record MacPkgPackager(MacPkgPackage pkg, BuildEnv env, Optional services, Path outputDir) { @@ -463,11 +465,12 @@ private void prepareConfigFiles() throws IOException { private void patchCPLFile(Path cpl) throws IOException { try (final var xsltResource = ResourceLocator.class.getResourceAsStream("adjust-component-plist.xsl")) { - final var srcXml = new StreamSource(new ByteArrayInputStream(Files.readAllBytes(cpl))); + final var srcXml = new DOMSource(XmlUtils.initDocumentBuilder().parse( + new ByteArrayInputStream(Files.readAllBytes(cpl)))); final var dstXml = new StreamResult(cpl.toFile()); final var xslt = TransformerFactory.newInstance().newTransformer(new StreamSource(xsltResource)); xslt.transform(srcXml, dstXml); - } catch (TransformerException ex) { + } catch (TransformerException|SAXException ex) { throw new RuntimeException(ex); } } From 4e7bb6cc8eff099a7ac49f75ced99d6b893ac0e6 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 26 Feb 2025 10:03:03 -0500 Subject: [PATCH 0344/1101] Fix bad merge --- .../jpackage/test/LauncherIconVerifier.java | 193 ------------------ 1 file changed, 193 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java index a0123f00d7aa3..a5eb24980ae25 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java @@ -77,199 +77,6 @@ public void applyTo(JPackageCommand cmd) throws IOException { } } - private static class WinIconVerifier { - - void verifyLauncherIcon(JPackageCommand cmd, String launcherName, - Path expectedIcon, boolean expectedDefault) { - TKit.withTempDirectory("icons", tmpDir -> { - Path launcher = cmd.appLauncherPath(launcherName); - Path iconWorkDir = tmpDir.resolve(launcher.getFileName()); - Path iconContainer = iconWorkDir.resolve("container.exe"); - Files.createDirectories(iconContainer.getParent()); - Files.copy(getDefaultAppLauncher(expectedIcon == null - && !expectedDefault), iconContainer); - if (expectedIcon != null) { - Executor.tryRunMultipleTimes(() -> { - setIcon(expectedIcon, iconContainer); - }, 3, 5); - } - - Path extractedExpectedIcon = extractIconFromExecutable( - iconWorkDir, iconContainer, "expected"); - Path extractedActualIcon = extractIconFromExecutable(iconWorkDir, - launcher, "actual"); - - TKit.trace(String.format( - "Check icon file [%s] of %s launcher is a copy of source icon file [%s]", - extractedActualIcon, - Optional.ofNullable(launcherName).orElse("main"), - extractedExpectedIcon)); - - if (Files.mismatch(extractedExpectedIcon, extractedActualIcon) - != -1) { - // On Windows11 .NET API extracting icons from executables - // produce slightly different output for the same icon. - // To workaround it, compare pixels of images and if the - // number of off pixels is below a threshold, assume - // equality. - BufferedImage expectedImg = ImageIO.read( - extractedExpectedIcon.toFile()); - BufferedImage actualImg = ImageIO.read( - extractedActualIcon.toFile()); - - int w = expectedImg.getWidth(); - int h = expectedImg.getHeight(); - - TKit.assertEquals(w, actualImg.getWidth(), - "Check expected and actual icons have the same width"); - TKit.assertEquals(h, actualImg.getHeight(), - "Check expected and actual icons have the same height"); - - int diffPixelCount = 0; - - for (int i = 0; i != w; ++i) { - for (int j = 0; j != h; ++j) { - int expectedRGB = expectedImg.getRGB(i, j); - int actualRGB = actualImg.getRGB(i, j); - - if (expectedRGB != actualRGB) { - TKit.trace(String.format( - "Images mismatch at [%d, %d] pixel", i, - j)); - diffPixelCount++; - } - } - } - - double threshold = 0.1; - TKit.assertTrue(((double) diffPixelCount) / (w * h) - < threshold, - String.format( - "Check the number of mismatched pixels [%d] of [%d] is < [%f] threshold", - diffPixelCount, (w * h), threshold)); - } - }); - } - - private WinIconVerifier() { - try { - executableRebranderClass = Class.forName( - "jdk.jpackage.internal.ExecutableRebrander"); - - lockResource = executableRebranderClass.getDeclaredMethod( - "lockResource", String.class); - // Note: this reflection call requires - // --add-opens jdk.jpackage/jdk.jpackage.internal=ALL-UNNAMED - lockResource.setAccessible(true); - - unlockResource = executableRebranderClass.getDeclaredMethod( - "unlockResource", long.class); - unlockResource.setAccessible(true); - - iconSwap = executableRebranderClass.getDeclaredMethod( - "iconSwap", long.class, String.class); - iconSwap.setAccessible(true); - } catch (ClassNotFoundException | NoSuchMethodException - | SecurityException ex) { - throw rethrowUnchecked(ex); - } - } - - private Path extractIconFromExecutable(Path outputDir, Path executable, - String label) { - // Run .NET code to extract icon from the given executable. - // ExtractAssociatedIcon() will succeed even if the target file - // is locked (by an antivirus). It will output a default icon - // in case of error. To prevent this "fail safe" behavior we try - // lock the target file with Open() call. If the attempt - // fails ExtractAssociatedIcon() is not called and the script exits - // with the exit code that will be trapped - // inside of Executor.executeAndRepeatUntilExitCode() method that - // will keep running the script until it succeeds or the number of - // allowed attempts is exceeded. - - Path extractedIcon = outputDir.resolve(label + ".bmp"); - String script = String.join(";", - String.format( - "try { [System.io.File]::Open('%s', 'Open', 'Read', 'None') } catch { exit 100 }", - executable.toAbsolutePath().normalize()), - "[System.Reflection.Assembly]::LoadWithPartialName('System.Drawing')", - String.format( - "[System.Drawing.Icon]::ExtractAssociatedIcon('%s').ToBitmap().Save('%s', [System.Drawing.Imaging.ImageFormat]::Bmp)", - executable.toAbsolutePath().normalize(), - extractedIcon.toAbsolutePath().normalize())); - - Executor.of("powershell", "-NoLogo", "-NoProfile", "-Command", - script).executeAndRepeatUntilExitCode(0, 5, 10); - - return extractedIcon; - } - - private Path getDefaultAppLauncher(boolean noIcon) { - // Create app image with the sole purpose to get the default app launcher - Path defaultAppOutputDir = TKit.workDir().resolve(String.format( - "out-%d", ProcessHandle.current().pid())); - JPackageCommand cmd = JPackageCommand.helloAppImage().setFakeRuntime().setArgumentValue( - "--dest", defaultAppOutputDir); - - String launcherName; - if (noIcon) { - launcherName = "no-icon"; - new AdditionalLauncher(launcherName).setNoIcon().applyTo(cmd); - } else { - launcherName = null; - } - - if (!Files.isExecutable(cmd.appLauncherPath(launcherName))) { - cmd.execute(); - } - return cmd.appLauncherPath(launcherName); - } - - private void setIcon(Path iconPath, Path launcherPath) { - TKit.trace(String.format("Set icon of [%s] launcher to [%s] file", - launcherPath, iconPath)); - try { - launcherPath.toFile().setWritable(true, true); - try { - long lock = 0; - try { - lock = (Long) lockResource.invoke(null, new Object[]{ - launcherPath.toAbsolutePath().normalize().toString()}); - if (lock == 0) { - throw new RuntimeException(String.format( - "Failed to lock [%s] executable", - launcherPath)); - } - var exitCode = (Integer) iconSwap.invoke(null, new Object[]{ - lock, - iconPath.toAbsolutePath().normalize().toString()}); - if (exitCode != 0) { - throw new RuntimeException(String.format( - "Failed to swap icon of [%s] executable", - launcherPath)); - } - } finally { - if (lock != 0) { - unlockResource.invoke(null, new Object[]{lock}); - } - } - } catch (IllegalAccessException | InvocationTargetException ex) { - throw rethrowUnchecked(ex); - } - } finally { - launcherPath.toFile().setWritable(false, true); - } - } - - static final WinIconVerifier instance = new WinIconVerifier(); - - private final Class executableRebranderClass; - private final Method lockResource; - private final Method unlockResource; - private final Method iconSwap; - } - private String launcherName; private Path expectedIcon; private boolean expectedDefault; From ca8f71c8c08ba4b6f60bee8906453993c858f540 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 26 Feb 2025 16:36:57 -0500 Subject: [PATCH 0345/1101] Remove trailing whitespace --- .../share/classes/jdk/jpackage/internal/PackageBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index d86690f86d184..02b2408bc0c25 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -93,7 +93,7 @@ PackageBuilder name(String v) { name = v; return this; } - + Optional name() { return Optional.ofNullable(name); } @@ -102,7 +102,7 @@ PackageBuilder fileName(Path v) { fileName = v; return this; } - + Optional fileName() { return Optional.ofNullable(fileName); } From a3cdac4b641d88cbd7a83713c1f367ae99ddddf3 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 26 Feb 2025 21:40:15 -0500 Subject: [PATCH 0346/1101] Move MacHelper.PListWrapper into PListReader and add unit tests --- .../internal/AppImageInfoPListFile.java | 36 +-- .../internal/MacPackagingPipeline.java | 12 +- .../{PListUtils.java => PListWriter.java} | 2 +- .../jpackage/internal/util/PListReader.java | 100 +++++++ .../helpers/jdk/jpackage/test/MacHelper.java | 86 +----- .../internal/util/PListReaderTest.java | 265 ++++++++++++++++++ .../macosx/MacFileAssociationsTest.java | 10 +- 7 files changed, 395 insertions(+), 116 deletions(-) rename src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/util/{PListUtils.java => PListWriter.java} (99%) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java create mode 100644 test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageInfoPListFile.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageInfoPListFile.java index 3468a7ea1740d..4787d1297bb62 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageInfoPListFile.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageInfoPListFile.java @@ -29,16 +29,9 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; - -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -import org.w3c.dom.Document; -import org.xml.sax.SAXException; - import jdk.jpackage.internal.model.DottedVersion; +import jdk.jpackage.internal.util.PListReader; +import org.xml.sax.SAXException; /** * Mandatory elements of Info.plist file of app image. @@ -56,30 +49,19 @@ static final class InvalidPlistFileException extends Exception { static AppImageInfoPListFile loadFromInfoPList(Path infoPListFile) throws IOException, InvalidPlistFileException, SAXException { - final var doc = initDocumentBuilder().parse(Files.newInputStream(infoPListFile)); - XPath xPath = XPathFactory.newInstance().newXPath(); + final var plistReader = new PListReader(initDocumentBuilder().parse(Files.newInputStream(infoPListFile))); try { return new AppImageInfoPListFile( - getStringValue(doc, xPath, "CFBundleIdentifier"), - getStringValue(doc, xPath, "CFBundleName"), - getStringValue(doc, xPath, "NSHumanReadableCopyright"), - DottedVersion.greedy(getStringValue(doc, xPath, "CFBundleShortVersionString")), - DottedVersion.greedy(getStringValue(doc, xPath, "CFBundleVersion")), - getStringValue(doc, xPath, "LSApplicationCategoryType")); - } catch (XPathExpressionException ex) { - // This should never happen as XPath expressions should be correct - throw new RuntimeException(ex); + plistReader.queryValue("CFBundleIdentifier"), + plistReader.queryValue("CFBundleName"), + plistReader.queryValue("NSHumanReadableCopyright"), + DottedVersion.greedy(plistReader.queryValue("CFBundleShortVersionString")), + DottedVersion.greedy(plistReader.queryValue("CFBundleVersion")), + plistReader.queryValue("LSApplicationCategoryType")); } catch (Exception ex) { throw new InvalidPlistFileException(ex); } } - - private static String getStringValue(Document doc, XPath xPath, String elementName) throws XPathExpressionException { - // Query for the value of element preceding - // element with value equal to the value of `elementName` - return (String) xPath.evaluate(String.format("//string[preceding-sibling::key = \"%s\"][1]", elementName), - doc, XPathConstants.STRING); - } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index 6336d4d694ad1..370a66e9271f8 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -24,12 +24,12 @@ */ package jdk.jpackage.internal; -import static jdk.jpackage.internal.util.PListUtils.writeArray; -import static jdk.jpackage.internal.util.PListUtils.writeBoolean; -import static jdk.jpackage.internal.util.PListUtils.writeDict; -import static jdk.jpackage.internal.util.PListUtils.writeKey; -import static jdk.jpackage.internal.util.PListUtils.writeString; -import static jdk.jpackage.internal.util.PListUtils.writeStringArray; +import static jdk.jpackage.internal.util.PListWriter.writeArray; +import static jdk.jpackage.internal.util.PListWriter.writeBoolean; +import static jdk.jpackage.internal.util.PListWriter.writeDict; +import static jdk.jpackage.internal.util.PListWriter.writeKey; +import static jdk.jpackage.internal.util.PListWriter.writeString; +import static jdk.jpackage.internal.util.PListWriter.writeStringArray; import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; import static jdk.jpackage.internal.util.function.ThrowingBiConsumer.toBiConsumer; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/util/PListUtils.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/util/PListWriter.java similarity index 99% rename from src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/util/PListUtils.java rename to src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/util/PListWriter.java index c41e7d31f3559..603e6bd52d78e 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/util/PListUtils.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/util/PListWriter.java @@ -31,7 +31,7 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -public final class PListUtils { +public final class PListWriter { public static void writeBoolean(XMLStreamWriter xml, String key, boolean value) throws XMLStreamException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java new file mode 100644 index 0000000000000..211a55897d0c2 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Optional; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; +import jdk.jpackage.internal.util.function.ThrowingSupplier; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + +public final class PListReader { + + public String queryValue(String keyName) { + final var node = getNode(keyName); + switch (node.getNodeName()) { + case "string" -> { + return node.getTextContent(); + } + default -> { + throw new NoSuchElementException(); + } + } + } + + public boolean queryBoolValue(String keyName) { + final var node = getNode(keyName); + switch (node.getNodeName()) { + case "true" -> { + return true; + } + case "false" -> { + return false; + } + default -> { + throw new NoSuchElementException(); + } + } + } + + public List queryArrayValue(String keyName) { + final var node = getNode(keyName); + switch (node.getNodeName()) { + case "array" -> { + return XmlUtils.toStream(node.getChildNodes()).filter(n -> { + return n.getNodeName().equals("string"); + }).map(Node::getTextContent).toList(); + } + default -> { + throw new NoSuchElementException(); + } + } + } + + public PListReader(Node doc) { + this.root = Objects.requireNonNull(doc); + } + + public PListReader(byte[] xmlData) throws ParserConfigurationException, SAXException, IOException { + this(XmlUtils.initDocumentBuilder().parse(new ByteArrayInputStream(xmlData))); + } + + private Node getNode(String keyName) { + final var xPath = XPathFactory.newInstance().newXPath(); + final var query = String.format("//*[preceding-sibling::key = \"%s\"][1]", keyName); + return Optional.ofNullable(ThrowingSupplier.toSupplier(() -> { + return (Node) xPath.evaluate(query, root, XPathConstants.NODE); + }).get()).orElseThrow(NoSuchElementException::new); + } + + private final Node root; +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index 72706129213e2..557c8c52d8d54 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -31,26 +31,21 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; import jdk.jpackage.internal.RetryExecutor; +import jdk.jpackage.internal.util.PListReader; import jdk.jpackage.internal.util.PathUtils; +import jdk.jpackage.internal.util.XmlUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.internal.util.function.ThrowingSupplier; import jdk.jpackage.test.PackageTest.PackageHandlers; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; public final class MacHelper { @@ -128,25 +123,25 @@ public static void withExplodedDmg(JPackageCommand cmd, } } - public static PListWrapper readPListFromAppImage(Path appImage) { + public static PListReader readPListFromAppImage(Path appImage) { return readPList(appImage.resolve("Contents/Info.plist")); } - public static PListWrapper readPList(Path path) { + public static PListReader readPList(Path path) { TKit.assertReadableFileExists(path); return ThrowingSupplier.toSupplier(() -> readPList(Files.readAllLines( path))).get(); } - public static PListWrapper readPList(List lines) { + public static PListReader readPList(List lines) { return readPList(lines.stream()); } - public static PListWrapper readPList(Stream lines) { - return ThrowingSupplier.toSupplier(() -> new PListWrapper(lines + public static PListReader readPList(Stream lines) { + return ThrowingSupplier.toSupplier(() -> new PListReader(lines // Skip leading lines before xml declaration .dropWhile(Pattern.compile("\\s?<\\?xml\\b.+\\?>").asPredicate().negate()) - .collect(Collectors.joining()))).get(); + .collect(Collectors.joining()).getBytes(StandardCharsets.UTF_8))).get(); } static PackageHandlers createDmgPackageHandlers() { @@ -217,7 +212,7 @@ static PackageHandlers createPkgPackageHandlers() { }).forEach(ThrowingConsumer.toConsumer(pkgDir -> { // Installation root of the package is stored in // /pkg-info@install-location attribute in $pkgDir/PackageInfo xml file - var doc = createDocumentBuilder().parse( + var doc = XmlUtils.initDocumentBuilder().parse( new ByteArrayInputStream(Files.readAllBytes( pkgDir.resolve("PackageInfo")))); var xPath = XPathFactory.newInstance().newXPath(); @@ -341,69 +336,6 @@ private static String getPackageId(JPackageCommand cmd) { }); } - public static final class PListWrapper { - public String queryValue(String keyName) { - XPath xPath = XPathFactory.newInstance().newXPath(); - // Query for the value of element preceding element - // with value equal to `keyName` - String query = String.format( - "//string[preceding-sibling::key = \"%s\"][1]", keyName); - return ThrowingSupplier.toSupplier(() -> (String) xPath.evaluate( - query, doc, XPathConstants.STRING)).get(); - } - - public Boolean queryBoolValue(String keyName) { - XPath xPath = XPathFactory.newInstance().newXPath(); - // Query boolean element preceding element - // with value equal to `keyName` - String query = String.format( - "name(//*[preceding-sibling::key = \"%s\"])", keyName); - String value = ThrowingSupplier.toSupplier(() -> (String) xPath.evaluate( - query, doc, XPathConstants.STRING)).get(); - return Boolean.valueOf(value); - } - - public List queryArrayValue(String keyName) { - XPath xPath = XPathFactory.newInstance().newXPath(); - // Query string array preceding element with value equal to `keyName` - String query = String.format( - "//array[preceding-sibling::key = \"%s\"]", keyName); - NodeList list = ThrowingSupplier.toSupplier(() -> (NodeList) xPath.evaluate( - query, doc, XPathConstants.NODESET)).get(); - if (list.getLength() != 1) { - throw new RuntimeException( - String.format("Unable to find element for key = \"%s\"]", - keyName)); - } - - NodeList childList = list.item(0).getChildNodes(); - List values = new ArrayList<>(childList.getLength()); - for (int i = 0; i < childList.getLength(); i++) { - if (childList.item(i).getNodeName().equals("string")) { - values.add(childList.item(i).getTextContent()); - } - } - return values; - } - - private PListWrapper(String xml) throws ParserConfigurationException, - SAXException, IOException { - doc = createDocumentBuilder().parse(new ByteArrayInputStream( - xml.getBytes(StandardCharsets.UTF_8))); - } - - private final org.w3c.dom.Document doc; - } - - private static DocumentBuilder createDocumentBuilder() throws - ParserConfigurationException { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); - dbf.setFeature( - "http://apache.org/xml/features/nonvalidating/load-external-dtd", - false); - return dbf.newDocumentBuilder(); - } - private static String getServicePListFileName(String packageName, String launcherName) { try { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java new file mode 100644 index 0000000000000..bae4921fda33c --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.io.StringReader; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Optional; +import java.util.function.BiFunction; +import javax.xml.parsers.ParserConfigurationException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.MethodSource; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + + +public class PListReaderTest { + + enum QueryType { + STRING(PListReader::queryValue), + BOOLEAN(PListReader::queryBoolValue), + STRING_ARRY(PListReader::queryArrayValue); + + QueryType(BiFunction queryMethod) { + this.queryMethod = Objects.requireNonNull(queryMethod); + } + + @SuppressWarnings("unchecked") + T queryValue(PListReader pListReader, String keyName) { + return (T)queryMethod.apply(pListReader, keyName); + } + + private final BiFunction queryMethod; + } + + public record QueryValueTestSpec(QueryType queryType, String keyName, Optional expectedValue, + Optional> expectedException, String... xml) { + + public QueryValueTestSpec { + Objects.requireNonNull(queryType); + Objects.requireNonNull(keyName); + Objects.requireNonNull(expectedValue); + Objects.requireNonNull(expectedException); + Objects.requireNonNull(xml); + if (expectedValue.isEmpty() == expectedException.isEmpty()) { + throw new IllegalArgumentException(); + } + } + + static final class Builder { + + Builder queryType(QueryType v) { + queryType = v; + return this; + } + + Builder keyName(String v) { + keyName = v; + return this; + } + + Builder expectedValue(Object v) { + expectedValue = v; + if (v instanceof String) { + queryType(QueryType.STRING); + } else if (v instanceof Boolean) { + queryType(QueryType.BOOLEAN); + } else if (v instanceof List) { + queryType(QueryType.STRING_ARRY); + } + return this; + } + + Builder expectedException(Class v) { + expectedException = v; + return this; + } + + Builder xml(String... v) { + xml = v; + return this; + } + + QueryValueTestSpec create() { + return new QueryValueTestSpec(queryType, keyName, Optional.ofNullable(expectedValue), + validatedExpectedException(), xml); + } + + private Optional> validatedExpectedException() { + if (expectedValue == null && expectedException == null) { + return Optional.of(NoSuchElementException.class); + } else { + return Optional.ofNullable(expectedException); + } + } + + private QueryType queryType = QueryType.STRING; + private String keyName = "foo"; + private Object expectedValue; + private Class expectedException; + private String[] xml = new String[0]; + } + + void test() { + final var plistReader = new PListReader(createXml(xml)); + + expectedValue.ifPresent(v -> { + final var actualValue = queryType.queryValue(plistReader, keyName); + assertEquals(v, actualValue); + }); + + expectedException.ifPresent(v -> { + assertThrows(v, () -> queryType.queryValue(plistReader, keyName)); + }); + } + + @Override + public String toString() { + final var sb = new StringBuilder(); + sb.append(queryType); + sb.append("; key=").append(keyName); + expectedValue.ifPresent(v -> { + sb.append("; expected="); + sb.append(v); + }); + expectedException.ifPresent(v -> { + sb.append("; throws="); + sb.append(v); + }); + sb.append("; xml="); + sb.append(String.join("", xml)); + return sb.toString(); + } + } + + @ParameterizedTest + @EnumSource(QueryType.class) + public void testNoSuchElement(QueryType queryType) { + testSpec(queryType).create().test(); + } + + @ParameterizedTest + @EnumSource(QueryType.class) + public void testWrongValueType(QueryType queryType) { + final var builder = testSpec(queryType).xml( + "string-key", + "a", + "boolean-true-key", + "", + "boolean-false-key", + "", + "array-key", + "b"); + + List testSpecs = new ArrayList<>(); + + switch (queryType) { + case STRING -> { + testSpecs.add(builder.keyName("boolean-true-key").create()); + testSpecs.add(builder.keyName("boolean-false-key").create()); + testSpecs.add(builder.keyName("array-key").create()); + } + case BOOLEAN -> { + testSpecs.add(builder.keyName("string-key").create()); + testSpecs.add(builder.keyName("array-key").create()); + } + case STRING_ARRY -> { + testSpecs.add(builder.keyName("string-key").create()); + testSpecs.add(builder.keyName("boolean-true-key").create()); + testSpecs.add(builder.keyName("boolean-false-key").create()); + } + } + + testSpecs.forEach(QueryValueTestSpec::test); + } + + @ParameterizedTest + @MethodSource + public void testQueryValue(QueryValueTestSpec testSpec) { + testSpec.test(); + } + + @Test + public void testByteArrayCtor() throws ParserConfigurationException, SAXException, IOException { + final var plistReader = new PListReader(xmlToString("fooA").getBytes(StandardCharsets.UTF_8)); + final var actualValue = plistReader.queryValue("foo"); + assertEquals("A", actualValue); + } + + private static List testQueryValue() { + return List.of( + testSpec().expectedValue("A").xml("fooA").create(), + testSpec().expectedValue("").xml("foo").create(), + testSpec().xml("foo").create(), + testSpec().expectedValue(Boolean.TRUE).xml("foo").create(), + testSpec().expectedValue(Boolean.FALSE).xml("foo").create(), + testSpec(QueryType.BOOLEAN).xml("foo").create(), + testSpec(QueryType.BOOLEAN).xml("foo").create(), + testSpec().expectedValue(List.of("foo", "bar")).xml("foofoobar").create(), + testSpec().expectedValue(List.of()).xml("foo").create(), + testSpec(QueryType.STRING_ARRY).xml("foo").create(), + testSpec().expectedValue("A").xml("fooAB").create(), + testSpec().expectedValue("A").xml("fooAfooB").create() + ); + } + + private static QueryValueTestSpec.Builder testSpec() { + return new QueryValueTestSpec.Builder(); + } + + private static QueryValueTestSpec.Builder testSpec(QueryType queryType) { + return testSpec().queryType(queryType); + } + + private static String xmlToString(String ...xml) { + final List content = new ArrayList<>(); + content.add(""); + content.add(""); + content.addAll(List.of(xml)); + content.add(""); + return String.join("", content.toArray(String[]::new)); + } + + private static Node createXml(String ...xml) { + try { + return XmlUtils.initDocumentBuilder().parse(new InputSource(new StringReader(xmlToString(xml)))); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } catch (SAXException ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java b/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java index 01c9e48b5fde4..016f6bded86e5 100644 --- a/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java +++ b/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java @@ -28,7 +28,7 @@ import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.TKit; import jdk.jpackage.test.MacHelper; -import jdk.jpackage.test.MacHelper.PListWrapper; +import jdk.jpackage.internal.util.PListReader; import jdk.jpackage.test.Annotations.Test; /** @@ -74,19 +74,19 @@ public static void test() throws Exception { verifyPList(appImage); } - private static void checkStringValue(PListWrapper plist, String key, String value) { + private static void checkStringValue(PListReader plist, String key, String value) { String result = plist.queryValue(key); TKit.assertEquals(value, result, String.format( "Check value of %s plist key", key)); } - private static void checkBoolValue(PListWrapper plist, String key, Boolean value) { + private static void checkBoolValue(PListReader plist, String key, Boolean value) { Boolean result = plist.queryBoolValue(key); TKit.assertEquals(value.toString(), result.toString(), String.format( "Check value of %s plist key", key)); } - private static void checkArrayValue(PListWrapper plist, String key, + private static void checkArrayValue(PListReader plist, String key, List values) { List result = plist.queryArrayValue(key); TKit.assertStringListEquals(values, result, String.format( @@ -94,7 +94,7 @@ private static void checkArrayValue(PListWrapper plist, String key, } private static void verifyPList(Path appImage) throws Exception { - PListWrapper plist = MacHelper.readPListFromAppImage(appImage); + var plist = MacHelper.readPListFromAppImage(appImage); checkStringValue(plist, "CFBundleTypeRole", "Viewer"); checkStringValue(plist, "LSHandlerRank", "Default"); checkStringValue(plist, "NSDocumentClass", "SomeClass"); From f5038745ba0c6e99bf9c951882dc05fb49d68349 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 26 Feb 2025 21:45:15 -0500 Subject: [PATCH 0347/1101] Fix bad merge --- .../jdk/jpackage/internal/WinExeBundler.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java index 08ccd46e00363..54f43f0571517 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,18 +24,17 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.WinExePackage; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.PackagerException; +import static jdk.jpackage.internal.StandardBundlerParam.ICON; +import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; + import java.io.IOException; -import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.Map; -import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; -import static jdk.jpackage.internal.StandardBundlerParam.ICON; -import jdk.jpackage.internal.resources.ResourceLocator; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.WinExePackage; @SuppressWarnings("restricted") public class WinExeBundler extends AbstractBundler { @@ -114,9 +113,11 @@ private Path buildEXE(BuildEnv env, WinExePackage pkg, Path msi, // Copy template msi wrapper next to msi file final Path exePath = msi.getParent().resolve(pkg.packageFileNameWithSuffix()); - try (InputStream is = ResourceLocator.class.getResourceAsStream("msiwrapper.exe")) { - Files.copy(is, exePath); - } + + env.createResource("msiwrapper.exe") + .setCategory(I18N.getString("resource.installer-exe")) + .setPublicName("installer.exe") + .saveToFile(exePath); new ExecutableRebrander(pkg, env::createResource, resourceLock -> { // Embed msi in msi wrapper exe. From cf25e97d4d6ecad951345f0249faca5cba68bbf6 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 6 Mar 2025 21:49:46 -0500 Subject: [PATCH 0348/1101] Fix bad merge --- .../jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java | 2 +- .../tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index ca2dab634d27e..1e5a271dd25c6 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -31,7 +31,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Set; @@ -41,6 +40,7 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; import jdk.jpackage.internal.RetryExecutor; +import jdk.jpackage.internal.util.PListReader; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.XmlUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index a907516e7ed57..e7b3f3e3a440b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -44,6 +44,7 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; From 2f75269a876bc9f503e050caec331aad548d0c34 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Mar 2025 00:19:39 -0400 Subject: [PATCH 0349/1101] Fix bad merge --- .../jdk/jpackage/internal/MacBaseInstallerBundler.java | 1 + .../classes/jdk/jpackage/internal/StandardBundlerParam.java | 4 ++-- .../tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java | 3 ++- .../jdk/jpackage/internal/model/DottedVersionTest.java | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index 3e2471538db4c..ac2b37870c808 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -60,6 +60,7 @@ public MacBaseInstallerBundler() { protected void validateAppImageAndBundeler( Map params) throws ConfigException { if (PREDEFINED_APP_IMAGE.fetchFrom(params) != null) { + Path applicationImage = PREDEFINED_APP_IMAGE.fetchFrom(params); if (new MacAppImageFileExtras(PREDEFINED_APP_IMAGE_FILE.fetchFrom(params)).signed()) { var appLayout = ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT.resolveAt(applicationImage); if (!Files.exists( diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index 86878be742adf..ac12bd10a416b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -261,8 +261,8 @@ final class StandardBundlerParam { (s, p) -> s ); - public static final StandardBundlerParam LICENSE_FILE = - new StandardBundlerParam<>( + public static final BundlerParamInfo LICENSE_FILE = + new BundlerParamInfo<>( Arguments.CLIOptions.LICENSE_FILE.getId(), String.class, params -> null, diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index d7b2a3a2887a3..da215672027aa 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -336,10 +336,11 @@ private static String getPackageId(JPackageCommand cmd) { return JavaAppDesc.parse(className).packageName(); }); }); + } + public static boolean isXcodeDevToolsInstalled() { return Inner.XCODE_DEV_TOOLS_INSTALLED; } - } private static String getServicePListFileName(String packageName, String launcherName) { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java index 1e56d2bfae0c5..885ea31f72655 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java @@ -132,7 +132,7 @@ void run() { expectedErrorMsg = MessageFormat.format(I18N.getString("error.version-string-invalid-component"), version, invalidComponent); } - final var ex = assertThrowsExactly(IllegalArgumentException.class, () -> new DottedVersion(version)); + final var ex = assertThrowsExactly(IllegalArgumentException.class, () -> DottedVersion.greedy(version)); assertEquals(expectedErrorMsg, ex.getMessage()); } From 03962e3afd3dc832ea8b78203b0c239e7bcfc4a7 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Mar 2025 01:16:18 -0400 Subject: [PATCH 0350/1101] Bugfix --- .../share/classes/jdk/jpackage/internal/AppImageFile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index 806a9d7360669..aa4a866e14b68 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -219,7 +219,7 @@ static AppImageFile load(Path appImageDir, ApplicationLayout appLayout) throws C throw I18N.buildConfigException("error.foreign-app-image", appImageDir).create(); } catch (InvalidAppImageFileException ex) { // Invalid input XML - throw I18N.buildConfigException("error.invalid-app-image", appImageDir, FILENAME).create(); + throw I18N.buildConfigException("error.invalid-app-image", appImageDir, srcFilePath).create(); } } From e77f8d3cd75eaff783334b053b96b8c447f002d4 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Mar 2025 12:47:55 -0400 Subject: [PATCH 0351/1101] Fix ErrorTest `--app-version` tests failed on Windows --- .../internal/WinMsiPackageBuilder.java | 1 + .../internal/model/WinApplication.java | 8 ++--- .../internal/model/WinApplicationMixin.java | 36 +++++++++++++++++++ .../internal/model/WinMsiPackage.java | 4 --- .../internal/model/WinMsiPackageMixin.java | 4 ++- 5 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplicationMixin.java diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java index 737bf97f2d607..69402b47b9320 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java @@ -64,6 +64,7 @@ WinMsiPackage create() throws ConfigException { } return WinMsiPackage.create(pkg, new WinMsiPackageMixin.Stub( + MsiVersion.of(pkg.version()), withInstallDirChooser, withShortcutPrompt, Optional.ofNullable(helpURL), diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java index 83c1179f37955..75cfe7787e084 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java @@ -26,13 +26,9 @@ import jdk.jpackage.internal.util.CompositeProxy; -public interface WinApplication extends Application { - - default DottedVersion winVersion() { - return DottedVersion.lazy(version()); - } +public interface WinApplication extends Application, WinApplicationMixin { public static WinApplication create(Application app) { - return CompositeProxy.create(WinApplication.class, app); + return CompositeProxy.create(WinApplication.class, app, new WinApplicationMixin.Stub(app)); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplicationMixin.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplicationMixin.java new file mode 100644 index 0000000000000..6da5d85622149 --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplicationMixin.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +public interface WinApplicationMixin { + + DottedVersion winVersion(); + + record Stub(DottedVersion winVersion) implements WinApplicationMixin { + public Stub(Application app) { + this(DottedVersion.greedy(app.version())); + } + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java index fdeb744c1c9fe..f9b12b4cd976d 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java @@ -28,10 +28,6 @@ public interface WinMsiPackage extends Package, WinMsiPackageMixin { - default DottedVersion msiVersion() { - return MsiVersion.of(version()); - } - public static WinMsiPackage create(Package pkg, WinMsiPackageMixin mixin) { return CompositeProxy.create(WinMsiPackage.class, pkg, mixin); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java index 48b2677fd7ea9..cf67d864c8d55 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java @@ -30,6 +30,8 @@ public interface WinMsiPackageMixin { + DottedVersion msiVersion(); + boolean withInstallDirChooser(); boolean withShortcutPrompt(); @@ -48,7 +50,7 @@ public interface WinMsiPackageMixin { Optional serviceInstaller(); - record Stub(boolean withInstallDirChooser, boolean withShortcutPrompt, + record Stub(DottedVersion msiVersion, boolean withInstallDirChooser, boolean withShortcutPrompt, Optional helpURL, Optional updateURL, String startMenuGroupName, boolean isSystemWideInstall, UUID upgradeCode, UUID productCode, Optional serviceInstaller) implements WinMsiPackageMixin {} From c9ef92748a9f8a0053385c8bf4822316bb871971 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Mar 2025 19:19:35 -0400 Subject: [PATCH 0352/1101] WIP commit --- .../jdk/jpackage/internal/CodesignConfig.java | 46 +-- .../jdk/jpackage/internal/Keychain.java | 105 +++++++ .../jpackage/internal/MacAppImageBuilder.java | 287 ------------------ .../internal/MacCertificateUtils.java | 54 +++- .../jdk/jpackage/internal/MacDmgPackager.java | 2 +- .../jdk/jpackage/internal/MacFromParams.java | 14 +- .../internal/MacPackagingPipeline.java | 4 +- .../jdk/jpackage/internal/MacPkgBundler.java | 6 +- .../jdk/jpackage/internal/MacPkgPackager.java | 6 +- .../internal/SigningConfigBuilder.java | 228 +++++++++----- ...fierImpl.java => SigningIdentityImpl.java} | 18 +- .../jdk/jpackage/internal/TempKeychain.java | 45 +-- .../internal/model/MacPkgPackage.java | 2 +- .../internal/model/SigningConfig.java | 8 +- ...ngIdentifier.java => SigningIdentity.java} | 4 +- .../internal/util/CollectionUtils.java | 17 +- 16 files changed, 385 insertions(+), 461 deletions(-) create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Keychain.java rename src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/{SigningIdentifierImpl.java => SigningIdentityImpl.java} (79%) rename src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/{SigningIdentifier.java => SigningIdentity.java} (95%) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java index 7717fca2f7d72..f03f408f1ddcc 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java @@ -28,13 +28,13 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; -import jdk.jpackage.internal.model.SigningIdentifier; import jdk.jpackage.internal.model.SigningConfig; +import jdk.jpackage.internal.model.SigningIdentity; import jdk.jpackage.internal.util.PathUtils; -record CodesignConfig(Optional identifier, - Optional entitlements, Optional keyChain) { +record CodesignConfig(Optional identity, + Optional entitlements, Optional keychain) { static final class Builder { @@ -42,8 +42,8 @@ private Builder() { } CodesignConfig create() { - return new CodesignConfig(Optional.ofNullable(identifier), - Optional.ofNullable(entitlements), Optional.ofNullable(keyChain)); + return new CodesignConfig(Optional.ofNullable(identity), + Optional.ofNullable(entitlements), Optional.ofNullable(keychain)); } Builder entitlements(Path v) { @@ -51,31 +51,35 @@ Builder entitlements(Path v) { return this; } - Builder identifier(SigningIdentifier v) { - identifier = v; + Builder identity(SigningIdentity v) { + identity = v; return this; } - Builder keyChain(Path v) { - keyChain = v; + Builder keychain(String v) { + return keychain(new Keychain(v)); + } + + Builder keychain(Keychain v) { + keychain = v; return this; } Builder from(SigningConfig v) { - return identifier(v.identifier().orElse(null)) + return identity(v.identity().orElse(null)) .entitlements(v.entitlements().orElse(null)) - .keyChain(v.keyChain().orElse(null)); + .keychain(v.keychain().orElse(null)); } Builder from(CodesignConfig v) { - return identifier(v.identifier().orElse(null)) + return identity(v.identity().orElse(null)) .entitlements(v.entitlements().orElse(null)) - .keyChain(v.keyChain().orElse(null)); + .keychain(v.keychain().orElse(null)); } - private SigningIdentifier identifier; + private SigningIdentity identity; private Path entitlements; - private Path keyChain; + private Keychain keychain; } static Builder build() { @@ -83,19 +87,19 @@ static Builder build() { } List toCodesignArgs() { - List args = new ArrayList<>(List.of("-s", identifier.map(SigningIdentifier::name).orElse(ADHOC_SIGNING_IDENTIFIER), "-vvvv")); + List args = new ArrayList<>(List.of("-s", identity.map(SigningIdentity::id).orElse(ADHOC_SIGNING_IDENTITY), "-vvvv")); - if (identifier.isPresent()) { + if (identity.isPresent()) { args.addAll(List.of("--timestamp", "--options", "runtime")); - identifier.flatMap(SigningIdentifier::prefix).ifPresent(identifierPrefix -> { + identity.flatMap(SigningIdentity::prefix).ifPresent(identifierPrefix -> { args.addAll(List.of("--prefix", identifierPrefix)); }); - keyChain.map(PathUtils::normalizedAbsolutePathString).ifPresent(theKeyChain -> args.addAll(List.of("--keychain", theKeyChain))); - entitlements.map(PathUtils::normalizedAbsolutePathString).ifPresent(theEntitlements -> args.addAll(List.of("--entitlements", theEntitlements))); + keychain.map(Keychain::asCliArg).ifPresent(k -> args.addAll(List.of("--keychain", k))); + entitlements.map(PathUtils::normalizedAbsolutePathString).ifPresent(e -> args.addAll(List.of("--entitlements", e))); } return args; } - static final String ADHOC_SIGNING_IDENTIFIER = "-"; + static final String ADHOC_SIGNING_IDENTITY = "-"; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Keychain.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Keychain.java new file mode 100644 index 0000000000000..606e403f2b18d --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Keychain.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; +import jdk.jpackage.internal.util.PathUtils; + +record Keychain(String name) { + Keychain { + Objects.requireNonNull(name); + } + + Path path() { + final var path = Path.of(name); + if (path.isAbsolute()) { + return path; + } else { + final var dir = Path.of(System.getProperty("user.home")).resolve("Library/Keychains"); + final var files = filenames(name).map(dir::resolve).toList(); + return files.stream().filter(Files::exists).findFirst().orElseGet(() -> { + // Can't find keychain file in "$HOME/Library/Keychains" folder. + // Detect keychain file name from the name of the login keychain file. + return files.stream().filter(f -> { + final var loginKeycahinFile = f.getParent().resolve("login.keychain" + f.getFileName().toString().substring(name.length())); + return Files.exists(loginKeycahinFile); + }).findFirst().orElseGet(() -> { + // login keychain file doesn't exist, fallback to "$HOME/Library/Keychains/-db" keychain file. + return files.getFirst(); + }); + }); + } + } + + String asCliArg() { + final var path = Path.of(name); + if (path.isAbsolute()) { + return PathUtils.normalizedAbsolutePathString(path); + } else { + return name; + } + } + + static List listKeychains() { + // Get the current keychain list + final List cmdOutput; + try { + cmdOutput = Executor.of("/usr/bin/security", "list-keychains").saveOutput(true).executeExpectSuccess().getOutput(); + } catch (IOException ex) { + throw I18N.buildException().message("message.keychain.error").cause(ex).create(KeychainException::new); + } + + // Typical output of /usr/bin/security command is: + // "/Users/foo/Library/Keychains/login.keychain-db" + // "/Library/Keychains/System.keychain" + return cmdOutput.stream().map(String::trim).map(str -> { + // Strip enclosing double quotes + return str.substring(1, str.length() - 1); + }).map(Keychain::new).toList(); + } + + final static class KeychainException extends RuntimeException { + + KeychainException(String msg) { + super(msg); + } + + KeychainException(String msg, Throwable cause) { + super(msg, cause); + } + + private static final long serialVersionUID = 1L; + } + + private static Stream filenames(String name) { + return Stream.of(name + "-db", name); + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java index 294e4842848a9..66fac82917166 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -25,33 +25,6 @@ package jdk.jpackage.internal; -import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; -import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.PosixFilePermission; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer; -import java.util.stream.Stream; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathFactory; - public class MacAppImageBuilder { static final BundlerParamInfo APP_STORE = @@ -65,264 +38,4 @@ public class MacAppImageBuilder { (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? null : Boolean.valueOf(s) ); - - public static final BundlerParamInfo MAC_CF_BUNDLE_IDENTIFIER = - new BundlerParamInfo<>( - Arguments.CLIOptions.MAC_BUNDLE_IDENTIFIER.getId(), - String.class, - params -> { - // Get identifier from app image if user provided - // app image and did not provide the identifier via CLI. - String identifier = extractBundleIdentifier(params); - if (identifier == null) { - identifier = MacAppBundler.getIdentifier(params); - } - if (identifier == null) { - identifier = APP_NAME.fetchFrom(params); - } - return identifier; - }, - (s, p) -> s); - - private static List getCodesignArgs( - boolean force, Path path, String signingIdentity, - String identifierPrefix, Path entitlements, String keyChain) { - List args = new ArrayList<>(); - args.addAll(Arrays.asList("/usr/bin/codesign", - "-s", signingIdentity, - "-vvvv")); - - if (!signingIdentity.equals("-")) { - args.addAll(Arrays.asList("--timestamp", - "--options", "runtime", - "--prefix", identifierPrefix)); - if (keyChain != null && !keyChain.isEmpty()) { - args.add("--keychain"); - args.add(keyChain); - } - if (Files.isExecutable(path)) { - if (entitlements != null) { - args.add("--entitlements"); - args.add(entitlements.toString()); - } - } - } - - if (force) { - args.add("--force"); - } - - args.add(path.toString()); - - return args; - } - - private static void runCodesign( - ProcessBuilder pb, boolean quiet, Map params) - throws IOException { - try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos)) { - try { - IOUtils.exec(pb, false, ps, false, - Executor.INFINITE_TIMEOUT, quiet); - } catch (IOException ioe) { - // Log output of "codesign" in case of error. It should help - // user to diagnose issues when using --mac-app-image-sign-identity. - // In addition add possible reason for failure. For example - // "--app-content" can fail "codesign". - - // APP_CONTENT is never null. - if (!APP_CONTENT.fetchFrom(params).isEmpty()) { - Log.info(I18N.getString( - "message.codesign.failed.reason.app.content")); - } - - // Signing might not work without Xcode with command line - // developer tools. Show user if Xcode is missing as possible - // reason. - if (!isXcodeDevToolsInstalled()) { - Log.info(I18N.getString( - "message.codesign.failed.reason.xcode.tools")); - } - - // Log "codesign" output - Log.info(MessageFormat.format(I18N.getString( - "error.tool.failed.with.output"), "codesign")); - Log.info(baos.toString().strip()); - - throw ioe; - } - } - } - - private static boolean isXcodeDevToolsInstalled() { - try { - Executor.of("/usr/bin/xcrun", "--help").executeExpectSuccess(); - } catch (IOException e) { - return false; - } - - return true; - } - - static void signAppBundle( - Map params, Path appLocation, - String signingIdentity, String identifierPrefix, Path entitlements) - throws IOException { - AtomicReference toThrow = new AtomicReference<>(); - String appExecutable = "/Contents/MacOS/" + APP_NAME.fetchFrom(params); - String keyChain = SIGNING_KEYCHAIN.fetchFrom(params); - - // sign all dylibs and executables - try (Stream stream = Files.walk(appLocation)) { - stream.peek(path -> { // fix permissions - try { - Set pfp - = Files.getPosixFilePermissions(path); - if (!pfp.contains(PosixFilePermission.OWNER_WRITE)) { - pfp = EnumSet.copyOf(pfp); - pfp.add(PosixFilePermission.OWNER_WRITE); - Files.setPosixFilePermissions(path, pfp); - } - } catch (IOException e) { - Log.verbose(e); - } - }).filter(p -> Files.isRegularFile(p) - && (Files.isExecutable(p) || p.toString().endsWith(".dylib")) - && !(p.toString().contains("dylib.dSYM/Contents")) - && !(p.toString().endsWith(appExecutable)) - ).forEach(p -> { - // noinspection ThrowableResultOfMethodCallIgnored - if (toThrow.get() != null) { - return; - } - - // If p is a symlink then skip the signing process. - if (Files.isSymbolicLink(p)) { - Log.verbose(MessageFormat.format(I18N.getString( - "message.ignoring.symlink"), p.toString())); - } else { - // unsign everything before signing - List args = new ArrayList<>(); - args.addAll(Arrays.asList("/usr/bin/codesign", - "--remove-signature", p.toString())); - try { - Set oldPermissions = - Files.getPosixFilePermissions(p); - p.toFile().setWritable(true, true); - ProcessBuilder pb = new ProcessBuilder(args); - // run quietly - IOUtils.exec(pb, false, null, false, - Executor.INFINITE_TIMEOUT, true); - Files.setPosixFilePermissions(p, oldPermissions); - } catch (IOException ioe) { - Log.verbose(ioe); - toThrow.set(ioe); - return; - } - - // Sign only if we have identity - if (signingIdentity != null) { - args = getCodesignArgs(false, p, signingIdentity, - identifierPrefix, entitlements, keyChain); - try { - Set oldPermissions - = Files.getPosixFilePermissions(p); - p.toFile().setWritable(true, true); - ProcessBuilder pb = new ProcessBuilder(args); - // run quietly - runCodesign(pb, true, params); - Files.setPosixFilePermissions(p, oldPermissions); - } catch (IOException ioe) { - toThrow.set(ioe); - } - } - } - }); - } - IOException ioe = toThrow.get(); - if (ioe != null) { - throw ioe; - } - - // We cannot continue signing without identity - if (signingIdentity == null) { - return; - } - - // sign all runtime and frameworks - Consumer signIdentifiedByPList = path -> { - //noinspection ThrowableResultOfMethodCallIgnored - if (toThrow.get() != null) return; - - try { - List args = getCodesignArgs(true, path, signingIdentity, - identifierPrefix, entitlements, keyChain); - ProcessBuilder pb = new ProcessBuilder(args); - runCodesign(pb, false, params); - } catch (IOException e) { - toThrow.set(e); - } - }; - - Path javaPath = appLocation.resolve("Contents/runtime"); - if (Files.isDirectory(javaPath)) { - signIdentifiedByPList.accept(javaPath); - - ioe = toThrow.get(); - if (ioe != null) { - throw ioe; - } - } - Path frameworkPath = appLocation.resolve("Contents/Frameworks"); - if (Files.isDirectory(frameworkPath)) { - try (var fileList = Files.list(frameworkPath)) { - fileList.forEach(signIdentifiedByPList); - } - - ioe = toThrow.get(); - if (ioe != null) { - throw ioe; - } - } - - // sign the app itself - List args = getCodesignArgs(true, appLocation, signingIdentity, - identifierPrefix, entitlements, keyChain); - ProcessBuilder pb = new ProcessBuilder(args); - runCodesign(pb, false, params); - } - - private static String extractBundleIdentifier(Map params) { - if (PREDEFINED_APP_IMAGE.fetchFrom(params) == null) { - return null; - } - - try { - Path infoPList = PREDEFINED_APP_IMAGE.fetchFrom(params).resolve("Contents"). - resolve("Info.plist"); - - DocumentBuilderFactory dbf - = DocumentBuilderFactory.newDefaultInstance(); - dbf.setFeature("http://apache.org/xml/features/" + - "nonvalidating/load-external-dtd", false); - DocumentBuilder b = dbf.newDocumentBuilder(); - org.w3c.dom.Document doc = b.parse(Files.newInputStream(infoPList)); - - XPath xPath = XPathFactory.newInstance().newXPath(); - // Query for the value of element preceding - // element with value equal to CFBundleIdentifier - String v = (String) xPath.evaluate( - "//string[preceding-sibling::key = \"CFBundleIdentifier\"][1]", - doc, XPathConstants.STRING); - - if (v != null && !v.isEmpty()) { - return v; - } - } catch (Exception ex) { - Log.verbose(ex); - } - - return null; - } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java index 93346cd5ed5ed..81b90cafe471b 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java @@ -25,52 +25,78 @@ package jdk.jpackage.internal; +import static jdk.jpackage.internal.util.CollectionUtils.toCollectionUBW; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.security.cert.Certificate; +import java.security.MessageDigest; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; +import java.util.HexFormat; import java.util.List; +import java.util.Objects; import java.util.Optional; -import jdk.jpackage.internal.util.PathUtils; public final class MacCertificateUtils { - public static Collection findCertificates(Optional keychain, Optional certificateNameFilter) { + public static Collection findCertificates(Optional keychain, Optional certificateNameFilter) { List args = new ArrayList<>(); args.add("/usr/bin/security"); args.add("find-certificate"); args.add("-a"); certificateNameFilter.ifPresent(filter -> args.addAll(List.of("-c", filter))); args.add("-p"); // PEM format - keychain.map(PathUtils::normalizedAbsolutePathString).ifPresent(args::add); + keychain.map(Keychain::asCliArg).ifPresent(args::add); - return toSupplier(() -> { + return toCollectionUBW(toSupplier(() -> { final var output = Executor.of(args.toArray(String[]::new)) .setQuiet(true).saveOutput(true).executeExpectSuccess() .getOutput(); final byte[] pemCertificatesBuffer = output.stream() .reduce(new StringBuilder(), - StringBuilder::append, - StringBuilder::append).toString().getBytes(StandardCharsets.US_ASCII); + MacCertificateUtils::append, + MacCertificateUtils::append).toString().getBytes(StandardCharsets.US_ASCII); try (var in = new ByteArrayInputStream(pemCertificatesBuffer)) { final var cf = CertificateFactory.getInstance("X.509"); return cf.generateCertificates(in); } - }).get(); + }).get()); } - public static Collection filterX509Certificates(Collection certs) { - return certs.stream() - .filter(X509Certificate.class::isInstance) - .map(X509Certificate.class::cast) - .toList(); + record CertificateHash(byte[] value) { + CertificateHash { + Objects.requireNonNull(value); + if (value.length != 20) { + throw new IllegalArgumentException("Invalid SHA-1 hash"); + } + } + + static CertificateHash of(X509Certificate cert) { + return new CertificateHash(toSupplier(() -> { + final MessageDigest md = MessageDigest.getInstance("SHA-1"); + md.update(cert.getEncoded()); + return md.digest(); + }).get()); + } + + @Override + public String toString() { + return FORMAT.formatHex(value); + } + + static CertificateHash fromHexString(String hash) { + return new CertificateHash(FORMAT.parseHex(hash)); + } + + private static final HexFormat FORMAT = HexFormat.of().withUpperCase(); + } + + private static StringBuilder append(StringBuilder sb, Object v) { + return sb.append(v).append('\n'); } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java index 777c0460a804b..79cc86b9f66cb 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java @@ -99,7 +99,7 @@ private Path validatedHdiutil() { // Location of SetFile utility may be different depending on MacOS version // We look for several known places and if none of them work will - // try ot find it + // try to find it static Optional findSetFileUtility() { String typicalPaths[] = {"/Developer/Tools/SetFile", "/usr/bin/SetFile", "/Developer/usr/bin/SetFile"}; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java index d81b492b4bb80..cd77de289091e 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java @@ -54,7 +54,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import jdk.jpackage.internal.SigningConfigBuilder.CertificateNameFilter; +import jdk.jpackage.internal.SigningConfigBuilder.StandardCertificateSelector; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.model.Launcher; @@ -113,15 +113,15 @@ private static MacApplication createMacApplication( if (sign) { final var signingBuilder = new SigningConfigBuilder(); - app.mainLauncher().flatMap(Launcher::startupInfo).ifPresent(signingBuilder::signingIdentifierPrefix); - BUNDLE_ID_SIGNING_PREFIX.copyInto(params, signingBuilder::signingIdentifierPrefix); - SIGNING_KEYCHAIN.copyInto(params, v -> signingBuilder.keyChain(Path.of(v))); + app.mainLauncher().flatMap(Launcher::startupInfo).ifPresent(signingBuilder::signingIdentityPrefix); + BUNDLE_ID_SIGNING_PREFIX.copyInto(params, signingBuilder::signingIdentityPrefix); + SIGNING_KEYCHAIN.copyInto(params, signingBuilder::keychain); ENTITLEMENTS.copyInto(params, signingBuilder::entitlements); - APP_IMAGE_SIGN_IDENTITY.copyInto(params, signingBuilder::signingIdentifier); + APP_IMAGE_SIGN_IDENTITY.copyInto(params, signingBuilder::signingIdentity); - final var certificateNameFilter = appStore ? CertificateNameFilter.APP_STORE_APP_IMAGE : CertificateNameFilter.APP_IMAGE; + final var filter = appStore ? StandardCertificateSelector.APP_STORE_APP_IMAGE : StandardCertificateSelector.APP_IMAGE; - signingBuilder.addCertificateNameFilters(certificateNameFilter.getFilters(SIGNING_KEY_USER.findIn(params))); + signingBuilder.addCertificateSelectors(StandardCertificateSelector.create(SIGNING_KEY_USER.findIn(params), filter)); appBuilder.signingBuilder(signingBuilder); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index 370a66e9271f8..03b6768b2c74e 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -263,8 +263,8 @@ private static void sign(AppImageBuildEnv AppImageSigner.createSigner(app, codesignConfigBuilder.create()).accept(appImageDir); }; - app.signingConfig().flatMap(SigningConfig::keyChain).ifPresentOrElse(keyChain -> { - toBiConsumer(TempKeychain::withKeychain).accept(keyChain, unused -> signAction.run()); + app.signingConfig().flatMap(SigningConfig::keychain).map(Keychain::new).ifPresentOrElse(keychain -> { + toBiConsumer(TempKeychain::withKeychain).accept(keychain, unused -> signAction.run()); }, signAction); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 0ff54517663b0..4769553bc1fc8 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -26,7 +26,6 @@ package jdk.jpackage.internal; import static jdk.jpackage.internal.MacAppImageBuilder.APP_STORE; -import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; import static jdk.jpackage.internal.MacApplicationBuilder.isValidBundleIdentifier; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; @@ -36,6 +35,7 @@ import java.util.Objects; import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.PackagerException; public class MacPkgBundler extends MacBaseInstallerBundler { @@ -90,13 +90,13 @@ public boolean validate(Map params) try { Objects.requireNonNull(params); - MacFromParams.PKG_PACKAGE.fetchFrom(params); + final var pkgPkg = MacFromParams.PKG_PACKAGE.fetchFrom(params); // run basic validation to ensure requirements are met // we are not interested in return code, only possible exception validateAppImageAndBundeler(params); - String identifier = MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params); + String identifier = ((MacApplication)pkgPkg.app()).bundleIdentifier(); if (identifier == null) { throw new ConfigException( I18N.getString("message.app-image-requires-identifier"), diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java index e269fe598e00a..5a7355dd38aab 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java @@ -529,11 +529,11 @@ private void productbuild() throws IOException { final var pkgSigningConfig = pkg.signingConfig().orElseThrow(); commandLine.add("--sign"); - commandLine.add(pkgSigningConfig.identifier().orElseThrow().name()); + commandLine.add(pkgSigningConfig.identity().orElseThrow().id()); - pkgSigningConfig.keyChain().ifPresent(keyChain -> { + pkgSigningConfig.keychain().map(Keychain::new).ifPresent(keychain -> { commandLine.add("--keychain"); - commandLine.add(keyChain.toString()); + commandLine.add(keychain.asCliArg()); }); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java index d00db3f74d6ba..35f4b1819ec64 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java @@ -24,8 +24,6 @@ */ package jdk.jpackage.internal; -import static java.util.stream.Collectors.toMap; -import static jdk.jpackage.internal.MacCertificateUtils.filterX509Certificates; import static jdk.jpackage.internal.MacCertificateUtils.findCertificates; import java.nio.file.Path; @@ -33,48 +31,52 @@ 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.Predicate; import java.util.stream.Stream; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; import javax.naming.ldap.Rdn; import javax.security.auth.x500.X500Principal; +import jdk.jpackage.internal.MacCertificateUtils.CertificateHash; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LauncherStartupInfo; import jdk.jpackage.internal.model.SigningConfig; -import jdk.jpackage.internal.model.SigningIdentifier; +import jdk.jpackage.internal.model.SigningIdentity; final class SigningConfigBuilder { - SigningConfigBuilder signingIdentifier(String v) { - signingIdentifier = v; + SigningConfigBuilder signingIdentity(String v) { + signingIdentity = v; return this; } - SigningConfigBuilder signingIdentifierPrefix(LauncherStartupInfo mainLauncherStartupInfo) { + SigningConfigBuilder signingIdentityPrefix(LauncherStartupInfo mainLauncherStartupInfo) { final var pkgName = mainLauncherStartupInfo.packageName(); if (!pkgName.isEmpty()) { - signingIdentifierPrefix(pkgName + "."); + signingIdentityPrefix(pkgName + "."); } return this; } - SigningConfigBuilder signingIdentifierPrefix(String v) { - signingIdentifierPrefix = v; + SigningConfigBuilder signingIdentityPrefix(String v) { + signingIdentityPrefix = v; return this; } - SigningConfigBuilder addCertificateNameFilters(String ...certificateNameFilters) { - return addCertificateNameFilters(List.of(certificateNameFilters)); + SigningConfigBuilder addCertificateSelectors(CertificateSelector ...v) { + return addCertificateSelectors(List.of(v)); } - SigningConfigBuilder addCertificateNameFilters(Collection certificateNameFilters) { - this.certificateNameFilters.addAll(certificateNameFilters); + SigningConfigBuilder addCertificateSelectors(Collection v) { + certificateSelectors.addAll(v); return this; } - SigningConfigBuilder keyChain(Path v) { - keyChain = v; + SigningConfigBuilder keychain(String v) { + keychain = v; return this; } @@ -84,99 +86,175 @@ SigningConfigBuilder entitlements(Path v) { } SigningConfig create() throws ConfigException { - return new SigningConfig.Stub(validatedSigningIdentifier(), validatedEntitlements(), - validatedKeyChain(), "sandbox.plist"); + return new SigningConfig.Stub(validatedSigningIdentity(), validatedEntitlements(), + validatedKeychain().map(Keychain::name), "sandbox.plist"); } private Optional validatedEntitlements() throws ConfigException { return Optional.ofNullable(entitlements); } - private Optional validatedKeyChain() throws ConfigException { - return Optional.ofNullable(keyChain); + private Optional validatedKeychain() throws ConfigException { + return Optional.ofNullable(keychain).map(Keychain::new); } - private Optional validatedSigningIdentifier() throws ConfigException { - if (signingIdentifier != null) { - return Optional.of(new SigningIdentifierImpl(signingIdentifier, Optional.ofNullable(signingIdentifierPrefix))); + private Optional validatedSigningIdentity() throws ConfigException { + CertificateHash signingIdentityHash = null; + if (signingIdentity != null) { + try { + signingIdentityHash = CertificateHash.fromHexString(signingIdentity); + } catch (Throwable t) { + // Not a valid certificate hash + } } - final var validatedKeyChain = validatedKeyChain(); - - final var signingIdentifierMap = certificateNameFilters.stream().collect(toMap(x -> x, certificateNameFilter -> { - return filterX509Certificates(findCertificates(validatedKeyChain, Optional.of(certificateNameFilter))).stream() - .map(SigningConfigBuilder::findSubjectCN) - .filter(Optional::isPresent) - .map(Optional::get).toList(); - })); - - for (var certificateNameFilter : certificateNameFilters) { - final var signingIdentifiers = signingIdentifierMap.get(certificateNameFilter); - switch (signingIdentifiers.size()) { - case 0 -> { - throw I18N.buildConfigException("error.explicit-sign-no-cert") - .advice("error.explicit-sign-no-cert.advice").create(); - } - case 1 -> { - return Optional.of(new SigningIdentifierImpl(signingIdentifiers.get(0), - Optional.ofNullable(signingIdentifierPrefix))); - } - default -> { - // Multiple certificates matching the same criteria found - // FIXME: warn the user? - break; - } + final var validatedKeychain = validatedKeychain(); + + final var allCertificates = findCertificates(validatedKeychain, Optional.empty()); + + if (signingIdentityHash != null) { + if (allCertificates.stream().map(CertificateHash::of).anyMatch(Predicate.isEqual(signingIdentityHash))) { + return Optional.of(new SigningIdentityImpl(signingIdentityHash.toString(), + Optional.ofNullable(signingIdentityPrefix))); + } else { + throw I18N.buildConfigException("error.cert.not.found", validatedKeychain.map(Keychain::name).orElse("")).create(); } } - throw I18N.buildConfigException("error.cert.not.found", validatedKeyChain).create(); + final var mappedCertficates = allCertificates.stream().>mapMulti((cert, acc) -> { + findSubjectCNs(cert).stream().map(cn -> { + return Map.entry(cn, cert); + }).forEach(acc::accept); + }).toList(); + + final var resolvedCertificateSelectors = certificateSelectors.stream().map(CertificateSelector::fullName).toList(); + + var matchingCertificates = mappedCertficates.stream().filter(e -> { + return resolvedCertificateSelectors.contains(e.getKey()); + }).map(Map.Entry::getValue).toList(); + + if (!matchingCertificates.isEmpty()) { + signingIdentityHash = selectSigningIdentity(matchingCertificates, certificateSelectors, validatedKeychain); + } else { + matchingCertificates = mappedCertficates.stream().filter(e -> { + return resolvedCertificateSelectors.stream().anyMatch(filter -> { + return filter.startsWith(e.getKey()); + }); + }).map(Map.Entry::getValue).toList(); + signingIdentityHash = selectSigningIdentity(matchingCertificates, certificateSelectors, validatedKeychain); + } + + return Optional.of(new SigningIdentityImpl(signingIdentityHash.toString(), + Optional.ofNullable(signingIdentityPrefix))); + } + + private static CertificateHash selectSigningIdentity(List certs, + List certificateSelectors, Optional keychain) throws ConfigException { + switch (certs.size()) { + case 0 -> { + throw I18N.buildConfigException("error.explicit-sign-no-cert") + .advice("error.explicit-sign-no-cert.advice").create(); + } + case 1 -> { + return CertificateHash.of(certs.getFirst()); + } + default -> { + Log.error(I18N.format("error.multiple.certs.found", + certificateSelectors.getFirst().team().orElse(""), keychain.map(Keychain::name).orElse(""))); + return CertificateHash.of(certs.getFirst()); + } + } } - private static Optional findSubjectCN(X509Certificate cert) { + private static List findSubjectCNs(X509Certificate cert) { final LdapName ldapName; try { ldapName = new LdapName(cert.getSubjectX500Principal().getName(X500Principal.RFC2253)); } catch (InvalidNameException e) { - return Optional.empty(); + return List.of(); } return ldapName.getRdns().stream().filter(rdn -> { return rdn.getType().equalsIgnoreCase("CN"); - }).map(Rdn::getValue).map(Object::toString).findFirst(); + }).map(Rdn::getValue).map(Object::toString).toList(); } - enum CertificateNameFilter { - APP_IMAGE("3rd Party Mac Developer Application: "), - PKG_INSTALLER("3rd Party Mac Developer Installer: "), - APP_STORE_APP_IMAGE("3rd Party Mac Developer Application: ", "Developer ID Application: "), - APP_STORE_PKG_INSTALLER("3rd Party Mac Developer Installer: ", "Developer ID Installer: "); + record CertificateSelector(StandardCertificatePrefix prefix, Optional team) { + CertificateSelector { + Objects.requireNonNull(prefix); + Objects.requireNonNull(team); + team.ifPresent(v -> { + if (v.isEmpty()) { + throw new IllegalArgumentException(); + } + }); + } - CertificateNameFilter(String ... prefixes) { - filters = List.of(prefixes); + CertificateSelector(StandardCertificatePrefix prefix) { + this(prefix, Optional.empty()); } - List getFilters(Optional certificateNameFilter) { - if (certificateNameFilter.map(CertificateNameFilter::useAsIs).orElse(false)) { - return List.of(certificateNameFilter.orElseThrow()); - } else { - return certificateNameFilter.map(filter -> { - return filters.stream().map(stdFilter -> { - return stdFilter + filter; - }).toList(); - }).orElse(filters); - } + static Optional createFromFullName(String fullName) { + Objects.requireNonNull(fullName); + return Stream.of(StandardCertificatePrefix.values()).map(CertificateSelector::new).filter(selector -> { + return fullName.startsWith(selector.fullName()); + }).reduce((x, y) -> { + throw new UnsupportedOperationException(); + }).map(selector -> { + final var team = fullName.substring(selector.fullName().length()); + return new CertificateSelector(selector.prefix, team.isEmpty() ? Optional.empty() : Optional.of(team)); + }); + } + + String fullName() { + final var sb = new StringBuilder(); + sb.append(prefix.value()).append(": "); + team.ifPresent(sb::append); + return sb.toString(); + } + } + + enum StandardCertificatePrefix { + APP_SIGN_APP_STORE("3rd Party Mac Developer Application"), + INSTALLER_SIGN_APP_STORE("3rd Party Mac Developer Installer"), + APP_SIGN_PERSONAL("Developer ID Application"), + INSTALLER_SIGN_PERSONAL("Developer ID Installer"); + + StandardCertificatePrefix(String value) { + this.value = value; + } + + String value() { + return value; + } + + private final String value; + } + + enum StandardCertificateSelector { + APP_IMAGE(StandardCertificatePrefix.APP_SIGN_PERSONAL), + PKG_INSTALLER(StandardCertificatePrefix.INSTALLER_SIGN_PERSONAL), + APP_STORE_APP_IMAGE(StandardCertificatePrefix.APP_SIGN_PERSONAL, StandardCertificatePrefix.APP_SIGN_APP_STORE), + APP_STORE_PKG_INSTALLER(StandardCertificatePrefix.INSTALLER_SIGN_PERSONAL, StandardCertificatePrefix.INSTALLER_SIGN_APP_STORE); + + StandardCertificateSelector(StandardCertificatePrefix ... prefixes) { + this.prefixes = List.of(prefixes); } - private static boolean useAsIs(String certificateNameFilter) { - return Stream.of("3rd Party Mac", "Developer ID").noneMatch(certificateNameFilter::startsWith); + static List create(Optional certificateName, StandardCertificateSelector defaultSelector) { + return certificateName.flatMap(CertificateSelector::createFromFullName).map(List::of).orElseGet(() -> { + return defaultSelector.prefixes.stream().map(prefix -> { + return new CertificateSelector(prefix, certificateName); + }).toList(); + }); } - private final List filters; + private final List prefixes; } - private String signingIdentifier; - private String signingIdentifierPrefix; - private List certificateNameFilters = new ArrayList<>(); - private Path keyChain; + private String signingIdentity; + private String signingIdentityPrefix; + private List certificateSelectors = new ArrayList<>(); + private String keychain; private Path entitlements; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentifierImpl.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityImpl.java similarity index 79% rename from src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentifierImpl.java rename to src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityImpl.java index 69c1df75693d6..640cb52f9ec42 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentifierImpl.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityImpl.java @@ -25,24 +25,24 @@ package jdk.jpackage.internal; -import static jdk.jpackage.internal.CodesignConfig.ADHOC_SIGNING_IDENTIFIER; +import static jdk.jpackage.internal.CodesignConfig.ADHOC_SIGNING_IDENTITY; import java.util.Objects; import java.util.Optional; -import jdk.jpackage.internal.model.SigningIdentifier; +import jdk.jpackage.internal.model.SigningIdentity; -record SigningIdentifierImpl(String name, Optional prefix) implements SigningIdentifier { +record SigningIdentityImpl(String id, Optional prefix) implements SigningIdentity { - SigningIdentifierImpl { - Objects.requireNonNull(name); + SigningIdentityImpl { + Objects.requireNonNull(id); Objects.requireNonNull(prefix); - if (ADHOC_SIGNING_IDENTIFIER.equals(name)) { - throw new IllegalArgumentException("Adhoc signing identifier no allowed"); + if (ADHOC_SIGNING_IDENTITY.equals(id)) { + throw new IllegalArgumentException("Adhoc signing identity no allowed"); } - if (name.contains(".") == prefix.isPresent()) { - throw new IllegalArgumentException("name and prefix mismatch"); + if (id.contains(".") == prefix.isPresent()) { + throw new IllegalArgumentException("id and prefix mismatch"); } prefix.ifPresent(thePrefix -> { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/TempKeychain.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/TempKeychain.java index 2425640671b2b..5c52e1835e510 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/TempKeychain.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/TempKeychain.java @@ -27,60 +27,43 @@ import java.io.Closeable; import java.io.IOException; -import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.Optional; import java.util.function.Predicate; import jdk.internal.util.OSVersion; -import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; final class TempKeychain implements Closeable { - static void withKeychain(Path keyChain, ThrowingConsumer keyChainConsumer) throws Throwable { - Objects.requireNonNull(keyChain); + static void withKeychain(Keychain keychain, ThrowingConsumer keychainConsumer) throws Throwable { + Objects.requireNonNull(keychain); if (OSVersion.current().compareTo(new OSVersion(10, 12)) < 0) { // we need this for OS X 10.12+ - try (var tempKeychain = new TempKeychain(keyChain)) { - keyChainConsumer.accept(tempKeychain.keyChain()); + try (var tempKeychain = new TempKeychain(keychain)) { + keychainConsumer.accept(tempKeychain.keychain); } } else { - keyChainConsumer.accept(PathUtils.normalizedAbsolutePath(keyChain)); + keychainConsumer.accept(keychain); } } - TempKeychain(Path keyChain) throws IOException { - this.keyChain = PathUtils.normalizedAbsolutePath(keyChain); + TempKeychain(Keychain keychain) throws IOException { + this.keychain = Objects.requireNonNull(keychain); - // Get the current keychain list - final List cmdOutput; - try { - cmdOutput = Executor.of("/usr/bin/security", "list-keychains").saveOutput(true).executeExpectSuccess().getOutput(); - } catch (IOException ex) { - throw I18N.buildException().message("message.keychain.error").cause(ex).create(IOException::new); // FIXME: should be PackagerException - } - - // Typical output of /usr/bin/security command is: - // "/Users/foo/Library/Keychains/login.keychain-db" - // "/Library/Keychains/System.keychain" - final var origKeychains = cmdOutput.stream().map(String::trim).map(str -> { - // Strip enclosing double quotes - return str.substring(1, str.length() - 1); - }).toList(); + final var currentKeychains = Keychain.listKeychains(); - final var keychainMissing = origKeychains.stream().map(Path::of).filter(Predicate.isEqual(keyChain)).findAny().isEmpty(); + final var keychainMissing = currentKeychains.stream().map(Keychain::path).filter(Predicate.isEqual(keychain.path())).findAny().isEmpty(); if (keychainMissing) { List args = new ArrayList<>(); args.add("/usr/bin/security"); args.add("list-keychains"); args.add("-s"); - args.addAll(origKeychains); + args.addAll(currentKeychains.stream().map(Keychain::name).toList()); restoreKeychainsCmd = List.copyOf(args); - args.add(keyChain.toString()); + args.add(keychain.asCliArg()); Executor.of(args.toArray(String[]::new)).executeExpectSuccess(); } else { @@ -88,8 +71,8 @@ static void withKeychain(Path keyChain, ThrowingConsumer keyChainConsumer) } } - Path keyChain() { - return keyChain; + Keychain keychain() { + return keychain; } @Override @@ -99,6 +82,6 @@ public void close() throws IOException { } } - private final Path keyChain; + private final Keychain keychain; private final List restoreKeychainsCmd; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java index dbeb40cb17938..7fef6ed2244c6 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java @@ -29,7 +29,7 @@ public interface MacPkgPackage extends MacPackage, MacPkgPackageMixin { default boolean sign() { - return signingConfig().flatMap(SigningConfig::identifier).isPresent(); + return signingConfig().flatMap(SigningConfig::identity).isPresent(); } public static MacPkgPackage create(MacPackage pkg, MacPkgPackageMixin mixin) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningConfig.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningConfig.java index e90f54a6a86a2..acf0929704843 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningConfig.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningConfig.java @@ -30,15 +30,15 @@ public interface SigningConfig { - Optional identifier(); + Optional identity(); Optional entitlements(); String entitlementsResourceName(); - Optional keyChain(); + Optional keychain(); - record Stub(Optional identifier, Optional entitlements, - Optional keyChain, String entitlementsResourceName) implements SigningConfig { + record Stub(Optional identity, Optional entitlements, + Optional keychain, String entitlementsResourceName) implements SigningConfig { } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentifier.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentity.java similarity index 95% rename from src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentifier.java rename to src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentity.java index 3450184758822..91d53c7bf2e46 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentifier.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentity.java @@ -27,9 +27,9 @@ import java.util.Optional; -public interface SigningIdentifier { +public interface SigningIdentity { - String name(); + String id(); Optional prefix(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java index 3ea2dd484794d..9a4891a2ca3eb 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java @@ -38,7 +38,7 @@ public final class CollectionUtils { * * @param the type of elements in this output collection * @param the type of elements in this input collection - * @param the input collection type + * @param the output collection type * @param v the input collection. Null is permitted. * @return the input collection cast to the requested type */ @@ -48,6 +48,21 @@ public static > C toCollection(Collectio return (C) tmp; } + /** + * Casts the given collection to the requested type. + * + * @param the type of elements in this output collection + * @param the upper bound type of elements in this input collection + * @param the output collection type + * @param v the input collection. Null is permitted. + * @return the input collection cast to the requested type + */ + @SuppressWarnings("unchecked") + public static > C toCollectionUBW(Collection v) { + Collection tmp = v; + return (C) tmp; + } + /** * Converts the given collection to {@link Set}. * From 97912f8c228813db35c065659b460a67e9cb8774 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Mar 2025 20:21:02 -0400 Subject: [PATCH 0353/1101] Fix AppImageSigner: launchers should be signed --- .../jdk/jpackage/internal/AppImageSigner.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java index 65980da72f091..2a7aff8729e77 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal; import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toSet; import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; import java.io.IOException; @@ -42,8 +41,6 @@ import java.util.stream.Stream; import jdk.jpackage.internal.Codesign.CodesignException; import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.ApplicationLayout; -import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.function.ExceptionBox; @@ -76,12 +73,6 @@ static final class SignFilter implements Predicate { SignFilter(Application app, Path appImage) { Objects.requireNonNull(appImage); - - launchers = app.asApplicationLayout().map(appLayout -> { - return appLayout.resolveAt(appImage); - }).map(ApplicationLayout::launchersDirectory).map(launchersDir -> { - return app.launchers().stream().map(Launcher::executableNameWithSuffix).map(launchersDir::resolve).collect(toSet()); - }).orElseGet(Set::of); } @Override @@ -91,7 +82,7 @@ public boolean test(Path path) { } if (Files.isExecutable(path) || path.getFileName().toString().endsWith(".dylib")) { - if (path.toString().contains("dylib.dSYM/Contents") || launchers.contains(path)) { + if (path.toString().contains("dylib.dSYM/Contents")) { return false; } @@ -100,8 +91,6 @@ public boolean test(Path path) { return false; } - - private final Set launchers; } private void sign(MacApplication app, Path appImage) throws CodesignException, IOException { From 51ab11885ff16cc2c2c6550852628ae45405d6b8 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Mar 2025 20:21:34 -0400 Subject: [PATCH 0354/1101] Fix setting up signing prefix --- .../classes/jdk/jpackage/internal/SigningConfigBuilder.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java index 35f4b1819ec64..7943e31c8e260 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java @@ -57,6 +57,8 @@ SigningConfigBuilder signingIdentityPrefix(LauncherStartupInfo mainLauncherStart final var pkgName = mainLauncherStartupInfo.packageName(); if (!pkgName.isEmpty()) { signingIdentityPrefix(pkgName + "."); + } else { + signingIdentityPrefix(mainLauncherStartupInfo.simpleClassName() + "."); } return this; } From f162a14ebfe86b2ba9e8490147b869016343b610 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Mar 2025 21:29:16 -0400 Subject: [PATCH 0355/1101] Redundant code removed --- .../jdk/jpackage/internal/MacAppBundler.java | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index 973970d6c02a1..5498f99b9ccdc 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -28,10 +28,9 @@ import static jdk.jpackage.internal.MacAppImageBuilder.APP_STORE; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; -import static jdk.jpackage.internal.StandardBundlerParam.MAIN_CLASS; +import static jdk.jpackage.internal.StandardBundlerParam.OUTPUT_DIR; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.StandardBundlerParam.OUTPUT_DIR; import java.text.MessageFormat; import java.util.Map; @@ -86,26 +85,6 @@ public MacAppBundler() { }, (s, p) -> s); - public static final BundlerParamInfo APP_IMAGE_SIGN_IDENTITY = - new BundlerParamInfo<>( - Arguments.CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getId(), - String.class, - params -> "", - null); - - static String getIdentifier(Map params) { - String s = MAIN_CLASS.fetchFrom(params); - if (s == null) { - return null; - } - - int idx = s.lastIndexOf("."); - if (idx >= 1) { - return s.substring(0, idx); - } - return s; - } - private static void doValidate(Map params) throws ConfigException { From b91d0096f3ba579c39d3ff4e5805c5bb789df1b2 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Mar 2025 21:29:28 -0400 Subject: [PATCH 0356/1101] More signing tests pass --- .../internal/SigningConfigBuilder.java | 68 +++++++++---------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java index 7943e31c8e260..cdeb226dd55a8 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java @@ -129,21 +129,29 @@ private Optional validatedSigningIdentity() throws ConfigExcept }).forEach(acc::accept); }).toList(); - final var resolvedCertificateSelectors = certificateSelectors.stream().map(CertificateSelector::fullName).toList(); + final List allCertificateSelectors; + if (signingIdentity != null) { + allCertificateSelectors = new ArrayList<>(certificateSelectors); + allCertificateSelectors.add(new CertificateSelector("", signingIdentity)); + } else { + allCertificateSelectors = certificateSelectors; + } + + final var resolvedCertificateSelectors = allCertificateSelectors.stream().map(CertificateSelector::fullName).toList(); var matchingCertificates = mappedCertficates.stream().filter(e -> { return resolvedCertificateSelectors.contains(e.getKey()); }).map(Map.Entry::getValue).toList(); if (!matchingCertificates.isEmpty()) { - signingIdentityHash = selectSigningIdentity(matchingCertificates, certificateSelectors, validatedKeychain); + signingIdentityHash = selectSigningIdentity(matchingCertificates, allCertificateSelectors, validatedKeychain); } else { matchingCertificates = mappedCertficates.stream().filter(e -> { return resolvedCertificateSelectors.stream().anyMatch(filter -> { return filter.startsWith(e.getKey()); }); }).map(Map.Entry::getValue).toList(); - signingIdentityHash = selectSigningIdentity(matchingCertificates, certificateSelectors, validatedKeychain); + signingIdentityHash = selectSigningIdentity(matchingCertificates, allCertificateSelectors, validatedKeychain); } return Optional.of(new SigningIdentityImpl(signingIdentityHash.toString(), @@ -161,8 +169,8 @@ private static CertificateHash selectSigningIdentity(List certs return CertificateHash.of(certs.getFirst()); } default -> { - Log.error(I18N.format("error.multiple.certs.found", - certificateSelectors.getFirst().team().orElse(""), keychain.map(Keychain::name).orElse(""))); + Log.error(I18N.format("error.multiple.certs.found", certificateSelectors.getFirst().name(), + keychain.map(Keychain::name).orElse(""))); return CertificateHash.of(certs.getFirst()); } } @@ -181,38 +189,17 @@ private static List findSubjectCNs(X509Certificate cert) { }).map(Rdn::getValue).map(Object::toString).toList(); } - record CertificateSelector(StandardCertificatePrefix prefix, Optional team) { + record CertificateSelector(String prefix, String name) { CertificateSelector { Objects.requireNonNull(prefix); - Objects.requireNonNull(team); - team.ifPresent(v -> { - if (v.isEmpty()) { - throw new IllegalArgumentException(); - } - }); - } - - CertificateSelector(StandardCertificatePrefix prefix) { - this(prefix, Optional.empty()); - } - - static Optional createFromFullName(String fullName) { - Objects.requireNonNull(fullName); - return Stream.of(StandardCertificatePrefix.values()).map(CertificateSelector::new).filter(selector -> { - return fullName.startsWith(selector.fullName()); - }).reduce((x, y) -> { - throw new UnsupportedOperationException(); - }).map(selector -> { - final var team = fullName.substring(selector.fullName().length()); - return new CertificateSelector(selector.prefix, team.isEmpty() ? Optional.empty() : Optional.of(team)); - }); + Objects.requireNonNull(name); + if (prefix.isEmpty() && name.isEmpty()) { + throw new IllegalArgumentException("Empty prefix and name"); + } } String fullName() { - final var sb = new StringBuilder(); - sb.append(prefix.value()).append(": "); - team.ifPresent(sb::append); - return sb.toString(); + return prefix + name; } } @@ -223,13 +210,22 @@ enum StandardCertificatePrefix { INSTALLER_SIGN_PERSONAL("Developer ID Installer"); StandardCertificatePrefix(String value) { - this.value = value; + this.value = value + ": "; } String value() { return value; } + static Optional findStandardCertificatePrefix(String fullName) { + Objects.requireNonNull(fullName); + return Stream.of(StandardCertificatePrefix.values()).filter(prefix -> { + return fullName.startsWith(prefix.value); + }).reduce((x, y) -> { + throw new UnsupportedOperationException(); + }); + } + private final String value; } @@ -244,9 +240,11 @@ enum StandardCertificateSelector { } static List create(Optional certificateName, StandardCertificateSelector defaultSelector) { - return certificateName.flatMap(CertificateSelector::createFromFullName).map(List::of).orElseGet(() -> { + return certificateName.flatMap(StandardCertificatePrefix::findStandardCertificatePrefix).map(prefix -> { + return new CertificateSelector(prefix.value(), certificateName.orElseThrow().substring(prefix.value().length())); + }).map(List::of).orElseGet(() -> { return defaultSelector.prefixes.stream().map(prefix -> { - return new CertificateSelector(prefix, certificateName); + return new CertificateSelector(prefix.value(), certificateName.orElse("")); }).toList(); }); } From ddc78d727f656e821fdedd8bfc5b61e5a397aafe Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Mar 2025 21:53:57 -0400 Subject: [PATCH 0357/1101] Remove redundant `Package` parameter from PackagingPipeline.copyAppImage(Package, AppImageDesc, AppImageDesc, boolean) method --- .../classes/jdk/jpackage/internal/MacPackagingPipeline.java | 2 +- .../classes/jdk/jpackage/internal/PackagingPipeline.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index 03b6768b2c74e..6e1e1552b505c 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -154,7 +154,7 @@ static PackagingPipeline.Builder build(Optional pkg) { private static void copyAppImage(Package pkg, AppImageDesc srcAppImage, AppImageDesc dstAppImage) throws IOException { - PackagingPipeline.copyAppImage(pkg, srcAppImage, dstAppImage, false/*!((MacApplication)pkg.app()).sign()*/); + PackagingPipeline.copyAppImage(srcAppImage, dstAppImage, false/*!((MacApplication)pkg.app()).sign()*/); } private static void copyJliLib( diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java index 19d8e08cda551..9e9e924d16f8d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java @@ -374,10 +374,10 @@ static Builder configurePackageTasks(Builder builder) { } static void copyAppImage(Package pkg, AppImageDesc srcAppImage, AppImageDesc dstAppImage) throws IOException { - copyAppImage(pkg, srcAppImage, dstAppImage, true); + copyAppImage(srcAppImage, dstAppImage, true); } - static void copyAppImage(Package pkg, AppImageDesc srcAppImage, AppImageDesc dstAppImage, + static void copyAppImage(AppImageDesc srcAppImage, AppImageDesc dstAppImage, boolean removeAppImageFile) throws IOException { final var srcLayout = srcAppImage.resolvedAppImagelayout(); final var srcLayoutPathGroup = AppImageLayout.toPathGroup(srcLayout); From 339e58eb4a6f5a50531e732c52f68d65a9554c32 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 26 Mar 2025 11:52:38 -0400 Subject: [PATCH 0358/1101] Bugfix --- .../classes/jdk/jpackage/internal/MacApplicationBuilder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java index 1ec208de45470..d0e330d150322 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java @@ -50,6 +50,7 @@ private MacApplicationBuilder(MacApplicationBuilder other) { category = other.category; appStore = other.appStore; externalInfoPlistFile = other.externalInfoPlistFile; + signingBuilder = other.signingBuilder; } MacApplicationBuilder icon(Path v) { From f81dbab4a3ce3455fadc5e35d6074896dca2d59a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 26 Mar 2025 13:12:33 -0400 Subject: [PATCH 0359/1101] Add methods to ApplicationBuilder class to override launcher startup info --- .../jpackage/internal/ApplicationBuilder.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 94bfd7d8ed042..566446396b33f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -39,6 +39,7 @@ import jdk.jpackage.internal.model.ApplicationLaunchers; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.LauncherStartupInfo; import jdk.jpackage.internal.model.RuntimeBuilder; final class ApplicationBuilder { @@ -106,6 +107,10 @@ ApplicationBuilder launchers(ApplicationLaunchers v) { return this; } + Optional launchers() { + return Optional.ofNullable(launchers); + } + ApplicationBuilder appImageLayout(AppImageLayout v) { appImageLayout = v; return this; @@ -146,6 +151,29 @@ ApplicationBuilder contentDirs(List v) { return this; } + static Launcher overrideLauncherStartupInfo(Launcher launcher, LauncherStartupInfo startupInfo) { + return new Launcher.Stub(launcher.name(), Optional.of(startupInfo), + launcher.fileAssociations(), launcher.isService(), launcher.description(), + launcher.icon(), launcher.defaultIconResourceName(), launcher.extraAppImageFileData()); + } + + record MainLauncherStartupInfo(String qualifiedClassName) implements LauncherStartupInfo { + @Override + public List javaOptions() { + throw new UnsupportedOperationException(); + } + + @Override + public List defaultParameters() { + throw new UnsupportedOperationException(); + } + + @Override + public List classPath() { + throw new UnsupportedOperationException(); + } + } + private record Defaults(String version, String vendor) { String copyright() { return I18N.format("param.copyright.default", new Date()); From d8d9d918528864db15727b2eafac4b597ff4a064 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 26 Mar 2025 16:06:13 -0400 Subject: [PATCH 0360/1101] Fix predefined app image signing --- .../jdk/jpackage/internal/MacAppBundler.java | 15 ++++-- .../jdk/jpackage/internal/MacFromParams.java | 29 ++++++++++-- .../internal/MacPackagingPipeline.java | 47 +++++++++++++++++-- .../jpackage/internal/AppImageBundler.java | 20 ++++---- 4 files changed, 88 insertions(+), 23 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index 5498f99b9ccdc..0377219ab6057 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -43,11 +43,18 @@ public MacAppBundler() { // Order is important! final var app = MacFromParams.APPLICATION.fetchFrom(params); - final var env = BuildEnv.withAppImageDir(BuildEnvFromParams.BUILD_ENV.fetchFrom(params), output); + final BuildEnv env; - MacPackagingPipeline.build(Optional.empty()) - .excludeDirFromCopying(output.getParent()) - .excludeDirFromCopying(OUTPUT_DIR.fetchFrom(params)).create().execute(env, app); + if (StandardBundlerParam.hasPredefinedAppImage(params)) { + env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + final var pkg = MacPackagingPipeline.createSignAppImagePackage(app, env); + MacPackagingPipeline.build(Optional.of(pkg)).create().execute(env, pkg, output); + } else { + env = BuildEnv.withAppImageDir(BuildEnvFromParams.BUILD_ENV.fetchFrom(params), output); + MacPackagingPipeline.build(Optional.empty()) + .excludeDirFromCopying(output.getParent()) + .excludeDirFromCopying(OUTPUT_DIR.fetchFrom(params)).create().execute(env, app); + } }); setParamsValidator(MacAppBundler::doValidate); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java index cd77de289091e..d6899fdf84233 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java @@ -54,9 +54,11 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Predicate; import jdk.jpackage.internal.SigningConfigBuilder.StandardCertificateSelector; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.model.ApplicationLaunchers; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.MacDmgPackage; @@ -64,6 +66,7 @@ import jdk.jpackage.internal.model.MacLauncher; import jdk.jpackage.internal.model.MacPkgPackage; import jdk.jpackage.internal.model.RuntimeLayout; +import static jdk.jpackage.internal.ApplicationBuilder.MainLauncherStartupInfo; final class MacFromParams { @@ -81,15 +84,28 @@ private static MacApplication createMacApplication( final var launcherFromParams = new LauncherFromParams(Optional.of(MacFromParams::createMacFa)); - final var app = createApplicationBuilder(params, toFunction(launcherParams -> { + final var superAppBuilder = createApplicationBuilder(params, toFunction(launcherParams -> { var launcher = launcherFromParams.create(launcherParams); return MacLauncher.create(launcher); - }), APPLICATION_LAYOUT, predefinedRuntimeLayout).create(); + }), APPLICATION_LAYOUT, predefinedRuntimeLayout); + + if (hasPredefinedAppImage(params)) { + // Set the main launcher start up info. + // AppImageFile assumes the main launcher start up info is available when + // it is constructed from Application instance. + // This happens when jpackage signs predefined app image. + final var mainLauncherStartupInfo = new MainLauncherStartupInfo(PREDEFINED_APP_IMAGE_FILE.fetchFrom(params).getMainClass()); + final var launchers = superAppBuilder.launchers().orElseThrow(); + final var mainLauncher = ApplicationBuilder.overrideLauncherStartupInfo(launchers.mainLauncher(), mainLauncherStartupInfo); + superAppBuilder.launchers(new ApplicationLaunchers(MacLauncher.create(mainLauncher), launchers.additionalLaunchers())); + } + + final var app = superAppBuilder.create(); final var appBuilder = new MacApplicationBuilder(app); if (hasPredefinedAppImage(params)) { - appBuilder.externalInfoPlistFile(PREDEFINED_APP_IMAGE.fetchFrom(params).resolve("Contents/Info.plist")); + appBuilder.externalInfoPlistFile(PREDEFINED_APP_IMAGE.findIn(params).orElseThrow().resolve("Contents/Info.plist")); } ICON.copyInto(params, appBuilder::icon); @@ -100,10 +116,10 @@ private static MacApplication createMacApplication( final boolean sign; final boolean appStore; - if (hasPredefinedAppImage(params)) { + if (hasPredefinedAppImage(params) && PACKAGE_TYPE.findIn(params).filter(Predicate.isEqual("app-image")).isEmpty()) { final var appImageFileExtras = new MacAppImageFileExtras(PREDEFINED_APP_IMAGE_FILE.fetchFrom(params)); sign = appImageFileExtras.signed(); - appStore = APP_STORE.findIn(params).orElse(false); + appStore = appImageFileExtras.appStore(); } else { sign = SIGN_BUNDLE.findIn(params).orElse(false); appStore = APP_STORE.findIn(params).orElse(false); @@ -200,6 +216,9 @@ private static MacFileAssociation createMacFa(FileAssociation fa, Map APP_IMAGE_SIGN_IDENTITY = createStringBundlerParam( Arguments.CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getId()); + private static final BundlerParamInfo PACKAGE_TYPE = createStringBundlerParam( + Arguments.CLIOptions.PACKAGE_TYPE.getId()); + private static final BundlerParamInfo FA_MAC_CFBUNDLETYPEROLE = createStringBundlerParam( Arguments.MAC_CFBUNDLETYPEROLE); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index 6e1e1552b505c..c94277aee7b63 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal; +import static jdk.jpackage.internal.ApplicationImageUtils.createWriteAppImageFileAction; import static jdk.jpackage.internal.util.PListWriter.writeArray; import static jdk.jpackage.internal.util.PListWriter.writeBoolean; import static jdk.jpackage.internal.util.PListWriter.writeDict; @@ -39,9 +40,11 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; @@ -51,6 +54,7 @@ import jdk.jpackage.internal.PackagingPipeline.BuildApplicationTaskID; import jdk.jpackage.internal.PackagingPipeline.CopyAppImageTaskID; import jdk.jpackage.internal.PackagingPipeline.PackageBuildEnv; +import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; import jdk.jpackage.internal.PackagingPipeline.TaskAction; import jdk.jpackage.internal.PackagingPipeline.TaskContext; @@ -62,6 +66,7 @@ import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.MacFileAssociation; import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.SigningConfig; import jdk.jpackage.internal.util.function.ThrowingConsumer; @@ -81,6 +86,7 @@ enum MacBuildApplicationTaskID implements TaskID { enum MacCopyAppImageTaskID implements TaskID { COPY_PACKAGE_FILE, + REPLACE_APP_IMAGE_FILE, COPY_SIGN } @@ -117,6 +123,9 @@ static PackagingPipeline.Builder build(Optional pkg) { .task(MacBuildApplicationTaskID.PACKAGE_FILE) .packageAction(MacPackagingPipeline::writePackageFile) .addDependents(BuildApplicationTaskID.CONTENT).add() + .task(MacCopyAppImageTaskID.REPLACE_APP_IMAGE_FILE) + .addDependent(PrimaryTaskID.COPY_APP_IMAGE) + .noaction().add() .task(MacCopyAppImageTaskID.COPY_PACKAGE_FILE) .packageAction(MacPackagingPipeline::writePackageFile) .addDependencies(CopyAppImageTaskID.COPY) @@ -141,17 +150,49 @@ static PackagingPipeline.Builder build(Optional pkg) { .add(); pkg.ifPresent(p -> { - if (p.isRuntimeInstaller() || (p.predefinedAppImage().isPresent() && ((MacApplication)p.app()).sign())) { + final List disabledTasks = new ArrayList<>(); + + if (p.type() instanceof SignAppImagePackageType) { + // This is a phony package signing predefined app image. + // Don't create ".package" file. + // Don't copy predefined app image, update it in place. + // Disable running user script after app image ready. + // Replace ".jpackage.xml" file. + // Use app image layout. + disabledTasks.add(MacCopyAppImageTaskID.COPY_PACKAGE_FILE); + disabledTasks.add(CopyAppImageTaskID.COPY); + disabledTasks.add(PackageTaskID.RUN_POST_IMAGE_USER_SCRIPT); + builder.task(MacCopyAppImageTaskID.REPLACE_APP_IMAGE_FILE).applicationAction(createWriteAppImageFileAction()).add(); + builder.appImageLayoutForPackaging(Package::appImageLayout); + } else if (p.isRuntimeInstaller() || (p.predefinedAppImage().isPresent() && ((MacApplication)p.app()).sign())) { // If this is a runtime package or a signed predefined app image, // don't create ".package" file and don't sign it. - builder.task(MacCopyAppImageTaskID.COPY_PACKAGE_FILE).noaction().add(); - builder.task(MacCopyAppImageTaskID.COPY_SIGN).noaction().add(); + disabledTasks.add(MacCopyAppImageTaskID.COPY_PACKAGE_FILE); + disabledTasks.add(MacCopyAppImageTaskID.COPY_SIGN); + } + + for (final var taskId : disabledTasks) { + builder.task(taskId).noaction().add(); } }); return builder; } + enum SignAppImagePackageType implements PackageType { + VALUE; + } + + static Package createSignAppImagePackage(MacApplication app, BuildEnv env) { + if (!app.sign()) { + throw new IllegalArgumentException(); + } + return toSupplier(() -> { + return new PackageBuilder(app, SignAppImagePackageType.VALUE).predefinedAppImage( + Objects.requireNonNull(env.appImageDir())).installDir(Path.of("/foo")).create(); + }).get(); + } + private static void copyAppImage(Package pkg, AppImageDesc srcAppImage, AppImageDesc dstAppImage) throws IOException { PackagingPipeline.copyAppImage(srcAppImage, dstAppImage, false/*!((MacApplication)pkg.app()).sign()*/); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java index f9e114118321f..d46856be409b3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java @@ -86,20 +86,18 @@ public final boolean validate(Map params) @Override public final Path execute(Map params, Path outputParentDir) throws PackagerException { - if (StandardBundlerParam.isRuntimeInstaller(params)) { - return PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); - } - var predefinedAppImage = PREDEFINED_APP_IMAGE.fetchFrom(params); - if (predefinedAppImage != null) { - return predefinedAppImage; - } + final var predefinedAppImage = PREDEFINED_APP_IMAGE.fetchFrom(params); try { - Path rootDirectory = createRoot(params, outputParentDir); - appImageSupplier.prepareApplicationFiles(params, rootDirectory); - return rootDirectory; - + if (predefinedAppImage == null) { + Path rootDirectory = createRoot(params, outputParentDir); + appImageSupplier.prepareApplicationFiles(params, rootDirectory); + return rootDirectory; + } else { + appImageSupplier.prepareApplicationFiles(params, predefinedAppImage); + return predefinedAppImage; + } } catch (PackagerException pe) { throw pe; } catch (RuntimeException|IOException ex) { From f9e3dd3b72976856c49e82075c8805034bd7d428 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 26 Mar 2025 18:05:34 -0400 Subject: [PATCH 0361/1101] Most .pkg signing tests pass --- .../internal/MacApplicationBuilder.java | 2 +- .../jdk/jpackage/internal/MacFromParams.java | 59 ++++++++++++++++--- .../internal/MacPkgPackageBuilder.java | 2 +- .../internal/SigningConfigBuilder.java | 25 +++++--- 4 files changed, 71 insertions(+), 17 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java index d0e330d150322..a2b2791ab4cd2 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java @@ -156,7 +156,7 @@ private MacApplicationBuilder createCopyForExternalInfoPlistFile() throws Config private Optional createSigningConfig() throws ConfigException { if (signingBuilder != null) { - return Optional.of(signingBuilder.create()); + return signingBuilder.create(); } else { return Optional.empty(); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java index d6899fdf84233..25cb52087be2b 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java @@ -55,10 +55,12 @@ import java.util.Map; import java.util.Optional; import java.util.function.Predicate; +import jdk.jpackage.internal.ApplicationBuilder.MainLauncherStartupInfo; import jdk.jpackage.internal.SigningConfigBuilder.StandardCertificateSelector; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLaunchers; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.FileAssociation; -import jdk.jpackage.internal.model.ApplicationLaunchers; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.MacDmgPackage; @@ -66,7 +68,6 @@ import jdk.jpackage.internal.model.MacLauncher; import jdk.jpackage.internal.model.MacPkgPackage; import jdk.jpackage.internal.model.RuntimeLayout; -import static jdk.jpackage.internal.ApplicationBuilder.MainLauncherStartupInfo; final class MacFromParams { @@ -128,16 +129,24 @@ private static MacApplication createMacApplication( appBuilder.appStore(appStore); if (sign) { - final var signingBuilder = new SigningConfigBuilder(); - app.mainLauncher().flatMap(Launcher::startupInfo).ifPresent(signingBuilder::signingIdentityPrefix); - BUNDLE_ID_SIGNING_PREFIX.copyInto(params, signingBuilder::signingIdentityPrefix); - SIGNING_KEYCHAIN.copyInto(params, signingBuilder::keychain); + final var signingBuilder = createSigningConfigBuilder(params, app); + if (appStore) { + signingBuilder.entitlementsResourceName("entitlements.plist"); + } + ENTITLEMENTS.copyInto(params, signingBuilder::entitlements); APP_IMAGE_SIGN_IDENTITY.copyInto(params, signingBuilder::signingIdentity); - final var filter = appStore ? StandardCertificateSelector.APP_STORE_APP_IMAGE : StandardCertificateSelector.APP_IMAGE; + SIGNING_KEY_USER.findIn(params).ifPresent(userName -> { + final StandardCertificateSelector filter; + if (appStore) { + filter = StandardCertificateSelector.APP_STORE_APP_IMAGE; + } else { + filter = StandardCertificateSelector.APP_IMAGE; + } - signingBuilder.addCertificateSelectors(StandardCertificateSelector.create(SIGNING_KEY_USER.findIn(params), filter)); + signingBuilder.addCertificateSelectors(StandardCertificateSelector.create(userName, filter)); + }); appBuilder.signingBuilder(signingBuilder); } @@ -168,9 +177,40 @@ private static MacPkgPackage createMacPkgPackage( final var pkgBuilder = new MacPkgPackageBuilder(superPkgBuilder); + final boolean sign = SIGN_BUNDLE.findIn(params).orElse(false); + final boolean appStore = APP_STORE.findIn(params).orElse(false); + + if (sign) { + final var signingBuilder = createSigningConfigBuilder(params, app); + INSTALLER_SIGN_IDENTITY.copyInto(params, signingBuilder::signingIdentity); + + SIGNING_KEY_USER.findIn(params).ifPresent(userName -> { + final List filters; + if (appStore) { + filters = List.of(StandardCertificateSelector.APP_STORE_PKG_INSTALLER); + } else { + filters = List.of(StandardCertificateSelector.PKG_INSTALLER); + } + + for (final var filter : filters) { + signingBuilder.addCertificateSelectors(StandardCertificateSelector.create(userName, filter)); + } + }); + + pkgBuilder.signingBuilder(signingBuilder); + } + return pkgBuilder.create(); } + private static SigningConfigBuilder createSigningConfigBuilder(Map params, Application app) { + final var builder = new SigningConfigBuilder(); + app.mainLauncher().flatMap(Launcher::startupInfo).ifPresent(builder::signingIdentityPrefix); + BUNDLE_ID_SIGNING_PREFIX.copyInto(params, builder::signingIdentityPrefix); + SIGNING_KEYCHAIN.copyInto(params, builder::keychain); + return builder; + } + private static MacFileAssociation createMacFa(FileAssociation fa, Map params) { final var builder = new MacFileAssociationBuilder(); @@ -216,6 +256,9 @@ private static MacFileAssociation createMacFa(FileAssociation fa, Map APP_IMAGE_SIGN_IDENTITY = createStringBundlerParam( Arguments.CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getId()); + static final BundlerParamInfo INSTALLER_SIGN_IDENTITY = createStringBundlerParam( + Arguments.CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getId()); + private static final BundlerParamInfo PACKAGE_TYPE = createStringBundlerParam( Arguments.CLIOptions.PACKAGE_TYPE.getId()); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java index ec4f256520dc2..ec67174003f53 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java @@ -50,7 +50,7 @@ MacPkgPackage create() throws ConfigException { private Optional createSigningConfig() throws ConfigException { if (signingBuilder != null) { - return Optional.of(signingBuilder.create()); + return signingBuilder.create(); } else { return Optional.empty(); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java index cdeb226dd55a8..f48ad3fa9a9f0 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java @@ -87,9 +87,19 @@ SigningConfigBuilder entitlements(Path v) { return this; } - SigningConfig create() throws ConfigException { - return new SigningConfig.Stub(validatedSigningIdentity(), validatedEntitlements(), - validatedKeychain().map(Keychain::name), "sandbox.plist"); + SigningConfigBuilder entitlementsResourceName(String v) { + entitlementsResourceName = v; + return this; + } + + Optional create() throws ConfigException { + if (signingIdentity == null && certificateSelectors.isEmpty()) { + return Optional.empty(); + } else { + return Optional.of(new SigningConfig.Stub(validatedSigningIdentity(), validatedEntitlements(), + validatedKeychain().map(Keychain::name), + Optional.ofNullable(entitlementsResourceName).orElse("sandbox.plist"))); + } } private Optional validatedEntitlements() throws ConfigException { @@ -239,12 +249,12 @@ enum StandardCertificateSelector { this.prefixes = List.of(prefixes); } - static List create(Optional certificateName, StandardCertificateSelector defaultSelector) { - return certificateName.flatMap(StandardCertificatePrefix::findStandardCertificatePrefix).map(prefix -> { - return new CertificateSelector(prefix.value(), certificateName.orElseThrow().substring(prefix.value().length())); + static List create(String certificateName, StandardCertificateSelector defaultSelector) { + return StandardCertificatePrefix.findStandardCertificatePrefix(certificateName).map(prefix -> { + return new CertificateSelector(prefix.value(), certificateName.substring(prefix.value().length())); }).map(List::of).orElseGet(() -> { return defaultSelector.prefixes.stream().map(prefix -> { - return new CertificateSelector(prefix.value(), certificateName.orElse("")); + return new CertificateSelector(prefix.value(), certificateName); }).toList(); }); } @@ -257,4 +267,5 @@ static List create(Optional certificateName, Standa private List certificateSelectors = new ArrayList<>(); private String keychain; private Path entitlements; + private String entitlementsResourceName; } From b166b4061a2ab6bbac8e3dea17ca56e5ac818cc1 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 26 Mar 2025 20:47:13 -0400 Subject: [PATCH 0362/1101] Add javadoc --- .../jdk/jpackage/internal/model/MacApplication.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java index 8949cff7fa7f4..f6b64503d3337 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java @@ -56,6 +56,13 @@ default Path appImageDirName() { } } + /** + * Returns {@code true} if the application image of this application should be + * signed. + * + * @return {@code true} if the application image of this application should be + * signed + */ default boolean sign() { return signingConfig().isPresent(); } From 3e651f1ff00b0d71cc467b18027e48432d9a033a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 26 Mar 2025 20:47:48 -0400 Subject: [PATCH 0363/1101] All but "SigningPackageTest.test(false, false, true, UNICODE_INDEX)" signing tests pass --- .../internal/MacDmgPackageBuilder.java | 14 ++--- .../jdk/jpackage/internal/MacFromParams.java | 18 ++++++- .../jpackage/internal/MacPackageBuilder.java | 54 +++++++++++++++++++ .../internal/MacPackagingPipeline.java | 3 +- .../internal/MacPkgPackageBuilder.java | 8 ++- .../jpackage/internal/model/MacPackage.java | 6 +-- .../internal/model/MacPackageMixin.java | 49 +++++++++++++++++ .../internal/model/MacPkgPackage.java | 7 ++- 8 files changed, 140 insertions(+), 19 deletions(-) create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackageBuilder.java create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackageMixin.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java index 23c7eb658dd8e..cf63e1742d1b9 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java @@ -32,11 +32,10 @@ import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.model.MacDmgPackageMixin; -import jdk.jpackage.internal.model.MacPackage; final class MacDmgPackageBuilder { - MacDmgPackageBuilder(PackageBuilder pkgBuilder) { + MacDmgPackageBuilder(MacPackageBuilder pkgBuilder) { this.pkgBuilder = Objects.requireNonNull(pkgBuilder); } @@ -55,15 +54,16 @@ List validatedDmgContent() { } MacDmgPackage create() throws ConfigException { - pkgBuilder.installDir().ifPresent(installDir -> { - final var defaultInstallDirLocation = pkgBuilder.defaultInstallDir().map(Path::getParent).orElseThrow(); + final var superPkgBuilder = pkgBuilder.pkgBuilder(); + superPkgBuilder.installDir().ifPresent(installDir -> { + final var defaultInstallDirLocation = superPkgBuilder.defaultInstallDir().map(Path::getParent).orElseThrow(); if (!defaultInstallDirLocation.equals(installDir)) { Log.info(I18N.format("message.install-dir-ignored", defaultInstallDirLocation)); - pkgBuilder.installDir(defaultInstallDirLocation); + superPkgBuilder.installDir(defaultInstallDirLocation); } }); - final var pkg = MacPackage.create(pkgBuilder.create()); + final var pkg = pkgBuilder.create(); return MacDmgPackage.create(pkg, new MacDmgPackageMixin.Stub( Optional.ofNullable(icon).or(((MacApplication)pkg.app())::icon), @@ -72,5 +72,5 @@ MacDmgPackage create() throws ConfigException { private Path icon; private List dmgContent; - private final PackageBuilder pkgBuilder; + private final MacPackageBuilder pkgBuilder; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java index 25cb52087be2b..eeeb2e3d6dd87 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java @@ -67,6 +67,7 @@ import jdk.jpackage.internal.model.MacFileAssociation; import jdk.jpackage.internal.model.MacLauncher; import jdk.jpackage.internal.model.MacPkgPackage; +import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.RuntimeLayout; @@ -154,12 +155,25 @@ private static MacApplication createMacApplication( return appBuilder.create(); } + private static MacPackageBuilder createMacPackageBuilder( + Map params, MacApplication app, + PackageType type) throws ConfigException { + final var builder = new MacPackageBuilder(createPackageBuilder(params, app, type)); + + PREDEFINED_APP_IMAGE_FILE.findIn(params) + .map(MacAppImageFileExtras::new) + .map(MacAppImageFileExtras::signed) + .ifPresent(builder::predefinedAppImageSigned); + + return builder; + } + private static MacDmgPackage createMacDmgPackage( Map params) throws ConfigException, IOException { final var app = APPLICATION.fetchFrom(params); - final var superPkgBuilder = createPackageBuilder(params, app, MAC_DMG); + final var superPkgBuilder = createMacPackageBuilder(params, app, MAC_DMG); final var pkgBuilder = new MacDmgPackageBuilder(superPkgBuilder); @@ -173,7 +187,7 @@ private static MacPkgPackage createMacPkgPackage( final var app = APPLICATION.fetchFrom(params); - final var superPkgBuilder = createPackageBuilder(params, app, MAC_PKG); + final var superPkgBuilder = createMacPackageBuilder(params, app, MAC_PKG); final var pkgBuilder = new MacPkgPackageBuilder(superPkgBuilder); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackageBuilder.java new file mode 100644 index 0000000000000..a16194a62601d --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackageBuilder.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.util.Objects; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.MacPackage; +import jdk.jpackage.internal.model.MacPackageMixin; + +final class MacPackageBuilder { + + MacPackageBuilder(PackageBuilder pkgBuilder) { + this.pkgBuilder = Objects.requireNonNull(pkgBuilder); + } + + MacPackageBuilder predefinedAppImageSigned(boolean v) { + predefinedAppImageSigned = v; + return this; + } + + PackageBuilder pkgBuilder() { + return pkgBuilder; + } + + MacPackage create() throws ConfigException { + final var pkg = pkgBuilder.create(); + return MacPackage.create(pkg, new MacPackageMixin.Stub(pkg.predefinedAppImage().map(v -> predefinedAppImageSigned))); + } + + private final PackageBuilder pkgBuilder; + private boolean predefinedAppImageSigned; +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index c94277aee7b63..f34b1e838b521 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -61,6 +61,7 @@ import jdk.jpackage.internal.PackagingPipeline.TaskID; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.MacPackage; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.model.MacApplication; @@ -164,7 +165,7 @@ static PackagingPipeline.Builder build(Optional pkg) { disabledTasks.add(PackageTaskID.RUN_POST_IMAGE_USER_SCRIPT); builder.task(MacCopyAppImageTaskID.REPLACE_APP_IMAGE_FILE).applicationAction(createWriteAppImageFileAction()).add(); builder.appImageLayoutForPackaging(Package::appImageLayout); - } else if (p.isRuntimeInstaller() || (p.predefinedAppImage().isPresent() && ((MacApplication)p.app()).sign())) { + } else if (p.isRuntimeInstaller() || ((MacPackage)p).predefinedAppImageSigned().orElse(false)) { // If this is a runtime package or a signed predefined app image, // don't create ".package" file and don't sign it. disabledTasks.add(MacCopyAppImageTaskID.COPY_PACKAGE_FILE); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java index ec67174003f53..493fc61e26a1a 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java @@ -27,14 +27,13 @@ import java.util.Objects; import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.MacPackage; import jdk.jpackage.internal.model.MacPkgPackage; import jdk.jpackage.internal.model.MacPkgPackageMixin; import jdk.jpackage.internal.model.SigningConfig; final class MacPkgPackageBuilder { - MacPkgPackageBuilder(PackageBuilder pkgBuilder) { + MacPkgPackageBuilder(MacPackageBuilder pkgBuilder) { this.pkgBuilder = Objects.requireNonNull(pkgBuilder); } @@ -44,8 +43,7 @@ MacPkgPackageBuilder signingBuilder(SigningConfigBuilder v) { } MacPkgPackage create() throws ConfigException { - return MacPkgPackage.create(MacPackage.create(pkgBuilder.create()), - new MacPkgPackageMixin.Stub(createSigningConfig())); + return MacPkgPackage.create(pkgBuilder.create(), new MacPkgPackageMixin.Stub(createSigningConfig())); } private Optional createSigningConfig() throws ConfigException { @@ -56,6 +54,6 @@ private Optional createSigningConfig() throws ConfigException { } } - private final PackageBuilder pkgBuilder; + private final MacPackageBuilder pkgBuilder; private SigningConfigBuilder signingBuilder; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java index 3acf2b425c0d1..2cf952b75b7e7 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java @@ -27,7 +27,7 @@ import java.nio.file.Path; import jdk.jpackage.internal.util.CompositeProxy; -public interface MacPackage extends Package { +public interface MacPackage extends Package, MacPackageMixin { @Override default AppImageLayout appImageLayout() { @@ -42,8 +42,8 @@ default Path installDir() { return Path.of("/").resolve(relativeInstallDir()); } - public static MacPackage create(Package pkg) { - return CompositeProxy.create(MacPackage.class, pkg); + public static MacPackage create(Package pkg, MacPackageMixin mixin) { + return CompositeProxy.create(MacPackage.class, pkg, mixin); } public final static RuntimeLayout RUNTIME_PACKAGE_LAYOUT = RuntimeLayout.create(Path.of("Contents/Home")); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackageMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackageMixin.java new file mode 100644 index 0000000000000..6a6af5d67331a --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackageMixin.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.util.Optional; + +public interface MacPackageMixin { + + /** + * Gets sign status of the predefined app image. + *

+ * Returns {@code Optional.of(Boolean.TRUE)} if the predefined app image is + * available and is signed. + *

+ * Returns {@code Optional.of(Boolean.FALSE)} if the predefined app image is + * available and is unsigned. + *

+ * Returns any empty {@link Optional} instance if the predefined app image is + * unavailable. + * + * @return sign status of the predefined app image if any + */ + Optional predefinedAppImageSigned(); + + record Stub(Optional predefinedAppImageSigned) implements MacPackageMixin { + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java index 7fef6ed2244c6..72b442cb38d3a 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackage.java @@ -28,8 +28,13 @@ public interface MacPkgPackage extends MacPackage, MacPkgPackageMixin { + /** + * Returns {@code true} if this PKG installer should be signed. + * + * @return {@code true} if this PKG installer should be signed + */ default boolean sign() { - return signingConfig().flatMap(SigningConfig::identity).isPresent(); + return signingConfig().isPresent(); } public static MacPkgPackage create(MacPackage pkg, MacPkgPackageMixin mixin) { From 40ba4daa224a8208a07295993290f0cca4a1c327 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 28 Mar 2025 14:50:36 -0400 Subject: [PATCH 0364/1101] Adjust JPackageCommand.assertAppImageFile() --- .../jdk/jpackage/test/JPackageCommand.java | 72 +++++++++++++++---- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index d72e84bfab115..977415d484aa5 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -374,7 +374,7 @@ public Path outputBundle() { String dirName; if (!TKit.isOSX()) { dirName = name(); - } else if (hasArgument("--app-image") && hasArgument("--mac-sign")) { + } else if (macSignPredefinedAppImage()) { // Request to sign external app image, not to build a new one dirName = getArgumentValue("--app-image"); } else { @@ -936,6 +936,51 @@ JPackageCommand assertAppLayout() { return this; } + private boolean expectAppImageFile() { + if (isRuntime()) { + return false; + } + + if (TKit.isOSX()) { + if (macSignPredefinedAppImage()) { + // Request to sign external app image, ".jpackage.xml" file should exist. + return true; + } + + if (!isImagePackageType() && hasArgument("--app-image")) { + // Build native macOS package from an external app image. + // If the external app image is signed, ".jpackage.xml" file should be kept, otherwise removed. + return AppImageFile.load(Path.of(getArgumentValue("--app-image"))).macSigned(); + } + } + + return isImagePackageType(); + } + + boolean macSignPredefinedAppImage() { + if (!TKit.isOSX()) { + throw new UnsupportedOperationException(); + } + return hasArgument("--mac-sign") && hasArgument("--app-image"); + } + + boolean macAppImageSigned() { + if (!TKit.isOSX()) { + throw new UnsupportedOperationException(); + } + + if (!hasArgument("--mac-sign")) { + return false; + } + + if (Optional.ofNullable(getArgumentValue("--app-image")).map(Path::of).map(AppImageFile::load).map(AppImageFile::macSigned).orElse(false)) { + // The external app image is signed, so the app image is signed too. + return true; + } + + return (hasArgument("--mac-signing-key-user-name") || hasArgument("--mac-app-image-sign-identity")); + } + private void assertAppImageFile() { Path appImageDir = Path.of(""); if (isImagePackageType() && hasArgument("--app-image")) { @@ -943,31 +988,26 @@ private void assertAppImageFile() { } final Path lookupPath = AppImageFile.getPathInAppImage(appImageDir); - if (isRuntime() || (!isImagePackageType() && !TKit.isOSX())) { + if (!expectAppImageFile()) { assertFileInAppImage(lookupPath, null); - } else if (!TKit.isOSX()) { - assertFileInAppImage(lookupPath, lookupPath); } else { assertFileInAppImage(lookupPath, lookupPath); - // If file exist validated important values based on arguments - // Exclude validation when we generating packages from predefined - // app images, since we do not know if image is signed or not. - if (isImagePackageType() || !hasArgument("--app-image")) { + if (TKit.isOSX()) { final Path rootDir = isImagePackageType() ? outputBundle() : pathToUnpackedPackageFile(appInstallationDirectory()); AppImageFile aif = AppImageFile.load(rootDir); - boolean expectedValue = hasArgument("--mac-sign"); + boolean expectedValue = macAppImageSigned(); boolean actualValue = aif.macSigned(); - TKit.assertEquals(Boolean.toString(expectedValue), Boolean.toString(actualValue), - "Check for unexptected value in app image file for "); + TKit.assertEquals(expectedValue, actualValue, + "Check for unexpected value of property in app image file"); expectedValue = hasArgument("--mac-app-store"); actualValue = aif.macAppStore(); - TKit.assertEquals(Boolean.toString(expectedValue), Boolean.toString(actualValue), - "Check for unexptected value in app image file for "); + TKit.assertEquals(expectedValue, actualValue, + "Check for unexpected value of property in app image file"); } } } @@ -1037,11 +1077,17 @@ JPackageCommand setUnpackedPackageLocation(Path path) { } JPackageCommand winMsiLogFile(Path v) { + if (!TKit.isWindows()) { + throw new UnsupportedOperationException(); + } this.winMsiLogFile = v; return this; } public Optional winMsiLogFile() { + if (!TKit.isWindows()) { + throw new UnsupportedOperationException(); + } return Optional.ofNullable(winMsiLogFile); } From 9211b776be2ef72b3dd2193a0eff4dc69004ad37 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 28 Mar 2025 17:08:18 -0400 Subject: [PATCH 0365/1101] Don't create app image file on macOS when not needed --- .../classes/jdk/jpackage/internal/MacAppImageBuilder.java | 5 +++++ .../jdk/jpackage/internal/AbstractAppImageBuilder.java | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java index dea7f4c4e2e8c..02860b61e4ff4 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -266,6 +266,11 @@ private void writeEntry(InputStream in, Path dstFile) throws IOException { Files.copy(in, dstFile); } + @Override + protected boolean withAppImageFile(Map params) { + return !withPackageFile; + } + @Override public void prepareApplicationFiles(Map params) throws IOException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java index b523e43f5aad8..9575e6ccb03c0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java @@ -66,6 +66,10 @@ public InputStream getResourceAsStream(String name) { public abstract void prepareApplicationFiles( Map params) throws IOException; + protected boolean withAppImageFile(Map params) { + return true; + } + protected void writeCfgFile(Map params) throws IOException { new CfgFile().initFromParams(params).create(root); @@ -96,7 +100,9 @@ protected void copyApplication(Map params) appLayout.appDirectory().toAbsolutePath(), excludes); } - AppImageFile.save(root, params); + if (withAppImageFile(params)) { + AppImageFile.save(root, params); + } List items = APP_CONTENT.fetchFrom(params); for (String item : items) { From 336fe3af2c4131800b7174d10965aa08c69ce987 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 28 Mar 2025 18:07:19 -0400 Subject: [PATCH 0366/1101] Strip ".jpackage.xml" from copied app image when permitted --- .../jdk/jpackage/internal/MacBaseInstallerBundler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index 1947cc0afda2c..a536019512a5d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -173,11 +173,11 @@ protected Path prepareAppBundle(Map params) FileUtils.copyRecursive(predefinedImage, appDir, LinkOption.NOFOLLOW_LINKS); - // Create PackageFile if predefined app image is not signed - if (!StandardBundlerParam.isRuntimeInstaller(params) && - !AppImageFile.load(predefinedImage).isSigned()) { + // Alter app image if predefined app image is not signed + if (!AppImageFile.load(predefinedImage).isSigned()) { new PackageFile(APP_NAME.fetchFrom(params)).save( ApplicationLayout.macAppImage().resolveAt(appDir)); + Files.deleteIfExists(AppImageFile.getPathInAppImage(appDir)); // We need to re-sign app image after adding ".package" to it. // We only do this if app image was not signed which means it is // signed with ad-hoc signature. App bundles with ad-hoc From b3c387ba5d607fd78e8dc343a16df8c768b6118d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 29 Mar 2025 09:09:06 -0400 Subject: [PATCH 0367/1101] Fix JPackageCommand.macAppImageSigned() and move it together with JPackageCommand.signPredefinedAppImage() to MacHelper class --- .../jdk/jpackage/test/JPackageCommand.java | 30 ++----------------- .../helpers/jdk/jpackage/test/MacHelper.java | 27 +++++++++++++++++ 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 977415d484aa5..fc5adf7fdea64 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -374,7 +374,7 @@ public Path outputBundle() { String dirName; if (!TKit.isOSX()) { dirName = name(); - } else if (macSignPredefinedAppImage()) { + } else if (MacHelper.signPredefinedAppImage(this)) { // Request to sign external app image, not to build a new one dirName = getArgumentValue("--app-image"); } else { @@ -942,7 +942,7 @@ private boolean expectAppImageFile() { } if (TKit.isOSX()) { - if (macSignPredefinedAppImage()) { + if (MacHelper.signPredefinedAppImage(this)) { // Request to sign external app image, ".jpackage.xml" file should exist. return true; } @@ -957,30 +957,6 @@ private boolean expectAppImageFile() { return isImagePackageType(); } - boolean macSignPredefinedAppImage() { - if (!TKit.isOSX()) { - throw new UnsupportedOperationException(); - } - return hasArgument("--mac-sign") && hasArgument("--app-image"); - } - - boolean macAppImageSigned() { - if (!TKit.isOSX()) { - throw new UnsupportedOperationException(); - } - - if (!hasArgument("--mac-sign")) { - return false; - } - - if (Optional.ofNullable(getArgumentValue("--app-image")).map(Path::of).map(AppImageFile::load).map(AppImageFile::macSigned).orElse(false)) { - // The external app image is signed, so the app image is signed too. - return true; - } - - return (hasArgument("--mac-signing-key-user-name") || hasArgument("--mac-app-image-sign-identity")); - } - private void assertAppImageFile() { Path appImageDir = Path.of(""); if (isImagePackageType() && hasArgument("--app-image")) { @@ -999,7 +975,7 @@ private void assertAppImageFile() { AppImageFile aif = AppImageFile.load(rootDir); - boolean expectedValue = macAppImageSigned(); + boolean expectedValue = MacHelper.appImageSigned(this); boolean actualValue = aif.macSigned(); TKit.assertEquals(expectedValue, actualValue, "Check for unexpected value of property in app image file"); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index 23d0ec80f1da1..4ecc0b818110a 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -33,6 +33,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.regex.Pattern; @@ -149,6 +150,32 @@ public static PListWrapper readPList(Stream lines) { .collect(Collectors.joining()))).get(); } + public static boolean signPredefinedAppImage(JPackageCommand cmd) { + Objects.requireNonNull(cmd); + if (!TKit.isOSX()) { + throw new UnsupportedOperationException(); + } + return cmd.hasArgument("--mac-sign") && cmd.hasArgument("--app-image"); + } + + public static boolean appImageSigned(JPackageCommand cmd) { + Objects.requireNonNull(cmd); + if (!TKit.isOSX()) { + throw new UnsupportedOperationException(); + } + + if (Optional.ofNullable(cmd.getArgumentValue("--app-image")).map(Path::of).map(AppImageFile::load).map(AppImageFile::macSigned).orElse(false)) { + // The external app image is signed, so the app image is signed too. + return true; + } + + if (!cmd.hasArgument("--mac-sign")) { + return false; + } + + return (cmd.hasArgument("--mac-signing-key-user-name") || cmd.hasArgument("--mac-app-image-sign-identity")); + } + static PackageHandlers createDmgPackageHandlers() { return new PackageHandlers(MacHelper::installDmg, MacHelper::uninstallDmg, MacHelper::unpackDmg); } From d5a3820791a576bb50e42be259c84ad12475dd9a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 31 Mar 2025 11:30:28 -0400 Subject: [PATCH 0368/1101] DEB packaging bugfix --- .../jpackage/internal/LinuxDebBundler.java | 2 +- .../internal/LinuxDebPackageBuilder.java | 8 +++---- .../internal/LinuxPackageBuilder.java | 12 +++++++--- .../jpackage/internal/LinuxRpmBundler.java | 4 ++-- .../internal/LinuxRpmPackageBuilder.java | 3 +++ .../internal/model/LinuxDebPackage.java | 22 +++++-------------- .../internal/model/LinuxDebPackageMixin.java | 2 +- .../jpackage/internal/model/LinuxPackage.java | 16 ++++++++++---- .../internal/model/LinuxPackageMixin.java | 16 ++++++++++---- 9 files changed, 49 insertions(+), 36 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index 491dc6f109971..852ffe644bfaf 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -326,7 +326,7 @@ private void prepareProjectConfig(Map data, BuildEnv env, LinuxP "resource.deb-postrm-script").setExecutable()); ((LinuxDebPackage)pkg).relativeCopyrightFilePath().ifPresent(copyrightFile -> { - debianFiles.add(new DebianFile(Path.of("/").resolve(copyrightFile), + debianFiles.add(new DebianFile(env.appImageDir().resolve(copyrightFile), "resource.copyright-file")); }); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java index 82acacc0e83f8..3fe7d758bba0f 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java @@ -27,8 +27,8 @@ import java.util.Objects; import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.LinuxRpmPackage; -import jdk.jpackage.internal.model.LinuxRpmPackageMixin; +import jdk.jpackage.internal.model.LinuxDebPackage; +import jdk.jpackage.internal.model.LinuxDebPackageMixin; final class LinuxDebPackageBuilder { @@ -36,9 +36,9 @@ final class LinuxDebPackageBuilder { this.pkgBuilder = Objects.requireNonNull(pkgBuilder); } - LinuxRpmPackage create() throws ConfigException { + LinuxDebPackage create() throws ConfigException { var pkg = pkgBuilder.create(); - return LinuxRpmPackage.create(pkg, new LinuxRpmPackageMixin.Stub( + return LinuxDebPackage.create(pkg, new LinuxDebPackageMixin.Stub( Optional.ofNullable(maintainerEmail).orElseGet( DEFAULTS::maintainerEmail))); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index 0499810ad3e8d..5fa5a4a7c7d9e 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -73,7 +73,7 @@ private LinuxPackage create(Package pkg, AppImageLayout pkgLayout) throws Config Optional.ofNullable(menuGroupName).orElseGet(DEFAULTS::menuGroupName), Optional.ofNullable(category).orElseGet(DEFAULTS::category), Optional.ofNullable(additionalDependencies), - Optional.ofNullable(release).orElseGet(DEFAULTS::release), + Optional.ofNullable(release), pkg.asStandardPackageType().map(LinuxPackageArch::getValue).orElseThrow())); } @@ -102,6 +102,10 @@ LinuxPackageBuilder release(String v) { return this; } + Optional release() { + return Optional.ofNullable(release); + } + private static LinuxApplicationLayout usrTreePackageLayout(Path prefix, String packageName) { final var lib = prefix.resolve(Path.of("lib", packageName)); return LinuxApplicationLayout.create( @@ -155,10 +159,12 @@ private static void validatePackageName(String packageName, .create(); } } + default -> { + } } } - private record Defaults(String release, String menuGroupName, String category) { + private record Defaults(String menuGroupName, String category) { } private String literalName; @@ -169,7 +175,7 @@ private record Defaults(String release, String menuGroupName, String category) { private final PackageBuilder pkgBuilder; - private static final Defaults DEFAULTS = new Defaults("1", I18N.getString( + private static final Defaults DEFAULTS = new Defaults(I18N.getString( "param.menu-group.default"), "misc"); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index 2031f527a03bb..f7d441092e70d 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -119,7 +119,7 @@ private static Path installPrefix(LinuxPackage pkg) { protected Map createReplacementData(BuildEnv env, LinuxPackage pkg) throws IOException { Map data = new HashMap<>(); - data.put("APPLICATION_RELEASE", pkg.release()); + data.put("APPLICATION_RELEASE", pkg.release().orElseThrow()); data.put("APPLICATION_PREFIX", installPrefix(pkg).toString()); data.put("APPLICATION_DIRECTORY", Path.of("/").resolve(pkg.relativeInstallDir()).toString()); data.put("APPLICATION_SUMMARY", pkg.packageName()); @@ -159,7 +159,7 @@ protected List verifyOutputBundle(BuildEnv env, LinuxPackage pk "APPLICATION_PACKAGE", specFileName), new PackageProperty("Version", pkg.version(), "APPLICATION_VERSION", specFileName), - new PackageProperty("Release", pkg.release(), + new PackageProperty("Release", pkg.release().orElseThrow(), "APPLICATION_RELEASE", specFileName), new PackageProperty("Arch", pkg.arch(), null, specFileName)); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java index 21adeead52140..7725012d61ffe 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java @@ -37,6 +37,9 @@ final class LinuxRpmPackageBuilder { } LinuxRpmPackage create() throws ConfigException { + if (pkgBuilder.release().isEmpty()) { + pkgBuilder.release("1"); + } var pkg = pkgBuilder.create(); return LinuxRpmPackage.create(pkg, new LinuxRpmPackageMixin.Stub( Optional.ofNullable(licenseType).orElseGet(DEFAULTS::licenseType))); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java index 6f8061e740b6f..77180975afe44 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java @@ -26,7 +26,6 @@ import java.nio.file.Path; import java.util.Optional; - import jdk.jpackage.internal.util.CompositeProxy; /** @@ -50,17 +49,6 @@ default String maintainer() { return String.format("%s <%s>", app().vendor(), maintainerEmail()); } - /** - * Gets the version with the release number of this DEB package. - * - * @see https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-version - * @return the version with the release number of this DEB package - */ - default String versionWithRelease() { - return String.format("%s-%s", version(), release()); - } - /** * Gets the relative path to this DEB package's copyright file. Returns empty * {@link Optional} instance if this DEB package has no copyright file. @@ -68,12 +56,12 @@ default String versionWithRelease() { * @return the relative path to the copyright file of this DEB package */ default Optional relativeCopyrightFilePath() { - if (isRuntimeInstaller()) { - return Optional.empty(); - } else if (isInstallDirInUsrTree() || Path.of("/").resolve(relativeInstallDir()).startsWith("/usr/")) { - return Optional.of(Path.of("/usr/share/doc/", packageName(), "copyright")); - } else { + if (isInstallDirInUsrTree() || Path.of("/").resolve(relativeInstallDir()).startsWith("/usr/")) { + return Optional.of(Path.of("usr/share/doc/", packageName(), "copyright")); + } else if (!isRuntimeInstaller()) { return Optional.of(relativeInstallDir().resolve("share/doc/copyright")); + } else { + return Optional.empty(); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java index eb7cbbdb26dda..b9202079a2fff 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java @@ -39,6 +39,6 @@ public interface LinuxDebPackageMixin { /** * Default implementation of {@link LinuxDebPackageMixin} interface. */ - record Stub(String maintainerEmail) { + record Stub(String maintainerEmail) implements LinuxDebPackageMixin { } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java index 4a92c50fdf341..aadca875361e6 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal.model; import java.nio.file.Path; - import jdk.jpackage.internal.util.CompositeProxy; /** @@ -43,10 +42,10 @@ default String packageFileName() { String packageFileNameTemlate = asStandardPackageType().map(stdType -> { switch (stdType) { case LINUX_DEB -> { - return "%s_%s-%s_%s"; + return "%s_%s_%s"; } case LINUX_RPM -> { - return "%s-%s-%s.%s"; + return "%s-%s.%s"; } default -> { throw new IllegalStateException(); @@ -54,7 +53,16 @@ default String packageFileName() { } }).orElseThrow(UnsupportedOperationException::new); - return String.format(packageFileNameTemlate, packageName(), version(), release(), arch()); + return String.format(packageFileNameTemlate, packageName(), versionWithRelease(), arch()); + } + + /** + * Gets the version with the release component of this Linux package. + * + * @return the version with the release component of this Linux package + */ + default String versionWithRelease() { + return String.format("%s%s", version(), release().map(r -> "-" + r).orElse("")); } /** diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java index cc0b19926c4a3..69f56385a760c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java @@ -64,11 +64,19 @@ public interface LinuxPackageMixin { Optional additionalDependencies(); /** - * Gets the release of this package. + * Gets the release of this package. Returns an empty {@link Optional} instance + * if this package doesn't have a release. + *

+ * For RPM packages, this is the value of a "Release" property in spec file. RPM + * packages always have a release. + *

+ * For DEB packages, this is an optional {@code debian_revision} component of a + * package version. See https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-version#. * * @return the release of this package */ - String release(); + Optional release(); /** * Gets the platform architecture of this package. @@ -81,7 +89,7 @@ public interface LinuxPackageMixin { * Default implementation of {@link LinuxPackageMixin} interface. */ record Stub(AppImageLayout packageLayout, String menuGroupName, - String category, Optional additionalDependencies, String release, - String arch) implements LinuxPackageMixin { + String category, Optional additionalDependencies, + Optional release, String arch) implements LinuxPackageMixin { } } From c179c549133a8a35ae32c55be9a4e7b4e361cc24 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 31 Mar 2025 13:18:42 -0400 Subject: [PATCH 0369/1101] whitespace cleanup --- .../classes/jdk/jpackage/internal/model/MacPackageMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackageMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackageMixin.java index 6a6af5d67331a..7a6c57ae3c028 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackageMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackageMixin.java @@ -39,7 +39,7 @@ public interface MacPackageMixin { *

* Returns any empty {@link Optional} instance if the predefined app image is * unavailable. - * + * * @return sign status of the predefined app image if any */ Optional predefinedAppImageSigned(); From 57fb80a15843a7da117dfceecf3c999f25da7049 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 31 Mar 2025 14:23:11 -0400 Subject: [PATCH 0370/1101] All mac signing tests pass --- .../jdk/jpackage/internal/MacPackagingPipeline.java | 10 ++-------- .../jdk/jpackage/internal/PackagingPipeline.java | 11 ++++++----- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index f34b1e838b521..89f6a4582f1f1 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -194,9 +194,9 @@ static Package createSignAppImagePackage(MacApplication app, BuildEnv env) { }).get(); } - private static void copyAppImage(Package pkg, AppImageDesc srcAppImage, + private static void copyAppImage(MacPackage pkg, AppImageDesc srcAppImage, AppImageDesc dstAppImage) throws IOException { - PackagingPipeline.copyAppImage(srcAppImage, dstAppImage, false/*!((MacApplication)pkg.app()).sign()*/); + PackagingPipeline.copyAppImage(srcAppImage, dstAppImage, !pkg.predefinedAppImageSigned().orElse(false)); } private static void copyJliLib( @@ -409,12 +409,6 @@ private record TaskContextProxy(TaskContext delegate, boolean forApp, boolean co @Override public boolean test(TaskID taskID) { - if (!forApp && !copyAppImage && taskID == BuildApplicationTaskID.APP_IMAGE_FILE) { - // Always create ".jpackage.xml" if not copying predefined app image for compatibility with the tests - // TODO: Don't create ".jpackage.xml" when bundling a package like on other platforms - return true; - } - if (!delegate.test(taskID)) { return false; } else if (taskID == MacBuildApplicationTaskID.PACKAGE_FILE) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java index 9e9e924d16f8d..7dd0ec216de31 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java @@ -134,8 +134,8 @@ interface AppImageTaskAction ex } @FunctionalInterface - interface CopyAppImageTaskAction extends TaskAction { - void execute(Package pkg, AppImageDesc srcAppImage, AppImageDesc dstAppImage) throws IOException, PackagerException; + interface CopyAppImageTaskAction extends TaskAction { + void execute(T pkg, AppImageDesc srcAppImage, AppImageDesc dstAppImage) throws IOException, PackagerException; } @FunctionalInterface @@ -183,7 +183,7 @@ TaskBuilder appImageAction(App return setAction(action); } - TaskBuilder copyAction(CopyAppImageTaskAction action) { + TaskBuilder copyAction(CopyAppImageTaskAction action) { return setAction(action); } @@ -514,8 +514,9 @@ public boolean test(TaskID taskID) { public void execute(TaskAction taskAction) throws IOException, PackagerException { if (taskAction instanceof PackageTaskAction) { ((PackageTaskAction)taskAction).execute(env); - } else if (taskAction instanceof CopyAppImageTaskAction copyAction) { - copyAction.execute(env.pkg(), srcAppImage, new AppImageDesc(env.envLayout(), env.env().appImageDir())); + } else if (taskAction instanceof CopyAppImageTaskAction) { + ((CopyAppImageTaskAction)taskAction).execute(env.pkg(), + srcAppImage, new AppImageDesc(env.envLayout(), env.env().appImageDir())); } else { throw new IllegalArgumentException(); } From 717979e933b9acc5dcf1f5e1cb2cce132cdf9eb2 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 31 Mar 2025 17:12:20 -0400 Subject: [PATCH 0371/1101] Move ErrorTest.testAppContentWarning() to signing tests --- .../helpers/jdk/jpackage/test/MacSign.java | 2 +- .../tools/jpackage/macosx/MacSignTest.java | 86 +++++++++++++++++++ .../jpackage/macosx/base/SigningBase.java | 37 ++++++-- test/jdk/tools/jpackage/share/ErrorTest.java | 29 ------- 4 files changed, 116 insertions(+), 38 deletions(-) create mode 100644 test/jdk/tools/jpackage/macosx/MacSignTest.java diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java index 1efae8a055c13..1d5dd16fe3730 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java @@ -287,7 +287,7 @@ public Builder password(String v) { } public Builder addCert(CertificateRequest v) { - certs.add(v); + certs.add(Objects.requireNonNull(v)); return this; } diff --git a/test/jdk/tools/jpackage/macosx/MacSignTest.java b/test/jdk/tools/jpackage/macosx/MacSignTest.java new file mode 100644 index 0000000000000..4313f1900e294 --- /dev/null +++ b/test/jdk/tools/jpackage/macosx/MacSignTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.CannedFormattedString; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageStringBundle; +import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.TKit; + +/* + * @test + * @summary jpackage with --mac-sign + * @library /test/jdk/tools/jpackage/helpers + * @library base + * @build SigningBase + * @build jdk.jpackage.test.* + * @build MacSignTest + * @requires (jpackage.test.MacSignTests == "run") + * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=MacSignTest + * --jpt-before-run=SigningBase.verifySignTestEnvReady + */ +public class MacSignTest { + + @Test + public static void testAppContentWarning() throws IOException { + + // Create app content directory with the name known to fail signing. + // This will trigger jpackage exit with status code "1". + final var appContent = TKit.createTempDirectory("app-content").resolve("foo.1"); + Files.createDirectory(appContent); + Files.createFile(appContent.resolve("file")); + + final List expectedStrings = new ArrayList<>(); + expectedStrings.add(JPackageStringBundle.MAIN.cannedFormattedString("message.codesign.failed.reason.app.content")); + + final var xcodeWarning = JPackageStringBundle.MAIN.cannedFormattedString("message.codesign.failed.reason.xcode.tools"); + if (!MacHelper.isXcodeDevToolsInstalled()) { + expectedStrings.add(xcodeWarning); + } + + // --app-content and --type app-image + // Expect `message.codesign.failed.reason.app.content` message in the log. + // This is not a fatal error, just a warning. + // To make jpackage fail, specify bad additional content. + final var cmd = JPackageCommand.helloAppImage() + .ignoreDefaultVerbose(true) + .validateOutput(expectedStrings.toArray(CannedFormattedString[]::new)) + .addArguments("--app-content", appContent) + .addArguments("--mac-sign") + .addArguments("--mac-signing-keychain", SigningBase.StandardKeychain.MAIN.spec().keychain().name()) + .addArguments("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.APP_IMAGE.spec().name()); + + if (MacHelper.isXcodeDevToolsInstalled()) { + // Check there is no warning about missing xcode command line developer tools. + cmd.validateOutput(TKit.assertTextStream(xcodeWarning.getValue()).negate()); + } + + cmd.execute(1); + } +} diff --git a/test/jdk/tools/jpackage/macosx/base/SigningBase.java b/test/jdk/tools/jpackage/macosx/base/SigningBase.java index d188a57dbd8f4..e3237197c7422 100644 --- a/test/jdk/tools/jpackage/macosx/base/SigningBase.java +++ b/test/jdk/tools/jpackage/macosx/base/SigningBase.java @@ -63,12 +63,33 @@ public class SigningBase { - enum StandardKeychain { - MAIN(DEFAULT_KEYCHAIN, - cert().userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()]).create(), - cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()]).create(), - cert().userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()]).create(), - cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()]).create()); + public enum StandardCertificateRequest { + APP_IMAGE(cert().userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), + INSTALLER(cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), + APP_IMAGE_UNICODE(cert().userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()])), + INSTALLER_UNICODE(cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()])); + + StandardCertificateRequest(CertificateRequest.Builder specBuilder) { + this.spec = specBuilder.create(); + } + + public CertificateRequest spec() { + return spec; + } + + private static CertificateRequest.Builder cert() { + return new CertificateRequest.Builder(); + } + + private final CertificateRequest spec; + } + + public enum StandardKeychain { + MAIN(DEFAULT_KEYCHAIN, StandardCertificateRequest.values()); + + StandardKeychain(String keychainName, StandardCertificateRequest... certs) { + this(keychainName, certs[0].spec(), Stream.of(certs).skip(1).map(StandardCertificateRequest::spec).toArray(CertificateRequest[]::new)); + } StandardKeychain(String keychainName, CertificateRequest cert, CertificateRequest... otherCerts) { final var builder = keychain(keychainName).addCert(cert); @@ -76,7 +97,7 @@ enum StandardKeychain { this.spec = builder.create(); } - KeychainWithCertsSpec spec() { + public KeychainWithCertsSpec spec() { return spec; } @@ -92,7 +113,7 @@ private static List signingEnv() { return Stream.of(values()).map(StandardKeychain::spec).toList(); } - final KeychainWithCertsSpec spec; + private final KeychainWithCertsSpec spec; } public static void setUp() { diff --git a/test/jdk/tools/jpackage/share/ErrorTest.java b/test/jdk/tools/jpackage/share/ErrorTest.java index 59b0ccb4bd7b5..9590115a2a1d8 100644 --- a/test/jdk/tools/jpackage/share/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/ErrorTest.java @@ -47,7 +47,6 @@ import jdk.jpackage.test.CannedFormattedString; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageStringBundle; -import jdk.jpackage.test.MacHelper; import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; @@ -558,34 +557,6 @@ public static Collection testMac() { return toTestArgs(testCases.stream()); } - @Test(ifOS = MACOS) - public static void testAppContentWarning() { - // --app-content and --type app-image - // Expect `message.codesign.failed.reason.app.content` message in the log. - // This is not a fatal error, just a warning. - // To make jpackage fail, specify invalid signing identity. - final var cmd = JPackageCommand.helloAppImage() - .addArguments("--app-content", TKit.TEST_SRC_ROOT.resolve("apps/dukeplug.png")) - .addArguments("--mac-sign", "--mac-app-image-sign-identity", "foo"); - - final List expectedStrings = new ArrayList<>(); - expectedStrings.add(JPackageStringBundle.MAIN.cannedFormattedString("message.codesign.failed.reason.app.content")); - - final var xcodeWarning = JPackageStringBundle.MAIN.cannedFormattedString("message.codesign.failed.reason.xcode.tools"); - if (!MacHelper.isXcodeDevToolsInstalled()) { - expectedStrings.add(xcodeWarning); - } - - defaultInit(cmd, expectedStrings); - - if (MacHelper.isXcodeDevToolsInstalled()) { - // Check there is no warning about missing xcode command line developer tools. - cmd.validateOutput(TKit.assertTextStream(xcodeWarning.getValue()).negate()); - } - - cmd.execute(1); - } - public static Collection testLinux() { final List testCases = new ArrayList<>(); From 7d4bd99a648fefee6b09dd1b9c3c34a42e2075e2 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 31 Mar 2025 18:53:15 -0400 Subject: [PATCH 0372/1101] Fix ExecutableRebrander. It never worked for embedding msi in exe installer --- .../internal/ExecutableRebrander.java | 56 ++++++++----------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java index 5422047aa5765..69e25041a8f78 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java @@ -24,10 +24,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.WinExePackage; -import jdk.jpackage.internal.model.WinLauncher; -import jdk.jpackage.internal.model.WinApplication; -import jdk.jpackage.internal.model.DottedVersion; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -37,15 +33,19 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.text.MessageFormat; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Properties; -import java.util.ResourceBundle; import java.util.function.Function; import java.util.stream.Stream; +import jdk.jpackage.internal.model.DottedVersion; +import jdk.jpackage.internal.model.WinApplication; +import jdk.jpackage.internal.model.WinExePackage; +import jdk.jpackage.internal.model.WinLauncher; @SuppressWarnings("restricted") final class ExecutableRebrander { @@ -62,15 +62,15 @@ final class ExecutableRebrander { Function resourceSupplier, UpdateResourceAction... extraActions) { this(ExecutableProperties.create(app, launcher), resourceSupplier.apply( - "WinLauncher.template").setPublicName( - launcher.executableName() + ".properties"), extraActions); + "WinLauncher.template").setPublicName(launcher.executableName() + ".properties"), + extraActions); } private ExecutableRebrander(ExecutableProperties props, OverridableResource propertiesFileResource, UpdateResourceAction... extraActions) { this.extraActions = List.of(extraActions); - this.propertiesFileResource = propertiesFileResource; + this.propertiesFileResource = Objects.requireNonNull(propertiesFileResource); this.props = new HashMap<>(); @@ -90,8 +90,7 @@ void execute(BuildEnv env, Path target, Optional icon) { UpdateResourceAction versionSwapper = resourceLock -> { if (versionSwap(resourceLock, propsArray) != 0) { - throw new RuntimeException(MessageFormat.format(I18N.getString( - "error.version-swap"), target)); + throw I18N.buildException().message("error.version-swap", target).create(RuntimeException::new); } }; @@ -101,32 +100,30 @@ void execute(BuildEnv env, Path target, Optional icon) { .map(absIcon -> { return resourceLock -> { if (iconSwap(resourceLock, absIcon.toString()) != 0) { - throw new RuntimeException(MessageFormat.format( - I18N.getString("error.icon-swap"), absIcon)); + throw I18N.buildException().message("error.icon-swap", absIcon).create(RuntimeException::new); } }; }); try { - if (updateIcon.isEmpty()) { - rebrandExecutable(env, target, versionSwapper); - } else { - rebrandExecutable(env, target, versionSwapper, updateIcon.orElseThrow()); - } + final List actions = new ArrayList<>(); + actions.add(versionSwapper); + updateIcon.ifPresent(actions::add); + actions.addAll(extraActions); + rebrandExecutable(env, target, actions); } catch (IOException ex) { throw new UncheckedIOException(ex); } } - private static void rebrandExecutable(BuildEnv env, - final Path target, UpdateResourceAction ... actions) throws IOException { + private static void rebrandExecutable(BuildEnv env, final Path target, + List actions) throws IOException { + Objects.requireNonNull(actions); + actions.forEach(Objects::requireNonNull); try { String tempDirectory = env.buildRoot().toAbsolutePath().toString(); - if (WindowsDefender.isThereAPotentialWindowsDefenderIssue( - tempDirectory)) { - Log.verbose(MessageFormat.format(I18N.getString( - "message.potential.windows.defender.issue"), - tempDirectory)); + if (WindowsDefender.isThereAPotentialWindowsDefenderIssue(tempDirectory)) { + Log.verbose(I18N.format("message.potential.windows.defender.issue", tempDirectory)); } target.toFile().setWritable(true, true); @@ -134,8 +131,7 @@ private static void rebrandExecutable(BuildEnv env, var shortTargetPath = ShortPathUtils.toShortPath(target); long resourceLock = lockResource(shortTargetPath.orElse(target).toString()); if (resourceLock == 0) { - throw new RuntimeException(MessageFormat.format( - I18N.getString("error.lock-resource"), shortTargetPath.orElse(target))); + throw I18N.buildException().message("error.lock-resource", shortTargetPath.orElse(target)).create(RuntimeException::new); } final boolean resourceUnlockedSuccess; @@ -160,8 +156,7 @@ private static void rebrandExecutable(BuildEnv env, } if (!resourceUnlockedSuccess) { - throw new RuntimeException(MessageFormat.format(I18N.getString( - "error.unlock-resource"), target)); + throw I18N.buildException().message("error.unlock-resource", target).create(RuntimeException::new); } } finally { target.toFile().setReadOnly(); @@ -243,9 +238,6 @@ static ExecutableProperties create(WinExePackage pkg) { private final List extraActions; private final OverridableResource propertiesFileResource; - private static final ResourceBundle I18N = ResourceBundle.getBundle( - "jdk.jpackage.internal.resources.WinResources"); - static { System.loadLibrary("jpackage"); } From 591c7833c9311f4debd04c209ad7ac56ec99d623 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 31 Mar 2025 19:25:36 -0400 Subject: [PATCH 0373/1101] Remove redundant imports from Arguments --- .../share/classes/jdk/jpackage/internal/Arguments.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java index 5981ef2ffbd11..f0abe85b04d5e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java @@ -32,7 +32,6 @@ import java.io.Reader; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.text.MessageFormat; import java.util.ArrayList; import java.util.EnumSet; @@ -44,7 +43,6 @@ import java.util.ResourceBundle; import java.util.regex.Matcher; import java.util.regex.Pattern; -import jdk.jpackage.internal.util.function.ExceptionBox; /** * Arguments From fe8f5f5995ef6cd0302780e4fecf045582385107 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 31 Mar 2025 19:48:39 -0400 Subject: [PATCH 0374/1101] Fix AppImageSigner to not sign only the main launcher and sign additional launchers --- .../jdk/jpackage/internal/AppImageSigner.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java index 2a7aff8729e77..d7b2431c1d3a9 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java @@ -41,6 +41,8 @@ import java.util.stream.Stream; import jdk.jpackage.internal.Codesign.CodesignException; import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.function.ExceptionBox; @@ -63,21 +65,22 @@ static Consumer createSigner(MacApplication app, CodesignConfig signingCfg }); } - static Consumer createUnsigner(MacApplication app) { - return toConsumer(appImage -> { - new AppImageSigner(Codesigners.nop()).sign(app, appImage); - }); - } - - static final class SignFilter implements Predicate { + private static final class SignFilter implements Predicate { SignFilter(Application app, Path appImage) { Objects.requireNonNull(appImage); + + // Don't explicitly sign main launcher. It will be implicitly signed when the bundle is signed. + otherExcludePaths = app.asApplicationLayout().map(appLayout -> { + return appLayout.resolveAt(appImage); + }).map(ApplicationLayout::launchersDirectory).flatMap(launchersDir -> { + return app.mainLauncher().map(Launcher::executableNameWithSuffix).map(launchersDir::resolve); + }).map(Set::of).orElseGet(Set::of); } @Override public boolean test(Path path) { - if (!Files.isRegularFile(path)) { + if (!Files.isRegularFile(path) || otherExcludePaths.contains(path)) { return false; } @@ -91,6 +94,8 @@ public boolean test(Path path) { return false; } + + private final Set otherExcludePaths; } private void sign(MacApplication app, Path appImage) throws CodesignException, IOException { @@ -219,11 +224,6 @@ private Optional> findCodesigner(Path path) { return Optional.empty(); } - static Codesigners nop() { - Consumer nop = path -> {}; - return new Codesigners(nop, nop, nop); - } - static Codesigners create(CodesignConfig signingCfg) { final var signingCfgWithoutEntitlements = CodesignConfig.build().from(signingCfg).entitlements(null).create(); From 4ac53db7f70e52b158cadd799eeacd73c24950b1 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 31 Mar 2025 20:03:40 -0400 Subject: [PATCH 0375/1101] Revert copyright year update --- .../classes/jdk/jpackage/internal/MacPkgInstallerScripts.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java index 6877d4568dd10..a1e153dd7fe89 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgInstallerScripts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 From a3779c48e6b69115b19c4e1df47eacd90d99f28d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 31 Mar 2025 20:23:43 -0400 Subject: [PATCH 0376/1101] Fix typo --- .../jdk/jpackage/internal/util/PListReaderTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java index bae4921fda33c..d766505cf1430 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java @@ -51,7 +51,7 @@ public class PListReaderTest { enum QueryType { STRING(PListReader::queryValue), BOOLEAN(PListReader::queryBoolValue), - STRING_ARRY(PListReader::queryArrayValue); + STRING_ARRAY(PListReader::queryArrayValue); QueryType(BiFunction queryMethod) { this.queryMethod = Objects.requireNonNull(queryMethod); @@ -98,7 +98,7 @@ Builder expectedValue(Object v) { } else if (v instanceof Boolean) { queryType(QueryType.BOOLEAN); } else if (v instanceof List) { - queryType(QueryType.STRING_ARRY); + queryType(QueryType.STRING_ARRAY); } return this; } @@ -196,7 +196,7 @@ public void testWrongValueType(QueryType queryType) { testSpecs.add(builder.keyName("string-key").create()); testSpecs.add(builder.keyName("array-key").create()); } - case STRING_ARRY -> { + case STRING_ARRAY -> { testSpecs.add(builder.keyName("string-key").create()); testSpecs.add(builder.keyName("boolean-true-key").create()); testSpecs.add(builder.keyName("boolean-false-key").create()); @@ -230,7 +230,7 @@ private static List testQueryValue() { testSpec(QueryType.BOOLEAN).xml("foo").create(), testSpec().expectedValue(List.of("foo", "bar")).xml("foofoobar").create(), testSpec().expectedValue(List.of()).xml("foo").create(), - testSpec(QueryType.STRING_ARRY).xml("foo").create(), + testSpec(QueryType.STRING_ARRAY).xml("foo").create(), testSpec().expectedValue("A").xml("fooAB").create(), testSpec().expectedValue("A").xml("fooAfooB").create() ); From bfe05fbbd50d3383b6fedfc844523d3eb0e4d6c5 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 31 Mar 2025 20:37:08 -0400 Subject: [PATCH 0377/1101] Rollback BasicTest local build tweaks --- test/jdk/tools/jpackage/share/BasicTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/tools/jpackage/share/BasicTest.java b/test/jdk/tools/jpackage/share/BasicTest.java index 90aec7d6b6b61..fe988533a28bd 100644 --- a/test/jdk/tools/jpackage/share/BasicTest.java +++ b/test/jdk/tools/jpackage/share/BasicTest.java @@ -46,7 +46,7 @@ import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.internal.util.function.ThrowingConsumer; -//import jdk.tools.jlink.internal.LinkableRuntimeImage; +import jdk.tools.jlink.internal.LinkableRuntimeImage; import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE_AND_UNPACK; /* @@ -79,7 +79,7 @@ public static Collection addModulesParams() { private static boolean isAllModulePathCapable() { Path jmods = Path.of(System.getProperty("java.home"), "jmods"); boolean noJmods = Files.notExists(jmods); - if (noJmods) { + if (LinkableRuntimeImage.isLinkableRuntime() && noJmods) { TKit.trace("ALL-MODULE-PATH test skipped for linkable run-time image"); return false; } From efa4f19e854ac8faaa3c16320cd5a9e9bd6d6485 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 1 Apr 2025 13:44:18 -0400 Subject: [PATCH 0378/1101] Remove redundant XmlUtils.elementValue() --- .../classes/jdk/jpackage/internal/AppImageFile.java | 2 +- .../classes/jdk/jpackage/internal/util/XmlUtils.java | 11 ----------- .../jdk/jpackage/internal/AppImageFileTest.java | 2 +- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index aa4a866e14b68..4200ec9fbccb6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -286,7 +286,7 @@ private static Map queryProperties(Element e, XPath xPath, Stri return XmlUtils.queryNodes(e, xPath, xpathExpr) .map(Element.class::cast) .collect(toMap(Node::getNodeName, selectedElement -> { - return XmlUtils.elementValue(selectedElement, xPath); + return selectedElement.getTextContent(); }, (a, b) -> b)); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java index e1320ad7aca2a..c78101c124504 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java @@ -31,7 +31,6 @@ import java.nio.file.Path; import java.util.Collection; import java.util.Optional; -import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; import javax.xml.parsers.DocumentBuilder; @@ -48,7 +47,6 @@ import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; -import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -137,13 +135,4 @@ public static Stream toStream(NamedNodeMap nodes) { return IntStream.range(0, v.getLength()).mapToObj(v::item); }).orElseGet(Stream::of); } - - public static String elementValue(Element e, XPath xPath) { - try { - return queryNodes(e, xPath, "text()").map(Node::getNodeValue).collect(Collectors.joining()); - } catch (XPathExpressionException ex) { - // Should never happen - throw new RuntimeException(ex); - } - } } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java index 09456abe58478..85424f51ebfcd 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java @@ -229,7 +229,7 @@ private static Stream testValidXml() { "ab", "foofootrue", "false", - "") + "AB") ) ); } From 8bc74d356bb8221289981b58a6801213f2189cf9 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 2 Apr 2025 12:24:05 -0400 Subject: [PATCH 0379/1101] Fix imports --- .../jdk/jpackage/internal/AppImageBundler.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java index d46856be409b3..92d2d6d1d1f1e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java @@ -25,9 +25,9 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.PackagerException; -import jdk.internal.util.OperatingSystem; +import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_DATA; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; import java.io.IOException; import java.nio.file.Files; @@ -35,10 +35,9 @@ import java.text.MessageFormat; import java.util.Map; import java.util.Objects; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_DATA; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; class AppImageBundler extends AbstractBundler { From ebcb9a8b128cc6411610566c8368db63d25a5127 Mon Sep 17 00:00:00 2001 From: David Beaumont Date: Thu, 3 Apr 2025 20:11:19 +0000 Subject: [PATCH 0380/1101] 8349206: j.u.l.Handler classes create deadlock risk via synchronized publish() method Reviewed-by: dfuchs, smarks --- .../java/util/logging/ConsoleHandler.java | 6 + .../java/util/logging/FileHandler.java | 13 +- .../classes/java/util/logging/Handler.java | 23 +- .../java/util/logging/SocketHandler.java | 13 +- .../java/util/logging/StreamHandler.java | 52 ++++- .../Handler/StreamHandlerLockingTest.java | 105 +++++++++ .../java/util/logging/TestStreamHandler.java | 54 +++++ .../java/util/logging/LoggingDeadlock5.java | 202 ++++++++++++++++++ 8 files changed, 445 insertions(+), 23 deletions(-) create mode 100644 test/jdk/java/util/logging/Handler/StreamHandlerLockingTest.java create mode 100644 test/jdk/java/util/logging/Handler/java.logging/java/util/logging/TestStreamHandler.java create mode 100644 test/jdk/java/util/logging/LoggingDeadlock5.java diff --git a/src/java.logging/share/classes/java/util/logging/ConsoleHandler.java b/src/java.logging/share/classes/java/util/logging/ConsoleHandler.java index cab4805b9e739..1561c7edebf44 100644 --- a/src/java.logging/share/classes/java/util/logging/ConsoleHandler.java +++ b/src/java.logging/share/classes/java/util/logging/ConsoleHandler.java @@ -87,6 +87,12 @@ public ConsoleHandler() { * The logging request was made initially to a {@code Logger} object, * which initialized the {@code LogRecord} and forwarded it here. * + * @implSpec This method is not synchronized, and subclasses must not define + * overridden {@code publish()} methods to be {@code synchronized} if they + * call {@code super.publish()} or format user arguments. See the + * {@linkplain Handler##threadSafety discussion in java.util.logging.Handler} + * for more information. + * * @param record description of the log event. A null record is * silently ignored and is not published */ diff --git a/src/java.logging/share/classes/java/util/logging/FileHandler.java b/src/java.logging/share/classes/java/util/logging/FileHandler.java index 3c36a21516c07..99afe7261b1e7 100644 --- a/src/java.logging/share/classes/java/util/logging/FileHandler.java +++ b/src/java.logging/share/classes/java/util/logging/FileHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -739,11 +739,14 @@ private synchronized void rotate() { * silently ignored and is not published */ @Override - public synchronized void publish(LogRecord record) { - if (!isLoggable(record)) { - return; - } + public void publish(LogRecord record) { super.publish(record); + } + + @Override + void synchronousPostWriteHook() { + // no need to synchronize here, this method is called from within a + // synchronized block. flush(); if (limit > 0 && (meter.written >= limit || meter.written < 0)) { rotate(); diff --git a/src/java.logging/share/classes/java/util/logging/Handler.java b/src/java.logging/share/classes/java/util/logging/Handler.java index 7b93e517e972a..8e5b3ee0a4f3c 100644 --- a/src/java.logging/share/classes/java/util/logging/Handler.java +++ b/src/java.logging/share/classes/java/util/logging/Handler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,10 +43,25 @@ * and {@code Level}. See the specific documentation for each concrete * {@code Handler} class. * + *

Thread Safety and Deadlock Risk in Handlers

+ * + * Implementations of {@code Handler} should be thread-safe. Handlers are + * expected to be invoked concurrently from arbitrary threads. However, + * over-use of synchronization may result in unwanted thread contention, + * performance issues or even deadlocking. + *

+ * In particular, subclasses should avoid acquiring locks around code which + * calls back to arbitrary user-supplied objects, especially during log record + * formatting. Holding a lock around any such callbacks creates a deadlock risk + * between logging code and user code. + *

+ * As such, general purpose {@code Handler} subclasses should not synchronize + * their {@link #publish(LogRecord)} methods, or call {@code super.publish()} + * while holding locks, since these are typically expected to need to process + * and format user-supplied arguments. * * @since 1.4 */ - public abstract class Handler { private static final int offValue = Level.OFF.intValue(); @@ -123,6 +138,10 @@ protected Handler() { } *

* The {@code Handler} is responsible for formatting the message, when and * if necessary. The formatting should include localization. + *

+ * @apiNote To avoid the risk of deadlock, implementations of this method + * should avoid holding any locks while calling out to application code, + * such as the formatting of {@code LogRecord}. * * @param record description of the log event. A null record is * silently ignored and is not published diff --git a/src/java.logging/share/classes/java/util/logging/SocketHandler.java b/src/java.logging/share/classes/java/util/logging/SocketHandler.java index 380cc20add44f..d20d857035777 100644 --- a/src/java.logging/share/classes/java/util/logging/SocketHandler.java +++ b/src/java.logging/share/classes/java/util/logging/SocketHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -168,14 +168,17 @@ public synchronized void close() { /** * Format and publish a {@code LogRecord}. * + * @implSpec This method is not synchronized, and subclasses must not define + * overridden {@code publish()} methods to be {@code synchronized} if they + * call {@code super.publish()} or format user arguments. See the + * {@linkplain Handler##threadSafety discussion in java.util.logging.Handler} + * for more information. + * * @param record description of the log event. A null record is * silently ignored and is not published */ @Override - public synchronized void publish(LogRecord record) { - if (!isLoggable(record)) { - return; - } + public void publish(LogRecord record) { super.publish(record); flush(); } diff --git a/src/java.logging/share/classes/java/util/logging/StreamHandler.java b/src/java.logging/share/classes/java/util/logging/StreamHandler.java index 31cb6605fbc79..5fc70b5dde9c3 100644 --- a/src/java.logging/share/classes/java/util/logging/StreamHandler.java +++ b/src/java.logging/share/classes/java/util/logging/StreamHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -180,17 +180,31 @@ public synchronized void setEncoding(String encoding) * {@code OutputStream}, the {@code Formatter}'s "head" string is * written to the stream before the {@code LogRecord} is written. * + * @implSpec This method avoids acquiring locks during {@code LogRecord} + * formatting, but {@code this} instance is synchronized when writing to the + * output stream. To avoid deadlock risk, subclasses must not hold locks + * while calling {@code super.publish()}. Specifically, subclasses must + * not define the overridden {@code publish()} method to be + * {@code synchronized} if they call {@code super.publish()}. + * * @param record description of the log event. A null record is * silently ignored and is not published */ @Override - public synchronized void publish(LogRecord record) { - if (!isLoggable(record)) { + public void publish(LogRecord record) { + if (!isLoggable(record)) { return; } + // Read once for consistency (whether in or outside the locked region + // is not important). + Formatter formatter = getFormatter(); + // JDK-8349206: To avoid deadlock risk, it is essential that the handler + // is not locked while formatting the log record. Methods such as + // reportError() and isLoggable() are defined to be thread safe, so we + // can restrict locking to just writing the message. String msg; try { - msg = getFormatter().format(record); + msg = formatter.format(record); } catch (Exception ex) { // We don't want to throw an exception here, but we // report the exception to any registered ErrorManager. @@ -199,12 +213,15 @@ public synchronized void publish(LogRecord record) { } try { - Writer writer = this.writer; - if (!doneHeader) { - writer.write(getFormatter().getHead(this)); - doneHeader = true; + synchronized(this) { + Writer writer = this.writer; + if (!doneHeader) { + writer.write(formatter.getHead(this)); + doneHeader = true; + } + writer.write(msg); + synchronousPostWriteHook(); } - writer.write(msg); } catch (Exception ex) { // We don't want to throw an exception here, but we // report the exception to any registered ErrorManager. @@ -212,6 +229,17 @@ public synchronized void publish(LogRecord record) { } } + /** + * Overridden by other handlers in this package to facilitate synchronous + * post-write behaviour. If other handlers need similar functionality, it + * might be feasible to make this method protected (see JDK-8349206), but + * please find a better name if you do ;). + */ + void synchronousPostWriteHook() { + // Empty by default. We could do: + // assert Thread.holdsLock(this); + // but this is already covered by unit tests. + } /** * Check if this {@code Handler} would actually log a given {@code LogRecord}. @@ -249,15 +277,17 @@ public synchronized void flush() { } } + // Called synchronously with "this" handler instance locked. private void flushAndClose() { Writer writer = this.writer; if (writer != null) { + Formatter formatter = getFormatter(); try { if (!doneHeader) { - writer.write(getFormatter().getHead(this)); + writer.write(formatter.getHead(this)); doneHeader = true; } - writer.write(getFormatter().getTail(this)); + writer.write(formatter.getTail(this)); writer.flush(); writer.close(); } catch (Exception ex) { diff --git a/test/jdk/java/util/logging/Handler/StreamHandlerLockingTest.java b/test/jdk/java/util/logging/Handler/StreamHandlerLockingTest.java new file mode 100644 index 0000000000000..bc137ea431515 --- /dev/null +++ b/test/jdk/java/util/logging/Handler/StreamHandlerLockingTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8349206 + * @summary j.u.l.Handler classes create deadlock risk via synchronized publish() method. + * @modules java.base/sun.util.logging + * java.logging + * @build java.logging/java.util.logging.TestStreamHandler + * @run main/othervm StreamHandlerLockingTest + */ + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.logging.Formatter; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.TestStreamHandler; + +public class StreamHandlerLockingTest { + static class TestFormatter extends Formatter { + final Handler handler; + + TestFormatter(Handler handler) { + this.handler = handler; + } + + @Override + public String format(LogRecord record) { + if (Thread.holdsLock(handler)) { + throw new AssertionError("format() was called with handler locked (bad)."); + } + return record.getMessage() + "\n"; + } + + @Override + public String getHead(Handler h) { + // This is currently true, and not easy to make unsynchronized. + if (!Thread.holdsLock(handler)) { + throw new AssertionError("getHead() expected to be called with handler locked."); + } + return "--HEAD--\n"; + } + + @Override + public String getTail(Handler h) { + // This is currently true, and not easy to make unsynchronized. + if (!Thread.holdsLock(handler)) { + throw new AssertionError("getTail() expected to be called with handler locked."); + } + return "--TAIL--\n"; + } + } + + private static final String EXPECTED_LOG = + String.join("\n","--HEAD--", "Hello World", "Some more logging...", "And we're done!", "--TAIL--", ""); + + public static void main(String[] args) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + TestStreamHandler handler = new TestStreamHandler(out); + TestFormatter formatter = new TestFormatter(handler); + handler.setFormatter(formatter); + + handler.publish(log("Hello World")); + handler.publish(log("Some more logging...")); + handler.publish(log("And we're done!")); + handler.close(); + + // Post write callback should have happened once per publish call (with lock held). + if (handler.callbackCount != 3) { + throw new AssertionError("Unexpected callback count: " + handler.callbackCount); + } + + String logged = out.toString("UTF-8"); + if (!EXPECTED_LOG.equals(logged)) { + throw new AssertionError("Unexpected log contents: " + logged); + } + } + + static LogRecord log(String msg) { + return new LogRecord(Level.INFO, msg); + } +} diff --git a/test/jdk/java/util/logging/Handler/java.logging/java/util/logging/TestStreamHandler.java b/test/jdk/java/util/logging/Handler/java.logging/java/util/logging/TestStreamHandler.java new file mode 100644 index 0000000000000..9446773f3fdbe --- /dev/null +++ b/test/jdk/java/util/logging/Handler/java.logging/java/util/logging/TestStreamHandler.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util.logging; + +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +/** + * A trivial UTF-8 stream handler subclass class to capture whether the + * (package protected) post-write callback method is synchronized. + */ +public class TestStreamHandler extends StreamHandler { + + public int callbackCount = 0; + + public TestStreamHandler(OutputStream out) { + setOutputStream(out); + try { + setEncoding("UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + @Override + void synchronousPostWriteHook() { + if (!Thread.holdsLock(this)) { + throw new AssertionError( + String.format("Post write callback [index=%d] was invoked without handler locked.", callbackCount)); + } + callbackCount++; + } +} diff --git a/test/jdk/java/util/logging/LoggingDeadlock5.java b/test/jdk/java/util/logging/LoggingDeadlock5.java new file mode 100644 index 0000000000000..6d75c84839a7b --- /dev/null +++ b/test/jdk/java/util/logging/LoggingDeadlock5.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8349206 + * @summary j.u.l.Handler classes create deadlock risk via synchronized publish() method. + * @modules java.base/sun.util.logging + * java.logging + * @run main/othervm LoggingDeadlock5 + */ + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.concurrent.Semaphore; +import java.util.logging.FileHandler; +import java.util.logging.Formatter; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import java.util.logging.StreamHandler; + +/** + * This test verifies that logging Handler implementations no longer suffer + * from the deadlock risk outlined in JDK-8349206. + * + *

This test should reliably cause, and detect, deadlocks in a timely + * manner if the problem occurs, and SHOULD NOT time out. + */ +public class LoggingDeadlock5 { + private static final String UTF_8 = StandardCharsets.UTF_8.name(); + + // Formatter which calls toString() on all arguments. + private static final Formatter TEST_FORMATTER = new Formatter() { + @Override + public String format(LogRecord record) { + // All we care about is that our formatter will invoke toString() on user arguments. + for (Object p : record.getParameters()) { + var unused = p.toString(); + } + return ""; + } + }; + + // A handler which *should* cause a deadlock by synchronizing publish(). + private static final Handler SELF_TEST_HANDLER = new Handler() { + @Override + public synchronized void publish(LogRecord record) { + TEST_FORMATTER.formatMessage(record); + } + + @Override + public void flush() { + } + + @Override + public void close() { + } + }; + + public static void main(String[] args) throws InterruptedException, IOException { + // Self test that deadlocks are correctly caught (and don't deadlock the test itself). + new DeadLocker(SELF_TEST_HANDLER).checkDeadlock(true); + + // In theory, we should test SocketHandler here as well because, while + // it is just a subclass, it could be adding locking around the call to + // super.publish(). However, it is problematic in a test environment + // since it needs to open sockets. It is not being tested for now. + assertNoDeadlock(new StreamHandler(new ByteArrayOutputStream(0), TEST_FORMATTER)); + + // Single log file in current directory, no rotation. JTreg will delete + // temporary files after test completion. + assertNoDeadlock(new FileHandler("temp_log_file")); + + // Any other problematic handler classes can be easily added here if + // they are simple enough to be constructed in a test environment. + } + + static void assertNoDeadlock(Handler handler) throws InterruptedException, UnsupportedEncodingException { + try { + handler.setEncoding(UTF_8); + new DeadLocker(handler).checkDeadlock(false); + } finally { + // Handlers may have open resources, so must be closed. + handler.close(); + } + } + + private static class DeadLocker { + private final static Duration JOIN_WAIT = Duration.ofMillis(500); + + private final Semaphore readyToDeadlock = new Semaphore(0); + private final Semaphore userLockIsHeld = new Semaphore(0); + private final Logger logger = Logger.getAnonymousLogger(); + private final Handler handlerUnderTest; + private final Object userLock = new Object(); + private boolean deadlockEncountered = true; + + DeadLocker(Handler handlerUnderTest) { + this.handlerUnderTest = handlerUnderTest; + + this.logger.setUseParentHandlers(false); + this.logger.addHandler(handlerUnderTest); + this.logger.setLevel(Level.INFO); + this.handlerUnderTest.setLevel(Level.INFO); + } + + void checkDeadlock(boolean expectDeadlock) throws InterruptedException { + // Note: Even though the message format string isn't used in the + // test formatter, it must be a valid log format string (Logger + // detects if there are no "{n}" placeholders and skips calling + // the formatter otherwise). + Thread t1 = runAsDaemon(() -> logger.log(Level.INFO, "Hello {0}", new Argument())); + readyToDeadlock.acquireUninterruptibly(); + // First thread is blocked until userLockIsHeld is released in t2. + Thread t2 = runAsDaemon(this::locksThenLogs); + + // If deadlock occurs, the join() calls both return false. + int threadsBlocked = 0; + if (!t1.join(JOIN_WAIT)) { + threadsBlocked += 1; + } + if (!t2.join(JOIN_WAIT)) { + threadsBlocked += 1; + } + // These indicate test problems, not a failure of the code under test. + errorIf(threadsBlocked == 1, "Inconsistent number of blocked threads."); + errorIf(deadlockEncountered != (threadsBlocked == 2), + "Deadlock reporting should coincide with number of blocked threads."); + + // This is the actual test assertion. + if (expectDeadlock != deadlockEncountered) { + String issue = expectDeadlock ? "Expected deadlock but none occurred" : "Unexpected deadlock"; + throw new AssertionError(errorMsg(issue)); + } + } + + void locksThenLogs() { + synchronized (userLock) { + userLockIsHeld.release(); + logger.log(Level.INFO, "This will cause a deadlock if the Handler locks!"); + } + } + + void calledFromToString() { + this.readyToDeadlock.release(); + this.userLockIsHeld.acquireUninterruptibly(); + synchronized (userLock) { + this.deadlockEncountered = false; + } + } + + class Argument { + @Override + public String toString() { + calledFromToString(); + return ""; + } + } + + String errorMsg(String msg) { + return String.format("Handler deadlock test [%s]: %s", handlerUnderTest.getClass().getName(), msg); + } + + void errorIf(boolean condition, String msg) { + if (condition) { + throw new RuntimeException(errorMsg("TEST ERROR - " + msg)); + } + } + } + + static Thread runAsDaemon(Runnable job) { + Thread thread = new Thread(job); + thread.setDaemon(true); + thread.start(); + return thread; + } +} From 57df89c46449a19bb626fee2ea01c868e6dfb712 Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Thu, 3 Apr 2025 21:15:00 +0000 Subject: [PATCH 0381/1101] 8353684: [BACKOUT] j.u.l.Handler classes create deadlock risk via synchronized publish() method Reviewed-by: dholmes --- .../java/util/logging/ConsoleHandler.java | 6 - .../java/util/logging/FileHandler.java | 13 +- .../classes/java/util/logging/Handler.java | 23 +- .../java/util/logging/SocketHandler.java | 13 +- .../java/util/logging/StreamHandler.java | 52 +---- .../Handler/StreamHandlerLockingTest.java | 105 --------- .../java/util/logging/TestStreamHandler.java | 54 ----- .../java/util/logging/LoggingDeadlock5.java | 202 ------------------ 8 files changed, 23 insertions(+), 445 deletions(-) delete mode 100644 test/jdk/java/util/logging/Handler/StreamHandlerLockingTest.java delete mode 100644 test/jdk/java/util/logging/Handler/java.logging/java/util/logging/TestStreamHandler.java delete mode 100644 test/jdk/java/util/logging/LoggingDeadlock5.java diff --git a/src/java.logging/share/classes/java/util/logging/ConsoleHandler.java b/src/java.logging/share/classes/java/util/logging/ConsoleHandler.java index 1561c7edebf44..cab4805b9e739 100644 --- a/src/java.logging/share/classes/java/util/logging/ConsoleHandler.java +++ b/src/java.logging/share/classes/java/util/logging/ConsoleHandler.java @@ -87,12 +87,6 @@ public ConsoleHandler() { * The logging request was made initially to a {@code Logger} object, * which initialized the {@code LogRecord} and forwarded it here. * - * @implSpec This method is not synchronized, and subclasses must not define - * overridden {@code publish()} methods to be {@code synchronized} if they - * call {@code super.publish()} or format user arguments. See the - * {@linkplain Handler##threadSafety discussion in java.util.logging.Handler} - * for more information. - * * @param record description of the log event. A null record is * silently ignored and is not published */ diff --git a/src/java.logging/share/classes/java/util/logging/FileHandler.java b/src/java.logging/share/classes/java/util/logging/FileHandler.java index 99afe7261b1e7..3c36a21516c07 100644 --- a/src/java.logging/share/classes/java/util/logging/FileHandler.java +++ b/src/java.logging/share/classes/java/util/logging/FileHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -739,14 +739,11 @@ private synchronized void rotate() { * silently ignored and is not published */ @Override - public void publish(LogRecord record) { + public synchronized void publish(LogRecord record) { + if (!isLoggable(record)) { + return; + } super.publish(record); - } - - @Override - void synchronousPostWriteHook() { - // no need to synchronize here, this method is called from within a - // synchronized block. flush(); if (limit > 0 && (meter.written >= limit || meter.written < 0)) { rotate(); diff --git a/src/java.logging/share/classes/java/util/logging/Handler.java b/src/java.logging/share/classes/java/util/logging/Handler.java index 8e5b3ee0a4f3c..7b93e517e972a 100644 --- a/src/java.logging/share/classes/java/util/logging/Handler.java +++ b/src/java.logging/share/classes/java/util/logging/Handler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -43,25 +43,10 @@ * and {@code Level}. See the specific documentation for each concrete * {@code Handler} class. * - *

Thread Safety and Deadlock Risk in Handlers

- * - * Implementations of {@code Handler} should be thread-safe. Handlers are - * expected to be invoked concurrently from arbitrary threads. However, - * over-use of synchronization may result in unwanted thread contention, - * performance issues or even deadlocking. - *

- * In particular, subclasses should avoid acquiring locks around code which - * calls back to arbitrary user-supplied objects, especially during log record - * formatting. Holding a lock around any such callbacks creates a deadlock risk - * between logging code and user code. - *

- * As such, general purpose {@code Handler} subclasses should not synchronize - * their {@link #publish(LogRecord)} methods, or call {@code super.publish()} - * while holding locks, since these are typically expected to need to process - * and format user-supplied arguments. * * @since 1.4 */ + public abstract class Handler { private static final int offValue = Level.OFF.intValue(); @@ -138,10 +123,6 @@ protected Handler() { } *

* The {@code Handler} is responsible for formatting the message, when and * if necessary. The formatting should include localization. - *

- * @apiNote To avoid the risk of deadlock, implementations of this method - * should avoid holding any locks while calling out to application code, - * such as the formatting of {@code LogRecord}. * * @param record description of the log event. A null record is * silently ignored and is not published diff --git a/src/java.logging/share/classes/java/util/logging/SocketHandler.java b/src/java.logging/share/classes/java/util/logging/SocketHandler.java index d20d857035777..380cc20add44f 100644 --- a/src/java.logging/share/classes/java/util/logging/SocketHandler.java +++ b/src/java.logging/share/classes/java/util/logging/SocketHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -168,17 +168,14 @@ public synchronized void close() { /** * Format and publish a {@code LogRecord}. * - * @implSpec This method is not synchronized, and subclasses must not define - * overridden {@code publish()} methods to be {@code synchronized} if they - * call {@code super.publish()} or format user arguments. See the - * {@linkplain Handler##threadSafety discussion in java.util.logging.Handler} - * for more information. - * * @param record description of the log event. A null record is * silently ignored and is not published */ @Override - public void publish(LogRecord record) { + public synchronized void publish(LogRecord record) { + if (!isLoggable(record)) { + return; + } super.publish(record); flush(); } diff --git a/src/java.logging/share/classes/java/util/logging/StreamHandler.java b/src/java.logging/share/classes/java/util/logging/StreamHandler.java index 5fc70b5dde9c3..31cb6605fbc79 100644 --- a/src/java.logging/share/classes/java/util/logging/StreamHandler.java +++ b/src/java.logging/share/classes/java/util/logging/StreamHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -180,31 +180,17 @@ public synchronized void setEncoding(String encoding) * {@code OutputStream}, the {@code Formatter}'s "head" string is * written to the stream before the {@code LogRecord} is written. * - * @implSpec This method avoids acquiring locks during {@code LogRecord} - * formatting, but {@code this} instance is synchronized when writing to the - * output stream. To avoid deadlock risk, subclasses must not hold locks - * while calling {@code super.publish()}. Specifically, subclasses must - * not define the overridden {@code publish()} method to be - * {@code synchronized} if they call {@code super.publish()}. - * * @param record description of the log event. A null record is * silently ignored and is not published */ @Override - public void publish(LogRecord record) { - if (!isLoggable(record)) { + public synchronized void publish(LogRecord record) { + if (!isLoggable(record)) { return; } - // Read once for consistency (whether in or outside the locked region - // is not important). - Formatter formatter = getFormatter(); - // JDK-8349206: To avoid deadlock risk, it is essential that the handler - // is not locked while formatting the log record. Methods such as - // reportError() and isLoggable() are defined to be thread safe, so we - // can restrict locking to just writing the message. String msg; try { - msg = formatter.format(record); + msg = getFormatter().format(record); } catch (Exception ex) { // We don't want to throw an exception here, but we // report the exception to any registered ErrorManager. @@ -213,15 +199,12 @@ public void publish(LogRecord record) { } try { - synchronized(this) { - Writer writer = this.writer; - if (!doneHeader) { - writer.write(formatter.getHead(this)); - doneHeader = true; - } - writer.write(msg); - synchronousPostWriteHook(); + Writer writer = this.writer; + if (!doneHeader) { + writer.write(getFormatter().getHead(this)); + doneHeader = true; } + writer.write(msg); } catch (Exception ex) { // We don't want to throw an exception here, but we // report the exception to any registered ErrorManager. @@ -229,17 +212,6 @@ public void publish(LogRecord record) { } } - /** - * Overridden by other handlers in this package to facilitate synchronous - * post-write behaviour. If other handlers need similar functionality, it - * might be feasible to make this method protected (see JDK-8349206), but - * please find a better name if you do ;). - */ - void synchronousPostWriteHook() { - // Empty by default. We could do: - // assert Thread.holdsLock(this); - // but this is already covered by unit tests. - } /** * Check if this {@code Handler} would actually log a given {@code LogRecord}. @@ -277,17 +249,15 @@ public synchronized void flush() { } } - // Called synchronously with "this" handler instance locked. private void flushAndClose() { Writer writer = this.writer; if (writer != null) { - Formatter formatter = getFormatter(); try { if (!doneHeader) { - writer.write(formatter.getHead(this)); + writer.write(getFormatter().getHead(this)); doneHeader = true; } - writer.write(formatter.getTail(this)); + writer.write(getFormatter().getTail(this)); writer.flush(); writer.close(); } catch (Exception ex) { diff --git a/test/jdk/java/util/logging/Handler/StreamHandlerLockingTest.java b/test/jdk/java/util/logging/Handler/StreamHandlerLockingTest.java deleted file mode 100644 index bc137ea431515..0000000000000 --- a/test/jdk/java/util/logging/Handler/StreamHandlerLockingTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8349206 - * @summary j.u.l.Handler classes create deadlock risk via synchronized publish() method. - * @modules java.base/sun.util.logging - * java.logging - * @build java.logging/java.util.logging.TestStreamHandler - * @run main/othervm StreamHandlerLockingTest - */ - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.logging.Formatter; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.logging.TestStreamHandler; - -public class StreamHandlerLockingTest { - static class TestFormatter extends Formatter { - final Handler handler; - - TestFormatter(Handler handler) { - this.handler = handler; - } - - @Override - public String format(LogRecord record) { - if (Thread.holdsLock(handler)) { - throw new AssertionError("format() was called with handler locked (bad)."); - } - return record.getMessage() + "\n"; - } - - @Override - public String getHead(Handler h) { - // This is currently true, and not easy to make unsynchronized. - if (!Thread.holdsLock(handler)) { - throw new AssertionError("getHead() expected to be called with handler locked."); - } - return "--HEAD--\n"; - } - - @Override - public String getTail(Handler h) { - // This is currently true, and not easy to make unsynchronized. - if (!Thread.holdsLock(handler)) { - throw new AssertionError("getTail() expected to be called with handler locked."); - } - return "--TAIL--\n"; - } - } - - private static final String EXPECTED_LOG = - String.join("\n","--HEAD--", "Hello World", "Some more logging...", "And we're done!", "--TAIL--", ""); - - public static void main(String[] args) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - TestStreamHandler handler = new TestStreamHandler(out); - TestFormatter formatter = new TestFormatter(handler); - handler.setFormatter(formatter); - - handler.publish(log("Hello World")); - handler.publish(log("Some more logging...")); - handler.publish(log("And we're done!")); - handler.close(); - - // Post write callback should have happened once per publish call (with lock held). - if (handler.callbackCount != 3) { - throw new AssertionError("Unexpected callback count: " + handler.callbackCount); - } - - String logged = out.toString("UTF-8"); - if (!EXPECTED_LOG.equals(logged)) { - throw new AssertionError("Unexpected log contents: " + logged); - } - } - - static LogRecord log(String msg) { - return new LogRecord(Level.INFO, msg); - } -} diff --git a/test/jdk/java/util/logging/Handler/java.logging/java/util/logging/TestStreamHandler.java b/test/jdk/java/util/logging/Handler/java.logging/java/util/logging/TestStreamHandler.java deleted file mode 100644 index 9446773f3fdbe..0000000000000 --- a/test/jdk/java/util/logging/Handler/java.logging/java/util/logging/TestStreamHandler.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.util.logging; - -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; - -/** - * A trivial UTF-8 stream handler subclass class to capture whether the - * (package protected) post-write callback method is synchronized. - */ -public class TestStreamHandler extends StreamHandler { - - public int callbackCount = 0; - - public TestStreamHandler(OutputStream out) { - setOutputStream(out); - try { - setEncoding("UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - - @Override - void synchronousPostWriteHook() { - if (!Thread.holdsLock(this)) { - throw new AssertionError( - String.format("Post write callback [index=%d] was invoked without handler locked.", callbackCount)); - } - callbackCount++; - } -} diff --git a/test/jdk/java/util/logging/LoggingDeadlock5.java b/test/jdk/java/util/logging/LoggingDeadlock5.java deleted file mode 100644 index 6d75c84839a7b..0000000000000 --- a/test/jdk/java/util/logging/LoggingDeadlock5.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8349206 - * @summary j.u.l.Handler classes create deadlock risk via synchronized publish() method. - * @modules java.base/sun.util.logging - * java.logging - * @run main/othervm LoggingDeadlock5 - */ - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; -import java.time.Duration; -import java.util.concurrent.Semaphore; -import java.util.logging.FileHandler; -import java.util.logging.Formatter; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.logging.Logger; -import java.util.logging.StreamHandler; - -/** - * This test verifies that logging Handler implementations no longer suffer - * from the deadlock risk outlined in JDK-8349206. - * - *

This test should reliably cause, and detect, deadlocks in a timely - * manner if the problem occurs, and SHOULD NOT time out. - */ -public class LoggingDeadlock5 { - private static final String UTF_8 = StandardCharsets.UTF_8.name(); - - // Formatter which calls toString() on all arguments. - private static final Formatter TEST_FORMATTER = new Formatter() { - @Override - public String format(LogRecord record) { - // All we care about is that our formatter will invoke toString() on user arguments. - for (Object p : record.getParameters()) { - var unused = p.toString(); - } - return ""; - } - }; - - // A handler which *should* cause a deadlock by synchronizing publish(). - private static final Handler SELF_TEST_HANDLER = new Handler() { - @Override - public synchronized void publish(LogRecord record) { - TEST_FORMATTER.formatMessage(record); - } - - @Override - public void flush() { - } - - @Override - public void close() { - } - }; - - public static void main(String[] args) throws InterruptedException, IOException { - // Self test that deadlocks are correctly caught (and don't deadlock the test itself). - new DeadLocker(SELF_TEST_HANDLER).checkDeadlock(true); - - // In theory, we should test SocketHandler here as well because, while - // it is just a subclass, it could be adding locking around the call to - // super.publish(). However, it is problematic in a test environment - // since it needs to open sockets. It is not being tested for now. - assertNoDeadlock(new StreamHandler(new ByteArrayOutputStream(0), TEST_FORMATTER)); - - // Single log file in current directory, no rotation. JTreg will delete - // temporary files after test completion. - assertNoDeadlock(new FileHandler("temp_log_file")); - - // Any other problematic handler classes can be easily added here if - // they are simple enough to be constructed in a test environment. - } - - static void assertNoDeadlock(Handler handler) throws InterruptedException, UnsupportedEncodingException { - try { - handler.setEncoding(UTF_8); - new DeadLocker(handler).checkDeadlock(false); - } finally { - // Handlers may have open resources, so must be closed. - handler.close(); - } - } - - private static class DeadLocker { - private final static Duration JOIN_WAIT = Duration.ofMillis(500); - - private final Semaphore readyToDeadlock = new Semaphore(0); - private final Semaphore userLockIsHeld = new Semaphore(0); - private final Logger logger = Logger.getAnonymousLogger(); - private final Handler handlerUnderTest; - private final Object userLock = new Object(); - private boolean deadlockEncountered = true; - - DeadLocker(Handler handlerUnderTest) { - this.handlerUnderTest = handlerUnderTest; - - this.logger.setUseParentHandlers(false); - this.logger.addHandler(handlerUnderTest); - this.logger.setLevel(Level.INFO); - this.handlerUnderTest.setLevel(Level.INFO); - } - - void checkDeadlock(boolean expectDeadlock) throws InterruptedException { - // Note: Even though the message format string isn't used in the - // test formatter, it must be a valid log format string (Logger - // detects if there are no "{n}" placeholders and skips calling - // the formatter otherwise). - Thread t1 = runAsDaemon(() -> logger.log(Level.INFO, "Hello {0}", new Argument())); - readyToDeadlock.acquireUninterruptibly(); - // First thread is blocked until userLockIsHeld is released in t2. - Thread t2 = runAsDaemon(this::locksThenLogs); - - // If deadlock occurs, the join() calls both return false. - int threadsBlocked = 0; - if (!t1.join(JOIN_WAIT)) { - threadsBlocked += 1; - } - if (!t2.join(JOIN_WAIT)) { - threadsBlocked += 1; - } - // These indicate test problems, not a failure of the code under test. - errorIf(threadsBlocked == 1, "Inconsistent number of blocked threads."); - errorIf(deadlockEncountered != (threadsBlocked == 2), - "Deadlock reporting should coincide with number of blocked threads."); - - // This is the actual test assertion. - if (expectDeadlock != deadlockEncountered) { - String issue = expectDeadlock ? "Expected deadlock but none occurred" : "Unexpected deadlock"; - throw new AssertionError(errorMsg(issue)); - } - } - - void locksThenLogs() { - synchronized (userLock) { - userLockIsHeld.release(); - logger.log(Level.INFO, "This will cause a deadlock if the Handler locks!"); - } - } - - void calledFromToString() { - this.readyToDeadlock.release(); - this.userLockIsHeld.acquireUninterruptibly(); - synchronized (userLock) { - this.deadlockEncountered = false; - } - } - - class Argument { - @Override - public String toString() { - calledFromToString(); - return ""; - } - } - - String errorMsg(String msg) { - return String.format("Handler deadlock test [%s]: %s", handlerUnderTest.getClass().getName(), msg); - } - - void errorIf(boolean condition, String msg) { - if (condition) { - throw new RuntimeException(errorMsg("TEST ERROR - " + msg)); - } - } - } - - static Thread runAsDaemon(Runnable job) { - Thread thread = new Thread(job); - thread.setDaemon(true); - thread.start(); - return thread; - } -} From a449aeef287d32437d23bb69027175d6d861e2a6 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 4 Apr 2025 00:58:32 +0000 Subject: [PATCH 0382/1101] 8350704: Create tests to ensure the failure behavior of core reflection APIs Reviewed-by: darcy --- .../generics/parser/SignatureParser.java | 3 +- .../BadEnclosingMethodTest.java | 123 ++++++++++ .../annotation/DuplicateAnnotationsTest.java | 141 +++++++++++ .../annotation/MalformedAnnotationTest.java | 77 ++++++ .../Generics/MalformedSignatureTest.java | 224 ++++++++++++++++++ .../reflect/Generics/TestBadSignatures.java | 55 ----- .../TypeNotPresentInSignatureTest.java | 166 +++++++++++++ 7 files changed, 732 insertions(+), 57 deletions(-) create mode 100644 test/jdk/java/lang/Class/getEnclosingMethod/BadEnclosingMethodTest.java create mode 100644 test/jdk/java/lang/annotation/DuplicateAnnotationsTest.java create mode 100644 test/jdk/java/lang/annotation/MalformedAnnotationTest.java create mode 100644 test/jdk/java/lang/reflect/Generics/MalformedSignatureTest.java delete mode 100644 test/jdk/java/lang/reflect/Generics/TestBadSignatures.java create mode 100644 test/jdk/java/lang/reflect/Generics/TypeNotPresentInSignatureTest.java diff --git a/src/java.base/share/classes/sun/reflect/generics/parser/SignatureParser.java b/src/java.base/share/classes/sun/reflect/generics/parser/SignatureParser.java index c7be9f2c6c630..c2820dfcb4e1d 100644 --- a/src/java.base/share/classes/sun/reflect/generics/parser/SignatureParser.java +++ b/src/java.base/share/classes/sun/reflect/generics/parser/SignatureParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -297,7 +297,6 @@ private FieldTypeSignature parseFieldTypeSignature(boolean allowArrays) { * "L" PackageSpecifier_opt SimpleClassTypeSignature ClassTypeSignatureSuffix* ";" */ private ClassTypeSignature parseClassTypeSignature(){ - assert(current() == 'L'); if (current() != 'L') { throw error("expected a class type");} advance(); List scts = new ArrayList<>(5); diff --git a/test/jdk/java/lang/Class/getEnclosingMethod/BadEnclosingMethodTest.java b/test/jdk/java/lang/Class/getEnclosingMethod/BadEnclosingMethodTest.java new file mode 100644 index 0000000000000..f673d01c835cc --- /dev/null +++ b/test/jdk/java/lang/Class/getEnclosingMethod/BadEnclosingMethodTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8350704 + * @summary Test behaviors with various bad EnclosingMethod attribute + * @library /test/lib + * @run junit BadEnclosingMethodTest + */ + +import jdk.test.lib.ByteCodeLoader; +import org.junit.jupiter.api.Test; + +import java.lang.classfile.ClassFile; +import java.lang.classfile.attribute.EnclosingMethodAttribute; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; +import java.util.Optional; + +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static org.junit.jupiter.api.Assertions.*; + +class BadEnclosingMethodTest { + + private static Path classPath(String className) { + return Path.of(System.getProperty("test.classes"), className + ".class"); + } + + /** + * Loads a test class that is transformed from the Enclosed local class in + * the Encloser::work method. This local class has its EnclosingMethod + * attribute transformed to the specific name and type, which may be malformed + * strings. + * + * @param name the new enclosing method name, may be malformed + * @param type the new enclosing method type, may be malformed + * @return the loaded test class, for reflective inspection + */ + private Class loadTestClass(String name, String type) throws Exception { + var outerName = "Encloser"; + var className = outerName + "$1Enclosed"; + + var cf = ClassFile.of(); + var cm = cf.parse(classPath(className)); + + var bytes = cf.transformClass(cm, (cb, ce) -> { + if (ce instanceof EnclosingMethodAttribute em) { + var cp = cb.constantPool(); + var enclosingMethodName = cp.utf8Entry(name); + var enclosingMethodType = cp.utf8Entry(type); // a malformed method type + cb.with(EnclosingMethodAttribute.of(em.enclosingClass(), Optional.of(cp.nameAndTypeEntry( + enclosingMethodName, enclosingMethodType + )))); + } else { + cb.with(ce); + } + }); + + var map = Map.of( + outerName, Files.readAllBytes(classPath(outerName)), + className, bytes + ); + + return new ByteCodeLoader(map, BadEnclosingMethodTest.class.getClassLoader()) + .loadClass(className); + } + + /** + * Test reflection behaviors when the EnclosingMethod attribute's type is + * an invalid string. + */ + @Test + void testMalformedTypes() throws Exception { + assertThrows(ClassFormatError.class, () -> loadTestClass("methodName", "(L[;)V")); + assertThrows(ClassFormatError.class, () -> loadTestClass(INIT_NAME, "(L[;)V")); + } + + /** + * Test reflective behaviors when the EnclosingMethod attribute's type is + * valid, but refers to a class or interface that cannot be found. + */ + @Test + void testAbsentMethods() throws Exception { + var absentMethodType = loadTestClass("methodName", "(Ldoes/not/Exist;)V"); + var ex = assertThrows(TypeNotPresentException.class, + absentMethodType::getEnclosingMethod); + assertEquals("does.not.Exist", ex.typeName()); + + var absentConstructorType = loadTestClass(INIT_NAME, "(Ldoes/not/Exist;)V"); + ex = assertThrows(TypeNotPresentException.class, + absentConstructorType::getEnclosingConstructor); + assertEquals("does.not.Exist", ex.typeName()); + } +} + +class Encloser { + private static void work() { + class Enclosed { + } + } +} diff --git a/test/jdk/java/lang/annotation/DuplicateAnnotationsTest.java b/test/jdk/java/lang/annotation/DuplicateAnnotationsTest.java new file mode 100644 index 0000000000000..1f0626cedde76 --- /dev/null +++ b/test/jdk/java/lang/annotation/DuplicateAnnotationsTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8345614 8350704 + * @summary Ensure behavior with duplicated annotations - class, method, or + * field fails fast on duplicate annotations, but parameter allows them + * @library /test/lib + * @run junit DuplicateAnnotationsTest + */ + +import java.io.IOException; +import java.lang.annotation.AnnotationFormatError; +import java.lang.classfile.*; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute; +import java.lang.constant.ClassDesc; +import java.lang.reflect.AnnotatedElement; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; + +import jdk.test.lib.ByteCodeLoader; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.function.Executable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.*; + +class DuplicateAnnotationsTest { + static ClassModel cm; + + @BeforeAll + static void setup() throws IOException { + Path annoDuplicatedClass = Path.of(System.getProperty("test.classes")).resolve("AnnotationDuplicated.class"); + cm = ClassFile.of().parse(annoDuplicatedClass); + } + + interface Extractor { + AnnotatedElement find(Class cl) throws ReflectiveOperationException; + } + + // Compiler hint + static Extractor extract(Extractor e) { + return e; + } + + static Arguments[] arguments() { + Annotation annotationOne = Annotation.of(ClassDesc.of("java.lang.Deprecated"), AnnotationElement.ofBoolean("forRemoval", true)); + Annotation annotationTwo = Annotation.of(ClassDesc.of("java.lang.Deprecated"), AnnotationElement.ofString("since", "24")); + RuntimeVisibleAnnotationsAttribute rvaa = RuntimeVisibleAnnotationsAttribute.of( + List.of(annotationOne, annotationTwo) + ); + + return new Arguments[]{ + Arguments.of( + "class", true, + ClassTransform.endHandler(cob -> cob.with(rvaa)), + extract(c -> c) + ), + Arguments.of( + "field", true, + ClassTransform.transformingFields(FieldTransform.endHandler(fb -> fb.with(rvaa))), + extract(c -> c.getDeclaredField("field")) + ), + Arguments.of( + "method", true, + ClassTransform.transformingMethods(MethodTransform.endHandler(mb -> mb.with(rvaa))), + extract(c -> c.getDeclaredConstructor(int.class)) + ), + Arguments.of( + "parameter", false, // Surprisingly, parameters always allowed duplicate annotations + ClassTransform.transformingMethods(MethodTransform.endHandler(mb -> mb.with( + RuntimeVisibleParameterAnnotationsAttribute.of( + List.of(List.of(annotationOne, annotationTwo)) + ) + ))), + extract(c -> c.getDeclaredConstructor(int.class).getParameters()[0]) + ), + }; + } + + /** + * A test case represents a declaration that can be annotated. + * Different declarations have different behaviors when multiple annotations + * of the same interface are present (without a container annotation). + * + * @param caseName the type of declaration, for pretty printing in JUnit + * @param fails whether this case should fail upon encountering duplicate annotations + * @param ct transform to install duplicate annotations on the specific declaration + * @param extractor function to access the AnnotatedElement representing that declaration + */ + @MethodSource("arguments") + @ParameterizedTest + void test(String caseName, boolean fails, ClassTransform ct, Extractor extractor) throws IOException, ReflectiveOperationException { + var clazz = ByteCodeLoader.load("AnnotationDuplicated", ClassFile.of().transformClass(cm, ct)); + var element = assertDoesNotThrow(() -> extractor.find(clazz)); + Executable exec = () -> element.getAnnotation(Deprecated.class); + if (fails) { + var ex = assertThrows(AnnotationFormatError.class, exec, "no duplicate annotation access"); + assertTrue(ex.getMessage().contains("Deprecated"), () -> "missing problematic annotation: " + ex.getMessage()); + assertTrue(ex.getMessage().contains("AnnotationDuplicated"), () -> "missing container class: " + ex.getMessage()); + } else { + assertDoesNotThrow(exec, "obtaining duplicate annotations should be fine"); + assertEquals(2, Arrays.stream(element.getAnnotations()) + .filter(anno -> anno instanceof Deprecated) + .count()); + } + } +} + +// Duplicate annotations on class, field, method (constructor), method parameter +class AnnotationDuplicated { + int field; + + AnnotationDuplicated(int arg) { + } +} diff --git a/test/jdk/java/lang/annotation/MalformedAnnotationTest.java b/test/jdk/java/lang/annotation/MalformedAnnotationTest.java new file mode 100644 index 0000000000000..e7096000fb1d5 --- /dev/null +++ b/test/jdk/java/lang/annotation/MalformedAnnotationTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8350704 + * @summary Test behaviors with malformed annotations (in class files) + * @library /test/lib + * @run junit MalformedAnnotationTest + */ + +import jdk.test.lib.ByteCodeLoader; +import org.junit.jupiter.api.Test; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.classfile.Annotation; +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.AnnotationValue; +import java.lang.classfile.ClassFile; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.constant.ClassDesc; +import java.lang.reflect.GenericSignatureFormatError; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class MalformedAnnotationTest { + + /** + * An annotation that has elements of the Class type. + * Useful for checking behavior when the string is not a descriptor string. + */ + @Retention(RetentionPolicy.RUNTIME) + @interface ClassCarrier { + Class value(); + } + + /** + * Ensures bad class descriptors in annotations lead to + * {@link GenericSignatureFormatError} and the error message contains the + * malformed descriptor string. + */ + @Test + void testMalformedClassValue() throws Exception { + var badDescString = "Not a_descriptor"; + var bytes = ClassFile.of().build(ClassDesc.of("Test"), clb -> clb + .with(RuntimeVisibleAnnotationsAttribute.of( + Annotation.of(ClassCarrier.class.describeConstable().orElseThrow(), + AnnotationElement.of("value", AnnotationValue.ofClass(clb + .constantPool().utf8Entry(badDescString)))) + ))); + var cl = new ByteCodeLoader("Test", bytes, MalformedAnnotationTest.class.getClassLoader()).loadClass("Test"); + var ex = assertThrows(GenericSignatureFormatError.class, () -> cl.getDeclaredAnnotation(ClassCarrier.class)); + assertTrue(ex.getMessage().contains(badDescString), () -> "Uninformative error: " + ex); + } +} diff --git a/test/jdk/java/lang/reflect/Generics/MalformedSignatureTest.java b/test/jdk/java/lang/reflect/Generics/MalformedSignatureTest.java new file mode 100644 index 0000000000000..8a86164613266 --- /dev/null +++ b/test/jdk/java/lang/reflect/Generics/MalformedSignatureTest.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6832374 7052898 8350704 + * @summary Test behaviors with malformed signature strings in Signature attribute. + * @library /test/lib + * @run junit MalformedSignatureTest + */ + +import java.lang.classfile.*; +import java.lang.classfile.attribute.RecordAttribute; +import java.lang.classfile.attribute.RecordComponentInfo; +import java.lang.classfile.attribute.SignatureAttribute; +import java.lang.constant.ClassDesc; +import java.lang.reflect.GenericSignatureFormatError; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import jdk.test.lib.ByteCodeLoader; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static java.lang.constant.ConstantDescs.MTD_void; +import static org.junit.jupiter.api.Assertions.*; + +class MalformedSignatureTest { + + private static final String BASIC_BAD_SIGNATURE_TEXT = "i_aM_NoT_A_Signature"; + static Class sampleClass, sampleRecord; + + @BeforeAll + static void setup() throws Exception { + var compiledDir = Path.of(System.getProperty("test.classes")); + var cf = ClassFile.of(); + + // Transform that installs malformed signature strings to classes, + // fields, methods, and record components. + var badSignatureTransform = new ClassTransform() { + private SignatureAttribute badSignature; + + @Override + public void atStart(ClassBuilder builder) { + badSignature = SignatureAttribute.of(builder.constantPool().utf8Entry(BASIC_BAD_SIGNATURE_TEXT)); + } + + @Override + public void accept(ClassBuilder builder, ClassElement element) { + switch (element) { + case SignatureAttribute _ -> {} // dropping + case FieldModel f -> builder + .transformField(f, FieldTransform.dropping(SignatureAttribute.class::isInstance) + .andThen(FieldTransform.endHandler(fb -> fb.with(badSignature)))); + case MethodModel m -> builder + .transformMethod(m, MethodTransform.dropping(SignatureAttribute.class::isInstance) + .andThen(MethodTransform.endHandler(fb -> fb.with(badSignature)))); + case RecordAttribute rec -> builder.with(RecordAttribute.of(rec.components().stream().map(comp -> + RecordComponentInfo.of(comp.name(), comp.descriptor(), Stream.concat( + Stream.of(badSignature), comp.attributes().stream() + .filter(Predicate.not(SignatureAttribute.class::isInstance))) + .toList())) + .toList())); + default -> builder.with(element); + } + } + + @Override + public void atEnd(ClassBuilder builder) { + builder.with(badSignature); + } + }; + + var plainBytes = cf.transformClass(cf.parse(compiledDir.resolve("SampleClass.class")), badSignatureTransform); + sampleClass = ByteCodeLoader.load("SampleClass", plainBytes); + var recordBytes = cf.transformClass(cf.parse(compiledDir.resolve("SampleRecord.class")), badSignatureTransform); + sampleRecord = ByteCodeLoader.load("SampleRecord", recordBytes); + } + + /** + * Ensures the reflective generic inspection of a malformed Class throws + * GenericSignatureFormatError while the non-generic inspection is fine. + */ + @Test + void testBasicClass() { + assertEquals(ArrayList.class, sampleClass.getSuperclass()); + assertArrayEquals(new Class[] {Predicate.class}, sampleClass.getInterfaces()); + var ex = assertThrows(GenericSignatureFormatError.class, sampleClass::getGenericSuperclass); + assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); + ex = assertThrows(GenericSignatureFormatError.class, sampleClass::getGenericInterfaces); + assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); + } + + /** + * Ensures the reflective generic inspection of a malformed Field throws + * GenericSignatureFormatError while the non-generic inspection is fine. + */ + @Test + void testBasicField() throws ReflectiveOperationException { + var field = sampleClass.getDeclaredField("field"); + assertEquals(Optional.class, field.getType()); + var ex = assertThrows(GenericSignatureFormatError.class, field::getGenericType); + assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); + } + + /** + * Ensures the reflective generic inspection of a malformed Constructor throws + * GenericSignatureFormatError while the non-generic inspection is fine. + */ + @Test + void testBasicConstructor() throws ReflectiveOperationException { + var constructor = sampleClass.getDeclaredConstructors()[0]; + assertArrayEquals(new Class[] {Optional.class}, constructor.getParameterTypes()); + assertArrayEquals(new Class[] {RuntimeException.class}, constructor.getExceptionTypes()); + var ex = assertThrows(GenericSignatureFormatError.class, constructor::getGenericParameterTypes); + assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); + ex = assertThrows(GenericSignatureFormatError.class, constructor::getGenericExceptionTypes); + assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); + } + + /** + * Ensures the reflective generic inspection of a malformed Method throws + * GenericSignatureFormatError while the non-generic inspection is fine. + */ + @Test + void testBasicMethod() throws ReflectiveOperationException { + var method = sampleClass.getDeclaredMethods()[0]; + assertEquals(Optional.class, method.getReturnType()); + assertArrayEquals(new Class[] {Optional.class}, method.getParameterTypes()); + assertArrayEquals(new Class[] {RuntimeException.class}, method.getExceptionTypes()); + var ex = assertThrows(GenericSignatureFormatError.class, method::getGenericReturnType); + assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); + ex = assertThrows(GenericSignatureFormatError.class, method::getGenericParameterTypes); + assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); + ex = assertThrows(GenericSignatureFormatError.class, method::getGenericExceptionTypes); + assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); + } + + /** + * Ensures the reflective generic inspection of a malformed RecordComponent throws + * GenericSignatureFormatError while the non-generic inspection is fine. + */ + @Test + void testBasicRecordComponent() { + var rcs = sampleRecord.getRecordComponents(); + assertNotNull(rcs); + assertEquals(1, rcs.length); + var rc = rcs[0]; + assertNotNull(rc); + + assertEquals(Optional.class, rc.getType()); + assertEquals(BASIC_BAD_SIGNATURE_TEXT, rc.getGenericSignature()); + var ex = assertThrows(GenericSignatureFormatError.class, rc::getGenericType); + assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); + } + + static String[] badMethodSignatures() { + return new String[] { + // Missing ":" after first type bound + "(TE;[Ljava/lang/RuntimeException;)V^[TE;", + }; + } + + /** + * Ensures that particular strings are invalid as method signature strings. + */ + @MethodSource("badMethodSignatures") + @ParameterizedTest + void testSignatureForMethod(String badSig) throws Throwable { + var className = "BadSignature"; + var bytes = ClassFile.of().build(ClassDesc.of(className), clb -> + clb.withMethod("test", MTD_void, 0, mb -> mb + .withCode(CodeBuilder::return_) + .with(SignatureAttribute.of(clb.constantPool().utf8Entry(badSig))))); + + var cl = ByteCodeLoader.load(className, bytes); + var method = cl.getDeclaredMethod("test"); + var ex = assertThrows(GenericSignatureFormatError.class, method::getGenericParameterTypes); + //assertTrue(ex.getMessage().contains(badSig), "Missing bad signature in error message"); + } +} + +// Sample classes shared with TypeNotPresentInSignatureTest +abstract class SampleClass extends ArrayList implements Predicate { // class + Optional field; // field + + SampleClass(Optional param) throws T { + } // constructor + + Optional method(Optional param) throws T { + return null; + } // method +} + +record SampleRecord(Optional component) { +} diff --git a/test/jdk/java/lang/reflect/Generics/TestBadSignatures.java b/test/jdk/java/lang/reflect/Generics/TestBadSignatures.java deleted file mode 100644 index 699c8cb8544e2..0000000000000 --- a/test/jdk/java/lang/reflect/Generics/TestBadSignatures.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 6832374 7052898 - * @summary Test bad signatures get a GenericSignatureFormatError thrown. - * @author Joseph D. Darcy - * @modules java.base/sun.reflect.generics.parser - */ - -import java.lang.reflect.*; -import sun.reflect.generics.parser.SignatureParser; - -public class TestBadSignatures { - public static void main(String[] args) { - String[] badSignatures = { - // Missing ":" after first type bound - "(TE;[Ljava/lang/RuntimeException;)V^[TE;", - }; - - for(String badSig : badSignatures) { - try { - SignatureParser.make().parseMethodSig(badSig); - throw new RuntimeException("Expected GenericSignatureFormatError for " + - badSig); - } catch(GenericSignatureFormatError gsfe) { - System.out.println(gsfe.toString()); // Expected - } - } - } -} diff --git a/test/jdk/java/lang/reflect/Generics/TypeNotPresentInSignatureTest.java b/test/jdk/java/lang/reflect/Generics/TypeNotPresentInSignatureTest.java new file mode 100644 index 0000000000000..569b1a8b31e40 --- /dev/null +++ b/test/jdk/java/lang/reflect/Generics/TypeNotPresentInSignatureTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8350704 + * @summary Test behaviors with Signature attribute with any absent + * class or interface (the string is of valid format) + * @library /test/lib + * @modules java.base/jdk.internal.classfile.components + * @compile MalformedSignatureTest.java + * @comment reuses Sample classes from MalformedSignatureTest + * @run junit TypeNotPresentInSignatureTest + */ + +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.attribute.ExceptionsAttribute; +import java.lang.constant.ClassDesc; +import java.lang.reflect.TypeVariable; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Map; +import java.util.Optional; +import java.util.function.Predicate; + +import jdk.internal.classfile.components.ClassRemapper; +import jdk.test.lib.ByteCodeLoader; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class TypeNotPresentInSignatureTest { + + static Class sampleClass, sampleRecord; + + @BeforeAll + static void setup() throws Exception { + var compiledDir = Path.of(System.getProperty("test.classes")); + var cf = ClassFile.of(); + + // Transforms all references to RuntimeException to an absent class or + // interface does.not.Exist. The signature string format is still valid. + var reDesc = ClassDesc.of("java.lang.RuntimeException"); + var fix = ClassRemapper.of(Map.of(reDesc, ClassDesc.of("does.not.Exist"))); + var f2 = ClassTransform.transformingMethods((mb, me) -> { + if (me instanceof ExceptionsAttribute) { + mb.with(ExceptionsAttribute.ofSymbols(reDesc)); + } else { + mb.with(me); + } + }); + + var plainBytes = cf.transformClass(cf.parse(compiledDir.resolve("SampleClass.class")), fix); + plainBytes = cf.transformClass(cf.parse(plainBytes), f2); + sampleClass = ByteCodeLoader.load("SampleClass", plainBytes); + var recordBytes = cf.transformClass(cf.parse(compiledDir.resolve("SampleRecord.class")), fix); + recordBytes = cf.transformClass(cf.parse(recordBytes), f2); + sampleRecord = ByteCodeLoader.load("SampleRecord", recordBytes); + } + + /** + * Ensures the reflective generic inspection of a Class with missing class + * or interface throws TypeNotPresentException while the non-generic + * inspection is fine. + */ + @Test + void testClass() { + assertEquals(ArrayList.class, sampleClass.getSuperclass()); + assertArrayEquals(new Class[] {Predicate.class}, sampleClass.getInterfaces()); + var ex = assertThrows(TypeNotPresentException.class, sampleClass::getGenericSuperclass); + assertEquals("does.not.Exist", ex.typeName()); + ex = assertThrows(TypeNotPresentException.class, sampleClass::getGenericInterfaces); + assertEquals("does.not.Exist", ex.typeName()); + } + + /** + * Ensures the reflective generic inspection of a Field with missing class + * or interface throws TypeNotPresentException while the non-generic + * inspection is fine. + */ + @Test + void testField() throws ReflectiveOperationException { + var field = sampleClass.getDeclaredField("field"); + assertEquals(Optional.class, field.getType()); + var ex = assertThrows(TypeNotPresentException.class, field::getGenericType); + assertEquals("does.not.Exist", ex.typeName()); + } + + /** + * Ensures the reflective generic inspection of a Constructor with missing class + * or interface throws TypeNotPresentException while the non-generic + * inspection is fine. + */ + @Test + void testConstructor() throws ReflectiveOperationException { + var constructor = sampleClass.getDeclaredConstructor(Optional.class); + assertArrayEquals(new Class[] {Optional.class}, constructor.getParameterTypes()); + assertArrayEquals(new Class[] {RuntimeException.class}, constructor.getExceptionTypes()); + var ex = assertThrows(TypeNotPresentException.class, constructor::getGenericParameterTypes); + assertEquals("does.not.Exist", ex.typeName()); + var typeVar = (TypeVariable) constructor.getGenericExceptionTypes()[0]; + ex = assertThrows(TypeNotPresentException.class, typeVar::getBounds); + assertEquals("does.not.Exist", ex.typeName()); + } + + /** + * Ensures the reflective generic inspection of a Method with missing class + * or interface throws TypeNotPresentException while the non-generic + * inspection is fine. + */ + @Test + void testMethod() throws ReflectiveOperationException { + var method = sampleClass.getDeclaredMethod("method", Optional.class); + assertEquals(Optional.class, method.getReturnType()); + assertArrayEquals(new Class[] {Optional.class}, method.getParameterTypes()); + assertArrayEquals(new Class[] {RuntimeException.class}, method.getExceptionTypes()); + var ex = assertThrows(TypeNotPresentException.class, method::getGenericReturnType); + assertEquals("does.not.Exist", ex.typeName()); + ex = assertThrows(TypeNotPresentException.class, method::getGenericParameterTypes); + assertEquals("does.not.Exist", ex.typeName()); + var typeVar = (TypeVariable) method.getGenericExceptionTypes()[0]; + ex = assertThrows(TypeNotPresentException.class, typeVar::getBounds); + assertEquals("does.not.Exist", ex.typeName()); + } + + /** + * Ensures the reflective generic inspection of a RecordComponent with missing class + * or interface throws TypeNotPresentException while the non-generic + * inspection is fine. + */ + @Test + void testRecordComponent() { + var rcs = sampleRecord.getRecordComponents(); + assertNotNull(rcs); + assertEquals(1, rcs.length); + var rc = rcs[0]; + assertNotNull(rc); + + assertEquals(Optional.class, rc.getType()); + assertEquals("Ljava/util/Optional;", rc.getGenericSignature()); + var ex = assertThrows(TypeNotPresentException.class, rc::getGenericType); + assertEquals("does.not.Exist", ex.typeName()); + } +} From 1c2a5533f4e8926db18365eb510588594f8fb6ba Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 4 Apr 2025 00:59:02 +0000 Subject: [PATCH 0383/1101] 8327858: Improve spliterator and forEach for single-element immutable collections Reviewed-by: smarks, vklang --- .../java/util/ImmutableCollections.java | 45 ++++++++++++++++++ test/jdk/java/util/Collection/MOAT.java | 37 ++++++++++++++- .../bench/java/util/ImmutableColls.java | 46 ++++++++++++++++++- 3 files changed, 126 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/util/ImmutableCollections.java b/src/java.base/share/classes/java/util/ImmutableCollections.java index dc505bb7f559a..205a6be6f89a3 100644 --- a/src/java.base/share/classes/java/util/ImmutableCollections.java +++ b/src/java.base/share/classes/java/util/ImmutableCollections.java @@ -32,7 +32,9 @@ import java.io.ObjectStreamException; import java.io.Serializable; import java.lang.reflect.Array; +import java.util.function.BiConsumer; import java.util.function.BiFunction; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.UnaryOperator; @@ -656,6 +658,24 @@ public T[] toArray(T[] a) { } return array; } + + @Override + @SuppressWarnings("unchecked") + public void forEach(Consumer action) { + action.accept(e0); // implicit null check + if (e1 != EMPTY) { + action.accept((E) e1); + } + } + + @Override + public Spliterator spliterator() { + if (e1 == EMPTY) { + return Collections.singletonSpliterator(e0); + } else { + return super.spliterator(); + } + } } @jdk.internal.ValueBased @@ -895,6 +915,26 @@ public T[] toArray(T[] a) { } return array; } + + @Override + @SuppressWarnings("unchecked") + public void forEach(Consumer action) { + if (e1 == EMPTY) { + action.accept(e0); // implicit null check + } else { + action.accept(REVERSE ? (E)e1 : e0); // implicit null check + action.accept(REVERSE ? e0 : (E)e1); + } + } + + @Override + public Spliterator spliterator() { + if (e1 == EMPTY) { + return Collections.singletonSpliterator(e0); + } else { + return super.spliterator(); + } + } } @@ -1158,6 +1198,11 @@ private Object writeReplace() { public int hashCode() { return k0.hashCode() ^ v0.hashCode(); } + + @Override + public void forEach(BiConsumer action) { + action.accept(k0, v0); // implicit null check + } } /** diff --git a/test/jdk/java/util/Collection/MOAT.java b/test/jdk/java/util/Collection/MOAT.java index d281e5db125f8..1a4e5503f63b0 100644 --- a/test/jdk/java/util/Collection/MOAT.java +++ b/test/jdk/java/util/Collection/MOAT.java @@ -26,7 +26,7 @@ * @bug 6207984 6272521 6192552 6269713 6197726 6260652 5073546 4137464 * 4155650 4216399 4294891 6282555 6318622 6355327 6383475 6420753 * 6431845 4802633 6570566 6570575 6570631 6570924 6691185 6691215 - * 4802647 7123424 8024709 8193128 + * 4802647 7123424 8024709 8193128 8327858 * @summary Run many tests on many Collection and Map implementations * @author Martin Buchholz * @modules java.base/java.util:open @@ -479,6 +479,8 @@ private static void testImmutableCollection(final Collection c, T t) { () -> c.removeAll(singleton(first)), () -> c.retainAll(emptyList())); } + testForEachMatch(c); + testSpliteratorMatch(c); } private static void testImmutableSeqColl(final SequencedCollection c, T t) { @@ -540,6 +542,39 @@ private static void testCollMutatorsAlwaysThrow(Collection c) { () -> c.retainAll(c)); } + // Ensures forEach supplies in the same order as the iterator + private static void testForEachMatch(Collection c) { + var itr = c.iterator(); + int[] index = {0}; + c.forEach(item -> { + T itrNext = null; + if (!itr.hasNext() || !Objects.equals(itrNext = itr.next(), item)) { + fail("forEach and iterator mismatch at " + index[0] + " forEach: " + item + ", itr: " + itrNext); + } + index[0]++; + }); + if (itr.hasNext()) { + fail("forEach and iterator mismatch at tail, extras in itr"); + } + } + + // Ensures spliterator returns in the same order as the iterator + private static void testSpliteratorMatch(Collection c) { + var itr = c.iterator(); + var split = c.spliterator(); + int[] index = {0}; + split.forEachRemaining(item -> { + T itrNext = null; + if (!itr.hasNext() || !Objects.equals(itrNext = itr.next(), item)) { + fail("iterator and spliterator mismatch at " + index[0] + " spliterator: " + item + ", itr: " + itrNext); + } + index[0]++; + }); + if (itr.hasNext()) { + fail("iterator and spliterator mismatch at tail, extra item in itr"); + } + } + /** * Test that calling a mutator always throws UOE, even if the mutator * wouldn't actually do anything on an empty collection. diff --git a/test/micro/org/openjdk/bench/java/util/ImmutableColls.java b/test/micro/org/openjdk/bench/java/util/ImmutableColls.java index 197312852a2dc..783f870ca5bd3 100644 --- a/test/micro/org/openjdk/bench/java/util/ImmutableColls.java +++ b/test/micro/org/openjdk/bench/java/util/ImmutableColls.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -297,6 +297,50 @@ public void iterateSet(Blackhole bh, Set coll) { } } + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void forEachOverSet(Blackhole bh) { + forEachSet(bh, fs4); + forEachSet(bh, s1); + forEachSet(bh, s3); + forEachSet(bh, fs2); + forEachSet(bh, s0); + } + + public void forEachSet(Blackhole bh, Set coll) { + coll.forEach(bh::consume); + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void iterateOverList(Blackhole bh) { + iterateList(bh, fl4); + iterateList(bh, fl1); + iterateList(bh, l3); + iterateList(bh, l0); + iterateList(bh, fl2); + } + + public void iterateList(Blackhole bh, List coll) { + for (String s : coll) { + bh.consume(s); + } + } + + @Benchmark + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void forEachOverList(Blackhole bh) { + forEachList(bh, fl4); + forEachList(bh, fl1); + forEachList(bh, l3); + forEachList(bh, l0); + forEachList(bh, fl2); + } + + public void forEachList(Blackhole bh, List coll) { + coll.forEach(bh::consume); + } + @Benchmark @CompilerControl(CompilerControl.Mode.DONT_INLINE) public void toArrayFromMap(Blackhole bh) { From 0ebdde9385cb44816ba1c925dbb6170f8fd62b74 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 3 Apr 2025 21:27:57 -0400 Subject: [PATCH 0384/1101] Sort out signing. --- .../AppImageSigningConfigBuilder.java | 87 ++++++++++ .../jdk/jpackage/internal/CodesignConfig.java | 40 ++++- .../internal/MacApplicationBuilder.java | 8 +- .../internal/MacCertificateUtils.java | 26 ++- .../jdk/jpackage/internal/MacFromParams.java | 55 ++++--- .../internal/MacPackagingPipeline.java | 8 +- .../internal/MacPkgPackageBuilder.java | 12 +- .../jdk/jpackage/internal/MacPkgPackager.java | 2 +- ...ilder.java => SigningIdentityBuilder.java} | 151 ++++++------------ .../internal/SigningIdentityImpl.java | 14 +- ...Config.java => AppImageSigningConfig.java} | 10 +- .../internal/model/MacApplicationMixin.java | 4 +- .../internal/model/MacPkgPackageMixin.java | 4 +- .../internal/model/PkgSigningConfig.java | 38 +++++ .../internal/model/SigningIdentity.java | 3 - 15 files changed, 283 insertions(+), 179 deletions(-) create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigningConfigBuilder.java rename src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/{SigningConfigBuilder.java => SigningIdentityBuilder.java} (54%) rename src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/{SigningConfig.java => AppImageSigningConfig.java} (85%) create mode 100644 src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/PkgSigningConfig.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigningConfigBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigningConfigBuilder.java new file mode 100644 index 0000000000000..05263a4129077 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigningConfigBuilder.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import jdk.jpackage.internal.model.AppImageSigningConfig; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LauncherStartupInfo; + +final class AppImageSigningConfigBuilder { + + AppImageSigningConfigBuilder(SigningIdentityBuilder signingIdentityBuilder) { + this.signingIdentityBuilder = Objects.requireNonNull(signingIdentityBuilder); + } + + AppImageSigningConfigBuilder entitlements(Path v) { + entitlements = v; + return this; + } + + AppImageSigningConfigBuilder entitlementsResourceName(String v) { + entitlementsResourceName = v; + return this; + } + + AppImageSigningConfigBuilder signingIdentifierPrefix(LauncherStartupInfo mainLauncherStartupInfo) { + final var pkgName = mainLauncherStartupInfo.packageName(); + if (!pkgName.isEmpty()) { + signingIdentifierPrefix(pkgName + "."); + } else { + signingIdentifierPrefix(mainLauncherStartupInfo.simpleClassName() + "."); + } + return this; + } + + AppImageSigningConfigBuilder signingIdentifierPrefix(String v) { + signingIdentifierPrefix = v; + return this; + } + + Optional create() throws ConfigException { + final var identityCfg = signingIdentityBuilder.create(); + if (identityCfg.isEmpty()) { + return Optional.empty(); + } else { + final var validatedEntitlements = validatedEntitlements(); + return identityCfg.map(cfg -> { + return new AppImageSigningConfig.Stub(cfg.identity(), signingIdentifierPrefix, + validatedEntitlements, cfg.keychain().map(Keychain::name), + Optional.ofNullable(entitlementsResourceName).orElse("sandbox.plist")); + }); + } + } + + private Optional validatedEntitlements() throws ConfigException { + return Optional.ofNullable(entitlements); + } + + private SigningIdentityBuilder signingIdentityBuilder; + private Path entitlements; + private String entitlementsResourceName; + private String signingIdentifierPrefix; +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java index f03f408f1ddcc..97f5f1d04e222 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java @@ -27,22 +27,40 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; -import jdk.jpackage.internal.model.SigningConfig; +import jdk.jpackage.internal.model.AppImageSigningConfig; import jdk.jpackage.internal.model.SigningIdentity; import jdk.jpackage.internal.util.PathUtils; -record CodesignConfig(Optional identity, +record CodesignConfig(Optional identity, Optional identifierPrefix, Optional entitlements, Optional keychain) { + CodesignConfig { + Objects.requireNonNull(identity); + Objects.requireNonNull(identifierPrefix); + Objects.requireNonNull(entitlements); + Objects.requireNonNull(keychain); + + if (identity.isPresent() != identifierPrefix.isPresent()) { + throw new IllegalArgumentException("Signing identity and identifier prefix mismatch"); + } + + identifierPrefix.ifPresent(v -> { + if (!v.endsWith(".")) { + throw new IllegalArgumentException("Invalid identifier prefix"); + } + }); + } + static final class Builder { private Builder() { } CodesignConfig create() { - return new CodesignConfig(Optional.ofNullable(identity), + return new CodesignConfig(Optional.ofNullable(identity), Optional.ofNullable(identifierPrefix), Optional.ofNullable(entitlements), Optional.ofNullable(keychain)); } @@ -56,6 +74,11 @@ Builder identity(SigningIdentity v) { return this; } + Builder identifierPrefix(String v) { + identifierPrefix = v; + return this; + } + Builder keychain(String v) { return keychain(new Keychain(v)); } @@ -65,19 +88,22 @@ Builder keychain(Keychain v) { return this; } - Builder from(SigningConfig v) { - return identity(v.identity().orElse(null)) + Builder from(AppImageSigningConfig v) { + return identity(v.identity()) + .identifierPrefix(v.identifierPrefix()) .entitlements(v.entitlements().orElse(null)) .keychain(v.keychain().orElse(null)); } Builder from(CodesignConfig v) { return identity(v.identity().orElse(null)) + .identifierPrefix(v.identifierPrefix().orElse(null)) .entitlements(v.entitlements().orElse(null)) .keychain(v.keychain().orElse(null)); } private SigningIdentity identity; + private String identifierPrefix; private Path entitlements; private Keychain keychain; } @@ -91,8 +117,8 @@ List toCodesignArgs() { if (identity.isPresent()) { args.addAll(List.of("--timestamp", "--options", "runtime")); - identity.flatMap(SigningIdentity::prefix).ifPresent(identifierPrefix -> { - args.addAll(List.of("--prefix", identifierPrefix)); + identifierPrefix.ifPresent(v -> { + args.addAll(List.of("--prefix", v)); }); keychain.map(Keychain::asCliArg).ifPresent(k -> args.addAll(List.of("--keychain", k))); entitlements.map(PathUtils::normalizedAbsolutePathString).ifPresent(e -> args.addAll(List.of("--entitlements", e))); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java index a2b2791ab4cd2..f54abdde027e8 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java @@ -34,7 +34,7 @@ import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.MacApplicationMixin; -import jdk.jpackage.internal.model.SigningConfig; +import jdk.jpackage.internal.model.AppImageSigningConfig; final class MacApplicationBuilder { @@ -83,7 +83,7 @@ MacApplicationBuilder externalInfoPlistFile(Path v) { return this; } - MacApplicationBuilder signingBuilder(SigningConfigBuilder v) { + MacApplicationBuilder signingBuilder(AppImageSigningConfigBuilder v) { signingBuilder = v; return this; } @@ -154,7 +154,7 @@ private MacApplicationBuilder createCopyForExternalInfoPlistFile() throws Config } } - private Optional createSigningConfig() throws ConfigException { + private Optional createSigningConfig() throws ConfigException { if (signingBuilder != null) { return signingBuilder.create(); } else { @@ -224,7 +224,7 @@ private record Defaults(String category) { private String category; private boolean appStore; private Path externalInfoPlistFile; - private SigningConfigBuilder signingBuilder; + private AppImageSigningConfigBuilder signingBuilder; private final Application app; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java index 81b90cafe471b..fe593e347fced 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java @@ -25,12 +25,13 @@ package jdk.jpackage.internal; -import static jdk.jpackage.internal.util.CollectionUtils.toCollectionUBW; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; +import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; +import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; @@ -51,7 +52,7 @@ public static Collection findCertificates(Optional ke args.add("-p"); // PEM format keychain.map(Keychain::asCliArg).ifPresent(args::add); - return toCollectionUBW(toSupplier(() -> { + return toSupplier(() -> { final var output = Executor.of(args.toArray(String[]::new)) .setQuiet(true).saveOutput(true).executeExpectSuccess() .getOutput(); @@ -61,11 +62,24 @@ public static Collection findCertificates(Optional ke MacCertificateUtils::append, MacCertificateUtils::append).toString().getBytes(StandardCharsets.US_ASCII); - try (var in = new ByteArrayInputStream(pemCertificatesBuffer)) { - final var cf = CertificateFactory.getInstance("X.509"); - return cf.generateCertificates(in); + final var cf = CertificateFactory.getInstance("X.509"); + + Collection certs = new ArrayList<>(); + + try (var in = new BufferedInputStream(new ByteArrayInputStream(pemCertificatesBuffer))) { + while (in.available() > 0) { + final X509Certificate cert; + try { + cert = (X509Certificate)cf.generateCertificate(in); + } catch (CertificateException ex) { + // Not a valid X505 certificate, silently ignore. + continue; + } + certs.add(cert); + } } - }).get()); + return certs; + }).get(); } record CertificateHash(byte[] value) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java index eeeb2e3d6dd87..988295ad5559e 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java @@ -56,7 +56,7 @@ import java.util.Optional; import java.util.function.Predicate; import jdk.jpackage.internal.ApplicationBuilder.MainLauncherStartupInfo; -import jdk.jpackage.internal.SigningConfigBuilder.StandardCertificateSelector; +import jdk.jpackage.internal.SigningIdentityBuilder.StandardCertificateSelector; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLaunchers; import jdk.jpackage.internal.model.ConfigException; @@ -130,25 +130,29 @@ private static MacApplication createMacApplication( appBuilder.appStore(appStore); if (sign) { - final var signingBuilder = createSigningConfigBuilder(params, app); - if (appStore) { - signingBuilder.entitlementsResourceName("entitlements.plist"); - } - - ENTITLEMENTS.copyInto(params, signingBuilder::entitlements); - APP_IMAGE_SIGN_IDENTITY.copyInto(params, signingBuilder::signingIdentity); - + final var signingIdentityBuilder = createSigningIdentityBuilder(params, app); + APP_IMAGE_SIGN_IDENTITY.copyInto(params, signingIdentityBuilder::signingIdentity); SIGNING_KEY_USER.findIn(params).ifPresent(userName -> { - final StandardCertificateSelector filter; + final StandardCertificateSelector domain; if (appStore) { - filter = StandardCertificateSelector.APP_STORE_APP_IMAGE; + domain = StandardCertificateSelector.APP_STORE_APP_IMAGE; } else { - filter = StandardCertificateSelector.APP_IMAGE; + domain = StandardCertificateSelector.APP_IMAGE; } - signingBuilder.addCertificateSelectors(StandardCertificateSelector.create(userName, filter)); + signingIdentityBuilder.certificateSelector(StandardCertificateSelector.create(userName, domain)); }); + final var signingBuilder = new AppImageSigningConfigBuilder(signingIdentityBuilder); + if (appStore) { + signingBuilder.entitlementsResourceName("entitlements.plist"); + } + + app.mainLauncher().flatMap(Launcher::startupInfo).ifPresent(signingBuilder::signingIdentifierPrefix); + SIGN_IDENTIFIER_PREFIX.copyInto(params, signingBuilder::signingIdentifierPrefix); + + ENTITLEMENTS.copyInto(params, signingBuilder::entitlements); + appBuilder.signingBuilder(signingBuilder); } @@ -195,32 +199,27 @@ private static MacPkgPackage createMacPkgPackage( final boolean appStore = APP_STORE.findIn(params).orElse(false); if (sign) { - final var signingBuilder = createSigningConfigBuilder(params, app); - INSTALLER_SIGN_IDENTITY.copyInto(params, signingBuilder::signingIdentity); - + final var signingIdentityBuilder = createSigningIdentityBuilder(params, app); + INSTALLER_SIGN_IDENTITY.copyInto(params, signingIdentityBuilder::signingIdentity); SIGNING_KEY_USER.findIn(params).ifPresent(userName -> { - final List filters; + final StandardCertificateSelector domain; if (appStore) { - filters = List.of(StandardCertificateSelector.APP_STORE_PKG_INSTALLER); + domain = StandardCertificateSelector.APP_STORE_PKG_INSTALLER; } else { - filters = List.of(StandardCertificateSelector.PKG_INSTALLER); + domain = StandardCertificateSelector.PKG_INSTALLER; } - for (final var filter : filters) { - signingBuilder.addCertificateSelectors(StandardCertificateSelector.create(userName, filter)); - } + signingIdentityBuilder.certificateSelector(StandardCertificateSelector.create(userName, domain)); }); - pkgBuilder.signingBuilder(signingBuilder); + pkgBuilder.signingBuilder(signingIdentityBuilder); } return pkgBuilder.create(); } - private static SigningConfigBuilder createSigningConfigBuilder(Map params, Application app) { - final var builder = new SigningConfigBuilder(); - app.mainLauncher().flatMap(Launcher::startupInfo).ifPresent(builder::signingIdentityPrefix); - BUNDLE_ID_SIGNING_PREFIX.copyInto(params, builder::signingIdentityPrefix); + private static SigningIdentityBuilder createSigningIdentityBuilder(Map params, Application app) { + final var builder = new SigningIdentityBuilder(); SIGNING_KEYCHAIN.copyInto(params, builder::keychain); return builder; } @@ -264,7 +263,7 @@ private static MacFileAssociation createMacFa(FileAssociation fa, Map MAC_CF_BUNDLE_IDENTIFIER = createStringBundlerParam( Arguments.CLIOptions.MAC_BUNDLE_IDENTIFIER.getId()); - static final BundlerParamInfo BUNDLE_ID_SIGNING_PREFIX = createStringBundlerParam( + static final BundlerParamInfo SIGN_IDENTIFIER_PREFIX = createStringBundlerParam( Arguments.CLIOptions.MAC_BUNDLE_SIGNING_PREFIX.getId()); static final BundlerParamInfo APP_IMAGE_SIGN_IDENTITY = createStringBundlerParam( diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index 89f6a4582f1f1..ee1f0df8f042d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -69,7 +69,7 @@ import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.SigningConfig; +import jdk.jpackage.internal.model.AppImageSigningConfig; import jdk.jpackage.internal.util.function.ThrowingConsumer; final class MacPackagingPipeline { @@ -287,9 +287,9 @@ private static void sign(AppImageBuildEnv final var codesignConfigBuilder = CodesignConfig.build(); app.signingConfig().ifPresent(codesignConfigBuilder::from); - if (app.sign() && app.signingConfig().flatMap(SigningConfig::entitlements).isEmpty()) { + if (app.sign() && app.signingConfig().flatMap(AppImageSigningConfig::entitlements).isEmpty()) { final var entitlementsDefaultResource = app.signingConfig().map( - SigningConfig::entitlementsResourceName).orElseThrow(); + AppImageSigningConfig::entitlementsResourceName).orElseThrow(); final var entitlementsFile = env.env().configDir().resolve(app.name() + ".entitlements"); @@ -305,7 +305,7 @@ private static void sign(AppImageBuildEnv AppImageSigner.createSigner(app, codesignConfigBuilder.create()).accept(appImageDir); }; - app.signingConfig().flatMap(SigningConfig::keychain).map(Keychain::new).ifPresentOrElse(keychain -> { + app.signingConfig().flatMap(AppImageSigningConfig::keychain).map(Keychain::new).ifPresentOrElse(keychain -> { toBiConsumer(TempKeychain::withKeychain).accept(keychain, unused -> signAction.run()); }, signAction); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java index 493fc61e26a1a..131650aebb516 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java @@ -29,7 +29,7 @@ import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.MacPkgPackage; import jdk.jpackage.internal.model.MacPkgPackageMixin; -import jdk.jpackage.internal.model.SigningConfig; +import jdk.jpackage.internal.model.PkgSigningConfig; final class MacPkgPackageBuilder { @@ -37,7 +37,7 @@ final class MacPkgPackageBuilder { this.pkgBuilder = Objects.requireNonNull(pkgBuilder); } - MacPkgPackageBuilder signingBuilder(SigningConfigBuilder v) { + MacPkgPackageBuilder signingBuilder(SigningIdentityBuilder v) { signingBuilder = v; return this; } @@ -46,14 +46,16 @@ MacPkgPackage create() throws ConfigException { return MacPkgPackage.create(pkgBuilder.create(), new MacPkgPackageMixin.Stub(createSigningConfig())); } - private Optional createSigningConfig() throws ConfigException { + private Optional createSigningConfig() throws ConfigException { if (signingBuilder != null) { - return signingBuilder.create(); + return signingBuilder.create().map(cfg -> { + return new PkgSigningConfig.Stub(cfg.identity(), cfg.keychain().map(Keychain::name)); + }); } else { return Optional.empty(); } } private final MacPackageBuilder pkgBuilder; - private SigningConfigBuilder signingBuilder; + private SigningIdentityBuilder signingBuilder; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java index 5a7355dd38aab..d27db11879852 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java @@ -529,7 +529,7 @@ private void productbuild() throws IOException { final var pkgSigningConfig = pkg.signingConfig().orElseThrow(); commandLine.add("--sign"); - commandLine.add(pkgSigningConfig.identity().orElseThrow().id()); + commandLine.add(pkgSigningConfig.identity().id()); pkgSigningConfig.keychain().map(Keychain::new).ifPresent(keychain -> { commandLine.add("--keychain"); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityBuilder.java similarity index 54% rename from src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java rename to src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityBuilder.java index f48ad3fa9a9f0..f818e3d56b79a 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningConfigBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityBuilder.java @@ -28,13 +28,10 @@ import java.nio.file.Path; import java.security.cert.X509Certificate; -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.Predicate; import java.util.stream.Stream; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; @@ -42,136 +39,89 @@ import javax.security.auth.x500.X500Principal; import jdk.jpackage.internal.MacCertificateUtils.CertificateHash; import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.LauncherStartupInfo; -import jdk.jpackage.internal.model.SigningConfig; import jdk.jpackage.internal.model.SigningIdentity; -final class SigningConfigBuilder { +final class SigningIdentityBuilder { - SigningConfigBuilder signingIdentity(String v) { - signingIdentity = v; - return this; - } - - SigningConfigBuilder signingIdentityPrefix(LauncherStartupInfo mainLauncherStartupInfo) { - final var pkgName = mainLauncherStartupInfo.packageName(); - if (!pkgName.isEmpty()) { - signingIdentityPrefix(pkgName + "."); - } else { - signingIdentityPrefix(mainLauncherStartupInfo.simpleClassName() + "."); + record SigningConfig(SigningIdentity identity, Optional keychain) { + SigningConfig { + Objects.requireNonNull(identity); + Objects.requireNonNull(keychain); } - return this; } - SigningConfigBuilder signingIdentityPrefix(String v) { - signingIdentityPrefix = v; + SigningIdentityBuilder signingIdentity(String v) { + signingIdentity = v; return this; } - SigningConfigBuilder addCertificateSelectors(CertificateSelector ...v) { - return addCertificateSelectors(List.of(v)); - } - - SigningConfigBuilder addCertificateSelectors(Collection v) { - certificateSelectors.addAll(v); + SigningIdentityBuilder certificateSelector(CertificateSelector v) { + certificateSelector = v; return this; } - SigningConfigBuilder keychain(String v) { + SigningIdentityBuilder keychain(String v) { keychain = v; return this; } - SigningConfigBuilder entitlements(Path v) { - entitlements = v; - return this; - } - - SigningConfigBuilder entitlementsResourceName(String v) { - entitlementsResourceName = v; - return this; - } - Optional create() throws ConfigException { - if (signingIdentity == null && certificateSelectors.isEmpty()) { + if (signingIdentity == null && certificateSelector == null) { return Optional.empty(); } else { - return Optional.of(new SigningConfig.Stub(validatedSigningIdentity(), validatedEntitlements(), - validatedKeychain().map(Keychain::name), - Optional.ofNullable(entitlementsResourceName).orElse("sandbox.plist"))); + return Optional.of(new SigningConfig(validatedSigningIdentity(), validatedKeychain())); } } - private Optional validatedEntitlements() throws ConfigException { - return Optional.ofNullable(entitlements); - } - private Optional validatedKeychain() throws ConfigException { return Optional.ofNullable(keychain).map(Keychain::new); } - private Optional validatedSigningIdentity() throws ConfigException { - CertificateHash signingIdentityHash = null; + private SigningIdentity validatedSigningIdentity() throws ConfigException { if (signingIdentity != null) { - try { - signingIdentityHash = CertificateHash.fromHexString(signingIdentity); - } catch (Throwable t) { - // Not a valid certificate hash - } + return new SigningIdentityImpl(signingIdentity); } + Objects.requireNonNull(certificateSelector); + final var validatedKeychain = validatedKeychain(); final var allCertificates = findCertificates(validatedKeychain, Optional.empty()); - if (signingIdentityHash != null) { - if (allCertificates.stream().map(CertificateHash::of).anyMatch(Predicate.isEqual(signingIdentityHash))) { - return Optional.of(new SigningIdentityImpl(signingIdentityHash.toString(), - Optional.ofNullable(signingIdentityPrefix))); - } else { - throw I18N.buildConfigException("error.cert.not.found", validatedKeychain.map(Keychain::name).orElse("")).create(); - } - } - final var mappedCertficates = allCertificates.stream().>mapMulti((cert, acc) -> { findSubjectCNs(cert).stream().map(cn -> { return Map.entry(cn, cert); }).forEach(acc::accept); }).toList(); - final List allCertificateSelectors; - if (signingIdentity != null) { - allCertificateSelectors = new ArrayList<>(certificateSelectors); - allCertificateSelectors.add(new CertificateSelector("", signingIdentity)); - } else { - allCertificateSelectors = certificateSelectors; - } - - final var resolvedCertificateSelectors = allCertificateSelectors.stream().map(CertificateSelector::fullName).toList(); + final var signingIdentityNames = certificateSelector.signingIdentities(); var matchingCertificates = mappedCertficates.stream().filter(e -> { - return resolvedCertificateSelectors.contains(e.getKey()); + return signingIdentityNames.contains(e.getKey()); }).map(Map.Entry::getValue).toList(); - if (!matchingCertificates.isEmpty()) { - signingIdentityHash = selectSigningIdentity(matchingCertificates, allCertificateSelectors, validatedKeychain); - } else { + if (matchingCertificates.isEmpty()) { matchingCertificates = mappedCertficates.stream().filter(e -> { - return resolvedCertificateSelectors.stream().anyMatch(filter -> { + return signingIdentityNames.stream().anyMatch(filter -> { return filter.startsWith(e.getKey()); }); }).map(Map.Entry::getValue).toList(); - signingIdentityHash = selectSigningIdentity(matchingCertificates, allCertificateSelectors, validatedKeychain); } - return Optional.of(new SigningIdentityImpl(signingIdentityHash.toString(), - Optional.ofNullable(signingIdentityPrefix))); + final CertificateHash signingIdentityHash = selectSigningIdentity(matchingCertificates, + certificateSelector, validatedKeychain); + + return new SigningIdentityImpl(signingIdentityHash.toString()); } private static CertificateHash selectSigningIdentity(List certs, - List certificateSelectors, Optional keychain) throws ConfigException { + CertificateSelector certificateSelector, Optional keychain) throws ConfigException { + Objects.requireNonNull(certificateSelector); + Objects.requireNonNull(keychain); switch (certs.size()) { case 0 -> { + Log.error(I18N.format("error.cert.not.found", certificateSelector.name(), + keychain.map(Keychain::name).orElse(""))); throw I18N.buildConfigException("error.explicit-sign-no-cert") .advice("error.explicit-sign-no-cert.advice").create(); } @@ -179,7 +129,7 @@ private static CertificateHash selectSigningIdentity(List certs return CertificateHash.of(certs.getFirst()); } default -> { - Log.error(I18N.format("error.multiple.certs.found", certificateSelectors.getFirst().name(), + Log.error(I18N.format("error.multiple.certs.found", certificateSelector.name(), keychain.map(Keychain::name).orElse(""))); return CertificateHash.of(certs.getFirst()); } @@ -196,20 +146,24 @@ private static List findSubjectCNs(X509Certificate cert) { return ldapName.getRdns().stream().filter(rdn -> { return rdn.getType().equalsIgnoreCase("CN"); - }).map(Rdn::getValue).map(Object::toString).toList(); + }).map(Rdn::getValue).map(Object::toString).distinct().toList(); } - record CertificateSelector(String prefix, String name) { + record CertificateSelector(String name, List prefixes) { CertificateSelector { - Objects.requireNonNull(prefix); + Objects.requireNonNull(prefixes); + prefixes.forEach(Objects::requireNonNull); Objects.requireNonNull(name); - if (prefix.isEmpty() && name.isEmpty()) { - throw new IllegalArgumentException("Empty prefix and name"); - } } - String fullName() { - return prefix + name; + List signingIdentities() { + if (prefixes().isEmpty()) { + return List.of(name); + } else { + return prefixes.stream().map(StandardCertificatePrefix::value).map(prefix -> { + return prefix + name; + }).toList(); + } } } @@ -227,10 +181,10 @@ String value() { return value; } - static Optional findStandardCertificatePrefix(String fullName) { - Objects.requireNonNull(fullName); + static Optional findStandardCertificatePrefix(String certificateLocator) { + Objects.requireNonNull(certificateLocator); return Stream.of(StandardCertificatePrefix.values()).filter(prefix -> { - return fullName.startsWith(prefix.value); + return certificateLocator.startsWith(prefix.value); }).reduce((x, y) -> { throw new UnsupportedOperationException(); }); @@ -249,13 +203,11 @@ enum StandardCertificateSelector { this.prefixes = List.of(prefixes); } - static List create(String certificateName, StandardCertificateSelector defaultSelector) { - return StandardCertificatePrefix.findStandardCertificatePrefix(certificateName).map(prefix -> { - return new CertificateSelector(prefix.value(), certificateName.substring(prefix.value().length())); - }).map(List::of).orElseGet(() -> { - return defaultSelector.prefixes.stream().map(prefix -> { - return new CertificateSelector(prefix.value(), certificateName); - }).toList(); + static CertificateSelector create(String certificateLocator, StandardCertificateSelector defaultSelector) { + return StandardCertificatePrefix.findStandardCertificatePrefix(certificateLocator).map(prefix -> { + return new CertificateSelector(certificateLocator, List.of()); + }).orElseGet(() -> { + return new CertificateSelector(certificateLocator, defaultSelector.prefixes); }); } @@ -263,8 +215,7 @@ static List create(String certificateName, StandardCertific } private String signingIdentity; - private String signingIdentityPrefix; - private List certificateSelectors = new ArrayList<>(); + private CertificateSelector certificateSelector; private String keychain; private Path entitlements; private String entitlementsResourceName; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityImpl.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityImpl.java index 640cb52f9ec42..fc8f1ec0d3020 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityImpl.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityImpl.java @@ -28,27 +28,15 @@ import static jdk.jpackage.internal.CodesignConfig.ADHOC_SIGNING_IDENTITY; import java.util.Objects; -import java.util.Optional; import jdk.jpackage.internal.model.SigningIdentity; -record SigningIdentityImpl(String id, Optional prefix) implements SigningIdentity { +record SigningIdentityImpl(String id) implements SigningIdentity { SigningIdentityImpl { Objects.requireNonNull(id); - Objects.requireNonNull(prefix); if (ADHOC_SIGNING_IDENTITY.equals(id)) { throw new IllegalArgumentException("Adhoc signing identity no allowed"); } - - if (id.contains(".") == prefix.isPresent()) { - throw new IllegalArgumentException("id and prefix mismatch"); - } - - prefix.ifPresent(thePrefix -> { - if (!thePrefix.endsWith(".")) { - throw new IllegalArgumentException("Illegal prefix"); - } - }); } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningConfig.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/AppImageSigningConfig.java similarity index 85% rename from src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningConfig.java rename to src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/AppImageSigningConfig.java index acf0929704843..fc807e21915bf 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningConfig.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/AppImageSigningConfig.java @@ -28,9 +28,11 @@ import java.nio.file.Path; import java.util.Optional; -public interface SigningConfig { +public interface AppImageSigningConfig { - Optional identity(); + SigningIdentity identity(); + + String identifierPrefix(); Optional entitlements(); @@ -38,7 +40,7 @@ public interface SigningConfig { Optional keychain(); - record Stub(Optional identity, Optional entitlements, - Optional keychain, String entitlementsResourceName) implements SigningConfig { + record Stub(SigningIdentity identity, String identifierPrefix, Optional entitlements, + Optional keychain, String entitlementsResourceName) implements AppImageSigningConfig { } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java index 31e2e6b44b4cb..c3f7a3d97902d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java @@ -39,9 +39,9 @@ public interface MacApplicationMixin { boolean appStore(); - Optional signingConfig(); + Optional signingConfig(); record Stub(Optional icon, String bundleName, String bundleIdentifier, String category, - boolean appStore, Optional signingConfig) implements MacApplicationMixin { + boolean appStore, Optional signingConfig) implements MacApplicationMixin { } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackageMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackageMixin.java index 2cc2ef32873dc..6b69299ea0349 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackageMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackageMixin.java @@ -28,8 +28,8 @@ public interface MacPkgPackageMixin { - Optional signingConfig(); + Optional signingConfig(); - record Stub(Optional signingConfig) implements MacPkgPackageMixin { + record Stub(Optional signingConfig) implements MacPkgPackageMixin { } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/PkgSigningConfig.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/PkgSigningConfig.java new file mode 100644 index 0000000000000..353cd7053c693 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/PkgSigningConfig.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.model; + +import java.util.Optional; + +public interface PkgSigningConfig { + + SigningIdentity identity(); + + Optional keychain(); + + record Stub(SigningIdentity identity, Optional keychain) implements PkgSigningConfig { + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentity.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentity.java index 91d53c7bf2e46..6ca6ac29922eb 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentity.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/SigningIdentity.java @@ -25,11 +25,8 @@ package jdk.jpackage.internal.model; -import java.util.Optional; - public interface SigningIdentity { String id(); - Optional prefix(); } From 41d4a0d7bdda2a96af1e7f549c05d99d68c040dc Mon Sep 17 00:00:00 2001 From: Varada M Date: Fri, 4 Apr 2025 06:41:08 +0000 Subject: [PATCH 0385/1101] 8352392: AIX: implement attach API v2 and streaming output Reviewed-by: mdoerr, jkern, amenkov --- src/hotspot/os/aix/attachListener_aix.cpp | 235 ++++-------------- .../sun/tools/attach/VirtualMachineImpl.java | 62 ++--- test/hotspot/jtreg/ProblemList.txt | 2 - 3 files changed, 80 insertions(+), 219 deletions(-) diff --git a/src/hotspot/os/aix/attachListener_aix.cpp b/src/hotspot/os/aix/attachListener_aix.cpp index 218ee04fdcc0e..e5101814f9771 100644 --- a/src/hotspot/os/aix/attachListener_aix.cpp +++ b/src/hotspot/os/aix/attachListener_aix.cpp @@ -73,16 +73,7 @@ class AixAttachListener: AllStatic { static bool _atexit_registered; - // reads a request from the given connected socket - static AixAttachOperation* read_request(int s); - public: - enum { - ATTACH_PROTOCOL_VER = 1 // protocol version - }; - enum { - ATTACH_ERROR_BADVERSION = 101 // error codes - }; static void set_path(char* path) { if (path == nullptr) { @@ -107,25 +98,65 @@ class AixAttachListener: AllStatic { static void set_shutdown(bool shutdown) { _shutdown = shutdown; } static bool is_shutdown() { return _shutdown; } - // write the given buffer to a socket - static int write_fully(int s, char* buf, size_t len); - static AixAttachOperation* dequeue(); }; +class SocketChannel : public AttachOperation::RequestReader, public AttachOperation::ReplyWriter { +private: + int _socket; +public: + SocketChannel(int socket) : _socket(socket) {} + ~SocketChannel() { + close(); + } + + bool opened() const { + return _socket != -1; + } + + void close() { + if (opened()) { + // SHUT_RDWR is not available + ::shutdown(_socket, 2); + ::close(_socket); + _socket = -1; + } + } + + // RequestReader + int read(void* buffer, int size) override { + ssize_t n; + RESTARTABLE(::read(_socket, buffer, (size_t)size), n); + return checked_cast(n); + } + + // ReplyWriter + int write(const void* buffer, int size) override { + ssize_t n; + RESTARTABLE(::write(_socket, buffer, size), n); + return checked_cast(n); + } + + void flush() override { + } +}; + class AixAttachOperation: public AttachOperation { private: // the connection to the client - int _socket; + SocketChannel _socket_channel; public: - void complete(jint res, bufferedStream* st); + AixAttachOperation(int socket) : AttachOperation(), _socket_channel(socket) {} - void set_socket(int s) { _socket = s; } - int socket() const { return _socket; } + void complete(jint res, bufferedStream* st) override; - AixAttachOperation(char* name) : AttachOperation(name) { - set_socket(-1); + ReplyWriter* get_reply_writer() override { + return &_socket_channel; + } + + bool read_request() { + return _socket_channel.read_request(this, &_socket_channel); } }; @@ -137,34 +168,6 @@ bool AixAttachListener::_atexit_registered = false; // Shutdown marker to prevent accept blocking during clean-up volatile bool AixAttachListener::_shutdown = false; -// Supporting class to help split a buffer into individual components -class ArgumentIterator : public StackObj { - private: - char* _pos; - char* _end; - public: - ArgumentIterator(char* arg_buffer, size_t arg_size) { - _pos = arg_buffer; - _end = _pos + arg_size - 1; - } - char* next() { - if (*_pos == '\0') { - // advance the iterator if possible (null arguments) - if (_pos < _end) { - _pos += 1; - } - return nullptr; - } - char* res = _pos; - char* next_pos = strchr(_pos, '\0'); - if (next_pos < _end) { - next_pos++; - } - _pos = next_pos; - return res; - } -}; - // On AIX if sockets block until all data has been transmitted // successfully in some communication domains a socket "close" may // never complete. We have to take care that after the socket shutdown @@ -258,106 +261,6 @@ int AixAttachListener::init() { return 0; } -// Given a socket that is connected to a peer we read the request and -// create an AttachOperation. As the socket is blocking there is potential -// for a denial-of-service if the peer does not response. However this happens -// after the peer credentials have been checked and in the worst case it just -// means that the attach listener thread is blocked. -// -AixAttachOperation* AixAttachListener::read_request(int s) { - char ver_str[8]; - os::snprintf_checked(ver_str, sizeof(ver_str), "%d", ATTACH_PROTOCOL_VER); - - // The request is a sequence of strings so we first figure out the - // expected count and the maximum possible length of the request. - // The request is: - // 00000 - // where is the protocol version (1), is the command - // name ("load", "datadump", ...), and is an argument - int expected_str_count = 2 + AttachOperation::arg_count_max; - const size_t max_len = (sizeof(ver_str) + 1) + (AttachOperation::name_length_max + 1) + - AttachOperation::arg_count_max*(AttachOperation::arg_length_max + 1); - - char buf[max_len]; - int str_count = 0; - - // Read until all (expected) strings have been read, the buffer is - // full, or EOF. - - size_t off = 0; - size_t left = max_len; - - do { - ssize_t n; - // Don't block on interrupts because this will - // hang in the clean-up when shutting down. - n = read(s, buf+off, left); - assert(n <= checked_cast(left), "buffer was too small, impossible!"); - buf[max_len - 1] = '\0'; - if (n == -1) { - return nullptr; // reset by peer or other error - } - if (n == 0) { - break; - } - for (int i=0; i so check it now to - // check for protocol mismatch - if (str_count == 1) { - if ((strlen(buf) != strlen(ver_str)) || - (atoi(buf) != ATTACH_PROTOCOL_VER)) { - char msg[32]; - os::snprintf_checked(msg, sizeof(msg), "%d\n", ATTACH_ERROR_BADVERSION); - write_fully(s, msg, strlen(msg)); - return nullptr; - } - } - } - } - off += n; - left -= n; - } while (left > 0 && str_count < expected_str_count); - - if (str_count != expected_str_count) { - return nullptr; // incomplete request - } - - // parse request - - ArgumentIterator args(buf, (max_len)-left); - - // version already checked - char* v = args.next(); - - char* name = args.next(); - if (name == nullptr || strlen(name) > AttachOperation::name_length_max) { - return nullptr; - } - - AixAttachOperation* op = new AixAttachOperation(name); - - for (int i=0; iset_arg(i, nullptr); - } else { - if (strlen(arg) > AttachOperation::arg_length_max) { - delete op; - return nullptr; - } - op->set_arg(i, arg); - } - } - - op->set_socket(s); - return op; -} - - // Dequeue an operation // // In the Aix implementation there is only a single operation and clients @@ -402,9 +305,9 @@ AixAttachOperation* AixAttachListener::dequeue() { } // peer credential look okay so we read the request - AixAttachOperation* op = read_request(s); - if (op == nullptr) { - ::close(s); + AixAttachOperation* op = new AixAttachOperation(s); + if (!op->read_request()) { + delete op; continue; } else { return op; @@ -412,21 +315,6 @@ AixAttachOperation* AixAttachListener::dequeue() { } } -// write the given buffer to the socket -int AixAttachListener::write_fully(int s, char* buf, size_t len) { - do { - ssize_t n = ::write(s, buf, len); - if (n == -1) { - if (errno != EINTR) return -1; - } else { - buf += n; - len -= n; - } - } - while (len > 0); - return 0; -} - // Complete an operation by sending the operation result and any result // output to the client. At this time the socket is in blocking mode so // potentially we can block if there is a lot of data and the client is @@ -436,24 +324,6 @@ int AixAttachListener::write_fully(int s, char* buf, size_t len) { // socket could be made non-blocking and a timeout could be used. void AixAttachOperation::complete(jint result, bufferedStream* st) { - JavaThread* thread = JavaThread::current(); - ThreadBlockInVM tbivm(thread); - - // write operation result - char msg[32]; - os::snprintf_checked(msg, sizeof(msg), "%d\n", result); - int rc = AixAttachListener::write_fully(this->socket(), msg, strlen(msg)); - - // write any result data - if (rc == 0) { - // Shutdown the socket in the cleanup function to enable more than - // one agent attach in a sequence (see comments to listener_cleanup()). - AixAttachListener::write_fully(this->socket(), (char*) st->base(), st->size()); - } - - // done - ::close(this->socket()); - delete this; } @@ -493,6 +363,7 @@ void AttachListener::vm_start() { } int AttachListener::pd_init() { + AttachListener::set_supported_version(ATTACH_API_V2); JavaThread* thread = JavaThread::current(); ThreadBlockInVM tbivm(thread); diff --git a/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java index 6df51d04b0a0a..f162ec48d2807 100644 --- a/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2019 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -47,6 +47,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { // Any changes to this needs to be synchronized with HotSpot. private static final String tmpdir = "/tmp"; String socket_path; + private OperationProperties props = new OperationProperties(VERSION_1); /** * Attaches to the target VM @@ -110,11 +111,18 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { // Check that we can connect to the process // - this ensures we throw the permission denied error now rather than // later when we attempt to enqueue a command. - int s = socket(); - try { - connect(s, socket_path); - } finally { - close(s); + if (isAPIv2Enabled()) { + props = getDefaultProps(); + } else { + // Check that we can connect to the process + // - this ensures we throw the permission denied error now rather than + // later when we attempt to enqueue a command. + int s = socket(); + try { + connect(s, socket_path); + } finally { + close(s); + } } } @@ -129,14 +137,10 @@ public void detach() throws IOException { } } - // protocol version - private static final String PROTOCOL_VERSION = "1"; - /** * Execute the given command in the target VM. */ InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException { - assert args.length <= 3; // includes null checkNulls(args); // did we detach? @@ -162,16 +166,8 @@ InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOEx // connected - write request // try { - writeString(s, PROTOCOL_VERSION); - writeString(s, cmd); - - for (int i = 0; i < 3; i++) { - if (i < args.length && args[i] != null) { - writeString(s, (String)args[i]); - } else { - writeString(s, ""); - } - } + SocketOutputStream writer = new SocketOutputStream(s); + writeCommand(writer, props, cmd, args); } catch (IOException x) { ioe = x; } @@ -187,6 +183,17 @@ InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOEx return sis; } + private static class SocketOutputStream implements AttachOutputStream { + private int fd; + public SocketOutputStream(int fd) { + this.fd = fd; + } + @Override + public void write(byte[] buffer, int offset, int length) throws IOException { + VirtualMachineImpl.write(fd, buffer, offset, length); + } + } + /* * InputStream for the socket connection to get target VM */ @@ -223,21 +230,6 @@ private File createAttachFile(int pid) throws IOException { return f; } - /* - * Write/sends the given to the target VM. String is transmitted in - * UTF-8 encoding. - */ - private void writeString(int fd, String s) throws IOException { - if (s.length() > 0) { - byte[] b = s.getBytes(UTF_8); - VirtualMachineImpl.write(fd, b, 0, b.length); - } - byte b[] = new byte[1]; - b[0] = 0; - write(fd, b, 0, 1); - } - - //-- native methods static native void sendQuitTo(int pid) throws IOException; diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 0e71df4f27fae..6dd35997caca3 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -128,8 +128,6 @@ containers/docker/TestJcmdWithSideCar.java 8341518 linux-x64 # :hotspot_serviceability -serviceability/attach/AttachAPIv2/StreamingOutputTest.java 8352392 aix-ppc64 - serviceability/sa/sadebugd/DebugdConnectTest.java 8239062,8270326 macosx-x64,macosx-aarch64 serviceability/sa/TestRevPtrsForInvokeDynamic.java 8241235 generic-all From a13e34da3f81039b572fd6030d6ee63dfffad612 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Fri, 4 Apr 2025 07:59:41 +0000 Subject: [PATCH 0386/1101] 8353274: [PPC64] Bug related to -XX:+UseCompactObjectHeaders -XX:-UseSIGTRAP in JDK-8305895 Reviewed-by: rrich, amitkumar --- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 25 +++++++++------------- src/hotspot/cpu/ppc/macroAssembler_ppc.hpp | 1 + 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 1786b13d33291..40019ef9f4bb3 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -1284,13 +1284,7 @@ int MacroAssembler::ic_check(int end_alignment) { if (use_trap_based_null_check) { trap_null_check(receiver); } - if (UseCompactObjectHeaders) { - load_narrow_klass_compact(tmp1, receiver); - } else if (UseCompressedClassPointers) { - lwz(tmp1, oopDesc::klass_offset_in_bytes(), receiver); - } else { - ld(tmp1, oopDesc::klass_offset_in_bytes(), receiver); - } + load_klass_no_decode(tmp1, receiver); // 2 instructions with UseCompactObjectHeaders ld(tmp2, in_bytes(CompiledICData::speculated_klass_offset()), data); trap_ic_miss_check(tmp1, tmp2); @@ -1306,11 +1300,7 @@ int MacroAssembler::ic_check(int end_alignment) { cmpdi(CR0, receiver, 0); beqctr(CR0); } - if (UseCompressedClassPointers) { - lwz(tmp1, oopDesc::klass_offset_in_bytes(), receiver); - } else { - ld(tmp1, oopDesc::klass_offset_in_bytes(), receiver); - } + load_klass_no_decode(tmp1, receiver); // 2 instructions with UseCompactObjectHeaders ld(tmp2, in_bytes(CompiledICData::speculated_klass_offset()), data); cmpd(CR0, tmp1, tmp2); bnectr(CR0); @@ -3536,18 +3526,23 @@ void MacroAssembler::decode_klass_not_null(Register dst, Register src) { } } -void MacroAssembler::load_klass(Register dst, Register src) { +void MacroAssembler::load_klass_no_decode(Register dst, Register src) { if (UseCompactObjectHeaders) { load_narrow_klass_compact(dst, src); - decode_klass_not_null(dst); } else if (UseCompressedClassPointers) { lwz(dst, oopDesc::klass_offset_in_bytes(), src); - decode_klass_not_null(dst); } else { ld(dst, oopDesc::klass_offset_in_bytes(), src); } } +void MacroAssembler::load_klass(Register dst, Register src) { + load_klass_no_decode(dst, src); + if (UseCompressedClassPointers) { // also true for UseCompactObjectHeaders + decode_klass_not_null(dst); + } +} + // Loads the obj's Klass* into dst. // Preserves all registers (incl src, rscratch1 and rscratch2). // Input: diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 69570517866d6..b709cf16713b0 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -802,6 +802,7 @@ class MacroAssembler: public Assembler { inline void decode_heap_oop(Register d); // Load/Store klass oop from klass field. Compress. + void load_klass_no_decode(Register dst, Register src); void load_klass(Register dst, Register src); void load_narrow_klass_compact(Register dst, Register src); void cmp_klass(ConditionRegister dst, Register obj, Register klass, Register tmp, Register tmp2); From 1161b566ca06786996cf47a4475bcdabaa24cde8 Mon Sep 17 00:00:00 2001 From: Varada M Date: Fri, 4 Apr 2025 10:30:43 +0000 Subject: [PATCH 0387/1101] 8353053: (fs) Add support for UserDefinedFileAttributeView on AIX Reviewed-by: mdoerr, jkern --- .../aix/classes/sun/nio/fs/AixFileStore.java | 26 +++++++++--- .../aix/classes/sun/nio/fs/AixFileSystem.java | 3 +- .../sun/nio/fs/AixFileSystemProvider.java | 29 ++++++++++++- .../fs/AixUserDefinedFileAttributeView.java | 41 +++++++++++++++++++ .../sun/nio/fs/UnixConstants.java.template | 4 +- .../native/libnio/fs/UnixNativeDispatcher.c | 16 +++++++- 6 files changed, 108 insertions(+), 11 deletions(-) create mode 100644 src/java.base/aix/classes/sun/nio/fs/AixUserDefinedFileAttributeView.java diff --git a/src/java.base/aix/classes/sun/nio/fs/AixFileStore.java b/src/java.base/aix/classes/sun/nio/fs/AixFileStore.java index 5e424e2f363b7..53ddf53e7ba5d 100644 --- a/src/java.base/aix/classes/sun/nio/fs/AixFileStore.java +++ b/src/java.base/aix/classes/sun/nio/fs/AixFileStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -88,18 +88,32 @@ UnixMountEntry findMountEntry() throws IOException { throw new IOException("Mount point not found"); } - @Override - protected boolean isExtendedAttributesEnabled(UnixPath path) { - return false; - } - @Override public boolean supportsFileAttributeView(Class type) { + // support UserDefinedAttributeView if extended attributes enabled + if (type == UserDefinedFileAttributeView.class) { + // lookup fstypes.properties + FeatureStatus status = checkIfFeaturePresent("user_xattr"); + if (status == FeatureStatus.PRESENT) + return true; + if (status == FeatureStatus.NOT_PRESENT) + return false; + + // typical AIX file system types that support xattr (JFS2 with EA enabled) + String fstype = entry().fstype(); + if ("jfs2".equals(fstype)) { + UnixPath dir = new UnixPath(file().getFileSystem(), entry().dir()); + return isExtendedAttributesEnabled(dir); + } + } return super.supportsFileAttributeView(type); } @Override public boolean supportsFileAttributeView(String name) { + if (name.equals("user")) + return supportsFileAttributeView(UserDefinedFileAttributeView.class); return super.supportsFileAttributeView(name); } + } diff --git a/src/java.base/aix/classes/sun/nio/fs/AixFileSystem.java b/src/java.base/aix/classes/sun/nio/fs/AixFileSystem.java index f1763ce3cae16..e8f0cb29b2887 100644 --- a/src/java.base/aix/classes/sun/nio/fs/AixFileSystem.java +++ b/src/java.base/aix/classes/sun/nio/fs/AixFileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -56,6 +56,7 @@ private static class SupportedFileFileAttributeViewsHolder { private static Set supportedFileAttributeViews() { Set result = new HashSet(); result.addAll(UnixFileSystem.standardFileAttributeViews()); + result.add("user"); return Collections.unmodifiableSet(result); } } diff --git a/src/java.base/aix/classes/sun/nio/fs/AixFileSystemProvider.java b/src/java.base/aix/classes/sun/nio/fs/AixFileSystemProvider.java index c0d17dd44b50f..5c5c7a1865abe 100644 --- a/src/java.base/aix/classes/sun/nio/fs/AixFileSystemProvider.java +++ b/src/java.base/aix/classes/sun/nio/fs/AixFileSystemProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,6 +26,8 @@ package sun.nio.fs; +import java.nio.file.*; +import java.nio.file.attribute.*; import java.io.IOException; /** @@ -49,4 +51,29 @@ AixFileSystem newFileSystem(String dir) { AixFileStore getFileStore(UnixPath path) throws IOException { return new AixFileStore(path); } + + @Override + @SuppressWarnings("unchecked") + public V getFileAttributeView(Path obj, + Class type, + LinkOption... options) + { + if (type == UserDefinedFileAttributeView.class) { + return (V) new AixUserDefinedFileAttributeView(UnixPath.toUnixPath(obj), + Util.followLinks(options)); + } + return super.getFileAttributeView(obj, type, options); + } + + @Override + public DynamicFileAttributeView getFileAttributeView(Path obj, + String name, + LinkOption... options) + { + if (name.equals("user")) { + return new AixUserDefinedFileAttributeView(UnixPath.toUnixPath(obj), + Util.followLinks(options)); + } + return super.getFileAttributeView(obj, name, options); + } } diff --git a/src/java.base/aix/classes/sun/nio/fs/AixUserDefinedFileAttributeView.java b/src/java.base/aix/classes/sun/nio/fs/AixUserDefinedFileAttributeView.java new file mode 100644 index 0000000000000..57a170642024e --- /dev/null +++ b/src/java.base/aix/classes/sun/nio/fs/AixUserDefinedFileAttributeView.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.nio.fs; + +class AixUserDefinedFileAttributeView + extends UnixUserDefinedFileAttributeView +{ + + AixUserDefinedFileAttributeView(UnixPath file, boolean followLinks) { + super(file, followLinks); + } + + @Override + protected int maxNameLength() { + return 255; + } + +} diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template b/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template index 7d2e73ea91544..6823833582f6d 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template +++ b/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,6 +124,8 @@ class UnixConstants { // fgetxattr error codes for absent attributes depend on the OS: #ifdef _ALLBSD_SOURCE static final int PREFIX_XATTR_NOT_FOUND = ENOATTR; +#elif defined(_AIX) + static final int PREFIX_XATTR_NOT_FOUND = ENOATTR; #elif defined(__linux__) static final int PREFIX_XATTR_NOT_FOUND = ENODATA; #else diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c index 87cdd228b2272..fefaac94b48ad 100644 --- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,6 +46,10 @@ #include #endif +#if defined(_AIX) +#include +#endif + /* For POSIX-compliant getpwuid_r */ #include #include @@ -387,7 +391,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) /* supports extended attributes */ -#if defined(_SYS_XATTR_H) || defined(_SYS_XATTR_H_) +#if defined(_SYS_XATTR_H) || defined(_SYS_XATTR_H_) || defined(_AIX) capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_XATTR; #endif @@ -1381,6 +1385,8 @@ Java_sun_nio_fs_UnixNativeDispatcher_fgetxattr0(JNIEnv* env, jclass clazz, res = fgetxattr(fd, name, value, valueLen); #elif defined(_ALLBSD_SOURCE) res = fgetxattr(fd, name, value, valueLen, 0, 0); +#elif defined(_AIX) + res = fgetea(fd, name, value, valueLen); #else throwUnixException(env, ENOTSUP); #endif @@ -1402,6 +1408,8 @@ Java_sun_nio_fs_UnixNativeDispatcher_fsetxattr0(JNIEnv* env, jclass clazz, res = fsetxattr(fd, name, value, valueLen, 0); #elif defined(_ALLBSD_SOURCE) res = fsetxattr(fd, name, value, valueLen, 0, 0); +#elif defined(_AIX) + res = fsetea(fd, name, value, valueLen, 0); #else throwUnixException(env, ENOTSUP); #endif @@ -1421,6 +1429,8 @@ Java_sun_nio_fs_UnixNativeDispatcher_fremovexattr0(JNIEnv* env, jclass clazz, res = fremovexattr(fd, name); #elif defined(_ALLBSD_SOURCE) res = fremovexattr(fd, name, 0); +#elif defined(_AIX) + res = fremoveea(fd, name); #else throwUnixException(env, ENOTSUP); #endif @@ -1440,6 +1450,8 @@ Java_sun_nio_fs_UnixNativeDispatcher_flistxattr(JNIEnv* env, jclass clazz, res = flistxattr(fd, list, (size_t)size); #elif defined(_ALLBSD_SOURCE) res = flistxattr(fd, list, (size_t)size, 0); +#elif defined(_AIX) + res = flistea(fd, list, (size_t)size); #else throwUnixException(env, ENOTSUP); #endif From 10d1fec3ff92de5b897737763972b62fba40753e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 4 Apr 2025 11:46:53 +0000 Subject: [PATCH 0388/1101] 8353679: Restructure classes in jdk.jpackage.internal package Reviewed-by: almatvee --- .../internal/LinuxAppImageBuilder.java | 4 +- .../jpackage/internal/LinuxDebBundler.java | 3 + .../internal/LinuxPackageBundler.java | 5 +- .../jpackage/internal/LinuxRpmBundler.java | 3 + .../jpackage/internal/PackageProperty.java | 3 +- .../jpackage/internal/CFBundleVersion.java | 5 +- .../jdk/jpackage/internal/MacAppBundler.java | 4 +- .../internal/MacBaseInstallerBundler.java | 3 + .../jdk/jpackage/internal/MacDmgBundler.java | 4 + .../jdk/jpackage/internal/MacPkgBundler.java | 3 + .../resources/MacResources.properties | 4 - .../jpackage/internal/AppImageBundler.java | 5 +- .../jpackage/internal/ApplicationLayout.java | 4 +- .../jdk/jpackage/internal/Arguments.java | 3 +- .../jdk/jpackage/internal/Bundler.java | 4 +- .../jdk/jpackage/internal/DeployParams.java | 1 + .../jpackage/internal/FileAssociation.java | 4 +- .../classes/jdk/jpackage/internal/I18N.java | 65 ++--- .../jdk/jpackage/internal/IOUtils.java | 3 +- .../jpackage/internal/JLinkBundlerHelper.java | 3 +- .../jdk/jpackage/internal/LauncherData.java | 2 +- .../internal/StandardBundlerParam.java | 1 + .../jdk/jpackage/internal/ToolValidator.java | 5 +- .../internal/{ => model}/ConfigException.java | 4 +- .../internal/{ => model}/DottedVersion.java | 20 +- .../jdk/jpackage/internal/model/I18N.java | 62 ++++ .../{ => model}/PackagerException.java | 4 +- .../internal/util/MultiResourceBundle.java | 75 +++++ .../jpackage/internal/util/PListReader.java | 100 +++++++ .../internal/{ => util}/PathGroup.java | 37 ++- .../jdk/jpackage/internal/util/XmlUtils.java | 36 ++- .../internal/ExecutableRebrander.java | 4 +- .../jdk/jpackage/internal/WinExeBundler.java | 2 + .../jdk/jpackage/internal/WinMsiBundler.java | 3 + .../internal/WixAppImageFragmentBuilder.java | 4 +- .../jpackage/internal/WixFragmentBuilder.java | 1 + .../jdk/jpackage/internal/WixTool.java | 2 + .../jdk/jpackage/internal/WixToolset.java | 1 + .../internal/{ => model}/MsiVersion.java | 10 +- .../helpers/jdk/jpackage/test/MacHelper.java | 86 +----- test/jdk/tools/jpackage/junit/TEST.properties | 1 + .../jpackage/internal/DeployParamsTest.java | 4 +- .../internal/PlatformVersionTest.java | 29 +- .../jpackage/internal/ToolValidatorTest.java | 10 +- .../{ => model}/DottedVersionTest.java | 4 +- .../internal/util/PListReaderTest.java | 265 ++++++++++++++++++ .../internal/{ => util}/PathGroupTest.java | 4 +- .../macosx/MacFileAssociationsTest.java | 12 +- 48 files changed, 707 insertions(+), 214 deletions(-) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/ConfigException.java (94%) rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/DottedVersion.java (94%) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => model}/PackagerException.java (95%) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java rename src/jdk.jpackage/share/classes/jdk/jpackage/internal/{ => util}/PathGroup.java (89%) rename src/jdk.jpackage/windows/classes/jdk/jpackage/internal/{ => model}/MsiVersion.java (91%) rename test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/{ => model}/DottedVersionTest.java (99%) create mode 100644 test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java rename test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/{ => util}/PathGroupTest.java (99%) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java index ab97e327003ca..7d9dcf4276b32 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,8 @@ import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; + +import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.util.PathUtils; public class LinuxAppImageBuilder extends AbstractAppImageBuilder { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index 956e14dfb36e1..436d414cac1fe 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -47,6 +47,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; + import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 5d160d4128c85..dcd8676ec337c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,9 @@ import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; + +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.util.FileUtils; abstract class LinuxPackageBundler extends AbstractBundler { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index 9c56d35ca7584..054e6cbdc18f8 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -38,6 +38,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.DottedVersion; +import jdk.jpackage.internal.model.PackagerException; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java index b9f43b93742aa..6b06190f89158 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package jdk.jpackage.internal; import java.text.MessageFormat; +import jdk.jpackage.internal.model.ConfigException; final class PackageProperty { /** diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java index 61bedfb8e67ca..17c310dbe568d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package jdk.jpackage.internal; import java.math.BigInteger; +import jdk.jpackage.internal.model.DottedVersion; final class CFBundleVersion { @@ -38,7 +39,7 @@ final class CFBundleVersion { * @throws IllegalArgumentException */ static DottedVersion of(String value) { - DottedVersion ver = new DottedVersion(value); + DottedVersion ver = DottedVersion.greedy(value); BigInteger[] components = ver.getComponents(); if (components.length > 3) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index ff772ce74b0b9..5da01aa293c9e 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,8 @@ import java.text.MessageFormat; import java.util.Map; import java.util.Optional; +import jdk.jpackage.internal.model.ConfigException; + import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index a536019512a5d..ef94a97e22bf1 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -38,6 +38,9 @@ import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; + +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.util.FileUtils; public abstract class MacBaseInstallerBundler extends AbstractBundler { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java index 484080c3fb6f7..a3e6b3424632d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java @@ -48,7 +48,11 @@ import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; import static jdk.jpackage.internal.StandardBundlerParam.VERBOSE; import static jdk.jpackage.internal.StandardBundlerParam.DMG_CONTENT; + +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.util.FileUtils; +import jdk.jpackage.internal.util.PathGroup; public class MacDmgBundler extends MacBaseInstallerBundler { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 8eb40b8741998..2aca9bd0e1f0b 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -62,6 +62,9 @@ import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; + +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.XmlUtils; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties index 29b24251e202f..f4e97aad72e8d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties @@ -34,10 +34,6 @@ error.explicit-sign-no-cert=Signature explicitly requested but no signing certif error.explicit-sign-no-cert.advice=Specify a valid mac-signing-key-user-name and mac-signing-keychain error.must-sign-app-store=Mac App Store apps must be signed, and signing has been disabled by bundler configuration error.must-sign-app-store.advice=Use --mac-sign option with appropriate user-name and keychain -error.no-app-signing-key=No Mac App Store App Signing Key -error.no-app-signing-key.advice=Install your app signing keys into your Mac Keychain using XCode. -error.no-pkg-signing-key=No Mac App Store Installer Signing Key -error.no-pkg-signing-key.advice=Install your app signing keys into your Mac Keychain using XCode. error.certificate.expired=Error: Certificate expired {0} error.cert.not.found=No certificate found matching [{0}] using keychain [{1}] error.multiple.certs.found=WARNING: Multiple certificates found matching [{0}] using keychain [{1}], using first one diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java index 68c5685650602..39178186e8e55 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,8 @@ package jdk.jpackage.internal; import jdk.internal.util.OperatingSystem; - +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java index e96b6b72de2c0..c89131b2d4b2a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ package jdk.jpackage.internal; import jdk.internal.util.OperatingSystem; - +import jdk.jpackage.internal.util.PathGroup; import java.nio.file.Path; import java.util.Map; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java index 907798a735b89..3102576a31e94 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java @@ -25,7 +25,8 @@ package jdk.jpackage.internal; import jdk.internal.util.OperatingSystem; - +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; import java.io.IOException; import java.io.Reader; import java.nio.file.Files; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java index 59916fc3ca194..0d29677e82631 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,8 @@ import java.nio.file.Path; import java.util.Map; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; /** * Bundler diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java index c95edbbad0a01..67214a3379685 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java @@ -38,6 +38,7 @@ import java.util.Set; import java.util.TreeSet; import java.util.stream.Stream; +import jdk.jpackage.internal.model.PackagerException; /** * DeployParams diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociation.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociation.java index 3eed999526500..36de9bbbe7278 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociation.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,8 @@ import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; +import jdk.jpackage.internal.model.ConfigException; + import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; import static jdk.jpackage.internal.StandardBundlerParam.FA_EXTENSIONS; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java index 2e37a5c91af32..d3093f77f50d4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,15 +24,12 @@ */ package jdk.jpackage.internal; -import java.util.ArrayList; +import java.text.MessageFormat; import java.util.List; -import java.util.ListResourceBundle; import java.util.Map; -import jdk.internal.util.OperatingSystem; - import java.util.ResourceBundle; -import static java.util.stream.Collectors.toMap; -import java.util.stream.Stream; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.util.MultiResourceBundle; class I18N { @@ -40,48 +37,26 @@ static String getString(String key) { return BUNDLE.getString(key); } - private static class MultiResourceBundle extends ListResourceBundle { - - MultiResourceBundle(ResourceBundle... bundles) { - contents = Stream.of(bundles).map(bundle -> { - return bundle.keySet().stream().map(key -> { - return Map.entry(key, bundle.getObject(key)); - }); - }).flatMap(x -> x).collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (o, n) -> { - // Override old value with the new one - return n; - })).entrySet().stream().map(e -> { - return new Object[]{e.getKey(), e.getValue()}; - }).toArray(Object[][]::new); - } - - @Override - protected Object[][] getContents() { - return contents; + static String format(String key, Object ... args) { + var str = getString(key); + if (args.length != 0) { + return MessageFormat.format(str, args); + } else { + return str; } - - private final Object[][] contents; } - private static final MultiResourceBundle BUNDLE; + private static final ResourceBundle BUNDLE; static { - List bundleNames = new ArrayList<>(); - - bundleNames.add("jdk.jpackage.internal.resources.MainResources"); - - if (OperatingSystem.isLinux()) { - bundleNames.add("jdk.jpackage.internal.resources.LinuxResources"); - } else if (OperatingSystem.isWindows()) { - bundleNames.add("jdk.jpackage.internal.resources.WinResources"); - bundleNames.add("jdk.jpackage.internal.resources.WinResourcesNoL10N"); - } else if (OperatingSystem.isMacOS()) { - bundleNames.add("jdk.jpackage.internal.resources.MacResources"); - } else { - throw new IllegalStateException("Unknown platform"); - } - - BUNDLE = new MultiResourceBundle(bundleNames.stream().map(ResourceBundle::getBundle) - .toArray(ResourceBundle[]::new)); + var prefix = "jdk.jpackage.internal.resources."; + BUNDLE = MultiResourceBundle.create( + prefix + "MainResources", + Map.of( + OperatingSystem.LINUX, List.of(prefix + "LinuxResources"), + OperatingSystem.MACOS, List.of(prefix + "MacResources"), + OperatingSystem.WINDOWS, List.of(prefix + "WinResources", prefix + "WinResourcesNoL10N") + ) + ); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java index cb8ef22790153..13c7a78b502ff 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.List; +import jdk.jpackage.internal.model.PackagerException; /** * IOUtils diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkBundlerHelper.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkBundlerHelper.java index a93f3cfc363e1..3b85bf730fab0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkBundlerHelper.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkBundlerHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,6 +49,7 @@ import java.util.stream.Stream; import jdk.internal.module.ModulePath; +import jdk.jpackage.internal.model.PackagerException; final class JLinkBundlerHelper { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java index d4509b553f9f6..aedc8f72d3320 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java @@ -25,7 +25,7 @@ package jdk.jpackage.internal; import jdk.internal.util.OperatingSystem; - +import jdk.jpackage.internal.model.ConfigException; import java.io.File; import java.io.IOException; import java.io.Reader; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index 6562d3425d92d..21d710b631ce4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -44,6 +44,7 @@ import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Stream; +import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.util.FileUtils; /** diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java index 64876468afbab..f673ac7e33e27 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,8 @@ package jdk.jpackage.internal; import jdk.internal.util.OperatingSystem; - +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.DottedVersion; import java.io.IOException; import java.nio.file.Path; import java.text.MessageFormat; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ConfigException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java similarity index 94% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/ConfigException.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java index 5a43fbe93fee4..fbc856b9a30f2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ConfigException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; public class ConfigException extends Exception { private static final long serialVersionUID = 1L; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DottedVersion.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DottedVersion.java similarity index 94% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/DottedVersion.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DottedVersion.java index b188a9b552c94..b49cbb025e92c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DottedVersion.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DottedVersion.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.math.BigInteger; import java.text.MessageFormat; @@ -34,11 +34,7 @@ /** * Dotted numeric version string. E.g.: 1.0.37, 10, 0.5 */ -final class DottedVersion { - - DottedVersion(String version) { - this(version, true); - } +public final class DottedVersion { private DottedVersion(String version, boolean greedy) { this.value = version; @@ -156,15 +152,15 @@ void throwException() { private final String input; } - static DottedVersion greedy(String version) { - return new DottedVersion(version); + public static DottedVersion greedy(String version) { + return new DottedVersion(version, true); } - static DottedVersion lazy(String version) { + public static DottedVersion lazy(String version) { return new DottedVersion(version, false); } - static int compareComponents(DottedVersion a, DottedVersion b) { + public static int compareComponents(DottedVersion a, DottedVersion b) { int result = 0; BigInteger[] aComponents = a.getComponents(); BigInteger[] bComponents = b.getComponents(); @@ -224,11 +220,11 @@ public String getUnprocessedSuffix() { return suffix; } - String toComponentsString() { + public String toComponentsString() { return Stream.of(components).map(BigInteger::toString).collect(Collectors.joining(".")); } - BigInteger[] getComponents() { + public BigInteger[] getComponents() { return components; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java new file mode 100644 index 0000000000000..6a9f8074e087a --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.text.MessageFormat; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.util.MultiResourceBundle; + +final class I18N { + + static String getString(String key) { + return BUNDLE.getString(key); + } + + static String format(String key, Object ... args) { + var str = getString(key); + if (args.length != 0) { + return MessageFormat.format(str, args); + } else { + return str; + } + } + + private static final ResourceBundle BUNDLE; + + static { + var prefix = "jdk.jpackage.internal.resources."; + BUNDLE = MultiResourceBundle.create( + prefix + "MainResources", + Map.of( + OperatingSystem.LINUX, List.of(prefix + "LinuxResources"), + OperatingSystem.MACOS, List.of(prefix + "MacResources"), + OperatingSystem.WINDOWS, List.of(prefix + "WinResources") + ) + ); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java similarity index 95% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerException.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java index b5f514ae1ab68..31f25b9874535 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.text.MessageFormat; import java.util.ResourceBundle; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java new file mode 100644 index 0000000000000..0ef0c5f59e0d9 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListResourceBundle; +import java.util.Map; +import java.util.Optional; +import java.util.ResourceBundle; +import static java.util.stream.Collectors.toMap; +import java.util.stream.Stream; +import jdk.internal.util.OperatingSystem; + +public final class MultiResourceBundle extends ListResourceBundle { + + public static ResourceBundle create(String sharedResourceBundleName, + Map> platformResourceBundleNames) { + List bundleNames = new ArrayList<>(); + Optional.ofNullable(sharedResourceBundleName).ifPresent(bundleNames::add); + Optional.ofNullable(platformResourceBundleNames.get(OperatingSystem.current())).ifPresent(bundleNames::addAll); + if (bundleNames.isEmpty()) { + throw new IllegalArgumentException("Empty resource bundle names list"); + } else { + var resourceBundles = bundleNames.stream().map(ResourceBundle::getBundle).toArray(ResourceBundle[]::new); + if (resourceBundles.length == 1) { + return resourceBundles[0]; + } else { + return new MultiResourceBundle(resourceBundles); + } + } + } + + private MultiResourceBundle(ResourceBundle... bundles) { + contents = Stream.of(bundles).map(bundle -> { + return bundle.keySet().stream().map(key -> { + return Map.entry(key, bundle.getObject(key)); + }); + }).flatMap(x -> x).collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (o, n) -> { + // Override old value with the new one + return n; + })).entrySet().stream().map(e -> { + return new Object[]{e.getKey(), e.getValue()}; + }).toArray(Object[][]::new); + } + + @Override + protected Object[][] getContents() { + return contents; + } + + private final Object[][] contents; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java new file mode 100644 index 0000000000000..211a55897d0c2 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Optional; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; +import jdk.jpackage.internal.util.function.ThrowingSupplier; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + +public final class PListReader { + + public String queryValue(String keyName) { + final var node = getNode(keyName); + switch (node.getNodeName()) { + case "string" -> { + return node.getTextContent(); + } + default -> { + throw new NoSuchElementException(); + } + } + } + + public boolean queryBoolValue(String keyName) { + final var node = getNode(keyName); + switch (node.getNodeName()) { + case "true" -> { + return true; + } + case "false" -> { + return false; + } + default -> { + throw new NoSuchElementException(); + } + } + } + + public List queryArrayValue(String keyName) { + final var node = getNode(keyName); + switch (node.getNodeName()) { + case "array" -> { + return XmlUtils.toStream(node.getChildNodes()).filter(n -> { + return n.getNodeName().equals("string"); + }).map(Node::getTextContent).toList(); + } + default -> { + throw new NoSuchElementException(); + } + } + } + + public PListReader(Node doc) { + this.root = Objects.requireNonNull(doc); + } + + public PListReader(byte[] xmlData) throws ParserConfigurationException, SAXException, IOException { + this(XmlUtils.initDocumentBuilder().parse(new ByteArrayInputStream(xmlData))); + } + + private Node getNode(String keyName) { + final var xPath = XPathFactory.newInstance().newXPath(); + final var query = String.format("//*[preceding-sibling::key = \"%s\"][1]", keyName); + return Optional.ofNullable(ThrowingSupplier.toSupplier(() -> { + return (Node) xPath.evaluate(query, root, XPathConstants.NODE); + }).get()).orElseThrow(NoSuchElementException::new); + } + + private final Node root; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java similarity index 89% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java index 296164551a118..c6938b6b986c5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.util; import java.io.IOException; import java.nio.file.Files; @@ -35,26 +35,25 @@ import java.util.function.BiFunction; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.util.FileUtils; /** * Group of paths. * Each path in the group is assigned a unique id. */ -final class PathGroup { - PathGroup(Map paths) { +public final class PathGroup { + public PathGroup(Map paths) { entries = new HashMap<>(paths); } - Path getPath(Object id) { + public Path getPath(Object id) { if (id == null) { throw new NullPointerException(); } return entries.get(id); } - void setPath(Object id, Path path) { + public void setPath(Object id, Path path) { if (path != null) { entries.put(id, path); } else { @@ -65,14 +64,14 @@ void setPath(Object id, Path path) { /** * All configured entries. */ - List paths() { + public List paths() { return entries.values().stream().toList(); } /** * Root entries. */ - List roots() { + public List roots() { // Sort by the number of path components in ascending order. List> sorted = normalizedPaths().stream().sorted( (a, b) -> a.getKey().getNameCount() - b.getKey().getNameCount()).toList(); @@ -88,7 +87,7 @@ List roots() { v -> v.getValue()).toList(); } - long sizeInBytes() throws IOException { + public long sizeInBytes() throws IOException { long reply = 0; for (Path dir : roots().stream().filter(f -> Files.isDirectory(f)).collect( Collectors.toList())) { @@ -100,25 +99,25 @@ long sizeInBytes() throws IOException { return reply; } - PathGroup resolveAt(Path root) { + public PathGroup resolveAt(Path root) { return new PathGroup(entries.entrySet().stream().collect( Collectors.toMap(e -> e.getKey(), e -> root.resolve(e.getValue())))); } - void copy(PathGroup dst) throws IOException { + public void copy(PathGroup dst) throws IOException { copy(this, dst, null, false); } - void move(PathGroup dst) throws IOException { + public void move(PathGroup dst) throws IOException { copy(this, dst, null, true); } - void transform(PathGroup dst, TransformHandler handler) throws IOException { + public void transform(PathGroup dst, TransformHandler handler) throws IOException { copy(this, dst, handler, false); } - static interface Facade { + public static interface Facade { PathGroup pathGroup(); default Collection paths() { @@ -149,9 +148,9 @@ default void transform(Facade dst, TransformHandler handler) throws } } - static interface TransformHandler { - public void copyFile(Path src, Path dst) throws IOException; - public void createDirectory(Path dir) throws IOException; + public static interface TransformHandler { + void copyFile(Path src, Path dst) throws IOException; + void createDirectory(Path dir) throws IOException; } private static void copy(PathGroup src, PathGroup dst, @@ -179,7 +178,7 @@ private static void copy(boolean move, List> entries, handler = new TransformHandler() { @Override public void copyFile(Path src, Path dst) throws IOException { - Files.createDirectories(IOUtils.getParent(dst)); + Files.createDirectories(dst.getParent()); if (move) { Files.move(src, dst); } else { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java index 57ad1759bf466..c78101c124504 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Collection; +import java.util.Optional; +import java.util.stream.IntStream; +import java.util.stream.Stream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -41,10 +44,25 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stax.StAXResult; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; public final class XmlUtils { + @FunctionalInterface + public interface XmlConsumerNoArg { + void accept() throws IOException, XMLStreamException; + } + + public static XmlConsumer toXmlConsumer(XmlConsumerNoArg xmlConsumer) { + return xml -> xmlConsumer.accept(); + } + public static void createXml(Path dstFile, XmlConsumer xmlConsumer) throws IOException { XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance(); @@ -101,4 +119,20 @@ public static DocumentBuilderFactory initDocumentBuilderFactory() { } return dbf; } + + public static Stream queryNodes(Node xml, XPath xPath, String xpathExpr) throws XPathExpressionException { + return toStream((NodeList) xPath.evaluate(xpathExpr, xml, XPathConstants.NODESET)); + } + + public static Stream toStream(NodeList nodes) { + return Optional.ofNullable(nodes).map(v -> { + return IntStream.range(0, v.getLength()).mapToObj(v::item); + }).orElseGet(Stream::of); + } + + public static Stream toStream(NamedNodeMap nodes) { + return Optional.ofNullable(nodes).map(v -> { + return IntStream.range(0, v.getLength()).mapToObj(v::item); + }).orElseGet(Stream::of); + } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java index 166675b5893d0..7a85687a12143 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,8 @@ import java.util.Properties; import java.util.ResourceBundle; import java.util.function.Supplier; +import jdk.jpackage.internal.model.DottedVersion; + import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.ShortPathUtils.adjustPath; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java index 04838fe6b87e3..f411cdc3b3f35 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java @@ -32,6 +32,8 @@ import java.nio.file.Path; import java.text.MessageFormat; import java.util.Map; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.util.PathUtils; @SuppressWarnings("restricted") diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index a17df722f1618..88bf18dc45d8b 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -55,6 +55,9 @@ import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import jdk.jpackage.internal.AppImageFile.LauncherInfo; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.MsiVersion; +import jdk.jpackage.internal.model.PackagerException; import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index a5d9a5de141ab..1b6c2178ca2fa 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,6 +64,8 @@ import static jdk.jpackage.internal.WinMsiBundler.SERVICE_INSTALLER; import static jdk.jpackage.internal.WinMsiBundler.WIN_APP_IMAGE; import jdk.jpackage.internal.WixToolset.WixToolsetType; +import jdk.jpackage.internal.model.DottedVersion; +import jdk.jpackage.internal.util.PathGroup; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.XmlUtils; import org.w3c.dom.NodeList; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java index 6d9f008dd7d60..8b2307768228c 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java @@ -43,6 +43,7 @@ import static jdk.jpackage.internal.OverridableResource.createResource; import jdk.jpackage.internal.WixSourceConverter.ResourceGroup; import jdk.jpackage.internal.WixToolset.WixToolsetType; +import jdk.jpackage.internal.model.DottedVersion; import jdk.jpackage.internal.util.XmlUtils; /** diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java index e2c84ab8be4d6..7e4353876b43a 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java @@ -41,6 +41,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.jpackage.internal.WixToolset.WixToolsetType; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.DottedVersion; import jdk.jpackage.internal.util.PathUtils; /** diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java index 046dc5efe4e15..e7bdbede368dc 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java @@ -29,6 +29,7 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.jpackage.internal.model.DottedVersion; final class WixToolset { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/MsiVersion.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java similarity index 91% rename from src/jdk.jpackage/windows/classes/jdk/jpackage/internal/MsiVersion.java rename to src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java index c1ced66916923..f6e0b0f34894e 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/MsiVersion.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,13 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.math.BigInteger; import java.text.MessageFormat; -final class MsiVersion { +public final class MsiVersion { /** * Parse the given string as Windows MSI Product version. * https://msdn.microsoft.com/en-us/library/aa370859%28v=VS.85%29.aspx The @@ -39,8 +39,8 @@ final class MsiVersion { * 65,535. * @throws IllegalArgumentException */ - static DottedVersion of(String value) { - DottedVersion ver = new DottedVersion(value); + public static DottedVersion of(String value) { + DottedVersion ver = DottedVersion.greedy(value); BigInteger[] components = ver.getComponents(); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index 4ecc0b818110a..7e057a6a72714 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -31,7 +31,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -39,19 +38,15 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; import jdk.jpackage.internal.RetryExecutor; +import jdk.jpackage.internal.util.PListReader; import jdk.jpackage.internal.util.PathUtils; +import jdk.jpackage.internal.util.XmlUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.internal.util.function.ThrowingSupplier; import jdk.jpackage.test.PackageTest.PackageHandlers; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; public final class MacHelper { @@ -129,25 +124,25 @@ public static void withExplodedDmg(JPackageCommand cmd, } } - public static PListWrapper readPListFromAppImage(Path appImage) { + public static PListReader readPListFromAppImage(Path appImage) { return readPList(appImage.resolve("Contents/Info.plist")); } - public static PListWrapper readPList(Path path) { + public static PListReader readPList(Path path) { TKit.assertReadableFileExists(path); return ThrowingSupplier.toSupplier(() -> readPList(Files.readAllLines( path))).get(); } - public static PListWrapper readPList(List lines) { + public static PListReader readPList(List lines) { return readPList(lines.stream()); } - public static PListWrapper readPList(Stream lines) { - return ThrowingSupplier.toSupplier(() -> new PListWrapper(lines + public static PListReader readPList(Stream lines) { + return ThrowingSupplier.toSupplier(() -> new PListReader(lines // Skip leading lines before xml declaration .dropWhile(Pattern.compile("\\s?<\\?xml\\b.+\\?>").asPredicate().negate()) - .collect(Collectors.joining()))).get(); + .collect(Collectors.joining()).getBytes(StandardCharsets.UTF_8))).get(); } public static boolean signPredefinedAppImage(JPackageCommand cmd) { @@ -261,7 +256,7 @@ private static Path unpackPkg(JPackageCommand cmd, Path destinationDir) { }).forEach(ThrowingConsumer.toConsumer(pkgDir -> { // Installation root of the package is stored in // /pkg-info@install-location attribute in $pkgDir/PackageInfo xml file - var doc = createDocumentBuilder().parse( + var doc = XmlUtils.initDocumentBuilder().parse( new ByteArrayInputStream(Files.readAllBytes( pkgDir.resolve("PackageInfo")))); var xPath = XPathFactory.newInstance().newXPath(); @@ -370,73 +365,10 @@ private static String getPackageId(JPackageCommand cmd) { }); } - public static final class PListWrapper { - public String queryValue(String keyName) { - XPath xPath = XPathFactory.newInstance().newXPath(); - // Query for the value of element preceding element - // with value equal to `keyName` - String query = String.format( - "//string[preceding-sibling::key = \"%s\"][1]", keyName); - return ThrowingSupplier.toSupplier(() -> (String) xPath.evaluate( - query, doc, XPathConstants.STRING)).get(); - } - - public Boolean queryBoolValue(String keyName) { - XPath xPath = XPathFactory.newInstance().newXPath(); - // Query boolean element preceding element - // with value equal to `keyName` - String query = String.format( - "name(//*[preceding-sibling::key = \"%s\"])", keyName); - String value = ThrowingSupplier.toSupplier(() -> (String) xPath.evaluate( - query, doc, XPathConstants.STRING)).get(); - return Boolean.valueOf(value); - } - - public List queryArrayValue(String keyName) { - XPath xPath = XPathFactory.newInstance().newXPath(); - // Query string array preceding element with value equal to `keyName` - String query = String.format( - "//array[preceding-sibling::key = \"%s\"]", keyName); - NodeList list = ThrowingSupplier.toSupplier(() -> (NodeList) xPath.evaluate( - query, doc, XPathConstants.NODESET)).get(); - if (list.getLength() != 1) { - throw new RuntimeException( - String.format("Unable to find element for key = \"%s\"]", - keyName)); - } - - NodeList childList = list.item(0).getChildNodes(); - List values = new ArrayList<>(childList.getLength()); - for (int i = 0; i < childList.getLength(); i++) { - if (childList.item(i).getNodeName().equals("string")) { - values.add(childList.item(i).getTextContent()); - } - } - return values; - } - - private PListWrapper(String xml) throws ParserConfigurationException, - SAXException, IOException { - doc = createDocumentBuilder().parse(new ByteArrayInputStream( - xml.getBytes(StandardCharsets.UTF_8))); - } - - private final org.w3c.dom.Document doc; - } - public static boolean isXcodeDevToolsInstalled() { return Inner.XCODE_DEV_TOOLS_INSTALLED; } - private static DocumentBuilder createDocumentBuilder() throws - ParserConfigurationException { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); - dbf.setFeature( - "http://apache.org/xml/features/nonvalidating/load-external-dtd", - false); - return dbf.newDocumentBuilder(); - } - private static String getServicePListFileName(String packageName, String launcherName) { try { diff --git a/test/jdk/tools/jpackage/junit/TEST.properties b/test/jdk/tools/jpackage/junit/TEST.properties index 931ff3c2d9ad4..28bac6ffe4c16 100644 --- a/test/jdk/tools/jpackage/junit/TEST.properties +++ b/test/jdk/tools/jpackage/junit/TEST.properties @@ -1,6 +1,7 @@ JUnit.dirs = share modules=jdk.jpackage/jdk.jpackage.internal:+open \ + jdk.jpackage/jdk.jpackage.internal.model:+open \ jdk.jpackage/jdk.jpackage.internal.util:+open \ jdk.jpackage/jdk.jpackage.internal.util.function:+open \ java.base/jdk.internal.util \ diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java index e4db8f5c0a5da..70ede94e34464 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,8 @@ import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import static org.junit.jupiter.api.Assertions.assertTrue; + +import jdk.jpackage.internal.model.PackagerException; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java index 21aea35220b85..5e3e27cacede2 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,12 +22,15 @@ */ package jdk.jpackage.internal; -import java.lang.reflect.InvocationTargetException; -import java.util.function.Function; -import java.lang.reflect.Method; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import static org.junit.jupiter.api.Assumptions.assumeTrue; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.function.Function; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.DottedVersion; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -80,11 +83,15 @@ private static void testImpl(PlatformVersion parser, String version, boolean val } enum PlatformVersion { - MAC_CFBUNDLE_VERSION_CLASS("jdk.jpackage.internal.CFBundleVersion"), - WIN_MSI_PRODUCT_VERSION_CLASS("jdk.jpackage.internal.MsiVersion"); + MAC_CFBUNDLE_VERSION_CLASS("jdk.jpackage.internal.CFBundleVersion", OperatingSystem.MACOS), + WIN_MSI_PRODUCT_VERSION_CLASS("jdk.jpackage.internal.model.MsiVersion", OperatingSystem.WINDOWS); - PlatformVersion(String className) { - parser = findParser(className); + PlatformVersion(String className, OperatingSystem os) { + if (os.equals(OperatingSystem.current())) { + parser = getParser(className); + } else { + parser = null; + } } DottedVersion parse(String versionString) { @@ -94,7 +101,7 @@ DottedVersion parse(String versionString) { private Function parser; } - private static Function findParser(String className) { + private static Function getParser(String className) { try { Method method = Class.forName(className).getDeclaredMethod("of", String.class); @@ -111,9 +118,7 @@ private static Function findParser(String className) { throw new RuntimeException(causeEx); } }; - } catch (ClassNotFoundException e) { - return null; - } catch (SecurityException | NoSuchMethodException ex) { + } catch (SecurityException | NoSuchMethodException | ClassNotFoundException ex) { throw new IllegalArgumentException(ex); } } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java index 9731deafe0217..c0acea5e3e746 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,8 @@ package jdk.jpackage.internal; +import jdk.jpackage.internal.model.DottedVersion; +import jdk.jpackage.internal.model.ConfigException; import java.nio.file.Path; import jdk.internal.util.OperatingSystem; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -52,11 +54,11 @@ public void testVersionParserUsage() { // Minimal version is 1, actual is 10. Should be OK. assertNull(new ToolValidator(TOOL_JAVA).setMinimalVersion( - new DottedVersion("1")).setVersionParser(unused -> "10").validate()); + DottedVersion.greedy("1")).setVersionParser(unused -> "10").validate()); // Minimal version is 5, actual is 4.99.37. Error expected. assertValidationFailure(new ToolValidator(TOOL_JAVA).setMinimalVersion( - new DottedVersion("5")).setVersionParser(unused -> "4.99.37").validate(), + DottedVersion.greedy("5")).setVersionParser(unused -> "4.99.37").validate(), false); // Minimal version is 8, actual is 10, lexicographical comparison is used. Error expected. @@ -65,7 +67,7 @@ public void testVersionParserUsage() { // Minimal version is 8, actual is 10, Use DottedVersion class for comparison. Should be OK. assertNull(new ToolValidator(TOOL_JAVA).setMinimalVersion( - new DottedVersion("8")).setVersionParser(unused -> "10").validate()); + DottedVersion.greedy("8")).setVersionParser(unused -> "10").validate()); } private static void assertValidationFailure(ConfigException v, boolean withCause) { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DottedVersionTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java similarity index 99% rename from test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DottedVersionTest.java rename to test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java index 8256782418972..885ea31f72655 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DottedVersionTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.model; import java.text.MessageFormat; import java.util.ArrayList; @@ -132,7 +132,7 @@ void run() { expectedErrorMsg = MessageFormat.format(I18N.getString("error.version-string-invalid-component"), version, invalidComponent); } - final var ex = assertThrowsExactly(IllegalArgumentException.class, () -> new DottedVersion(version)); + final var ex = assertThrowsExactly(IllegalArgumentException.class, () -> DottedVersion.greedy(version)); assertEquals(expectedErrorMsg, ex.getMessage()); } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java new file mode 100644 index 0000000000000..bae4921fda33c --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.io.StringReader; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Optional; +import java.util.function.BiFunction; +import javax.xml.parsers.ParserConfigurationException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.MethodSource; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + + +public class PListReaderTest { + + enum QueryType { + STRING(PListReader::queryValue), + BOOLEAN(PListReader::queryBoolValue), + STRING_ARRY(PListReader::queryArrayValue); + + QueryType(BiFunction queryMethod) { + this.queryMethod = Objects.requireNonNull(queryMethod); + } + + @SuppressWarnings("unchecked") + T queryValue(PListReader pListReader, String keyName) { + return (T)queryMethod.apply(pListReader, keyName); + } + + private final BiFunction queryMethod; + } + + public record QueryValueTestSpec(QueryType queryType, String keyName, Optional expectedValue, + Optional> expectedException, String... xml) { + + public QueryValueTestSpec { + Objects.requireNonNull(queryType); + Objects.requireNonNull(keyName); + Objects.requireNonNull(expectedValue); + Objects.requireNonNull(expectedException); + Objects.requireNonNull(xml); + if (expectedValue.isEmpty() == expectedException.isEmpty()) { + throw new IllegalArgumentException(); + } + } + + static final class Builder { + + Builder queryType(QueryType v) { + queryType = v; + return this; + } + + Builder keyName(String v) { + keyName = v; + return this; + } + + Builder expectedValue(Object v) { + expectedValue = v; + if (v instanceof String) { + queryType(QueryType.STRING); + } else if (v instanceof Boolean) { + queryType(QueryType.BOOLEAN); + } else if (v instanceof List) { + queryType(QueryType.STRING_ARRY); + } + return this; + } + + Builder expectedException(Class v) { + expectedException = v; + return this; + } + + Builder xml(String... v) { + xml = v; + return this; + } + + QueryValueTestSpec create() { + return new QueryValueTestSpec(queryType, keyName, Optional.ofNullable(expectedValue), + validatedExpectedException(), xml); + } + + private Optional> validatedExpectedException() { + if (expectedValue == null && expectedException == null) { + return Optional.of(NoSuchElementException.class); + } else { + return Optional.ofNullable(expectedException); + } + } + + private QueryType queryType = QueryType.STRING; + private String keyName = "foo"; + private Object expectedValue; + private Class expectedException; + private String[] xml = new String[0]; + } + + void test() { + final var plistReader = new PListReader(createXml(xml)); + + expectedValue.ifPresent(v -> { + final var actualValue = queryType.queryValue(plistReader, keyName); + assertEquals(v, actualValue); + }); + + expectedException.ifPresent(v -> { + assertThrows(v, () -> queryType.queryValue(plistReader, keyName)); + }); + } + + @Override + public String toString() { + final var sb = new StringBuilder(); + sb.append(queryType); + sb.append("; key=").append(keyName); + expectedValue.ifPresent(v -> { + sb.append("; expected="); + sb.append(v); + }); + expectedException.ifPresent(v -> { + sb.append("; throws="); + sb.append(v); + }); + sb.append("; xml="); + sb.append(String.join("", xml)); + return sb.toString(); + } + } + + @ParameterizedTest + @EnumSource(QueryType.class) + public void testNoSuchElement(QueryType queryType) { + testSpec(queryType).create().test(); + } + + @ParameterizedTest + @EnumSource(QueryType.class) + public void testWrongValueType(QueryType queryType) { + final var builder = testSpec(queryType).xml( + "string-key", + "a", + "boolean-true-key", + "", + "boolean-false-key", + "", + "array-key", + "b"); + + List testSpecs = new ArrayList<>(); + + switch (queryType) { + case STRING -> { + testSpecs.add(builder.keyName("boolean-true-key").create()); + testSpecs.add(builder.keyName("boolean-false-key").create()); + testSpecs.add(builder.keyName("array-key").create()); + } + case BOOLEAN -> { + testSpecs.add(builder.keyName("string-key").create()); + testSpecs.add(builder.keyName("array-key").create()); + } + case STRING_ARRY -> { + testSpecs.add(builder.keyName("string-key").create()); + testSpecs.add(builder.keyName("boolean-true-key").create()); + testSpecs.add(builder.keyName("boolean-false-key").create()); + } + } + + testSpecs.forEach(QueryValueTestSpec::test); + } + + @ParameterizedTest + @MethodSource + public void testQueryValue(QueryValueTestSpec testSpec) { + testSpec.test(); + } + + @Test + public void testByteArrayCtor() throws ParserConfigurationException, SAXException, IOException { + final var plistReader = new PListReader(xmlToString("fooA").getBytes(StandardCharsets.UTF_8)); + final var actualValue = plistReader.queryValue("foo"); + assertEquals("A", actualValue); + } + + private static List testQueryValue() { + return List.of( + testSpec().expectedValue("A").xml("fooA").create(), + testSpec().expectedValue("").xml("foo").create(), + testSpec().xml("foo").create(), + testSpec().expectedValue(Boolean.TRUE).xml("foo").create(), + testSpec().expectedValue(Boolean.FALSE).xml("foo").create(), + testSpec(QueryType.BOOLEAN).xml("foo").create(), + testSpec(QueryType.BOOLEAN).xml("foo").create(), + testSpec().expectedValue(List.of("foo", "bar")).xml("foofoobar").create(), + testSpec().expectedValue(List.of()).xml("foo").create(), + testSpec(QueryType.STRING_ARRY).xml("foo").create(), + testSpec().expectedValue("A").xml("fooAB").create(), + testSpec().expectedValue("A").xml("fooAfooB").create() + ); + } + + private static QueryValueTestSpec.Builder testSpec() { + return new QueryValueTestSpec.Builder(); + } + + private static QueryValueTestSpec.Builder testSpec(QueryType queryType) { + return testSpec().queryType(queryType); + } + + private static String xmlToString(String ...xml) { + final List content = new ArrayList<>(); + content.add(""); + content.add(""); + content.addAll(List.of(xml)); + content.add(""); + return String.join("", content.toArray(String[]::new)); + } + + private static Node createXml(String ...xml) { + try { + return XmlUtils.initDocumentBuilder().parse(new InputSource(new StringReader(xmlToString(xml)))); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } catch (SAXException ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PathGroupTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java similarity index 99% rename from test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PathGroupTest.java rename to test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java index 5913f257db5be..42578227cf555 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PathGroupTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,7 +21,7 @@ * questions. */ -package jdk.jpackage.internal; +package jdk.jpackage.internal.util; import java.io.IOException; import java.nio.file.Files; diff --git a/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java b/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java index 01c9e48b5fde4..889a5bb374ed8 100644 --- a/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java +++ b/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.TKit; import jdk.jpackage.test.MacHelper; -import jdk.jpackage.test.MacHelper.PListWrapper; +import jdk.jpackage.internal.util.PListReader; import jdk.jpackage.test.Annotations.Test; /** @@ -74,19 +74,19 @@ public static void test() throws Exception { verifyPList(appImage); } - private static void checkStringValue(PListWrapper plist, String key, String value) { + private static void checkStringValue(PListReader plist, String key, String value) { String result = plist.queryValue(key); TKit.assertEquals(value, result, String.format( "Check value of %s plist key", key)); } - private static void checkBoolValue(PListWrapper plist, String key, Boolean value) { + private static void checkBoolValue(PListReader plist, String key, Boolean value) { Boolean result = plist.queryBoolValue(key); TKit.assertEquals(value.toString(), result.toString(), String.format( "Check value of %s plist key", key)); } - private static void checkArrayValue(PListWrapper plist, String key, + private static void checkArrayValue(PListReader plist, String key, List values) { List result = plist.queryArrayValue(key); TKit.assertStringListEquals(values, result, String.format( @@ -94,7 +94,7 @@ private static void checkArrayValue(PListWrapper plist, String key, } private static void verifyPList(Path appImage) throws Exception { - PListWrapper plist = MacHelper.readPListFromAppImage(appImage); + var plist = MacHelper.readPListFromAppImage(appImage); checkStringValue(plist, "CFBundleTypeRole", "Viewer"); checkStringValue(plist, "LSHandlerRank", "Default"); checkStringValue(plist, "NSDocumentClass", "SomeClass"); From cfcb3305f078b61b37037ef6f652303d6c2c7098 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 4 Apr 2025 11:49:57 +0000 Subject: [PATCH 0389/1101] 8353681: jpackage suppresses errors when executed with --verbose option Reviewed-by: almatvee --- .../jdk/jpackage/internal/Arguments.java | 17 +++---- .../jdk/jpackage/test/JPackageCommand.java | 27 ++++++----- test/jdk/tools/jpackage/share/BasicTest.java | 45 ++++++++++++++----- 3 files changed, 59 insertions(+), 30 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java index 3102576a31e94..96a6c5f6e002d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java @@ -552,16 +552,13 @@ public boolean processArguments() { generateBundle(bp.getBundleParamsAsMap()); return true; } catch (Exception e) { - if (Log.isVerbose()) { - Log.verbose(e); - } else { - String msg1 = e.getMessage(); - Log.fatalError(msg1); - if (e.getCause() != null && e.getCause() != e) { - String msg2 = e.getCause().getMessage(); - if (msg2 != null && !msg1.contains(msg2)) { - Log.fatalError(msg2); - } + Log.verbose(e); + String msg1 = e.getMessage(); + Log.fatalError(msg1); + if (e.getCause() != null && e.getCause() != e) { + String msg2 = e.getCause().getMessage(); + if (msg2 != null && !msg1.contains(msg2)) { + Log.fatalError(msg2); } } return false; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index fc5adf7fdea64..77e3b772cfadf 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -42,7 +42,6 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; -import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -1174,16 +1173,20 @@ public static String escapeAndJoin(List args) { } public static Stream stripTimestamps(Stream stream) { - // [HH:mm:ss.SSS] - final Pattern timestampRegexp = Pattern.compile( - "^\\[\\d\\d:\\d\\d:\\d\\d.\\d\\d\\d\\] "); - return stream.map(str -> { - Matcher m = timestampRegexp.matcher(str); - if (m.find()) { - str = str.substring(m.end()); - } + return stream.map(JPackageCommand::stripTimestamp); + } + + public static String stripTimestamp(String str) { + final var m = TIMESTAMP_REGEXP.matcher(str); + if (m.find()) { + return str.substring(m.end()); + } else { return str; - }); + } + } + + public static boolean withTimestamp(String str) { + return TIMESTAMP_REGEXP.matcher(str).find(); } @Override @@ -1279,4 +1282,8 @@ public void run() { }).get(); private static final String UNPACKED_PATH_ARGNAME = "jpt-unpacked-folder"; + + // [HH:mm:ss.SSS] + private static final Pattern TIMESTAMP_REGEXP = Pattern.compile( + "^\\[\\d\\d:\\d\\d:\\d\\d.\\d\\d\\d\\] "); } diff --git a/test/jdk/tools/jpackage/share/BasicTest.java b/test/jdk/tools/jpackage/share/BasicTest.java index fe988533a28bd..68c1b2c76cb0d 100644 --- a/test/jdk/tools/jpackage/share/BasicTest.java +++ b/test/jdk/tools/jpackage/share/BasicTest.java @@ -22,32 +22,34 @@ */ +import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE_AND_UNPACK; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.List; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Optional; import java.util.function.Function; import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Stream; -import jdk.jpackage.test.TKit; +import jdk.jpackage.internal.util.function.ThrowingConsumer; +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.Executor; +import jdk.jpackage.test.HelloApp; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageStringBundle; import jdk.jpackage.test.JavaAppDesc; -import jdk.jpackage.test.PackageTest; -import jdk.jpackage.test.HelloApp; -import jdk.jpackage.test.Executor; import jdk.jpackage.test.JavaTool; -import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Annotations.Parameter; -import jdk.jpackage.test.Annotations.ParameterSupplier; -import jdk.jpackage.internal.util.function.ThrowingConsumer; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.TKit; import jdk.tools.jlink.internal.LinkableRuntimeImage; -import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE_AND_UNPACK; /* * @test @@ -228,6 +230,29 @@ public void testVerbose() { }); } + @Test + @Parameter("false") + @Parameter("true") + public void testErrorsAlwaysPrinted(boolean verbose) { + final var cmd = JPackageCommand.helloAppImage() + .ignoreDefaultVerbose(true) + .useToolProvider(false) + .removeArgumentWithValue("--main-class"); + + if (verbose) { + cmd.addArgument("--verbose"); + } + + final var textVerifier = Stream.of( + List.of("error.no-main-class-with-main-jar", "hello.jar"), + List.of("error.no-main-class-with-main-jar.advice", "hello.jar") + ).map(args -> { + return JPackageStringBundle.MAIN.cannedFormattedString(args.getFirst(), args.subList(1, args.size()).toArray()); + }).map(CannedFormattedString::getValue).map(TKit::assertTextStream).reduce(TKit.TextStreamVerifier::andThen).orElseThrow(); + + textVerifier.apply(cmd.saveConsoleOutput(true).execute(1).getOutput().stream().filter(Predicate.not(JPackageCommand::withTimestamp))); + } + @Test public void testNoName() { final String mainClassName = "Greetings"; From b92a44364d3a2267f5bc9aef3077805bebdf9fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Fri, 4 Apr 2025 11:53:11 +0000 Subject: [PATCH 0390/1101] 8353471: ZGC: Redundant generation id in ZGeneration Reviewed-by: stefank, eosterlund --- src/hotspot/share/gc/z/zGeneration.cpp | 10 +++++----- src/hotspot/share/gc/z/zGeneration.hpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 0dc8e93b8e716..f847525673378 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -182,9 +182,9 @@ static double fragmentation_limit(ZGenerationId generation) { } } -void ZGeneration::select_relocation_set(ZGenerationId generation, bool promote_all) { +void ZGeneration::select_relocation_set(bool promote_all) { // Register relocatable pages with selector - ZRelocationSetSelector selector(fragmentation_limit(generation)); + ZRelocationSetSelector selector(fragmentation_limit(_id)); { ZGenerationPagesIterator pt_iter(_page_table, _id, _page_allocator); for (ZPage* page; pt_iter.next(&page);) { @@ -238,7 +238,7 @@ void ZGeneration::select_relocation_set(ZGenerationId generation, bool promote_a // Selecting tenuring threshold must be done after select // which produces the liveness data, but before install, // which consumes the tenuring threshold. - if (generation == ZGenerationId::young) { + if (is_young()) { ZGeneration::young()->select_tenuring_threshold(selector.stats(), promote_all); } @@ -811,7 +811,7 @@ uint ZGenerationYoung::compute_tenuring_threshold(ZRelocationSetSelectorStats st void ZGenerationYoung::concurrent_select_relocation_set() { ZStatTimerYoung timer(ZPhaseConcurrentSelectRelocationSetYoung); const bool promote_all = type() == ZYoungType::major_full_preclean; - select_relocation_set(_id, promote_all); + select_relocation_set(promote_all); } class VM_ZRelocateStartYoung : public VM_ZYoungOperation { @@ -1153,7 +1153,7 @@ void ZGenerationOld::pause_verify() { void ZGenerationOld::concurrent_select_relocation_set() { ZStatTimerOld timer(ZPhaseConcurrentSelectRelocationSetOld); - select_relocation_set(_id, false /* promote_all */); + select_relocation_set(false /* promote_all */); } class VM_ZRelocateStartOld : public VM_ZOperation { diff --git a/src/hotspot/share/gc/z/zGeneration.hpp b/src/hotspot/share/gc/z/zGeneration.hpp index 2670ab5169909..922efe5ef9e37 100644 --- a/src/hotspot/share/gc/z/zGeneration.hpp +++ b/src/hotspot/share/gc/z/zGeneration.hpp @@ -91,7 +91,7 @@ class ZGeneration { void mark_free(); - void select_relocation_set(ZGenerationId generation, bool promote_all); + void select_relocation_set(bool promote_all); void reset_relocation_set(); ZGeneration(ZGenerationId id, ZPageTable* page_table, ZPageAllocator* page_allocator); From 4dca735bf30bcef17d127b8156cc41c4144fb536 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Fri, 4 Apr 2025 13:19:42 +0000 Subject: [PATCH 0391/1101] 8315844: $LSB_RELEASE is not defined before use Reviewed-by: jwaters, erikj, djelinski --- make/autoconf/basic_tools.m4 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/make/autoconf/basic_tools.m4 b/make/autoconf/basic_tools.m4 index eceb0ae6cc44f..eac14207b1da9 100644 --- a/make/autoconf/basic_tools.m4 +++ b/make/autoconf/basic_tools.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -57,6 +57,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_FUNDAMENTAL_TOOLS], UTIL_LOOKUP_PROGS(LOCALE, locale) UTIL_LOOKUP_PROGS(PATHTOOL, cygpath wslpath) UTIL_LOOKUP_PROGS(CMD, cmd.exe, $PATH:/cygdrive/c/windows/system32:/mnt/c/windows/system32:/c/windows/system32) + UTIL_LOOKUP_PROGS(LSB_RELEASE, lsb_release) ]) ################################################################################ @@ -106,9 +107,6 @@ AC_DEFUN_ONCE([BASIC_SETUP_TOOLS], UTIL_LOOKUP_PROGS(READLINK, greadlink readlink) UTIL_LOOKUP_PROGS(WHOAMI, whoami) - # Tools only needed on some platforms - UTIL_LOOKUP_PROGS(LSB_RELEASE, lsb_release) - # For compare.sh only UTIL_LOOKUP_PROGS(CMP, cmp) UTIL_LOOKUP_PROGS(UNIQ, uniq) From 37f8e419f9661ba30b3c34bd9fecef71ab1eddb1 Mon Sep 17 00:00:00 2001 From: Johannes Graham Date: Fri, 4 Apr 2025 13:24:22 +0000 Subject: [PATCH 0392/1101] 8347645: C2: XOR bounded value handling blocks constant folding Reviewed-by: epeter, vlivanov, qamai, jkarthikeyan --- src/hotspot/share/opto/addnode.cpp | 67 ++--- src/hotspot/share/opto/utilities/xor.hpp | 47 ++++ test/hotspot/gtest/opto/test_xor_node.cpp | 102 ++++++++ .../c2/irTests/XorINodeIdealizationTests.java | 238 +++++++++++++++++- .../c2/irTests/XorLNodeIdealizationTests.java | 191 +++++++++++++- 5 files changed, 593 insertions(+), 52 deletions(-) create mode 100644 src/hotspot/share/opto/utilities/xor.hpp create mode 100644 test/hotspot/gtest/opto/test_xor_node.cpp diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index 51b7ae7f6d4b4..a097a08607ae9 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -33,6 +33,7 @@ #include "opto/phaseX.hpp" #include "opto/subnode.hpp" #include "runtime/stubRoutines.hpp" +#include "opto/utilities/xor.hpp" // Portions of code courtesy of Clifford Click @@ -1007,23 +1008,9 @@ const Type* XorINode::Value(PhaseGVN* phase) const { if (in1->eqv_uncast(in2)) { return add_id(); } - // result of xor can only have bits sets where any of the - // inputs have bits set. lo can always become 0. - const TypeInt* t1i = t1->is_int(); - const TypeInt* t2i = t2->is_int(); - if ((t1i->_lo >= 0) && - (t1i->_hi > 0) && - (t2i->_lo >= 0) && - (t2i->_hi > 0)) { - // hi - set all bits below the highest bit. Using round_down to avoid overflow. - const TypeInt* t1x = TypeInt::make(0, round_down_power_of_2(t1i->_hi) + (round_down_power_of_2(t1i->_hi) - 1), t1i->_widen); - const TypeInt* t2x = TypeInt::make(0, round_down_power_of_2(t2i->_hi) + (round_down_power_of_2(t2i->_hi) - 1), t2i->_widen); - return t1x->meet(t2x); - } return AddNode::Value(phase); } - //------------------------------add_ring--------------------------------------- // Supplied function returns the sum of the inputs IN THE CURRENT RING. For // the logical operations the ring's ADD is really a logical OR function. @@ -1033,16 +1020,20 @@ const Type *XorINode::add_ring( const Type *t0, const Type *t1 ) const { const TypeInt *r0 = t0->is_int(); // Handy access const TypeInt *r1 = t1->is_int(); - // Complementing a boolean? - if( r0 == TypeInt::BOOL && ( r1 == TypeInt::ONE - || r1 == TypeInt::BOOL)) - return TypeInt::BOOL; + if (r0->is_con() && r1->is_con()) { + // compute constant result + return TypeInt::make(r0->get_con() ^ r1->get_con()); + } - if( !r0->is_con() || !r1->is_con() ) // Not constants - return TypeInt::INT; // Any integer, but still no symbols. + // At least one of the arguments is not constant - // Otherwise just XOR them bits. - return TypeInt::make( r0->get_con() ^ r1->get_con() ); + if (r0->_lo >= 0 && r1->_lo >= 0) { + // Combine [r0->_lo, r0->_hi] ^ [r0->_lo, r1->_hi] -> [0, upper_bound] + jint upper_bound = xor_upper_bound_for_ranges(r0->_hi, r1->_hi); + return TypeInt::make(0, upper_bound, MAX2(r0->_widen, r1->_widen)); + } + + return TypeInt::INT; } //============================================================================= @@ -1051,12 +1042,20 @@ const Type *XorLNode::add_ring( const Type *t0, const Type *t1 ) const { const TypeLong *r0 = t0->is_long(); // Handy access const TypeLong *r1 = t1->is_long(); - // If either input is not a constant, just return all integers. - if( !r0->is_con() || !r1->is_con() ) - return TypeLong::LONG; // Any integer, but still no symbols. + if (r0->is_con() && r1->is_con()) { + // compute constant result + return TypeLong::make(r0->get_con() ^ r1->get_con()); + } - // Otherwise just OR them bits. - return TypeLong::make( r0->get_con() ^ r1->get_con() ); + // At least one of the arguments is not constant + + if (r0->_lo >= 0 && r1->_lo >= 0) { + // Combine [r0->_lo, r0->_hi] ^ [r0->_lo, r1->_hi] -> [0, upper_bound] + julong upper_bound = xor_upper_bound_for_ranges(r0->_hi, r1->_hi); + return TypeLong::make(0, upper_bound, MAX2(r0->_widen, r1->_widen)); + } + + return TypeLong::LONG; } Node* XorLNode::Ideal(PhaseGVN* phase, bool can_reshape) { @@ -1092,19 +1091,7 @@ const Type* XorLNode::Value(PhaseGVN* phase) const { if (in1->eqv_uncast(in2)) { return add_id(); } - // result of xor can only have bits sets where any of the - // inputs have bits set. lo can always become 0. - const TypeLong* t1l = t1->is_long(); - const TypeLong* t2l = t2->is_long(); - if ((t1l->_lo >= 0) && - (t1l->_hi > 0) && - (t2l->_lo >= 0) && - (t2l->_hi > 0)) { - // hi - set all bits below the highest bit. Using round_down to avoid overflow. - const TypeLong* t1x = TypeLong::make(0, round_down_power_of_2(t1l->_hi) + (round_down_power_of_2(t1l->_hi) - 1), t1l->_widen); - const TypeLong* t2x = TypeLong::make(0, round_down_power_of_2(t2l->_hi) + (round_down_power_of_2(t2l->_hi) - 1), t2l->_widen); - return t1x->meet(t2x); - } + return AddNode::Value(phase); } diff --git a/src/hotspot/share/opto/utilities/xor.hpp b/src/hotspot/share/opto/utilities/xor.hpp new file mode 100644 index 0000000000000..20edaf0d01779 --- /dev/null +++ b/src/hotspot/share/opto/utilities/xor.hpp @@ -0,0 +1,47 @@ +#ifndef SHARE_OPTO_UTILITIES_XOR_HPP +#define SHARE_OPTO_UTILITIES_XOR_HPP + +#include "utilities/powerOfTwo.hpp" +// Code separated into its own header to allow access from GTEST + +// Given 2 non-negative values in the ranges [0, hi_0] and [0, hi_1], respectively. The bitwise +// xor of these values should also be non-negative. This method calculates an upper bound. + +// S and U type parameters correspond to the signed and unsigned +// variants of an integer to operate on. +template +static S xor_upper_bound_for_ranges(const S hi_0, const S hi_1) { + static_assert(S(-1) < S(0), "S must be signed"); + static_assert(U(-1) > U(0), "U must be unsigned"); + + assert(hi_0 >= 0, "must be non-negative"); + assert(hi_1 >= 0, "must be non-negative"); + + // x ^ y cannot have any bit set that is higher than both the highest bits set in x and y + // x cannot have any bit set that is higher than the highest bit set in hi_0 + // y cannot have any bit set that is higher than the highest bit set in hi_1 + + // We want to find a value that has all 1 bits everywhere up to and including + // the highest bits set in hi_0 as well as hi_1. For this, we can take the next + // power of 2 strictly greater than both hi values and subtract 1 from it. + + // Example 1: + // hi_0 = 5 (0b0101) hi_1=1 (0b0001) + // (5|1)+1 = 0b0110 + // round_up_pow2 = 0b1000 + // -1 = 0b0111 = max + + // Example 2 - this demonstrates need for the +1: + // hi_0 = 4 (0b0100) hi_1=4 (0b0100) + // (4|4)+1 = 0b0101 + // round_up_pow2 = 0b1000 + // -1 = 0b0111 = max + // Without the +1, round_up_pow2 would be 0b0100, resulting in 0b0011 as max + + // Note: cast to unsigned happens before +1 to avoid signed overflow, and + // round_up is safe because high bit is unset (0 <= lo <= hi) + + return round_up_power_of_2(U(hi_0 | hi_1) + 1) - 1; +} + +#endif // SHARE_OPTO_UTILITIES_XOR_HPP diff --git a/test/hotspot/gtest/opto/test_xor_node.cpp b/test/hotspot/gtest/opto/test_xor_node.cpp new file mode 100644 index 0000000000000..ff21d9c4a9007 --- /dev/null +++ b/test/hotspot/gtest/opto/test_xor_node.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "unittest.hpp" +#include "opto/utilities/xor.hpp" +#include "utilities/globalDefinitions.hpp" // For jint, juint + +jint test_calc_max(const jint hi_0, const jint hi_1) { + return xor_upper_bound_for_ranges(hi_0, hi_1); +} + +jlong test_calc_max(const jlong hi_0, const jlong hi_1) { + return xor_upper_bound_for_ranges(hi_0, hi_1); +} + +template +void test_xor_bounds(S hi_0, S hi_1, S val_0, S val_1) { + ASSERT_GE(hi_0, 0); + ASSERT_GE(hi_1, 0); + + // Skip out-of-bounds values for convenience + if (val_0 > hi_0 || val_0 < S(0) || val_1 > hi_1 || val_1 < S(0)) { + return; + } + + S v = val_0 ^ val_1; + S max = test_calc_max(hi_0, hi_1); + EXPECT_LE(v, max); +} + +template +void test_sample_values(S hi_0, S hi_1) { + for (S i = 0; i <= 3; i++) { + for (S j = 0; j <= 3; j++) { + // Some bit combinations near the low and high ends of the range + test_xor_bounds(hi_0, hi_1, i, j); + test_xor_bounds(hi_0, hi_1, hi_0 - i, hi_1 - j); + } + } +} + +template +void test_in_ranges(S lo, S hi){ + ASSERT_GE(lo, 0); + ASSERT_LE(lo, hi); + + for (S hi_0 = lo; hi_0 <= hi; hi_0++) { + for (S hi_1 = hi_0; hi_1 <=hi; hi_1++) { + test_sample_values(hi_0, hi_1); + } + } +} + +template +void test_exhaustive(S limit) { + for (S hi_0 = 0; hi_0 <= limit; hi_0++) { + for (S hi_1 = hi_0; hi_1 <= limit; hi_1++) { + for (S val_0 = 0; val_0 <= hi_0; val_0++) { + for (S val_1 = val_0; val_1 <= hi_1; val_1++) { + test_xor_bounds(hi_0, hi_1, val_0, val_1); + } + } + } + } +} + +template +void exec_tests() { + S top_bit = max_power_of_2(); + S prev_bit = top_bit >> 1; + + test_exhaustive(15); + + test_in_ranges(top_bit - 1, top_bit); + test_in_ranges(prev_bit - 1, prev_bit); +} + +TEST_VM(opto, xor_max) { + exec_tests(); + exec_tests(); +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/XorINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/XorINodeIdealizationTests.java index f1a0320330b14..b0a1c4c9e3775 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/XorINodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/XorINodeIdealizationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,16 +23,24 @@ package compiler.c2.irTests; import jdk.test.lib.Asserts; +import compiler.lib.generators.*; import compiler.lib.ir_framework.*; +import static java.lang.Integer.MAX_VALUE; +import static java.lang.Integer.MIN_VALUE; + /* * @test - * @bug 8281453 - * @summary Convert ~x into -1-x when ~x is used in an arithmetic expression + * @bug 8281453 8347645 8261008 8267332 + * @summary Test correctness of optimizations of xor * @library /test/lib / * @run driver compiler.c2.irTests.XorINodeIdealizationTests */ public class XorINodeIdealizationTests { + private static final RestrictableGenerator G = Generators.G.ints(); + private static final int CONST_1 = G.next(); + private static final int CONST_2 = G.next(); + public static void main(String[] args) { TestFramework.run(); } @@ -42,15 +50,17 @@ public static void main(String[] args) { "test7", "test8", "test9", "test10", "test11", "test12", "test13", "test14", "test15", - "test16", "test17"}) + "test16", "test17", + "testConstXor", "testXorSelf" + }) public void runMethod() { int a = RunInfo.getRandom().nextInt(); int b = RunInfo.getRandom().nextInt(); int c = RunInfo.getRandom().nextInt(); int d = RunInfo.getRandom().nextInt(); - int min = Integer.MIN_VALUE; - int max = Integer.MAX_VALUE; + int min = MIN_VALUE; + int max = MAX_VALUE; assertResult(0, 0, 0, 0); assertResult(a, b, c, d); @@ -77,6 +87,8 @@ public void assertResult(int a, int b, int c, int d) { Asserts.assertEQ(~a , test15(a)); Asserts.assertEQ((~a + b) + (~a | c), test16(a, b, c)); Asserts.assertEQ(-2023 - a , test17(a)); + Asserts.assertEQ(CONST_1 ^ CONST_2 , testConstXor()); + Asserts.assertEQ(0 , testXorSelf(a)); } @Test @@ -217,4 +229,218 @@ public int test16(int x, int y, int z) { public int test17(int x) { return ~(x + 2022); } + + @Test + @IR(failOn = {IRNode.XOR}) + @IR(counts = {IRNode.CON_I, "1"}) + // Checks (c1 ^ c2) => c3 (constant folded) + public int testConstXor() { + return CONST_1 ^ CONST_2; + } + + @Test + @IR(failOn = {IRNode.XOR}) + @IR(counts = {IRNode.CON_I, "1"}) + // Checks (x ^ x) => c (constant folded) + public int testXorSelf(int x) { + return x ^ x; + } + + private static final boolean CONST_BOOL_1 = RunInfo.getRandom().nextBoolean(); + private static final boolean CONST_BOOL_2 = RunInfo.getRandom().nextBoolean(); + + @Run(test={ + "testConstXorBool", "testXorSelfBool", "testXorIntAsBool" + }) + public void runBooleanTests() { + int c = G.next(); + int d = G.next(); + + assertBooleanResult(true, c, d); + assertBooleanResult(false, c, d); + } + + @DontCompile + public void assertBooleanResult(boolean b, int x, int y) { + Asserts.assertEQ(CONST_BOOL_1 ^ CONST_BOOL_2, testConstXorBool()); + Asserts.assertEQ(false, testXorSelfBool(b)); + Asserts.assertEQ(true, testXorIntAsBool(x, y)); + } + + @Test + @IR(failOn = {IRNode.XOR}) + @IR(counts = {IRNode.CON_I, "1"}) + // Checks (c1 ^ c2) => c3 (constant folded) + public boolean testConstXorBool() { + return CONST_BOOL_1 ^ CONST_BOOL_2; + } + + @Test + @IR(failOn = {IRNode.XOR}) + @IR(counts = {IRNode.CON_I, "1"}) + // Checks (x ^ x) => c (constant folded) + public boolean testXorSelfBool(boolean x) { + return x ^ x; + } + + @Test + @IR(failOn = {IRNode.XOR}) + @IR(counts = {IRNode.CON_I, "1"}) + // This test explicitly checks for constant folding over ints representing booleans. + // Checks (x ^ y) => z in [0, 1] when x and y are known to be in [0, 1] (constant folded) + public boolean testXorIntAsBool(int xi, int yi) { + int xor = (xi & 1) ^ (yi & 1); + return 0 <= xor && xor <= 1; + } + + @Run(test = { + "testFoldableXor", "testFoldableXorPow2", "testUnfoldableXorPow2", + "testFoldableXorDifferingLength", "testXorMax", + "testFoldableRange","testRandomLimits" + }) + public void runRangeTests() { + int a = G.next(); + int b = G.next(); + checkXor(a, b); + + for (a = 0; a < 32; a++) { + for (b = a; b < 32; b++) { + checkXor(a, b); + checkXor(MAX_VALUE, MAX_VALUE - b); + } + } + } + + @DontCompile + public void checkXor(int a, int b) { + Asserts.assertEQ(true, testFoldableXor(a, b)); + Asserts.assertEQ(((a & 0b1000) ^ (b & 0b1000)) < 0b1000, testUnfoldableXorPow2(a, b)); + Asserts.assertEQ(true, testFoldableXorPow2(a, b)); + Asserts.assertEQ(true, testFoldableXorDifferingLength(a, b)); + Asserts.assertEQ((a & MAX_VALUE) ^ (b & 0b11), testXorMax(a, b)); + Asserts.assertEQ(testRandomLimitsInterpreted(a, b), testRandomLimits(a, b)); + Asserts.assertEQ(true, testFoldableRange(a, b)); + } + + @Test + @IR(failOn = {IRNode.XOR}) + @IR(counts = {IRNode.CON_I, "1"}) + public boolean testFoldableXorPow2(int x, int y) { + return ((x & 0b1000) ^ (y & 0b1000)) < 0b10000; + } + + @Test + @IR(counts = {IRNode.XOR, "1"}) + public boolean testUnfoldableXorPow2(int x, int y) { + return ((x & 0b1000) ^ (y & 0b1000)) < 0b1000; + } + + @Test + @IR(failOn = {IRNode.XOR}) + @IR(counts = {IRNode.CON_I, "1"}) + public boolean testFoldableXor(int x, int y) { + var xor = (x & 0b111) ^ (y & 0b100); + return xor < 0b1000; + } + + @Test + @IR(failOn = {IRNode.XOR}) + @IR(counts = {IRNode.CON_I, "1"}) + public boolean testFoldableXorDifferingLength(int x, int y) { + var xor = (x & 0b111) ^ (y & 0b11); + return xor < 0b1000; + } + + @Test + public int testXorMax(int x, int y) { + return (x & MAX_VALUE) ^ (y & 0b11); + // can't do the folding range check here since xor <= MAX_VALUE is + // constant with or without the xor + } + + private static final Range RANGE_1 = Range.generate(G.restricted(0, MAX_VALUE)); + private static final Range RANGE_2 = Range.generate(G.restricted(0, MAX_VALUE)); + private static final int UPPER_BOUND = Integer.max(0, Integer.highestOneBit(RANGE_1.hi() | RANGE_2.hi()) * 2 - 1); + + private static final int LIMIT_1 = G.next(); + private static final int LIMIT_2 = G.next(); + private static final int LIMIT_3 = G.next(); + private static final int LIMIT_4 = G.next(); + private static final int LIMIT_5 = G.next(); + private static final int LIMIT_6 = G.next(); + private static final int LIMIT_7 = G.next(); + private static final int LIMIT_8 = G.next(); + + + @Test + @IR(failOn = {IRNode.XOR}) + @IR(counts = {IRNode.CON_I, "1"}) + public boolean testFoldableRange(int x, int y) { + return (RANGE_1.clamp(x) ^ RANGE_2.clamp(y)) <= UPPER_BOUND; + } + + @Test + public int testRandomLimits(int x, int y) { + x = RANGE_1.clamp(x); + y = RANGE_2.clamp(y); + + int z = x ^ y; + // This should now have a new range, possibly some [0, max] + // Now let's test the range with some random if branches. + int sum = 0; + if (z > LIMIT_1) { sum += 1; } + if (z > LIMIT_2) { sum += 2; } + if (z > LIMIT_3) { sum += 4; } + if (z > LIMIT_4) { sum += 8; } + if (z > LIMIT_5) { sum += 16; } + if (z > LIMIT_6) { sum += 32; } + if (z > LIMIT_7) { sum += 64; } + if (z > LIMIT_8) { sum += 128; } + + return sum; + } + + @DontCompile + private int testRandomLimitsInterpreted(int x, int y) { + x = RANGE_1.clamp(x); + y = RANGE_2.clamp(y); + + var z = x ^ y; + // This should now have a new range, possibly some [0, max] + // Now let's test the range with some random if branches. + int sum = 0; + if (z > LIMIT_1) { sum += 1; } + if (z > LIMIT_2) { sum += 2; } + if (z > LIMIT_3) { sum += 4; } + if (z > LIMIT_4) { sum += 8; } + if (z > LIMIT_5) { sum += 16; } + if (z > LIMIT_6) { sum += 32; } + if (z > LIMIT_7) { sum += 64; } + if (z > LIMIT_8) { sum += 128; } + + return sum; + } + + record Range(int lo, int hi) { + Range { + if (lo > hi) { + throw new IllegalArgumentException("lo > hi"); + } + } + + int clamp(int v) { + return Math.min(hi, Math.max(v, lo)); + } + + static Range generate(Generator g) { + var a = g.next(); + var b = g.next(); + if (a > b) { + var tmp = a; + a = b; + b = tmp; + } + return new Range(a, b); + } + } } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/XorLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/XorLNodeIdealizationTests.java index 22f3997a15ca9..ce328f7a37b00 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/XorLNodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/XorLNodeIdealizationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,16 +23,24 @@ package compiler.c2.irTests; import jdk.test.lib.Asserts; +import compiler.lib.generators.*; import compiler.lib.ir_framework.*; +import static java.lang.Long.MAX_VALUE; +import static java.lang.Long.MIN_VALUE; + /* * @test - * @bug 8281453 - * @summary Convert ~x into -1-x when ~x is used in an arithmetic expression + * @bug 8281453 8347645 8261008 8267332 + * @summary Test correctness of optimizations of xor * @library /test/lib / * @run driver compiler.c2.irTests.XorLNodeIdealizationTests */ public class XorLNodeIdealizationTests { + private static final RestrictableGenerator G = Generators.G.longs(); + private static final long CONST_1 = G.next(); + private static final long CONST_2 = G.next(); + public static void main(String[] args) { TestFramework.run(); } @@ -42,15 +50,17 @@ public static void main(String[] args) { "test7", "test8", "test9", "test10", "test11", "test12", "test13", "test14", "test15", - "test16", "test17"}) + "test16", "test17", + "testConstXor", "testXorSelf", + }) public void runMethod() { long a = RunInfo.getRandom().nextLong(); long b = RunInfo.getRandom().nextLong(); long c = RunInfo.getRandom().nextLong(); long d = RunInfo.getRandom().nextLong(); - long min = Long.MIN_VALUE; - long max = Long.MAX_VALUE; + long min = MIN_VALUE; + long max = MAX_VALUE; assertResult(0, 0, 0, 0); assertResult(a, b, c, d); @@ -77,6 +87,8 @@ public void assertResult(long a, long b, long c, long d) { Asserts.assertEQ(~a , test15(a)); Asserts.assertEQ((~a + b) + (~a | c), test16(a, b, c)); Asserts.assertEQ(-2023 - a , test17(a)); + Asserts.assertEQ(CONST_1 ^ CONST_2 , testConstXor()); + Asserts.assertEQ(0L , testXorSelf(a)); } @Test @@ -217,4 +229,171 @@ public long test16(long x, long y, long z) { public long test17(long x) { return ~(x + 2022); } + + @Test + @IR(failOn = {IRNode.XOR}) + @IR(counts = {IRNode.CON_L, "1"}) + // Checks (c1 ^ c2) => c3 (constant folded) + public long testConstXor() { + return CONST_1 ^ CONST_2; + } + + @Test + @IR(failOn = {IRNode.XOR}) + @IR(counts = {IRNode.CON_L, "1"}) + // Checks (x ^ x) => c (constant folded) + public long testXorSelf(long x) { + return x ^ x; + } + + @Run(test = { + "testFoldableXor", "testFoldableXorPow2", "testUnfoldableXorPow2", + "testFoldableXorDifferingLength", "testXorMax", + "testFoldableRange","testRandomLimits" + }) + public void runRangeTests() { + long a = G.next(); + long b = G.next(); + checkXor(a, b); + + for (a = 0; a < 32; a++) { + for (b = a; b < 32; b++) { + checkXor(a, b); + checkXor(MAX_VALUE, MAX_VALUE - b); + } + } + } + + @DontCompile + public void checkXor(long a, long b) { + Asserts.assertEQ(true, testFoldableXor(a, b)); + Asserts.assertEQ(((a & 0b1000) ^ (b & 0b1000)) < 0b1000, testUnfoldableXorPow2(a, b)); + Asserts.assertEQ(true, testFoldableXorPow2(a, b)); + Asserts.assertEQ(true, testFoldableXorDifferingLength(a, b)); + Asserts.assertEQ((a & MAX_VALUE) ^ (b & 0b11), testXorMax(a, b)); + Asserts.assertEQ(testRandomLimitsInterpreted(a, b), testRandomLimits(a, b)); + Asserts.assertEQ(true, testFoldableRange(a, b)); + } + + @Test + @IR(failOn = {IRNode.XOR}) + @IR(counts = {IRNode.CON_I, "1"}) // boolean is a CON_I + public boolean testFoldableXorPow2(long x, long y) { + return ((x & 0b1000) ^ (y & 0b1000)) < 0b10000; + } + + @Test + @IR(counts = {IRNode.XOR, "1"}) + public boolean testUnfoldableXorPow2(long x, long y) { + return ((x & 0b1000) ^ (y & 0b1000)) < 0b1000; + } + + @Test + @IR(failOn = {IRNode.XOR}) + @IR(counts = {IRNode.CON_I, "1"}) // boolean is a CON_I + public boolean testFoldableXor(long x, long y) { + var xor = (x & 0b111) ^ (y & 0b100); + return xor < 0b1000; + } + + @Test + @IR(failOn = {IRNode.XOR}) + @IR(counts = {IRNode.CON_I, "1"}) // boolean is a CON_I + public boolean testFoldableXorDifferingLength(long x, long y) { + var xor = (x & 0b111) ^ (y & 0b11); + return xor < 0b1000; + } + + @Test + public long testXorMax(long x, long y) { + return (x & MAX_VALUE) ^ (y & 0b11); + // can't do the folding range check here since xor <= MAX_VALUE is + // constant with or without the xor + } + + private static final Range RANGE_1 = Range.generate(G.restricted(0L, MAX_VALUE)); + private static final Range RANGE_2 = Range.generate(G.restricted(0L, MAX_VALUE)); + private static final long UPPER_BOUND = Math.max(0, Long.highestOneBit(RANGE_1.hi() | RANGE_2.hi()) * 2 - 1); + + private static final long LIMIT_1 = G.next(); + private static final long LIMIT_2 = G.next(); + private static final long LIMIT_3 = G.next(); + private static final long LIMIT_4 = G.next(); + private static final long LIMIT_5 = G.next(); + private static final long LIMIT_6 = G.next(); + private static final long LIMIT_7 = G.next(); + private static final long LIMIT_8 = G.next(); + + + @Test + @IR(failOn = {IRNode.XOR}) + @IR(counts = {IRNode.CON_I, "1"}) // Boolean is CON_I + public boolean testFoldableRange(long x, long y) { + return (RANGE_1.clamp(x) ^ RANGE_2.clamp(y)) <= UPPER_BOUND; + } + + @Test + public int testRandomLimits(long x, long y) { + x = RANGE_1.clamp(x); + y = RANGE_2.clamp(y); + + var z = x ^ y; + // This should now have a new range, possibly some [0, max] + // Now let's test the range with some random if branches. + int sum = 0; + if (z > LIMIT_1) { sum += 1; } + if (z > LIMIT_2) { sum += 2; } + if (z > LIMIT_3) { sum += 4; } + if (z > LIMIT_4) { sum += 8; } + if (z > LIMIT_5) { sum += 16; } + if (z > LIMIT_6) { sum += 32; } + if (z > LIMIT_7) { sum += 64; } + if (z > LIMIT_8) { sum += 128; } + + return sum; + } + + @DontCompile + private int testRandomLimitsInterpreted(long x, long y) { + x = RANGE_1.clamp(x); + y = RANGE_2.clamp(y); + + var z = x ^ y; + // This should now have a new range, possibly some [0, max] + // Now let's test the range with some random if branches. + int sum = 0; + if (z > LIMIT_1) { sum += 1; } + if (z > LIMIT_2) { sum += 2; } + if (z > LIMIT_3) { sum += 4; } + if (z > LIMIT_4) { sum += 8; } + if (z > LIMIT_5) { sum += 16; } + if (z > LIMIT_6) { sum += 32; } + if (z > LIMIT_7) { sum += 64; } + if (z > LIMIT_8) { sum += 128; } + + return sum; + } + + record Range(long lo, long hi) { + Range { + if (lo > hi) { + throw new IllegalArgumentException("lo > hi"); + } + } + + long clamp(long v) { + return Math.min(hi, Math.max(v, lo)); + } + + static Range generate(Generator g) { + var a = g.next(); + var b = g.next(); + if (a > b) { + var tmp = a; + a = b; + b = tmp; + } + return new Range(a, b); + } + } } From 3241b4e111e3dbf475c0e5be117c2a8d1a63ad35 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Fri, 4 Apr 2025 13:32:26 +0000 Subject: [PATCH 0393/1101] 8353066: Properly detect Windows/aarch64 as build platform Co-authored-by: Mikael Vidstedt Reviewed-by: mikael, prr, erikj --- make/autoconf/build-aux/config.guess | 12 ++++++++---- make/autoconf/toolchain_microsoft.m4 | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/make/autoconf/build-aux/config.guess b/make/autoconf/build-aux/config.guess index afdf7cb5f9205..ce9fb6cd16f38 100644 --- a/make/autoconf/build-aux/config.guess +++ b/make/autoconf/build-aux/config.guess @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2021, Azul Systems, Inc. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # @@ -53,10 +53,10 @@ if [ "x$OUT" = x ]; then fi fi -# Test and fix cygwin on x86_64 -echo $OUT | grep 86-pc-cygwin > /dev/null 2> /dev/null +# Test and fix cygwin/msys CPUs +echo $OUT | grep -e "-pc-cygwin" > /dev/null 2> /dev/null if test $? != 0; then - echo $OUT | grep 86-pc-mingw > /dev/null 2> /dev/null + echo $OUT | grep -e "-pc-mingw" > /dev/null 2> /dev/null fi if test $? = 0; then case `echo $PROCESSOR_IDENTIFIER | cut -f1 -d' '` in @@ -64,6 +64,10 @@ if test $? = 0; then REAL_CPU=x86_64 OUT=$REAL_CPU`echo $OUT | sed -e 's/[^-]*//'` ;; + ARMv8) + REAL_CPU=aarch64 + OUT=$REAL_CPU`echo $OUT | sed -e 's/[^-]*//'` + ;; esac fi diff --git a/make/autoconf/toolchain_microsoft.m4 b/make/autoconf/toolchain_microsoft.m4 index 4f970df7b5f7c..17ad2666b3ab8 100644 --- a/make/autoconf/toolchain_microsoft.m4 +++ b/make/autoconf/toolchain_microsoft.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -87,7 +87,7 @@ AC_DEFUN([TOOLCHAIN_CHECK_POSSIBLE_VISUAL_STUDIO_ROOT], elif test "x$TARGET_CPU" = xaarch64; then # for host x86-64, target aarch64 # aarch64 requires Visual Studio 16.8 or higher - VCVARSFILES="vcvarsamd64_arm64.bat vcvarsx86_arm64.bat" + VCVARSFILES="vcvarsarm64.bat vcvarsamd64_arm64.bat vcvarsx86_arm64.bat" fi for VCVARSFILE in $VCVARSFILES; do From 3670fde77f4cbf699bb43866f0c2fb5a867f0fc5 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Fri, 4 Apr 2025 13:43:55 +0000 Subject: [PATCH 0394/1101] 8349467: INIT_TARGETS tab completions on "make" lost with JDK-8348998 Reviewed-by: erikj --- make/PreInit.gmk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/make/PreInit.gmk b/make/PreInit.gmk index b70e15a3b8c25..a01971e845dc1 100644 --- a/make/PreInit.gmk +++ b/make/PreInit.gmk @@ -48,6 +48,10 @@ include $(TOPDIR)/make/common/LogUtils.gmk # a configuration. This will define ALL_GLOBAL_TARGETS. include $(TOPDIR)/make/Global.gmk +# Targets provided by Init.gmk. +ALL_INIT_TARGETS := print-modules print-targets print-configuration \ + print-tests reconfigure pre-compare-build post-compare-build + # CALLED_TARGETS is the list of targets that the user provided, # or "default" if unspecified. CALLED_TARGETS := $(if $(MAKECMDGOALS), $(MAKECMDGOALS), default) @@ -93,10 +97,6 @@ ifneq ($(SKIP_SPEC), true) # This will setup ALL_MAIN_TARGETS. $(eval $(call DefineMainTargets, FORCE, $(firstword $(SPECS)))) - # Targets provided by Init.gmk. - ALL_INIT_TARGETS := print-modules print-targets print-configuration \ - print-tests reconfigure pre-compare-build post-compare-build - # Separate called targets depending on type. INIT_TARGETS := $(filter $(ALL_INIT_TARGETS), $(CALLED_SPEC_TARGETS)) MAIN_TARGETS := $(filter $(ALL_MAIN_TARGETS), $(CALLED_SPEC_TARGETS)) From 5520ff12ec26dc2b490fb702101c3679a2af9a2d Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Fri, 4 Apr 2025 13:44:16 +0000 Subject: [PATCH 0395/1101] 8340341: Abort in configure when using Xcode 16.0 or 16.1 Reviewed-by: jwaters, erikj --- make/autoconf/toolchain.m4 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 9013f9cf9221f..b7a010746862e 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -291,6 +291,11 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION], # For Xcode, we set the Xcode version as TOOLCHAIN_VERSION TOOLCHAIN_VERSION=`$ECHO $XCODE_VERSION_OUTPUT | $CUT -f 2 -d ' '` TOOLCHAIN_DESCRIPTION="$TOOLCHAIN_DESCRIPTION from Xcode $TOOLCHAIN_VERSION" + if test "x$TOOLCHAIN_VERSION" = "x16" || test "x$TOOLCHAIN_VERSION" = "x16.1" ; then + AC_MSG_NOTICE([Xcode $TOOLCHAIN_VERSION has a compiler bug that causes the build to fail.]) + AC_MSG_NOTICE([Please use Xcode 16.2 or later, or a version prior to 16.]) + AC_MSG_ERROR([Compiler version is not supported.]) + fi fi fi AC_SUBST(TOOLCHAIN_VERSION) From 9fb3609955b01c7026665d7baf06de9761391ce4 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Fri, 4 Apr 2025 13:44:36 +0000 Subject: [PATCH 0396/1101] 8350774: Generated test- targets broken after JDK-8348998 Reviewed-by: erikj --- make/{RunTestsPrebuiltFindTests.gmk => GenerateFindTests.gmk} | 0 make/Init.gmk | 4 +--- make/PreInitSupport.gmk | 3 +++ make/RunTestsPrebuilt.gmk | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) rename make/{RunTestsPrebuiltFindTests.gmk => GenerateFindTests.gmk} (100%) diff --git a/make/RunTestsPrebuiltFindTests.gmk b/make/GenerateFindTests.gmk similarity index 100% rename from make/RunTestsPrebuiltFindTests.gmk rename to make/GenerateFindTests.gmk diff --git a/make/Init.gmk b/make/Init.gmk index 6da2fb985b62f..2a8f6399a184a 100644 --- a/make/Init.gmk +++ b/make/Init.gmk @@ -37,11 +37,9 @@ include MakeFileStart.gmk include $(TOPDIR)/make/InitSupport.gmk include LogUtils.gmk -# Force early generation of module-deps.gmk and find-tests.gmk +# Force early generation of module-deps.gmk GENERATE_MODULE_DEPS_FILE := true include Modules.gmk -GENERATE_FIND_TESTS_FILE := true -include FindTests.gmk # Inclusion of this pseudo-target will cause make to execute this file # serially, regardless of -j. diff --git a/make/PreInitSupport.gmk b/make/PreInitSupport.gmk index 66bcbd2209cdc..668363d872576 100644 --- a/make/PreInitSupport.gmk +++ b/make/PreInitSupport.gmk @@ -267,6 +267,9 @@ define DefineMainTargets $$(main_targets_file): @( cd $$(TOPDIR) && \ + $$(MAKE) $$(MAKE_LOG_FLAGS) -r -R -f $$(TOPDIR)/make/GenerateFindTests.gmk \ + -I $$(TOPDIR)/make/common SPEC=$(strip $2) ) + @( cd $$(TOPDIR) && \ $$(MAKE) $$(MAKE_LOG_FLAGS) -r -R -f $$(TOPDIR)/make/Main.gmk \ -I $$(TOPDIR)/make/common SPEC=$(strip $2) NO_RECIPES=true \ $$(MAKE_LOG_VARS) \ diff --git a/make/RunTestsPrebuilt.gmk b/make/RunTestsPrebuilt.gmk index ea38e73d49cb4..ba9731789b06d 100644 --- a/make/RunTestsPrebuilt.gmk +++ b/make/RunTestsPrebuilt.gmk @@ -298,7 +298,7 @@ test-prebuilt: @$(RM) -f $(MAKESUPPORT_OUTPUTDIR)/exit-with-error # We need to fill the FindTest cache before entering RunTests.gmk. @cd $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) SPEC=$(SPEC) \ - -f RunTestsPrebuiltFindTests.gmk + -f GenerateFindTests.gmk @cd $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f RunTests.gmk run-test \ TEST="$(TEST)" From 3cc43b3224efdf1a3f35fff58b993027a9e1f4ad Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Fri, 4 Apr 2025 13:44:55 +0000 Subject: [PATCH 0397/1101] 8349075: Once again allow -compilejdk in JAVA_OPTIONS Reviewed-by: rehn, erikj --- make/RunTests.gmk | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 4f81c096a3330..b9fd3e755d179 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -75,9 +75,6 @@ endif # This is the JDK that we will test JDK_UNDER_TEST := $(JDK_IMAGE_DIR) -# The JDK used to compile jtreg test code. By default it is the same as -# JDK_UNDER_TEST. -JDK_FOR_COMPILE := $(JDK_IMAGE_DIR) TEST_RESULTS_DIR := $(OUTPUTDIR)/test-results TEST_SUPPORT_DIR := $(OUTPUTDIR)/test-support @@ -945,6 +942,11 @@ define SetupRunJtregTestBody $1_JTREG_BASIC_OPTIONS += -e:JIB_HOME=$$(JIB_HOME) endif + ifneq ($$(JDK_FOR_COMPILE), ) + # Allow overriding the JDK used for compilation from the command line + $1_JTREG_BASIC_OPTIONS += -compilejdk:$$(JDK_FOR_COMPILE) + endif + $1_JTREG_BASIC_OPTIONS += -e:TEST_IMAGE_DIR=$(TEST_IMAGE_DIR) $1_JTREG_BASIC_OPTIONS += -e:DOCS_JDK_IMAGE_DIR=$$(DOCS_JDK_IMAGE_DIR) @@ -997,7 +999,6 @@ define SetupRunJtregTestBody $$(JTREG_JAVA) $$($1_JTREG_LAUNCHER_OPTIONS) \ -Dprogram=jtreg -jar $$(JT_HOME)/lib/jtreg.jar \ $$($1_JTREG_BASIC_OPTIONS) \ - -compilejdk:$$(JDK_FOR_COMPILE) \ -testjdk:$$(JDK_UNDER_TEST) \ -dir:$$(JTREG_TOPDIR) \ -reportDir:$$($1_TEST_RESULTS_DIR) \ From 08946c60d22ad481335c3fac99f45e9e5032651f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 4 Apr 2025 09:10:53 -0400 Subject: [PATCH 0398/1101] Fix bad merge --- .../jpackage/internal/PackageProperty.java | 4 +-- .../jpackage/internal/CFBundleVersion.java | 4 +-- .../internal/SigningIdentityImpl.java | 6 +--- .../jdk/jpackage/internal/AppImageDesc.java | 7 +---- .../jdk/jpackage/internal/AppImageFile.java | 2 +- .../jdk/jpackage/internal/Arguments.java | 2 -- .../jdk/jpackage/internal/Bundler.java | 6 ++-- .../jpackage/internal/BundlerParamInfo.java | 1 + .../jdk/jpackage/internal/DeployParams.java | 1 - .../jdk/jpackage/internal/IOUtils.java | 1 - .../jdk/jpackage/internal/LauncherData.java | 1 - .../internal/StandardBundlerParam.java | 4 +-- .../jdk/jpackage/internal/ToolValidator.java | 2 -- .../internal/util/MultiResourceBundle.java | 2 +- .../jpackage/internal/WixFragmentBuilder.java | 3 +- .../jdk/jpackage/internal/WixTool.java | 2 -- .../jdk/jpackage/internal/WixToolset.java | 1 - .../jpackage/internal/DeployParamsTest.java | 1 - .../internal/PlatformVersionTest.java | 30 +++++++++++-------- 19 files changed, 31 insertions(+), 49 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java index 939f3f88ad97d..6b06190f89158 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/PackageProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,8 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; import java.text.MessageFormat; +import jdk.jpackage.internal.model.ConfigException; final class PackageProperty { /** diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java index 052c14f68642c..17c310dbe568d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,8 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.DottedVersion; import java.math.BigInteger; +import jdk.jpackage.internal.model.DottedVersion; final class CFBundleVersion { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityImpl.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityImpl.java index 1c0418762e692..fc8f1ec0d3020 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityImpl.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityImpl.java @@ -1,9 +1,5 @@ /* -<<<<<<<< HEAD:src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityImpl.java * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. -======== - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. ->>>>>>>> master:src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +23,7 @@ * questions. */ -package jdk.jpackage.internal.model; +package jdk.jpackage.internal; import static jdk.jpackage.internal.CodesignConfig.ADHOC_SIGNING_IDENTITY; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageDesc.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageDesc.java index 4541dbad0f6bc..075fb7daa479a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageDesc.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageDesc.java @@ -1,10 +1,5 @@ /* -<<<<<<<< HEAD:src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageDesc.java * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. -======== - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. ->>>>>>>> master:src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java - * 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 @@ -27,7 +22,7 @@ * questions. */ -package jdk.jpackage.internal.model; +package jdk.jpackage.internal; import java.nio.file.Path; import java.util.Objects; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index 4200ec9fbccb6..6aee0218c44f4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java index 0f8cd77bf9284..4700231a16248 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java @@ -24,8 +24,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.PackagerException; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.PackagerException; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java index ce3466bf85bdf..0d29677e82631 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,10 +25,10 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.PackagerException; import java.nio.file.Path; import java.util.Map; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.PackagerException; /** * Bundler diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java index 40442bc2fc8ad..81030b18f6da6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java @@ -22,6 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.jpackage.internal; import java.nio.file.Path; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java index 80caa19525380..67214a3379685 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.PackagerException; import java.io.File; import java.io.IOException; import java.nio.file.Files; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java index b309a5aaa2159..13c7a78b502ff 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.PackagerException; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java index 39deeb1b6913b..d3f1f9d832851 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java @@ -24,7 +24,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.model.ConfigException; import java.io.File; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index ac12bd10a416b..9b0f328cdc33b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -26,7 +26,6 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -41,11 +40,10 @@ import java.util.Map; import java.util.Set; import java.util.stream.Stream; +import jdk.jpackage.internal.model.ConfigException; import static jdk.jpackage.internal.ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT; -import jdk.jpackage.internal.util.function.ThrowingFunction; import jdk.jpackage.internal.resources.ResourceLocator; import static jdk.jpackage.internal.model.RuntimeBuilder.getDefaultModulePath; -import static jdk.jpackage.internal.util.function.ThrowingBiFunction.toBiFunction; /** * Standard bundler parameters. diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java index 42555a91c1b32..f673ac7e33e27 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java @@ -24,8 +24,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.DottedVersion; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.DottedVersion; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java index d6a78ef8b4120..0ef0c5f59e0d9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/MultiResourceBundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java index 79285b97ed729..3479df10dee35 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java @@ -24,8 +24,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.WinMsiPackage; -import jdk.jpackage.internal.model.DottedVersion; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; @@ -44,6 +42,7 @@ import jdk.jpackage.internal.WixSourceConverter.ResourceGroup; import jdk.jpackage.internal.WixToolset.WixToolsetType; import jdk.jpackage.internal.model.DottedVersion; +import jdk.jpackage.internal.model.WinMsiPackage; import jdk.jpackage.internal.util.XmlUtils; /** diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java index d29b48350cb44..7e4353876b43a 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java @@ -24,8 +24,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.DottedVersion; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Files; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java index 10e82352b414a..e7bdbede368dc 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java @@ -24,7 +24,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.DottedVersion; import java.nio.file.Path; import java.util.Map; import java.util.Set; diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java index 2236f0fa07d03..70ede94e34464 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/DeployParamsTest.java @@ -22,7 +22,6 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.PackagerException; import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java index b5cd1f60f353a..5e3e27cacede2 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,13 +22,15 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.DottedVersion; -import java.lang.reflect.InvocationTargetException; -import java.util.function.Function; -import java.lang.reflect.Method; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import static org.junit.jupiter.api.Assumptions.assumeTrue; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.function.Function; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.DottedVersion; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -81,11 +83,15 @@ private static void testImpl(PlatformVersion parser, String version, boolean val } enum PlatformVersion { - MAC_CFBUNDLE_VERSION_CLASS("jdk.jpackage.internal.CFBundleVersion"), - WIN_MSI_PRODUCT_VERSION_CLASS("jdk.jpackage.internal.MsiVersion"); + MAC_CFBUNDLE_VERSION_CLASS("jdk.jpackage.internal.CFBundleVersion", OperatingSystem.MACOS), + WIN_MSI_PRODUCT_VERSION_CLASS("jdk.jpackage.internal.model.MsiVersion", OperatingSystem.WINDOWS); - PlatformVersion(String className) { - parser = findParser(className); + PlatformVersion(String className, OperatingSystem os) { + if (os.equals(OperatingSystem.current())) { + parser = getParser(className); + } else { + parser = null; + } } DottedVersion parse(String versionString) { @@ -95,7 +101,7 @@ DottedVersion parse(String versionString) { private Function parser; } - private static Function findParser(String className) { + private static Function getParser(String className) { try { Method method = Class.forName(className).getDeclaredMethod("of", String.class); @@ -112,9 +118,7 @@ private static Function findParser(String className) { throw new RuntimeException(causeEx); } }; - } catch (ClassNotFoundException e) { - return null; - } catch (SecurityException | NoSuchMethodException ex) { + } catch (SecurityException | NoSuchMethodException | ClassNotFoundException ex) { throw new IllegalArgumentException(ex); } } From 7ebd61d8e01c11494207ab7181918761a1780e3e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 4 Apr 2025 09:43:27 -0400 Subject: [PATCH 0399/1101] Clean warnings --- .../jdk/jpackage/internal/LinuxRpmBundler.java | 10 +++------- .../jpackage/internal/MacBaseInstallerBundler.java | 1 - .../jpackage/internal/SigningIdentityBuilder.java | 3 --- .../jdk/jpackage/internal/JLinkRuntimeBuilder.java | 12 +++++------- .../classes/jdk/jpackage/internal/WinMsiBundler.java | 1 - 5 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index d644f5201aff3..b2fe52d570763 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -25,12 +25,6 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.LinuxPackage; -import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.LinuxRpmPackage; -import jdk.jpackage.internal.model.DottedVersion; import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; @@ -38,13 +32,15 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.DottedVersion; +import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.LinuxRpmPackage; +import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackagerException; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index ac2b37870c808..88c5aa4cd629a 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityBuilder.java index f818e3d56b79a..422e30463f58b 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityBuilder.java @@ -26,7 +26,6 @@ import static jdk.jpackage.internal.MacCertificateUtils.findCertificates; -import java.nio.file.Path; import java.security.cert.X509Certificate; import java.util.List; import java.util.Map; @@ -217,6 +216,4 @@ static CertificateSelector create(String certificateLocator, StandardCertificate private String signingIdentity; private CertificateSelector certificateSelector; private String keychain; - private Path entitlements; - private String entitlementsResourceName; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java index 67e16e30f15db..b7557d32aebe2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java @@ -24,13 +24,7 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.LauncherStartupInfo; -import jdk.jpackage.internal.model.LauncherModularStartupInfo; -import jdk.jpackage.internal.model.RuntimeBuilder; import java.io.File; -import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.module.Configuration; @@ -52,9 +46,13 @@ import java.util.spi.ToolProvider; import java.util.stream.Collectors; import java.util.stream.Stream; - import jdk.internal.module.ModulePath; import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LauncherModularStartupInfo; +import jdk.jpackage.internal.model.LauncherStartupInfo; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.RuntimeBuilder; final class JLinkRuntimeBuilder implements RuntimeBuilder { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 7e38a2c888824..ce81354082e13 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -42,7 +42,6 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; From 7e8d64622fb2c086def3d8a00095be296dcc1f3a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 4 Apr 2025 10:22:14 -0400 Subject: [PATCH 0400/1101] Blessed modifiers order --- .../internal/LinuxPackagingPipeline.java | 2 +- .../jdk/jpackage/internal/Codesign.java | 4 ++-- .../jdk/jpackage/internal/Keychain.java | 2 +- .../internal/MacPackagingPipeline.java | 2 +- .../internal/model/MacFileAssociation.java | 2 +- .../jpackage/internal/model/MacPackage.java | 2 +- .../jdk/jpackage/internal/AppImageFile.java | 2 +- .../internal/ApplicationLayoutUtils.java | 8 +++---- .../jdk/jpackage/internal/PackageBuilder.java | 4 ++-- .../internal/cli/StandardValueConverter.java | 8 +++---- .../internal/model/AppImagePackageType.java | 2 +- .../internal/pipeline/BinaryMatrix.java | 4 ++-- .../jpackage/internal/pipeline/FixedDAG.java | 2 +- .../internal/util/CompositeProxy.java | 2 +- .../util/LocalizedExceptionBuilder.java | 14 ++++++------ .../internal/WinPackagingPipeline.java | 2 +- .../jpackage/internal/WixFragmentBuilder.java | 10 ++++----- .../jpackage/internal/WixSourceConverter.java | 4 ++-- .../internal/pipeline/FixedDAGTest.java | 20 ++++++++--------- .../pipeline/TaskPipelineBuilderTest.java | 22 +++++++++---------- 20 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java index 8c169b959b2d0..db85c53732cc1 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java @@ -81,6 +81,6 @@ private static void writeLauncherIcons( } } - final static LinuxApplicationLayout APPLICATION_LAYOUT = LinuxApplicationLayout.create( + static final LinuxApplicationLayout APPLICATION_LAYOUT = LinuxApplicationLayout.create( ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT, Path.of("lib/libapplauncher.so")); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Codesign.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Codesign.java index 39d372701751d..920b75df39829 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Codesign.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Codesign.java @@ -39,7 +39,7 @@ public final class Codesign { - public final static class CodesignException extends Exception { + public static final class CodesignException extends Exception { CodesignException(String[] output) { this.output = output; @@ -54,7 +54,7 @@ String[] getOutput() { private static final long serialVersionUID = 1L; } - public final static class Builder { + public static final class Builder { private Builder(Supplier> args) { this.args = Objects.requireNonNull(args); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Keychain.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Keychain.java index 606e403f2b18d..8670eff260894 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Keychain.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/Keychain.java @@ -86,7 +86,7 @@ static List listKeychains() { }).map(Keychain::new).toList(); } - final static class KeychainException extends RuntimeException { + static final class KeychainException extends RuntimeException { KeychainException(String msg) { super(msg); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index ee1f0df8f042d..7d76aba8a4057 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -425,6 +425,6 @@ public void execute(TaskAction taskAction) throws IOException, PackagerException } } - final static MacApplicationLayout APPLICATION_LAYOUT = MacApplicationLayout.create( + static final MacApplicationLayout APPLICATION_LAYOUT = MacApplicationLayout.create( ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT, Path.of("Contents/runtime")); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociation.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociation.java index 765e9c1cce44a..9d34cd144e42c 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociation.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociation.java @@ -28,7 +28,7 @@ public interface MacFileAssociation extends FileAssociation, MacFileAssociationMixin { - static public MacFileAssociation create(FileAssociation fa, MacFileAssociationMixin mixin) { + public static MacFileAssociation create(FileAssociation fa, MacFileAssociationMixin mixin) { return CompositeProxy.create(MacFileAssociation.class, fa, mixin); } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java index 2cf952b75b7e7..bb2b7deac2424 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java @@ -46,5 +46,5 @@ public static MacPackage create(Package pkg, MacPackageMixin mixin) { return CompositeProxy.create(MacPackage.class, pkg, mixin); } - public final static RuntimeLayout RUNTIME_PACKAGE_LAYOUT = RuntimeLayout.create(Path.of("Contents/Home")); + public static final RuntimeLayout RUNTIME_PACKAGE_LAYOUT = RuntimeLayout.create(Path.of("Contents/Home")); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index 6aee0218c44f4..c80549dca896b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -237,7 +237,7 @@ static String getPlatform() { return PLATFORM_LABELS.get(OperatingSystem.current()); } - private final static class AppImageProperties { + private static final class AppImageProperties { private AppImageProperties(Map data, Set stdKeys) { this.data = data; this.stdKeys = stdKeys; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java index c822a46637310..a2a5a15196616 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java @@ -31,16 +31,16 @@ final class ApplicationLayoutUtils { - public final static ApplicationLayout PLATFORM_APPLICATION_LAYOUT; + public static final ApplicationLayout PLATFORM_APPLICATION_LAYOUT; - private final static ApplicationLayout WIN_APPLICATION_LAYOUT = ApplicationLayout.build() + private static final ApplicationLayout WIN_APPLICATION_LAYOUT = ApplicationLayout.build() .setAll("") .appDirectory("app") .runtimeDirectory("runtime") .appModsDirectory(Path.of("app", "mods")) .create(); - private final static ApplicationLayout MAC_APPLICATION_LAYOUT = ApplicationLayout.build() + private static final ApplicationLayout MAC_APPLICATION_LAYOUT = ApplicationLayout.build() .launchersDirectory("Contents/MacOS") .appDirectory("Contents/app") .runtimeDirectory("Contents/runtime/Contents/Home") @@ -49,7 +49,7 @@ final class ApplicationLayoutUtils { .contentDirectory("Contents") .create(); - private final static ApplicationLayout LINUX_APPLICATION_LAYOUT = ApplicationLayout.build() + private static final ApplicationLayout LINUX_APPLICATION_LAYOUT = ApplicationLayout.build() .launchersDirectory("bin") .appDirectory("lib/app") .runtimeDirectory("lib/runtime") diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index 02b2408bc0c25..854b0193e7804 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -244,6 +244,6 @@ private static Optional defaultInstallDir(StandardPackageType pkgType, Str private Path predefinedAppImage; private Path installDir; - final private PackageType type; - final private Application app; + private final PackageType type; + private final Application app; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java index 836769fcfdb71..0fb48b76e347f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java @@ -32,7 +32,7 @@ final class StandardValueConverter { - final static ValueConverter IDENTITY_CONV = new ValueConverter<>() { + static final ValueConverter IDENTITY_CONV = new ValueConverter<>() { @Override public String convert(String value) { return Objects.requireNonNull(value); @@ -44,7 +44,7 @@ public Class valueType() { } }; - final static ValueConverter PATH_CONV = new ValueConverter<>() { + static final ValueConverter PATH_CONV = new ValueConverter<>() { @Override public Path convert(String value) { return Path.of(value); @@ -56,7 +56,7 @@ public Class valueType() { } }; - final static ValueConverter STRING_ARRAY_CONV = new ValueConverter<>() { + static final ValueConverter STRING_ARRAY_CONV = new ValueConverter<>() { @Override public String[] convert(String value) { return value.split("[,\\s]"); @@ -68,7 +68,7 @@ public Class valueType() { } }; - final static ValueConverter PATH_ARRAY_CONV = new ValueConverter<>() { + static final ValueConverter PATH_ARRAY_CONV = new ValueConverter<>() { @Override public Path[] convert(String value) { return Stream.of(value.split(File.pathSeparator)).map(Path::of).toArray(Path[]::new); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java index 21733fe141559..a27383f134f4a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java @@ -37,5 +37,5 @@ private AppImagePackageType() { /** * Singleton */ - public final static AppImagePackageType APP_IMAGE = new AppImagePackageType(); + public static final AppImagePackageType APP_IMAGE = new AppImagePackageType(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java index 452cb24ce327c..7b9aa5cfc9831 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/BinaryMatrix.java @@ -169,12 +169,12 @@ private abstract class SelectionIterator implements Iterator { } @Override - final public boolean hasNext() { + public final boolean hasNext() { return index < limit; } @Override - final public Cursor next() { + public final Cursor next() { if (!hasNext()) { throw new NoSuchElementException(); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/FixedDAG.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/FixedDAG.java index 2270a24e952c9..24ac187ea3a28 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/FixedDAG.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/pipeline/FixedDAG.java @@ -58,7 +58,7 @@ public static Builder build() { return new Builder<>(); } - public final static class Builder { + public static final class Builder { public Builder addNode(U node) { Objects.requireNonNull(node); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java index 36352cc88a5b7..6cc5119d6231a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java @@ -117,7 +117,7 @@ public final class CompositeProxy { /** * Builder of {@link CompositeProxy} instances. */ - public final static class Builder { + public static final class Builder { /** * Returns a proxy instance for the specified interface that dispatches method diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java index 0f7eca4832690..4b9714397796a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java @@ -57,7 +57,7 @@ public static LocalizedExceptionBuilder buildLocalizedException(StringBundle * @param exceptionCtor the exception constructor * @return the exception */ - final public U create(BiFunction exceptionCtor) { + public final U create(BiFunction exceptionCtor) { return exceptionCtor.apply(msg, cause); } @@ -75,7 +75,7 @@ final public U create(BiFunction exc * * @see #noformat() */ - final public T format(boolean v) { + public final T format(boolean v) { format = v; return thiz(); } @@ -87,7 +87,7 @@ final public T format(boolean v) { * * @see #format(boolean) */ - final public T noformat() { + public final T noformat() { return format(false); } @@ -99,7 +99,7 @@ final public T noformat() { * @param args the arguments for formatting message * @return this */ - final public T message(String msgId, Object... args) { + public final T message(String msgId, Object... args) { msg = formatString(msgId, args); return thiz(); } @@ -111,7 +111,7 @@ final public T message(String msgId, Object... args) { * is nonexistent or unknown. * @return this */ - final public T cause(Throwable v) { + public final T cause(Throwable v) { cause = v; return thiz(); } @@ -123,12 +123,12 @@ final public T cause(Throwable v) { * @param t the cause. Must not be null. * @return this */ - final public T causeAndMessage(Throwable t) { + public final T causeAndMessage(Throwable t) { boolean oldformat = format; return noformat().message(t.getMessage()).cause(t).format(oldformat); } - final protected String formatString(String keyId, Object... args) { + protected final String formatString(String keyId, Object... args) { if (format) { return i18n.format(keyId, args); } else if (args.length == 0) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java index 5729b3287d927..4a173225615d0 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java @@ -81,5 +81,5 @@ private static void rebrandLaunchers(AppImageBuildEnv getWixNamespaces() { + protected final Map getWixNamespaces() { switch (wixType) { case Wix3 -> { return Map.of(WixNamespace.Default, @@ -145,24 +145,24 @@ static boolean is64Bit() { return Architecture.is64bit(); } - final protected Path getConfigRoot() { + protected final Path getConfigRoot() { return configRoot; } protected abstract Collection getFragmentWriters(); - final protected void defineWixVariable(String variableName) { + protected final void defineWixVariable(String variableName) { setWixVariable(variableName, "yes"); } - final protected void setWixVariable(String variableName, String variableValue) { + protected final void setWixVariable(String variableName, String variableValue) { if (wixVariables == null) { wixVariables = new WixVariables(); } wixVariables.setWixVariable(variableName, variableValue); } - final protected void addResource(OverridableResource resource, String saveAsName) { + protected final void addResource(OverridableResource resource, String saveAsName) { if (additionalResources == null) { additionalResources = new ResourceGroup(getWixType()); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java index 58f777bd71b48..dfe0f0503af8f 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java @@ -161,7 +161,7 @@ private static byte[] saveResourceInMemory(OverridableResource resource) throws return buf.toByteArray(); } - final static class ResourceGroup { + static final class ResourceGroup { ResourceGroup(WixToolsetType wixToolsetType) { this.wixToolsetType = wixToolsetType; @@ -416,7 +416,7 @@ private Map.Entry createValue(Object prefix) { private final XMLOutputFactory outputFactory; // The list of WiX v3 namespaces this converter can handle - private final static Set KNOWN_NAMESPACES = Set.of( + private static final Set KNOWN_NAMESPACES = Set.of( "http://schemas.microsoft.com/wix/2006/localization", "http://schemas.microsoft.com/wix/2006/wi"); } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/FixedDAGTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/FixedDAGTest.java index e6763d6e556a3..ea3710b98dda1 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/FixedDAGTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/FixedDAGTest.java @@ -425,14 +425,14 @@ private static DirectedEdge edge(T tail, T head) { return DirectedEdge.create(tail, head); } - private final static String A = "A"; - private final static String B = "B"; - private final static String C = "C"; - private final static String D = "D"; - private final static String K = "K"; - private final static String L = "L"; - private final static String M = "M"; - private final static String N = "N"; - private final static String O = "O"; - private final static String P = "P"; + private static final String A = "A"; + private static final String B = "B"; + private static final String C = "C"; + private static final String D = "D"; + private static final String K = "K"; + private static final String L = "L"; + private static final String M = "M"; + private static final String N = "N"; + private static final String O = "O"; + private static final String P = "P"; } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java index 0eb3189e7f4c2..8d34c1be155b1 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java @@ -128,7 +128,7 @@ private record TaskSpec(TestTask task, List dependencies, TestTask dep Objects.requireNonNull(dependencies); } - final static class Builder { + static final class Builder { Builder(TestTask task) { this.task = Objects.requireNonNull(task); @@ -168,7 +168,7 @@ public record TestSpec(List taskSpecs, Object expectedString, Set onlyChars(Character... chars) { }, String.format("only %s", List.of(chars))); } - private final static TestTask A = TestTask.A; - private final static TestTask B = TestTask.B; - private final static TestTask C = TestTask.C; - private final static TestTask D = TestTask.D; - private final static TestTask K = TestTask.K; - private final static TestTask L = TestTask.L; - private final static TestTask M = TestTask.M; - private final static TestTask N = TestTask.N; - private final static TestTask THROW_1 = TestTask.THROW_1; + private static final TestTask A = TestTask.A; + private static final TestTask B = TestTask.B; + private static final TestTask C = TestTask.C; + private static final TestTask D = TestTask.D; + private static final TestTask K = TestTask.K; + private static final TestTask L = TestTask.L; + private static final TestTask M = TestTask.M; + private static final TestTask N = TestTask.N; + private static final TestTask THROW_1 = TestTask.THROW_1; } From 7708d99859f0def58a0f854227c6e78becad59d7 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 4 Apr 2025 10:05:37 -0400 Subject: [PATCH 0401/1101] Update copyright year --- .../classes/jdk/jpackage/internal/DesktopIntegration.java | 2 +- .../linux/classes/jdk/jpackage/internal/LinuxAppBundler.java | 2 +- .../classes/jdk/jpackage/internal/LinuxApplicationLayout.java | 2 +- .../jdk/jpackage/internal/LinuxApplicationLayoutMixin.java | 2 +- .../linux/classes/jdk/jpackage/internal/LinuxDebBundler.java | 2 +- .../classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java | 2 +- .../linux/classes/jdk/jpackage/internal/LinuxFromParams.java | 2 +- .../jdk/jpackage/internal/LinuxLaunchersAsServices.java | 2 +- .../linux/classes/jdk/jpackage/internal/LinuxPackageArch.java | 2 +- .../classes/jdk/jpackage/internal/LinuxPackageBuilder.java | 2 +- .../classes/jdk/jpackage/internal/LinuxPackageBundler.java | 2 +- .../classes/jdk/jpackage/internal/LinuxPackagingPipeline.java | 2 +- .../linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java | 2 +- .../classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java | 2 +- .../classes/jdk/jpackage/internal/model/LinuxApplication.java | 2 +- .../classes/jdk/jpackage/internal/model/LinuxDebPackage.java | 2 +- .../jdk/jpackage/internal/model/LinuxDebPackageMixin.java | 2 +- .../classes/jdk/jpackage/internal/model/LinuxLauncher.java | 2 +- .../jdk/jpackage/internal/model/LinuxLauncherMixin.java | 2 +- .../classes/jdk/jpackage/internal/model/LinuxPackage.java | 2 +- .../jdk/jpackage/internal/model/LinuxPackageMixin.java | 2 +- .../classes/jdk/jpackage/internal/model/LinuxRpmPackage.java | 2 +- .../jdk/jpackage/internal/model/LinuxRpmPackageMixin.java | 2 +- .../jdk/jpackage/internal/resources/LinuxResources.properties | 2 +- .../macosx/classes/jdk/jpackage/internal/MacAppBundler.java | 2 +- .../classes/jdk/jpackage/internal/MacAppImageBuilder.java | 2 +- .../classes/jdk/jpackage/internal/MacApplicationLayout.java | 2 +- .../jdk/jpackage/internal/MacApplicationLayoutMixin.java | 2 +- .../jdk/jpackage/internal/MacBaseInstallerBundler.java | 2 +- .../macosx/classes/jdk/jpackage/internal/MacDmgPackager.java | 2 +- .../classes/jdk/jpackage/internal/MacLaunchersAsServices.java | 2 +- .../jdk/jpackage/internal/model/MacApplicationMixin.java | 2 +- .../jdk/jpackage/internal/model/MacDmgPackageMixin.java | 2 +- .../jdk/jpackage/internal/model/MacFileAssociation.java | 2 +- .../jdk/jpackage/internal/model/MacFileAssociationMixin.java | 2 +- .../classes/jdk/jpackage/internal/model/MacPackageMixin.java | 2 +- .../jdk/jpackage/internal/model/MacPkgPackageMixin.java | 2 +- .../share/classes/jdk/jpackage/internal/AbstractBundler.java | 2 +- .../share/classes/jdk/jpackage/internal/AppImageBundler.java | 2 +- .../classes/jdk/jpackage/internal/ApplicationBuilder.java | 2 +- .../classes/jdk/jpackage/internal/ApplicationLayoutUtils.java | 2 +- .../share/classes/jdk/jpackage/internal/BuildEnv.java | 2 +- .../share/classes/jdk/jpackage/internal/BuildEnvBuilder.java | 2 +- .../classes/jdk/jpackage/internal/BuildEnvFromParams.java | 2 +- .../share/classes/jdk/jpackage/internal/CfgFile.java | 2 +- .../share/classes/jdk/jpackage/internal/I18N.java | 2 +- .../share/classes/jdk/jpackage/internal/InstallableFile.java | 2 +- .../classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java | 2 +- .../classes/jdk/jpackage/internal/LauncherAsService.java | 2 +- .../classes/jdk/jpackage/internal/LauncherFromParams.java | 2 +- .../jdk/jpackage/internal/LauncherStartupInfoBuilder.java | 2 +- .../classes/jdk/jpackage/internal/OverridableResource.java | 2 +- .../share/classes/jdk/jpackage/internal/PackageBuilder.java | 2 +- .../share/classes/jdk/jpackage/internal/PackageFile.java | 2 +- .../share/classes/jdk/jpackage/internal/PackagerBuilder.java | 2 +- .../classes/jdk/jpackage/internal/PackagingPipeline.java | 2 +- .../classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java | 2 +- .../share/classes/jdk/jpackage/internal/ScriptRunner.java | 2 +- .../classes/jdk/jpackage/internal/cli/AdditionalLauncher.java | 2 +- .../jdk/jpackage/internal/cli/CliApplicationBuilder.java | 2 +- .../classes/jdk/jpackage/internal/cli/CliPackageBuilder.java | 2 +- .../share/classes/jdk/jpackage/internal/cli/Option.java | 2 +- .../share/classes/jdk/jpackage/internal/cli/OptionSpec.java | 2 +- .../classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java | 2 +- .../classes/jdk/jpackage/internal/cli/PackageTypeGroup.java | 2 +- .../classes/jdk/jpackage/internal/cli/ParsedOptions.java | 2 +- .../classes/jdk/jpackage/internal/cli/StandardOption.java | 2 +- .../jdk/jpackage/internal/cli/StandardValueConverter.java | 2 +- .../jdk/jpackage/internal/cli/StandardValueValidator.java | 2 +- .../classes/jdk/jpackage/internal/cli/ValueConverter.java | 2 +- .../classes/jdk/jpackage/internal/model/AppImageLayout.java | 2 +- .../jdk/jpackage/internal/model/AppImagePackageType.java | 2 +- .../classes/jdk/jpackage/internal/model/Application.java | 2 +- .../jdk/jpackage/internal/model/ApplicationLaunchers.java | 2 +- .../jdk/jpackage/internal/model/ApplicationLayout.java | 2 +- .../jdk/jpackage/internal/model/ApplicationLayoutMixin.java | 2 +- .../jdk/jpackage/internal/model/ApplicationWriter.java | 2 +- .../classes/jdk/jpackage/internal/model/ConfigException.java | 2 +- .../jdk/jpackage/internal/model/CustomLauncherIcon.java | 2 +- .../jdk/jpackage/internal/model/DefaultLauncherIcon.java | 2 +- .../classes/jdk/jpackage/internal/model/FileAssociation.java | 2 +- .../share/classes/jdk/jpackage/internal/model/I18N.java | 2 +- .../share/classes/jdk/jpackage/internal/model/Launcher.java | 2 +- .../classes/jdk/jpackage/internal/model/LauncherIcon.java | 2 +- .../jdk/jpackage/internal/model/LauncherJarStartupInfo.java | 2 +- .../jpackage/internal/model/LauncherJarStartupInfoMixin.java | 2 +- .../jpackage/internal/model/LauncherModularStartupInfo.java | 2 +- .../internal/model/LauncherModularStartupInfoMixin.java | 2 +- .../jdk/jpackage/internal/model/LauncherStartupInfo.java | 2 +- .../share/classes/jdk/jpackage/internal/model/Package.java | 2 +- .../classes/jdk/jpackage/internal/model/PackageType.java | 2 +- .../classes/jdk/jpackage/internal/model/PackageWriter.java | 2 +- .../jdk/jpackage/internal/model/PackagerException.java | 2 +- .../classes/jdk/jpackage/internal/model/RuntimeBuilder.java | 2 +- .../jdk/jpackage/internal/model/StandardPackageType.java | 2 +- .../classes/jdk/jpackage/internal/util/CollectionUtils.java | 4 ++-- .../classes/jdk/jpackage/internal/util/CompositeProxy.java | 2 +- .../jdk/jpackage/internal/util/LocalizedExceptionBuilder.java | 2 +- .../share/classes/jdk/jpackage/internal/util/PathGroup.java | 2 +- .../share/classes/jdk/jpackage/internal/util/PathUtils.java | 2 +- .../classes/jdk/jpackage/internal/util/StringBundle.java | 2 +- src/jdk.jpackage/share/classes/module-info.java | 2 +- .../unix/classes/jdk/jpackage/internal/PackageScripts.java | 2 +- .../unix/classes/jdk/jpackage/internal/ShellCustomAction.java | 2 +- .../jdk/jpackage/internal/ShellCustomActionFactory.java | 2 +- .../jdk/jpackage/internal/UnixLaunchersAsServices.java | 2 +- .../classes/jdk/jpackage/internal/ExecutableRebrander.java | 2 +- .../windows/classes/jdk/jpackage/internal/WinAppBundler.java | 2 +- .../classes/jdk/jpackage/internal/WinExePackageBuilder.java | 2 +- .../classes/jdk/jpackage/internal/WinMsiPackageBuilder.java | 2 +- .../classes/jdk/jpackage/internal/WinPackagingPipeline.java | 2 +- .../jdk/jpackage/internal/WixAppImageFragmentBuilder.java | 2 +- .../classes/jdk/jpackage/internal/WixSourceConverter.java | 2 +- .../classes/jdk/jpackage/internal/WixUiFragmentBuilder.java | 2 +- .../classes/jdk/jpackage/internal/model/MsiVersion.java | 2 +- .../classes/jdk/jpackage/internal/model/WinApplication.java | 2 +- .../jdk/jpackage/internal/model/WinApplicationMixin.java | 2 +- .../classes/jdk/jpackage/internal/model/WinExePackage.java | 2 +- .../jdk/jpackage/internal/model/WinExePackageMixin.java | 2 +- .../classes/jdk/jpackage/internal/model/WinLauncher.java | 2 +- .../classes/jdk/jpackage/internal/model/WinLauncherMixin.java | 2 +- .../classes/jdk/jpackage/internal/model/WinMsiPackage.java | 2 +- .../jdk/jpackage/internal/model/WinMsiPackageMixin.java | 2 +- .../jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java | 2 +- .../jdk/jpackage/internal/model/ApplicationLayoutTest.java | 2 +- .../jdk/jpackage/internal/util/CompositeProxyTest.java | 2 +- 126 files changed, 127 insertions(+), 127 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 7a1eaf9b5d09c..cd2edabe41cc0 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java index 4b385899b30c7..992ec630c0e43 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java index aab7fc27ebe14..ea87363a9bbec 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java index d5a669c964fdc..a88dbc9e16ed7 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index 852ffe644bfaf..5c47a649bfe4e 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java index 3fe7d758bba0f..ced62f6c5d8c1 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java index deaa2f35303e4..7dff3cd73ae68 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java index 11e6e338c1c03..dce48e5d15145 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java index bb016e8d56530..836d1fb2c3760 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageArch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index 5fa5a4a7c7d9e..65b61f1331294 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 2e1001daa1de7..b65937193eb98 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java index db85c53732cc1..8e0071e643702 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackagingPipeline.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index b2fe52d570763..3f4382008a418 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java index 7725012d61ffe..bc361eac759c1 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java index 2a1dbc89bbc45..66225948fbb91 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java index 77180975afe44..3a4dc9bf0821c 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java index b9202079a2fff..6e3ae4665787f 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxDebPackageMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java index b4ad887b1d053..8970f2198c286 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java index 8ee7963068bea..d5e15101c7e5a 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java index aadca875361e6..b147ae7bc98c3 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java index 69f56385a760c..5d98112c09ed3 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java index dabf60fced80b..15283395ea414 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackageMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackageMixin.java index 5874980177417..c0e7dd10b0192 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackageMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxRpmPackageMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties index a28e9a395280f..fbc83ba2e10e0 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index 0377219ab6057..99b7bce58722d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java index 66fac82917166..91d3bc66b4a55 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayout.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayout.java index a5867c121633a..971548ea4f5e3 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayout.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayoutMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayoutMixin.java index 0d7f3c695e6f0..b6342b173dc92 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayoutMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayoutMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index 88c5aa4cd629a..7473289589b0f 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java index 79cc86b9f66cb..e30710cd07fff 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java index 859d4da0c9ab5..a614ef41c7db1 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacLaunchersAsServices.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java index c3f7a3d97902d..9c95442656786 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplicationMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java index 28d1703be316e..0b502e7ce7e11 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociation.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociation.java index 9d34cd144e42c..8cf6aa1dfbe2c 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociation.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociationMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociationMixin.java index 973e885d1296b..1fc7c849804ef 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociationMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacFileAssociationMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackageMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackageMixin.java index 7a6c57ae3c028..a6f6b099764f3 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackageMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackageMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackageMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackageMixin.java index 6b69299ea0349..3e43961a09af9 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackageMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPkgPackageMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java index d43c1fd8c78e1..762b65b530ef7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java index 92d2d6d1d1f1e..192630a565693 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 566446396b33f..82b715317b21a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java index a2a5a15196616..904858075d73f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java index de3907b290f1e..1d2a43bf5d637 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java index 57872489a713c..c36a9f9d3d766 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java index 6cfb8e7960a64..cc9b490b188aa 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java index 11515ff787895..9debe1c1f8947 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java index 785e4f05691a4..71df0dee8f552 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java index c43c92bfc86d2..0fc547e539372 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/InstallableFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java index b7557d32aebe2..c09c1ae4b1f68 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java index b97cacbac7dbf..dc20609b1afad 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherAsService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java index 87723cf2655d7..e776bccc9dba6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java index 85a48ac4200e6..0f3f41a2093ab 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java index 5331696c44635..019cb08f649d2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OverridableResource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index 854b0193e7804..5ef18df5b851b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java index 4ee8d7f68ccc3..b97fc707f843c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerBuilder.java index c9f2c50b7f298..4ba2f0fbda666 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java index 7dd0ec216de31..a24f00b258204 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java index 62f0cd5844126..8cbb34191926f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java index 10fd9f87c9b70..caa3674b67ee8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ScriptRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/AdditionalLauncher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/AdditionalLauncher.java index edfd8dbf1068e..4834622af0554 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/AdditionalLauncher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/AdditionalLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliApplicationBuilder.java index 7631940e3ef48..b33ac826a806a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliApplicationBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliPackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliPackageBuilder.java index dc6766bac8691..87267312e7cb1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliPackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliPackageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Option.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Option.java index e5df9cbc318bb..c95aae86dc388 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Option.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Option.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java index 960a236182bfa..94becc3f6463b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java index e1c48784666a3..cea03092f3729 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionSpecBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/PackageTypeGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/PackageTypeGroup.java index 04b6bee1dc2e7..896f48737cbbc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/PackageTypeGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/PackageTypeGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ParsedOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ParsedOptions.java index 37c571aad9c9e..8f3e210c49192 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ParsedOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ParsedOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index c1676a39aa955..4e00a5ae9412b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java index 0fb48b76e347f..5b83d9d3fe3ae 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueValidator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueValidator.java index dbc0d79147e8f..c87fa8c7e3010 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueValidator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java index d505a72e6f299..91ac38acc2dea 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/ValueConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java index e92eb19087a63..1cd0e0f6c2e26 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java index a27383f134f4a..4e28bb05aefe9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImagePackageType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index 7e5296ad00a90..019ea060e79e0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java index 94503ddd570e6..af52696a54677 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLaunchers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index 7f1c6603c2efa..0a87c25ced1e1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java index 2fc4871a57a1e..b39a9e1b81a1f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayoutMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java index be0bd04a0933a..14827a5072917 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java index a709273a40023..a2a799d7f1b92 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ConfigException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/CustomLauncherIcon.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/CustomLauncherIcon.java index fc270ecd03ec9..132165356803d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/CustomLauncherIcon.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/CustomLauncherIcon.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DefaultLauncherIcon.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DefaultLauncherIcon.java index b9ee8c6defb55..6e36949190ef7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DefaultLauncherIcon.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/DefaultLauncherIcon.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java index 74162a6137c85..de96f93523e7a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/FileAssociation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java index 18913117a5095..2a87c53ca445b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/I18N.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java index f744d61477edd..9c20d5432ee6c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Launcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java index 69e719a490408..bd7a9955b9006 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherIcon.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java index 24b6d4b66edea..5dd747c92a907 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java index 812280e133627..c8ead435146d5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherJarStartupInfoMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java index 9a17d61d844ea..b151b56a59b93 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java index 7744aac2cf670..4f57975f7107c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java index bbceaa7dc30e8..dd62c5a7a716b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherStartupInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java index 0bf4e14d094c9..186a6cabcf71d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java index bd02d30e9ec04..d0a4fd010e6e3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java index 8f05bc98b18fc..79f0b48836378 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java index 60f747e570fa1..4ac2599a38173 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackagerException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java index 4e439a29d053e..bce3b417b7c25 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java index 0938fa6bf7db3..ccdeceb4a0409 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/StandardPackageType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java index 9a4891a2ca3eb..386db21f532c0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,7 @@ public static > C toCollection(Collectio } /** - * Casts the given collection to the requested type. + * Casts the given collection to the requested upper bounded wildcard (UBW) type. * * @param the type of elements in this output collection * @param the upper bound type of elements in this input collection diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java index 6cc5119d6231a..458e5a63a489b 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java index 4b9714397796a..965988a0d9f80 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/LocalizedExceptionBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java index 06edb95f6abfe..6e2122230eddf 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java index 7ffb4ddfaa772..31019832b73ec 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java index d97e73ddf12fd..2dd79a5abe408 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/StringBundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/share/classes/module-info.java b/src/jdk.jpackage/share/classes/module-info.java index e5cd2cb3f9548..5536e9be75bd6 100644 --- a/src/jdk.jpackage/share/classes/module-info.java +++ b/src/jdk.jpackage/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java index a0053d369bdc7..74220c0d2af37 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/PackageScripts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java index d0a654a2d04e4..55068a571f837 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomAction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java index 683773ffcbad8..972e896b79735 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/ShellCustomActionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java index 5f63165931839..508ed526f8eaa 100644 --- a/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java +++ b/src/jdk.jpackage/unix/classes/jdk/jpackage/internal/UnixLaunchersAsServices.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java index 69e25041a8f78..913a44dbe18b6 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java index 06a34f9e52c0a..7bd799b87889c 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java index 6d5159d631722..28d1c3b6ff120 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java index 69402b47b9320..9d52d0a47adf7 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java index 4a173225615d0..be529bdc19e53 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index fa21928899099..17e6a4479aec7 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java index dfe0f0503af8f..e8f0eef5e6e2d 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixSourceConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java index b7c03c00d1b3d..0933f368c1f78 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java index 7eb5ac4b08bf3..a57ee495ec1f1 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/MsiVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java index 75cfe7787e084..65f0f563ee14c 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplicationMixin.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplicationMixin.java index 6da5d85622149..283b5d84ae3c9 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplicationMixin.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinApplicationMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java index 4509a20c3777e..6244090b71fb5 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackageMixin.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackageMixin.java index 11d1f4a08f001..766caf1e75dfe 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackageMixin.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackageMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java index 5cc64a18d72c2..b10ca99d483ec 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncherMixin.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncherMixin.java index 89990b749e104..65b6a1bab46f2 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncherMixin.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncherMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java index f9b12b4cd976d..52a2ccaafb3c8 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java index cf67d864c8d55..94d7c30fe57df 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinMsiPackageMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java index 85424f51ebfcd..22c6b09a4a0ca 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java index b1ec4c0c2e40e..d5f73522693ce 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java index 163246dbe9271..1ece83be0a62a 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it From 31a6de2e743923c92e976d5f5536120736d56029 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 4 Apr 2025 18:13:22 +0000 Subject: [PATCH 0402/1101] 8353309: Open source several Swing text tests Reviewed-by: aivanov, serb --- .../swing/text/BoxView/BaselineTest.java | 182 ++++++++++++++++++ .../swing/text/GlyphView/bug4188841.java | 93 +++++++++ .../html/FormView/4473401/bug4473401.java | 90 +++++++++ .../text/html/FormView/4473401/frame1.html | 9 + .../text/html/FormView/4473401/frame2.html | 4 + .../html/FormView/4473401/frameresult.html | 5 + .../text/html/FormView/4473401/frameset.html | 11 ++ .../swing/text/html/FormView/bug4529702.java | 62 ++++++ .../html/FrameSetView/4890934/bug4890934.java | 91 +++++++++ .../html/FrameSetView/4890934/frame1.html | 8 + .../html/FrameSetView/4890934/frame2.html | 4 + .../FrameSetView/4890934/frameresult.html | 7 + .../html/FrameSetView/4890934/frameset.html | 11 ++ 13 files changed, 577 insertions(+) create mode 100644 test/jdk/javax/swing/text/BoxView/BaselineTest.java create mode 100644 test/jdk/javax/swing/text/GlyphView/bug4188841.java create mode 100644 test/jdk/javax/swing/text/html/FormView/4473401/bug4473401.java create mode 100644 test/jdk/javax/swing/text/html/FormView/4473401/frame1.html create mode 100644 test/jdk/javax/swing/text/html/FormView/4473401/frame2.html create mode 100644 test/jdk/javax/swing/text/html/FormView/4473401/frameresult.html create mode 100644 test/jdk/javax/swing/text/html/FormView/4473401/frameset.html create mode 100644 test/jdk/javax/swing/text/html/FormView/bug4529702.java create mode 100644 test/jdk/javax/swing/text/html/FrameSetView/4890934/bug4890934.java create mode 100644 test/jdk/javax/swing/text/html/FrameSetView/4890934/frame1.html create mode 100644 test/jdk/javax/swing/text/html/FrameSetView/4890934/frame2.html create mode 100644 test/jdk/javax/swing/text/html/FrameSetView/4890934/frameresult.html create mode 100644 test/jdk/javax/swing/text/html/FrameSetView/4890934/frameset.html diff --git a/test/jdk/javax/swing/text/BoxView/BaselineTest.java b/test/jdk/javax/swing/text/BoxView/BaselineTest.java new file mode 100644 index 0000000000000..1af8d6cb28626 --- /dev/null +++ b/test/jdk/javax/swing/text/BoxView/BaselineTest.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4519537 4522866 + * @summary Tests that text and components in paragraph views line up at their baselines. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual BaselineTest + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.GridLayout; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTextPane; + +import javax.swing.text.ComponentView; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyledEditorKit; +import javax.swing.text.View; +import javax.swing.text.ViewFactory; + +public class BaselineTest { + + static final String INSTRUCTIONS = """ + Test that components displayed in a JTextPane properly respect their vertical alignment. + There are two text panes, stacked vertically with similar content except the bottom components are taller. + The content consists of a leading and trailing text string, with pink coloured components between. + The text string content means the strings 'Default Size Text' and 'Large Size Text'. + Text content baseline is at the bottom of CAPITAL letters in the text. + Each pink component has a string displaying its alignment setting in the range 0.0 to 1.0 + NB: The position of the strings "align = 0.0" etc is not important, it is the component position that matters. + 0.0 means it should be aligned with its top at the text content baseline, + 1.0 means it should be aligned with its bottom at the text content baseline. + A value in between will be a proportional alignment, eg 0.5 is centered on the text content baseline + If the content displays as described, the test PASSES. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("BaselineTest Test Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .rows(12) + .testUI(BaselineTest::createUI) + .positionTestUIBottomRowCentered() + .build() + .awaitAndCheck(); + } + + public static JFrame createUI() { + JFrame frame = new JFrame("BaselineTest"); + frame.setLayout(new GridLayout(2, 1)); + + JTextPane prefPane = new JTextPane(); + initJTextPane(prefPane); + frame.add(new JScrollPane(prefPane)); + + JTextPane variablePane = new JTextPane(); + variablePane.setEditorKit(new CustomEditorKit()); + initJTextPane(variablePane); + frame.add(new JScrollPane(variablePane)); + frame.setSize(800, 400); + return frame; + } + + static void initJTextPane(JTextPane tp) { + + try { + Document doc = tp.getDocument(); + + doc.insertString(0, " Default Size Text ", null); + tp.setCaretPosition(doc.getLength()); + tp.insertComponent(new PaintLabel(0.0f)); + tp.insertComponent(new PaintLabel(0.2f)); + tp.insertComponent(new PaintLabel(0.5f)); + tp.insertComponent(new PaintLabel(0.7f)); + tp.insertComponent(new PaintLabel(1.0f)); + SimpleAttributeSet set = new SimpleAttributeSet(); + StyleConstants.setFontSize(set, 20); + tp.setCaretPosition(doc.getLength()); + doc.insertString(doc.getLength(), " Large Size Text ", set); + } catch (BadLocationException ble) { + throw new RuntimeException(ble); + } + } + + static class PaintLabel extends JLabel { + + private int pref = 40; + private int min = pref - 30; + private int max = pref + 30; + + public PaintLabel(float align) { + + setAlignmentY(align); + String alignStr = String.valueOf(align); + + setText("align = " + alignStr); + setOpaque(true); + setBackground(Color.PINK); + } + + public Dimension getMinimumSize() { + return new Dimension(super.getMinimumSize().width, min); + } + + public Dimension getPreferredSize() { + return new Dimension(super.getPreferredSize().width, pref); + } + + public Dimension getMaximumSize() { + return new Dimension(super.getMaximumSize().width, max); + } + + public void paintComponent(Graphics g) { + g.setColor(Color.PINK); + g.fillRect(0, 0, getWidth(), getHeight()); + int y = (int)(getAlignmentY() * getHeight()); + g.setColor(Color.BLACK); + g.drawLine(0, y, getWidth(), y); + g.drawString(getText(), 0, 10); + } + } + + static class CustomComponentView extends ComponentView { + + public CustomComponentView(Element elem) { + super(elem); + } + + public int getResizeWeight(int axis) { + return 1; + } +} + + static class CustomEditorKit extends StyledEditorKit implements ViewFactory { + + public View create(Element elem) { + if (StyleConstants.ComponentElementName.equals(elem.getName())) { + return new CustomComponentView(elem); + } else { + return super.getViewFactory().create(elem); + } + } + + public ViewFactory getViewFactory() { + return this; + } +} + +} diff --git a/test/jdk/javax/swing/text/GlyphView/bug4188841.java b/test/jdk/javax/swing/text/GlyphView/bug4188841.java new file mode 100644 index 0000000000000..1b3cc0bcdd45a --- /dev/null +++ b/test/jdk/javax/swing/text/GlyphView/bug4188841.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4188841 + * @summary Tests a JTextPane wrapping issue + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4188841 +*/ + +import java.awt.Dimension; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTextPane; + +public class bug4188841 { + + static final String INSTRUCTIONS = """ + The text pane contains the phrase "the quick brown fox jumps over the lazy dog", + all the words are separated by tabs. When the test starts, the whole phrase should + appear on one line. If it is wrapped along two or more lines, the test FAILS. + + Otherwise, place the text caret in the very end of the line (e.g. by clicking + in the line and hitting End). Press Enter twice. The text should appear as one + line at all times. If the text wraps when you press Enter, the test FAILS. + """; + + static class NoWrapTextPane extends JTextPane { + + public boolean getScrollableTracksViewportWidth() { + //should not allow text to be wrapped + return false; + } + + public void setSize(Dimension d) { + // don't let the Textpane get sized smaller than its parent + if (d.width < getParent().getSize().width) { + super.setSize(getParent().getSize()); + } + else { + super.setSize(d); + } + } + } + + static JFrame createUI() { + + JFrame frame = new JFrame("bug4188841"); + + NoWrapTextPane nwp = new NoWrapTextPane(); + nwp.setText("the\tslow\tbrown\tfox\tjumps\tover\tthe\tlazy\tdog!"); + nwp.setCaretPosition(nwp.getText().length()); + + JScrollPane scrollPane = new JScrollPane(nwp, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + + frame.add(scrollPane); + frame.setSize(400, 300); + return frame; + } + + public static void main(String args[]) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(bug4188841::createUI) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/javax/swing/text/html/FormView/4473401/bug4473401.java b/test/jdk/javax/swing/text/html/FormView/4473401/bug4473401.java new file mode 100644 index 0000000000000..29dbba7ca0458 --- /dev/null +++ b/test/jdk/javax/swing/text/html/FormView/4473401/bug4473401.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4473401 + * @summary Tests if FormSubmitEvent is submitted correctly. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4473401 +*/ + +import java.io.File; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import javax.swing.text.html.FormSubmitEvent; +import javax.swing.text.html.HTMLEditorKit; + +public class bug4473401 implements HyperlinkListener { + + static final String INSTRUCTIONS = """ + The test window displays an HTML frameset with a frame + on the left and another to the right. + Push the 'Submit Query' button in the left frame to perform testing. + The window should be updated to have only one frame with the + message 'If you see this page the test PASSED'. + If it appears, PASS the test, otherwise FAIL the test. + """; + + static JEditorPane jep; + static JFrame createUI() { + + JFrame frame = new JFrame("bug4473401"); + jep = new JEditorPane(); + jep.addHyperlinkListener(new bug4473401()); + HTMLEditorKit kit = new HTMLEditorKit(); + kit.setAutoFormSubmission(false); + jep.setEditorKit(kit); + jep.setEditable(false); + + try { + File file = new File(System.getProperty("test.src", "."), "frameset.html"); + System.out.println(file.toURI().toURL()); + jep.setPage(file.toURL()); + } catch (Exception e) { + throw new RuntimeException(e); + } + + frame.add(jep); + frame.setSize(500, 500); + return frame; + } + + public void hyperlinkUpdate(HyperlinkEvent e) { + if (e instanceof FormSubmitEvent) { + jep.setText("If you see this page the test PASSED"); + } + } + + public static void main(String args[]) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4473401::createUI) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/javax/swing/text/html/FormView/4473401/frame1.html b/test/jdk/javax/swing/text/html/FormView/4473401/frame1.html new file mode 100644 index 0000000000000..833bc1f635297 --- /dev/null +++ b/test/jdk/javax/swing/text/html/FormView/4473401/frame1.html @@ -0,0 +1,9 @@ + + +Push the Submit query button +
+
+ +
+ + diff --git a/test/jdk/javax/swing/text/html/FormView/4473401/frame2.html b/test/jdk/javax/swing/text/html/FormView/4473401/frame2.html new file mode 100644 index 0000000000000..5bc6dba57fc4c --- /dev/null +++ b/test/jdk/javax/swing/text/html/FormView/4473401/frame2.html @@ -0,0 +1,4 @@ + + + + diff --git a/test/jdk/javax/swing/text/html/FormView/4473401/frameresult.html b/test/jdk/javax/swing/text/html/FormView/4473401/frameresult.html new file mode 100644 index 0000000000000..6ef5c8198cc35 --- /dev/null +++ b/test/jdk/javax/swing/text/html/FormView/4473401/frameresult.html @@ -0,0 +1,5 @@ + + +If you see this page the test FAILED. + + diff --git a/test/jdk/javax/swing/text/html/FormView/4473401/frameset.html b/test/jdk/javax/swing/text/html/FormView/4473401/frameset.html new file mode 100644 index 0000000000000..1e7f8298d628b --- /dev/null +++ b/test/jdk/javax/swing/text/html/FormView/4473401/frameset.html @@ -0,0 +1,11 @@ + + + + Manual test for bug 4463014 + + + + + + + \ No newline at end of file diff --git a/test/jdk/javax/swing/text/html/FormView/bug4529702.java b/test/jdk/javax/swing/text/html/FormView/bug4529702.java new file mode 100644 index 0000000000000..4962a0a666304 --- /dev/null +++ b/test/jdk/javax/swing/text/html/FormView/bug4529702.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4529702 + * @summary Test that radio buttons with different names should be selectable at the same time + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4529702 +*/ + +import javax.swing.JFrame; +import javax.swing.JTextPane; + +public class bug4529702 { + + static final String INSTRUCTIONS = """ + There are two rows of radio buttons, each row having two buttons. + If you can select radio buttons from the first and the second rows + at the same time the test PASSES otherwise the test FAILS. + """; + + static JFrame createUI() { + JFrame frame = new JFrame("bug4529702"); + JTextPane jtp = new JTextPane(); + jtp.setContentType("text/html"); + jtp.setText("

" + + "
"); + frame.add(jtp); + frame.setSize(200, 200); + return frame; + } + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4529702::createUI) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/javax/swing/text/html/FrameSetView/4890934/bug4890934.java b/test/jdk/javax/swing/text/html/FrameSetView/4890934/bug4890934.java new file mode 100644 index 0000000000000..988db296f7b6f --- /dev/null +++ b/test/jdk/javax/swing/text/html/FrameSetView/4890934/bug4890934.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4890934 + * @summary Tests if JEditor Pane updates the correct frame when using + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4890934 +*/ + +import java.io.File; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import javax.swing.text.html.HTMLDocument; +import javax.swing.text.html.HTMLEditorKit; +import javax.swing.text.html.HTMLFrameHyperlinkEvent; + +public class bug4890934 implements HyperlinkListener { + + static final String INSTRUCTIONS = """ + The test window displays an HTML frameset with a frame + on the left and another to the right. + Click the link in the left frame which should change the view. + The resulting page will tell you if the test PASSED or FAILED. + """; + + static JFrame createUI() { + + JFrame frame = new JFrame("bug4890934"); + JEditorPane jep = new JEditorPane(); + jep.setEditorKit(new HTMLEditorKit()); + jep.setEditable(false); + jep.addHyperlinkListener(new bug4890934()); + + try { + File file = new File(System.getProperty("test.src", "."), "frameset.html"); + System.out.println(file.toURI().toURL()); + jep.setPage(file.toURL()); + } catch (Exception e) { + throw new RuntimeException(e); + } + + frame.add(jep); + frame.setSize(600, 300); + return frame; + } + + public void hyperlinkUpdate(HyperlinkEvent e) { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + JEditorPane pane = (JEditorPane) e.getSource(); + if (e instanceof HTMLFrameHyperlinkEvent) { + HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent)e; + HTMLDocument doc = (HTMLDocument)pane.getDocument(); + doc.processHTMLFrameHyperlinkEvent(evt); + } + } + } + + public static void main(String args[]) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4890934::createUI) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/javax/swing/text/html/FrameSetView/4890934/frame1.html b/test/jdk/javax/swing/text/html/FrameSetView/4890934/frame1.html new file mode 100644 index 0000000000000..31f95568aaeec --- /dev/null +++ b/test/jdk/javax/swing/text/html/FrameSetView/4890934/frame1.html @@ -0,0 +1,8 @@ + + + + + + a link + + diff --git a/test/jdk/javax/swing/text/html/FrameSetView/4890934/frame2.html b/test/jdk/javax/swing/text/html/FrameSetView/4890934/frame2.html new file mode 100644 index 0000000000000..5bc6dba57fc4c --- /dev/null +++ b/test/jdk/javax/swing/text/html/FrameSetView/4890934/frame2.html @@ -0,0 +1,4 @@ + + + + diff --git a/test/jdk/javax/swing/text/html/FrameSetView/4890934/frameresult.html b/test/jdk/javax/swing/text/html/FrameSetView/4890934/frameresult.html new file mode 100644 index 0000000000000..a31045833b5c6 --- /dev/null +++ b/test/jdk/javax/swing/text/html/FrameSetView/4890934/frameresult.html @@ -0,0 +1,7 @@ + + +If you see this text in the RIGHT frame the test PASSED. +

If you see this text in the LEFT frame the test FAILED. + + + diff --git a/test/jdk/javax/swing/text/html/FrameSetView/4890934/frameset.html b/test/jdk/javax/swing/text/html/FrameSetView/4890934/frameset.html new file mode 100644 index 0000000000000..9462e1894a590 --- /dev/null +++ b/test/jdk/javax/swing/text/html/FrameSetView/4890934/frameset.html @@ -0,0 +1,11 @@ + + + + Manual test for bug 4463014 + + + + + + + From 74c2d8f41bbb770e959a77ae1ce468162d68beaf Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 4 Apr 2025 18:16:57 +0000 Subject: [PATCH 0403/1101] 8353320: Open source more Swing text tests Reviewed-by: aivanov, serb --- .../html/FrameView/4463014/bug4463014.java | 74 +++++++++++++++++ .../text/html/FrameView/4463014/frame1.html | 9 +++ .../text/html/FrameView/4463014/frame2.html | 4 + .../html/FrameView/4463014/frameresult.html | 7 ++ .../text/html/FrameView/4463014/frameset.html | 11 +++ .../text/html/HTMLEditorKit/bug4102068.java | 77 ++++++++++++++++++ .../text/html/HTMLEditorKit/bug4198022.java | 81 +++++++++++++++++++ .../text/html/HTMLEditorKit/bug4245401.java | 78 ++++++++++++++++++ .../text/html/StyleSheet/bug4619595.java | 77 ++++++++++++++++++ 9 files changed, 418 insertions(+) create mode 100644 test/jdk/javax/swing/text/html/FrameView/4463014/bug4463014.java create mode 100644 test/jdk/javax/swing/text/html/FrameView/4463014/frame1.html create mode 100644 test/jdk/javax/swing/text/html/FrameView/4463014/frame2.html create mode 100644 test/jdk/javax/swing/text/html/FrameView/4463014/frameresult.html create mode 100644 test/jdk/javax/swing/text/html/FrameView/4463014/frameset.html create mode 100644 test/jdk/javax/swing/text/html/HTMLEditorKit/bug4102068.java create mode 100644 test/jdk/javax/swing/text/html/HTMLEditorKit/bug4198022.java create mode 100644 test/jdk/javax/swing/text/html/HTMLEditorKit/bug4245401.java create mode 100644 test/jdk/javax/swing/text/html/StyleSheet/bug4619595.java diff --git a/test/jdk/javax/swing/text/html/FrameView/4463014/bug4463014.java b/test/jdk/javax/swing/text/html/FrameView/4463014/bug4463014.java new file mode 100644 index 0000000000000..4b7199c901754 --- /dev/null +++ b/test/jdk/javax/swing/text/html/FrameView/4463014/bug4463014.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4463014 + * @summary Tests if JEditorPane updates the correct frame when using

+ * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4463014 + */ + +import java.io.File; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.text.html.HTMLEditorKit; + +public class bug4463014 { + + static final String INSTRUCTIONS = """ + The test window displays an HTML frameset with a frame + on the left and another to the right. + Follow the instructions displayed in the left frame to perform testing. + The test PASSES only if the test behaves as per instructions. + """; + + static JFrame createUI() { + JFrame frame = new JFrame("bug4463014"); + JEditorPane jep = new JEditorPane(); + jep.setEditorKit(new HTMLEditorKit()); + jep.setEditable(false); + + try { + File file = new File(System.getProperty("test.src", "."), "frameset.html"); + System.out.println(file.toURL()); + jep.setPage(file.toURL()); + } catch (Exception e) { + } + + frame.add(jep); + frame.setSize(500,500); + return frame; + } + + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4463014::createUI) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/javax/swing/text/html/FrameView/4463014/frame1.html b/test/jdk/javax/swing/text/html/FrameView/4463014/frame1.html new file mode 100644 index 0000000000000..833bc1f635297 --- /dev/null +++ b/test/jdk/javax/swing/text/html/FrameView/4463014/frame1.html @@ -0,0 +1,9 @@ + + +Push the Submit query button + +
+ +
+ + diff --git a/test/jdk/javax/swing/text/html/FrameView/4463014/frame2.html b/test/jdk/javax/swing/text/html/FrameView/4463014/frame2.html new file mode 100644 index 0000000000000..5bc6dba57fc4c --- /dev/null +++ b/test/jdk/javax/swing/text/html/FrameView/4463014/frame2.html @@ -0,0 +1,4 @@ + + + + diff --git a/test/jdk/javax/swing/text/html/FrameView/4463014/frameresult.html b/test/jdk/javax/swing/text/html/FrameView/4463014/frameresult.html new file mode 100644 index 0000000000000..a31045833b5c6 --- /dev/null +++ b/test/jdk/javax/swing/text/html/FrameView/4463014/frameresult.html @@ -0,0 +1,7 @@ + + +If you see this text in the RIGHT frame the test PASSED. +

If you see this text in the LEFT frame the test FAILED. + + + diff --git a/test/jdk/javax/swing/text/html/FrameView/4463014/frameset.html b/test/jdk/javax/swing/text/html/FrameView/4463014/frameset.html new file mode 100644 index 0000000000000..1e7f8298d628b --- /dev/null +++ b/test/jdk/javax/swing/text/html/FrameView/4463014/frameset.html @@ -0,0 +1,11 @@ + + + + Manual test for bug 4463014 + + + + + + + \ No newline at end of file diff --git a/test/jdk/javax/swing/text/html/HTMLEditorKit/bug4102068.java b/test/jdk/javax/swing/text/html/HTMLEditorKit/bug4102068.java new file mode 100644 index 0000000000000..39dd1d539255a --- /dev/null +++ b/test/jdk/javax/swing/text/html/HTMLEditorKit/bug4102068.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4102068 + * @summary Tests HTML editor JEditorPane change mouse icon over the link + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4102068 + */ + +import java.awt.Cursor; +import javax.swing.JFrame; +import javax.swing.JTextPane; +import javax.swing.text.html.HTMLEditorKit; + +public class bug4102068 { + + static final String INSTRUCTIONS = """ + The test window contains an HTML frame containing a string with one hyperlink. + Move the mouse pointer over this hyperlink. + If the pointer over the hyperlink became a HAND cursor then the test PASSES, + otherwise the test FAILS. + """; + + static JFrame createUI() { + + JFrame frame = new JFrame("bug4102068"); + JTextPane ep = new JTextPane(); + ep.setContentType("text/html"); + HTMLEditorKit ek = new HTMLEditorKit(); + ep.setEditorKit(ek); + ep.setText("Here is a HyperLink Cursor Test"); + ek.setDefaultCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + Cursor ct = ek.getDefaultCursor(); + ek.setLinkCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + Cursor cl = ek.getLinkCursor(); + if (ct.getType() != Cursor.DEFAULT_CURSOR || cl.getType() != Cursor.HAND_CURSOR) { + throw new RuntimeException("Error with cursor settings..."); + } + ep.setEditable(false); + + frame.add(ep); + frame.setSize(300, 300); + return frame; + } + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4102068::createUI) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/javax/swing/text/html/HTMLEditorKit/bug4198022.java b/test/jdk/javax/swing/text/html/HTMLEditorKit/bug4198022.java new file mode 100644 index 0000000000000..2d26ace21318c --- /dev/null +++ b/test/jdk/javax/swing/text/html/HTMLEditorKit/bug4198022.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4198022 + * @summary Tests if HTML tags , and are supported in JEditorPane + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4198022 + */ + +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.text.html.HTMLEditorKit; + +public class bug4198022 { + + static final String INSTRUCTIONS = """ + There are two "lines" of text in the displayed HTML window + The first line/string contains and HTML elements. + The word "subscript" should be subscripted (placed lower than the word "Testing"), + and the word "superscript" should be superscripted (placed higher than "Testing"). + If instead these words are placed on the same level then the test FAILS. + + The second line/string contains a sentence marked with tag. + It should be presented as one long line without breaks. + It is OK for the line to extend past the end of the window and not be all visible. + If the line is broken up so you see multiple lines the test FAILS. + + If all behaves as expected, the test PASSES. + """; + + static JFrame createUI() { + + JFrame frame = new JFrame("bug4198022"); + JEditorPane ep = new JEditorPane(); + HTMLEditorKit ek = new HTMLEditorKit(); + ep.setEditorKit(ek); + ep.setText( + "Testing subscript and superscript.
" + + "
This text is intended to be presented as a single line without " + + "any word wrapping, regardless of whether it fits the viewable area of " + + "the editor pane or not."); + + ep.setEditable(false); + + frame.add(ep); + frame.setSize(500, 300); + return frame; + } + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(bug4198022::createUI) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/javax/swing/text/html/HTMLEditorKit/bug4245401.java b/test/jdk/javax/swing/text/html/HTMLEditorKit/bug4245401.java new file mode 100644 index 0000000000000..1f9bc7da914e7 --- /dev/null +++ b/test/jdk/javax/swing/text/html/HTMLEditorKit/bug4245401.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4245401 + * @summary Tests that JTextPane with HTMLEditorKit handles the HEAD tag properly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4245401 + */ + +import java.io.StringReader; +import javax.swing.JFrame; +import javax.swing.JTextPane; +import javax.swing.text.html.HTMLDocument; +import javax.swing.text.html.HTMLEditorKit; + +public class bug4245401 { + + static final String INSTRUCTIONS = """ + Place the cursor before the "H" in the word "HTML" + Then press and . + If an extra HEAD tag appear, the test FAILS, otherwise it PASSES. + """; + + static JFrame createUI() { + + JFrame frame = new JFrame("bug4245401"); + JTextPane ep = new JTextPane(); + ep.setEditable(true); + ep.setContentType("text/html"); + HTMLEditorKit kit = (HTMLEditorKit) ep.getEditorKit(); + ep.setEditorKit(kit); + HTMLDocument doc = (HTMLDocument) kit.createDefaultDocument(); + ep.setDocument(doc); + + try { + String text = "HTML Test... Test is a test..."; + kit.read(new StringReader(text), doc, 0); + } catch (Exception e) { + throw new RuntimeException(e); + } + + frame.add(ep); + frame.setSize(300, 300); + return frame; + } + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4245401::createUI) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/javax/swing/text/html/StyleSheet/bug4619595.java b/test/jdk/javax/swing/text/html/StyleSheet/bug4619595.java new file mode 100644 index 0000000000000..2d99d867cddd3 --- /dev/null +++ b/test/jdk/javax/swing/text/html/StyleSheet/bug4619595.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4619595 + * @summary Tests that embedded list items do not inherit the 'value' + * property from their parent list item + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4619595 + */ + +import javax.swing.JEditorPane; +import javax.swing.JFrame; + +public class bug4619595 { + + static final String INSTRUCTIONS = """ + The test window contains numbered lists. + Look at the three indented/embedded list items (the ones that are bold). + If they are not numbered 1, 2 and 3, then press FAIL. + + Below the lists there should also be a line saying: "The quick brown fox". + If you don't see this, press FAIL. + + If all is as expected, PASS the test. + """; + + final static String HTML = "" + + "

  1. Let's start
  2. Look @ inner list" + + "
    1. Inner list starts
    2. Second inner item" + + "
    3. Inner list ends
    " + + "
  3. That's all
" + + "

The quick brown fox

" + + " "; + + static JFrame createUI() { + + JFrame frame = new JFrame("bug4619595"); + JEditorPane pane = new JEditorPane(); + pane.setContentType("text/html"); + pane.setText(HTML); + frame.add(pane); + frame.setSize(400, 400); + return frame; + } + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4619595::createUI) + .build() + .awaitAndCheck(); + } +} From 9fcb06f9340f4f8f5bf2b74d0c4007f237625a72 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 4 Apr 2025 18:19:05 +0000 Subject: [PATCH 0404/1101] 8352997: Open source several Swing JTabbedPane tests Reviewed-by: azvegint, serb, honkar --- .../swing/JTabbedPane/4287208/bug4287208.java | 90 ++++++++++++++ .../javax/swing/JTabbedPane/4287208/duke.gif | Bin 0 -> 1617 bytes .../javax/swing/JTabbedPane/bug4273320.java | 90 ++++++++++++++ .../javax/swing/JTabbedPane/bug4287268.java | 102 ++++++++++++++++ .../javax/swing/JTabbedPane/bug4362226.java | 76 ++++++++++++ .../javax/swing/JTabbedPane/bug4668865.java | 112 ++++++++++++++++++ 6 files changed, 470 insertions(+) create mode 100644 test/jdk/javax/swing/JTabbedPane/4287208/bug4287208.java create mode 100644 test/jdk/javax/swing/JTabbedPane/4287208/duke.gif create mode 100644 test/jdk/javax/swing/JTabbedPane/bug4273320.java create mode 100644 test/jdk/javax/swing/JTabbedPane/bug4287268.java create mode 100644 test/jdk/javax/swing/JTabbedPane/bug4362226.java create mode 100644 test/jdk/javax/swing/JTabbedPane/bug4668865.java diff --git a/test/jdk/javax/swing/JTabbedPane/4287208/bug4287208.java b/test/jdk/javax/swing/JTabbedPane/4287208/bug4287208.java new file mode 100644 index 0000000000000..d7dfe01cff0e3 --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/4287208/bug4287208.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4287208 + * @summary Tests if JTabbedPane's setEnabledAt properly renders bounds of Tabs + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4287208 +*/ + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; + +public class bug4287208 implements ActionListener { + + static final String INSTRUCTIONS = """ + There are two tabs in the test window. Press the "Test" button 5 times. + If this causes tabs to overlap at any time, the test FAILS, otherwise + the test PASSES. + """; + + static boolean state = true; + static JTabbedPane jtp; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4287208 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4287208::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("bug4287208"); + + JButton start = new JButton("Test"); + start.addActionListener(new bug4287208()); + JPanel buttonPanel = new JPanel(); + buttonPanel.add(start); + frame.add(buttonPanel,BorderLayout.SOUTH); + + jtp = new JTabbedPane(); + jtp.addTab("Panel One", new JPanel()); + String s = System.getProperty("test.src",".") + + System.getProperty("file.separator") + "duke.gif"; + ImageIcon ii = new ImageIcon(s); + jtp.addTab("Panel Two", ii, new JPanel()); + + frame.add(jtp, BorderLayout.CENTER); + frame.setSize(500, 300); + return frame; + } + + public void actionPerformed(ActionEvent evt) { + jtp.setEnabledAt(0, state); + jtp.setEnabledAt(1, !state); + state = !state; + } + +} diff --git a/test/jdk/javax/swing/JTabbedPane/4287208/duke.gif b/test/jdk/javax/swing/JTabbedPane/4287208/duke.gif new file mode 100644 index 0000000000000000000000000000000000000000..a02a42fd606741170756cd1a33b48f609692b7f3 GIT binary patch literal 1617 zcmdUu>r)d~7>7?Fz!CwMYgeQ;%S983OoA0jYb}I;F*qYe>gWm@T%>g3RCKjoq7KRm zM%Eift#q|OSSYr!$gu6$c56UMLG9L#8nqu%I@$)QHZs#T)mG92^`GeZupi#DGw<(t zesdNrF3Qzb+|{iet#ekaB`fLq7VR30B``502l!<0YCsi0$>4v z0w56Zi=rFH;ZBrua!%eUxCJ|FXE~O#QWnZWT1XRNB1l4K)M<5EjaGvzaSX>$3`I}` zAOOWN+Ro@qM#4hASR4$xVVKD%ydZFs`Ceq@IGSN#dVeqoF|0HVd3d)QvT-~Q@gOIp zrR{cz2gxBnv|xgBf`CS}Mk7=M1wl;!LF^n%E3%vu!l#;`FHMPG z?#i1zZ+BI~>B`jRW@-KNkGfoGODjrd=HwGMrw&b5g{qHXomJO?tmeuF^H}k>3*)YB zFTWO-F`!s8pf4MG&uKrn=#F>C%FjDe^|e`^^5JejSeX8Ic$Hz>W63GWvxRFE9iOTt z^Uam%@+*I&0R4Ker|vmV3|zYkp1Z0*}z_~j|*(Jg4sVWnaCWb?($o}?o8 zA>|K)?>J&gdgZT(vVT(sXO1(Auo~WBZa7 zXU$FP4jPC5bmYI8pnfYtzRP@neXF|1cDOjX@8-0nNw3z&fsz_SGKqym&N{NI$(B-_ zb+59fLY96#Rw@2uNN?QIW}BIOWm;!=u4;vEV-j+1qz$O>QX=)WtLEmMCl%fO?g`?6Yl_mH8eUMfY% z{RPHHdHJl#+*dKx^x5-|H3iGI$W95w%?xmnj@s(^?w0mt51Fa literal 0 HcmV?d00001 diff --git a/test/jdk/javax/swing/JTabbedPane/bug4273320.java b/test/jdk/javax/swing/JTabbedPane/bug4273320.java new file mode 100644 index 0000000000000..d1bcca743b5ec --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/bug4273320.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4273320 + * @summary JTabbedPane.setTitleAt() should refresh when using HTML text + * @key headful +*/ + +import java.awt.BorderLayout; +import java.awt.Rectangle; +import java.awt.Robot; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; +import javax.swing.plaf.TabbedPaneUI; + +public class bug4273320 { + + static JFrame frame; + static volatile JTabbedPane tabs; + + static final String PLAIN = "Plain"; + static final String HTML = "A fairly long HTML text label"; + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(bug4273320::createUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(1000); + + TabbedPaneUI ui = tabs.getUI(); + Rectangle origSize = ui.getTabBounds(tabs, 0); + + SwingUtilities.invokeAndWait(() -> { + tabs.setTitleAt(0, HTML); + }); + robot.waitForIdle(); + robot.delay(1000); + + Rectangle newSize = ui.getTabBounds(tabs, 0); + // The tab should be resized larger if the longer HTML text is added + System.out.println("orig = " + origSize.width + " x " + origSize.height); + System.out.println("new = " + newSize.width + " x " + newSize.height); + if (origSize.width >= newSize.width) { + throw new RuntimeException("Tab text is not updated."); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + static void createUI() { + frame = new JFrame("bug4273320"); + tabs = new JTabbedPane(); + JPanel panel = new JPanel(); + tabs.addTab(PLAIN, panel); + frame.getContentPane().add(tabs, BorderLayout.CENTER); + frame.setSize(500, 300); + frame.setVisible(true); + } +} diff --git a/test/jdk/javax/swing/JTabbedPane/bug4287268.java b/test/jdk/javax/swing/JTabbedPane/bug4287268.java new file mode 100644 index 0000000000000..8f7156b93e056 --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/bug4287268.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4287268 + * @summary Tests if setIconAt(index,Icon) does not set Tab's disabled icon + * @key headful +*/ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; + +public class bug4287268 { + + static JFrame frame; + static volatile JTabbedPane jtp; + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(bug4287268::createUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(1000); + + Point point = jtp.getLocationOnScreen(); + int width = jtp.getWidth(); + int height = jtp.getHeight(); + Rectangle r = new Rectangle(point.x, point.y, width, height); + BufferedImage cap = robot.createScreenCapture(r); + + int red = Color.red.getRGB(); + for (int x = 0; x < cap.getWidth(); x++) { + for (int y = 0; y < cap.getHeight(); y++) { + int rgb = cap.getRGB(x, y); + if (rgb == red) { + try { + javax.imageio.ImageIO.write(cap, "png", new java.io.File("cap.png")); + } catch (Exception ee) { + } + throw new RuntimeException("Test failed : found red"); + } + } + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + static void createUI() { + frame = new JFrame("bug4287268"); + jtp = new JTabbedPane(); + JPanel panel = new JPanel(); + jtp.add("Panel One", panel); + int size = 64; + BufferedImage img = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB); + Graphics g = img.createGraphics(); + g.setColor(Color.red); + g.fillRect(0, 0, size, size); + ImageIcon ii = new ImageIcon(img); + jtp.setIconAt(0, ii); + jtp.setEnabledAt(0, false); + frame.getContentPane().add(jtp, BorderLayout.CENTER); + frame.pack(); + frame.setVisible(true); + } +} diff --git a/test/jdk/javax/swing/JTabbedPane/bug4362226.java b/test/jdk/javax/swing/JTabbedPane/bug4362226.java new file mode 100644 index 0000000000000..5339de29119ae --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/bug4362226.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4362226 + * @summary JTabbedPane's HTML title should have proper offsets + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4362226 +*/ + +import java.awt.BorderLayout; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.UIManager; +import javax.swing.plaf.metal.MetalLookAndFeel; + +public class bug4362226 { + + static final String PLAIN = "Label"; + static final String HTML = "Label"; + + static final String INSTRUCTIONS = """ + The test window contains a JTabbedPane with two tabs. + The titles for both tabs should look similar and drawn with the same fonts. + The text of the tabs should start in a position that is offset from the left + boundary of the tab, so there is clear space between them. + If there is no space, then the test FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4362226 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(bug4362226::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + try { + UIManager.setLookAndFeel(new MetalLookAndFeel()); + } catch (Exception e) { + } + JFrame frame = new JFrame("bug4362226"); + JTabbedPane tabs = new JTabbedPane(); + tabs.addTab(PLAIN, new JPanel()); + tabs.addTab(HTML, new JPanel()); + frame.add(tabs, BorderLayout.CENTER); + frame.setSize(500, 300); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTabbedPane/bug4668865.java b/test/jdk/javax/swing/JTabbedPane/bug4668865.java new file mode 100644 index 0000000000000..711ef12f68277 --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/bug4668865.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4668865 + * @summary Tests if JTabbedPane's setEnabledAt properly renders bounds of Tabs + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4668865 +*/ + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JTabbedPane; +import javax.swing.JTextField; + +public class bug4668865 { + + static final String INSTRUCTIONS = """ + This tests that tooltips are shown for all tabs in all orientations, + when it is necessary to scroll to see all the tabs. + Use the buttons to select each orientation (top/bottom/left/right) in turn. + Scroll through the 8 tabs - using the navigation arrows as needed. + Move the mouse over each tab in turn and verify that the matching tooltip is shown + after sufficient hover time. + The test PASSES if the tooltips are shown for all cases, and FAILS otherwise. + """; + + static JTabbedPane tabPane; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4668865 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4668865::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("bug4668865"); + + tabPane = new JTabbedPane(JTabbedPane.TOP, JTabbedPane.SCROLL_TAB_LAYOUT); + for(int i = 1; i < 9; i++) { + tabPane.addTab("Tab" + i, null, new JTextField("Tab" + i), "Tab" + i); + } + frame.add(tabPane, BorderLayout.CENTER); + + JButton top = new JButton(new AbstractAction() { + public void actionPerformed(ActionEvent e) { + tabPane.setTabPlacement(JTabbedPane.TOP); + } + }); + top.setText("Top"); + frame.add(top, BorderLayout.NORTH); + + JButton bottom = new JButton(new AbstractAction() { + public void actionPerformed(ActionEvent e) { + tabPane.setTabPlacement(JTabbedPane.BOTTOM); + } + }); + bottom.setText("Bottom"); + frame.add(bottom, BorderLayout.SOUTH); + + JButton left = new JButton(new AbstractAction() { + public void actionPerformed(ActionEvent e) { + tabPane.setTabPlacement(JTabbedPane.LEFT); + } + }); + + left.setText("Left"); + frame.add(left, BorderLayout.WEST); + + JButton right = new JButton(new AbstractAction() { + public void actionPerformed(ActionEvent e) { + tabPane.setTabPlacement(JTabbedPane.RIGHT); + } + }); + + right.setText("Right"); + frame.add(right, BorderLayout.EAST); + + frame.setSize(400, 400); + return frame; + } + +} From e17c3994b8392357b0aacea0bae6b354a2cc90a5 Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Fri, 4 Apr 2025 22:41:59 +0000 Subject: [PATCH 0405/1101] 8353201: Open source Swing Tooltip tests - Set 2 Reviewed-by: dnguyen, prr, azvegint --- .../swing/ToolTipManager/bug4250178.java | 66 ++++++++ .../swing/ToolTipManager/bug4294808.java | 64 ++++++++ .../swing/ToolTipManager/bug6178004.java | 152 ++++++++++++++++++ 3 files changed, 282 insertions(+) create mode 100644 test/jdk/javax/swing/ToolTipManager/bug4250178.java create mode 100644 test/jdk/javax/swing/ToolTipManager/bug4294808.java create mode 100644 test/jdk/javax/swing/ToolTipManager/bug6178004.java diff --git a/test/jdk/javax/swing/ToolTipManager/bug4250178.java b/test/jdk/javax/swing/ToolTipManager/bug4250178.java new file mode 100644 index 0000000000000..18a9c4d93e2cf --- /dev/null +++ b/test/jdk/javax/swing/ToolTipManager/bug4250178.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4250178 + * @summary Tooltip in incorrect location on ToolBar + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4250178 + */ + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.ToolTipManager; + +public class bug4250178 { + private static final String INSTRUCTIONS = """ + Click somewhere in the test UI frame to make it focused. + Move mouse to the bottom right corner of the button in this frame + and wait until tooltip appears. + + If the tooltip fits into the frame OR partially covered by the mouse + cursor then test fails. Otherwise test passes. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(bug4250178::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createAndShowUI() { + JFrame fr = new JFrame("bug4250178"); + JButton button = new JButton("Button"); + button.setToolTipText("ToolTip"); + ToolTipManager.sharedInstance().setLightWeightPopupEnabled(true); + fr.add(button); + fr.setSize(250, 100); + return fr; + } +} diff --git a/test/jdk/javax/swing/ToolTipManager/bug4294808.java b/test/jdk/javax/swing/ToolTipManager/bug4294808.java new file mode 100644 index 0000000000000..d4ec109020a29 --- /dev/null +++ b/test/jdk/javax/swing/ToolTipManager/bug4294808.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4294808 + * @summary Tooltip blinking. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4294808 + */ + +import java.awt.Dimension; +import javax.swing.JButton; +import javax.swing.JComponent; + +public class bug4294808 { + private static final String INSTRUCTIONS = """ + Move mouse cursor to the button named "Tooltip Button" + at the bottom of the instruction window and wait until + tooltip has appeared. + + If tooltip appears and eventually disappears without + rapid blinking then press PASS else FAIL. + """; + + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4294808 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .splitUIBottom(bug4294808::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static JComponent createAndShowUI() { + JButton bt = new JButton("Tooltip Button"); + bt.setToolTipText("Long tooltip text here"); + bt.setPreferredSize(new Dimension(200, 60)); + return bt; + } +} diff --git a/test/jdk/javax/swing/ToolTipManager/bug6178004.java b/test/jdk/javax/swing/ToolTipManager/bug6178004.java new file mode 100644 index 0000000000000..e33a6391e8959 --- /dev/null +++ b/test/jdk/javax/swing/ToolTipManager/bug6178004.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4148057 6178004 + * @summary REGRESSION: setToolTipText does not work if the + * component is not focused + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug6178004 + */ + +import java.awt.Point; +import java.awt.Window; +import java.awt.event.MouseEvent; +import java.util.List; +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; +import javax.swing.ToolTipManager; +import javax.swing.UIManager; + +public class bug6178004 { + private static JFrame frame1; + private static JFrame frame2; + private static final int SIZE = 300; + + private static final String INSTRUCTIONS = """ + You can change Look And Feel using the menu "Change LaF". + + Make sure that Frame2 or instruction window is active. + Move mouse over the button inside "Frame 1". + If tooltip is NOT shown or Frame 1 jumped on top of + the Frame2, press FAIL. + + For Metal/Windows LaF: + Tooltips are shown only if one of the frames (or the instruction + window) is active. To test it click on any other application to + make frames and instruction window inactive and then verify that + tooltips are not shown any more. + + For Motif/GTK/Nimbus/Aqua LaF: + Tooltips should be shown for all frames irrespective of whether + the application is active or inactive. + + Note: Tooltip for Frame1 is always shown at the top-left corner. + Tooltips could be shown partly covered by another frame. + + If above is true press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug6178004 Test Instructions") + .instructions(INSTRUCTIONS) + .testTimeOut(10) + .columns(40) + .testUI(createAndShowUI()) + .positionTestUI(bug6178004::positionTestWindows) + .build() + .awaitAndCheck(); + } + + private static List createAndShowUI() { + ToolTipManager.sharedInstance().setInitialDelay(0); + + frame1 = new JFrame("bug6178004 Frame1"); + frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + JButton button = new JButton("Test") { + public Point getToolTipLocation(MouseEvent event) { + return new Point(10, 10); + } + }; + button.setToolTipText("Tooltip-1"); + frame1.add(button); + frame1.setSize(SIZE, SIZE); + + frame2 = new JFrame("bug6178004 Frame2"); + frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + JButton button2 = new JButton("Click me") ; + button2.setToolTipText("Tooltip-2"); + frame2.add(button2); + frame2.setSize(SIZE, SIZE); + + JMenuBar bar = new JMenuBar(); + JMenu lafMenu = new JMenu("Change LaF"); + ButtonGroup lafGroup = new ButtonGroup(); + + LookAndFeel currentLaf = UIManager.getLookAndFeel(); + UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels(); + for (final UIManager.LookAndFeelInfo lafInfo : lafs) { + JCheckBoxMenuItem lafItem = new JCheckBoxMenuItem(lafInfo.getName()); + lafItem.addActionListener(e -> setLaF(lafInfo.getClassName())); + if (lafInfo.getClassName().equals(currentLaf.getClass().getName())) { + lafItem.setSelected(true); + } + + lafGroup.add(lafItem); + lafMenu.add(lafItem); + } + + bar.add(lafMenu); + frame2.setJMenuBar(bar); + return List.of(frame1, frame2); + } + + private static void setLaF(String laf) { + try { + UIManager.setLookAndFeel(laf); + SwingUtilities.updateComponentTreeUI(frame1); + SwingUtilities.updateComponentTreeUI(frame2); + } catch (Exception e) { + e.printStackTrace(); + } + } + + // custom window layout required for this test + private static void positionTestWindows(List testWindows, + PassFailJFrame.InstructionUI instructionUI) { + int gap = 5; + int x = instructionUI.getLocation().x + instructionUI.getSize().width + gap; + // the two test frames need to overlap for this test + testWindows.get(0).setLocation(x, instructionUI.getLocation().y); + testWindows.get(1).setLocation((x + SIZE / 2), instructionUI.getLocation().y); + } +} From 9bb804b14e164982860db6323c7db33214cd0d36 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Sat, 5 Apr 2025 01:12:48 +0000 Subject: [PATCH 0406/1101] 8338554: Fix inconsistencies in javadoc/doclet/testLinkOption/TestRedirectLinks.java Reviewed-by: liach, nbenalla --- .../testLinkOption/TestRedirectLinks.java | 111 ++++++------------ 1 file changed, 38 insertions(+), 73 deletions(-) diff --git a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java index ec7e63115a67c..a6a04c808346e 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,40 +25,36 @@ * @test * @bug 8190312 * @summary test redirected URLs for -link - * @library /tools/lib ../../lib - * @library /test/lib + * @library /tools/lib ../../lib /test/lib * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main * jdk.javadoc/jdk.javadoc.internal.api * jdk.javadoc/jdk.javadoc.internal.tool * @build toolbox.ToolBox toolbox.JavacTask javadoc.tester.* * @build jtreg.SkippedException - * @build jdk.test.lib.Platform + * @build jdk.test.lib.Platform jdk.test.lib.net.SimpleSSLContext jdk.test.lib.net.URIBuilder * @run main TestRedirectLinks */ import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; import java.net.UnknownHostException; import java.nio.file.Files; import java.nio.file.Path; -import java.security.KeyStore; import java.time.Duration; import java.time.Instant; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManagerFactory; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpServer; @@ -66,6 +62,8 @@ import com.sun.net.httpserver.HttpsServer; import javadoc.tester.JavadocTester; +import jdk.test.lib.net.SimpleSSLContext; +import jdk.test.lib.net.URIBuilder; import toolbox.JavacTask; import toolbox.ToolBox; @@ -73,6 +71,9 @@ import jtreg.SkippedException; public class TestRedirectLinks extends JavadocTester { + // represents the HTTP response body length when the response contains no body + private static final int NO_RESPONSE_BODY = -1; + /** * The entry point of the test. * @param args the array of command line arguments. @@ -206,17 +207,28 @@ public void testWithServers() throws Exception { // start web servers // use loopback address to avoid any issues if proxy is in use - InetAddress localHost = InetAddress.getLoopbackAddress(); + InetAddress loopback = InetAddress.getLoopbackAddress(); try { - oldServer = HttpServer.create(new InetSocketAddress(localHost, 0), 0); - String oldURL = "http:/" + oldServer.getAddress(); + oldServer = HttpServer.create(new InetSocketAddress(loopback, 0), 0); + String oldURL = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(oldServer.getAddress().getPort()) + .build().toString(); oldServer.createContext("/", this::handleOldRequest); out.println("Starting old server (" + oldServer.getClass().getSimpleName() + ") on " + oldURL); oldServer.start(); SSLContext sslContext = new SimpleSSLContext().get(); - newServer = HttpsServer.create(new InetSocketAddress(localHost, 0), 0); - String newURL = "https:/" + newServer.getAddress(); + if (sslContext == null) { + throw new AssertionError("Could not create a SSLContext"); + } + newServer = HttpsServer.create(new InetSocketAddress(loopback, 0), 0); + String newURL = URIBuilder.newBuilder() + .scheme("https") + .loopback() + .port(newServer.getAddress().getPort()) + .build().toString(); newServer.setHttpsConfigurator(new HttpsConfigurator(sslContext)); newServer.createContext("/", this::handleNewRequest); out.println("Starting new server (" + newServer.getClass().getSimpleName() + ") on " + newURL); @@ -240,7 +252,7 @@ public void testWithServers() throws Exception { javadoc("-d", "api", "--module-source-path", src.toString(), "--module-path", libModules.toString(), - "-link", "http:/" + oldServer.getAddress(), + "-link", oldURL, "--module", "mC", "-Xdoclint:none"); @@ -281,10 +293,19 @@ private void handleOldRequest(HttpExchange x) throws IOException { + x.getRequestMethod() + " " + x.getRequestURI()); String newProtocol = (newServer instanceof HttpsServer) ? "https" : "http"; - String redirectTo = newProtocol + ":/" + newServer.getAddress() + x.getRequestURI(); + String redirectTo; + try { + redirectTo = URIBuilder.newBuilder().scheme(newProtocol) + .host(newServer.getAddress().getAddress()) + .port(newServer.getAddress().getPort()) + .path(x.getRequestURI().getPath()) + .build().toString(); + } catch (URISyntaxException e) { + throw new IOException(e); + } out.println(" redirect to: " + redirectTo); x.getResponseHeaders().add("Location", redirectTo); - x.sendResponseHeaders(HttpURLConnection.HTTP_MOVED_PERM, 0); + x.sendResponseHeaders(HttpURLConnection.HTTP_MOVED_PERM, NO_RESPONSE_BODY); x.getResponseBody().close(); } @@ -305,64 +326,8 @@ private void handleNewRequest(HttpExchange x) throws IOException { responseStream.write(bytes); } } else { - x.sendResponseHeaders(HttpURLConnection.HTTP_NOT_FOUND, 0); + x.sendResponseHeaders(HttpURLConnection.HTTP_NOT_FOUND, NO_RESPONSE_BODY); x.getResponseBody().close(); } } - - /** - * Creates a simple usable SSLContext for an HttpsServer using - * a default keystore in the test tree. - *

- * This class is based on - * test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SimpleSSLContext.java - */ - static class SimpleSSLContext { - - private final SSLContext ssl; - - /** - * Loads default keystore. - */ - SimpleSSLContext() throws Exception { - Path p = Path.of(System.getProperty("test.src", ".")).toAbsolutePath(); - while (!Files.exists(p.resolve("TEST.ROOT"))) { - p = p.getParent(); - if (p == null) { - throw new IOException("can't find TEST.ROOT"); - } - } - - System.err.println("Test suite root: " + p); - Path testKeys = p.resolve("../lib/jdk/test/lib/net/testkeys").normalize(); - if (!Files.exists(testKeys)) { - throw new IOException("can't find testkeys"); - } - System.err.println("Test keys: " + testKeys); - - try (InputStream fis = Files.newInputStream(testKeys)) { - ssl = init(fis); - } - } - - private SSLContext init(InputStream i) throws Exception { - char[] passphrase = "passphrase".toCharArray(); - KeyStore ks = KeyStore.getInstance("PKCS12"); - ks.load(i, passphrase); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); - tmf.init(ks); - - SSLContext ssl = SSLContext.getInstance("TLS"); - ssl.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - return ssl; - } - - SSLContext get() { - return ssl; - } - } } From 6d37e633e6afa11ecd40bed10c0efbde6f9f6181 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Sat, 5 Apr 2025 20:25:30 +0000 Subject: [PATCH 0407/1101] 8353753: Remove unnecessary forward declaration in oop.hpp Reviewed-by: kbarrett --- src/hotspot/share/oops/oop.hpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index f52baab0de640..8048c8770c2ba 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,11 +44,6 @@ // // no virtual functions allowed -// Forward declarations. -class OopClosure; -class PSPromotionManager; -class ParCompactionManager; - class oopDesc { friend class VMStructs; friend class JVMCIVMStructs; From 660b17a6b9afe26dee2d9647755c75d817888eda Mon Sep 17 00:00:00 2001 From: Evgeny Astigeevich Date: Sun, 6 Apr 2025 17:38:28 +0000 Subject: [PATCH 0408/1101] 8350852: Implement JMH benchmark for sparse CodeCache Reviewed-by: kvn --- .../bench/vm/compiler/SparseCodeCache.java | 368 ++++++++++++++++++ 1 file changed, 368 insertions(+) create mode 100644 test/micro/org/openjdk/bench/vm/compiler/SparseCodeCache.java diff --git a/test/micro/org/openjdk/bench/vm/compiler/SparseCodeCache.java b/test/micro/org/openjdk/bench/vm/compiler/SparseCodeCache.java new file mode 100644 index 0000000000000..473ce100e0a60 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/SparseCodeCache.java @@ -0,0 +1,368 @@ +/* + * 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. + * + */ + +package org.openjdk.bench.vm.compiler; + +import java.lang.reflect.Method; +import java.util.Random; + +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.CompilerControl; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import org.openjdk.bench.util.InMemoryJavaCompiler; + +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.NMethod; + +/* + * This benchmark is used to check performance when the code cache is sparse. + * + * We use C2 compiler to compile the same Java method multiple times + * to produce as many code as needed. + * These compiled methods represent the active methods in the code cache. + * We split active methods into groups. + * We put a group into a fixed size code region. + * We make a code region size aligned. + * CodeCache becomes sparse when code regions are not fully filled. + * + * The benchmark parameters are active method count, group count, and code region size. + */ + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@State(Scope.Benchmark) +@Fork(value = 3, jvmArgs = { + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+WhiteBoxAPI", + "-Xbootclasspath/a:lib-test/wb.jar", + "-XX:CompileCommand=dontinline,A::sum", + "-XX:-UseCodeCacheFlushing", + "-XX:-TieredCompilation", + "-XX:+SegmentedCodeCache", + "-XX:ReservedCodeCacheSize=512m", + "-XX:InitialCodeCacheSize=512m", + "-XX:+UseSerialGC", + "-XX:+PrintCodeCache" +}) +public class SparseCodeCache { + + private static final int C2_LEVEL = 4; + private static final int DUMMY_BLOB_SIZE = 1024 * 1024; + private static final int DUMMY_BLOB_COUNT = 128; + + static byte[] num1; + static byte[] num2; + + @State(Scope.Thread) + public static class ThreadState { + byte[] result; + + @Setup + public void setup() { + result = new byte[num1.length + 1]; + } + } + + private static Object WB; + + @Param({"256", "512", "1024"}) + public int activeMethodCount; + + @Param({"1", "32", "64", "128"}) + public int groupCount; + + @Param({"2097152"}) + public int codeRegionSize; + + private TestMethod[] methods = {}; + + private static byte[] genNum(Random random, int digitCount) { + byte[] num = new byte[digitCount]; + int d; + do { + d = random.nextInt(10); + } while (d == 0); + + num[0] = (byte)d; + for (int i = 1; i < digitCount; ++i) { + num[i] = (byte)random.nextInt(10); + } + return num; + } + + private static void initWhiteBox() { + WB = WhiteBox.getWhiteBox(); + } + + private static void initNums() { + final long seed = 8374592837465123L; + Random random = new Random(seed); + + final int digitCount = 40; + num1 = genNum(random, digitCount); + num2 = genNum(random, digitCount); + } + + private static WhiteBox getWhiteBox() { + return (WhiteBox)WB; + } + + private static final class TestMethod { + private static final String CLASS_NAME = "A"; + private static final String METHOD_TO_COMPILE = "sum"; + private static final String JAVA_CODE = """ + public class A { + + public static void sum(byte[] n1, byte[] n2, byte[] out) { + final int digitCount = n1.length; + int carry = 0; + for (int i = digitCount - 1; i >= 0; --i) { + int sum = n1[i] + n2[i] + carry; + out[i] = (byte)(sum % 10); + carry = sum / 10; + } + if (carry != 0) { + for (int i = digitCount; i > 0; --i) { + out[i] = out[i - 1]; + } + out[0] = (byte)carry; + } + } + }"""; + + private static final byte[] BYTE_CODE; + + static { + BYTE_CODE = InMemoryJavaCompiler.compile(CLASS_NAME, JAVA_CODE); + } + + private final Method method; + + private static ClassLoader createClassLoaderFor() { + return new ClassLoader() { + @Override + public Class loadClass(String name) throws ClassNotFoundException { + if (!name.equals(CLASS_NAME)) { + return super.loadClass(name); + } + + return defineClass(name, BYTE_CODE, 0, BYTE_CODE.length); + } + }; + } + + public TestMethod() throws Exception { + var cl = createClassLoaderFor().loadClass(CLASS_NAME); + method = cl.getMethod(METHOD_TO_COMPILE, byte[].class, byte[].class, byte[].class); + getWhiteBox().testSetDontInlineMethod(method, true); + } + + public void profile(byte[] num1, byte[] num2, byte[] result) throws Exception { + method.invoke(null, num1, num2, result); + getWhiteBox().markMethodProfiled(method); + } + + public void invoke(byte[] num1, byte[] num2, byte[] result) throws Exception { + method.invoke(null, num1, num2, result); + } + + public void compileWithC2() throws Exception { + getWhiteBox().enqueueMethodForCompilation(method, C2_LEVEL); + while (getWhiteBox().isMethodQueuedForCompilation(method)) { + Thread.onSpinWait(); + } + if (getWhiteBox().getMethodCompilationLevel(method) != C2_LEVEL) { + throw new IllegalStateException("Method " + method + " is not compiled by C2."); + } + } + + public NMethod getNMethod() { + return NMethod.get(method, false); + } + } + + private void generateOneGroupCode() throws Exception { + byte[] result = new byte[num1.length + 1]; + + methods = new TestMethod[activeMethodCount]; + for (int i = 0; i < activeMethodCount; ++i) { + methods[i] = new TestMethod(); + methods[i].profile(num1, num2, result); + methods[i].compileWithC2(); + } + allocateDummyBlobs(DUMMY_BLOB_COUNT, DUMMY_BLOB_SIZE, methods[activeMethodCount - 1].getNMethod().code_blob_type.id); + compileCallMethods(); + } + + private void allocateDummyBlobs(int count, int size, int codeBlobType) { + getWhiteBox().lockCompilation(); + for (int i = 0; i < count; i++) { + var dummyBlob = getWhiteBox().allocateCodeBlob(size, codeBlobType); + if (dummyBlob == 0) { + throw new IllegalStateException("Failed to allocate dummy blob."); + } + } + getWhiteBox().unlockCompilation(); + } + + private void generateCode() throws Exception { + initNums(); + + if (groupCount == 1) { + generateOneGroupCode(); + return; + } + + final int defaultMethodsPerGroup = activeMethodCount / groupCount; + if (defaultMethodsPerGroup == 0) { + throw new IllegalArgumentException("activeMethodCount = " + activeMethodCount + + ", groupCount = " + groupCount + + ". 'activeMethodCount' must be greater than or equal to 'groupCount'."); + } + + if ((codeRegionSize & (codeRegionSize - 1)) != 0) { + throw new IllegalArgumentException("codeRegionSize = " + codeRegionSize + + ". 'codeRegionSize' must be a power of 2."); + } + + byte[] result = new byte[num1.length + 1]; + methods = new TestMethod[activeMethodCount]; + methods[0] = new TestMethod(); + methods[0].profile(num1, num2, result); + methods[0].compileWithC2(); + final var nmethod = methods[0].getNMethod(); + if (nmethod.size * defaultMethodsPerGroup > codeRegionSize) { + throw new IllegalArgumentException("codeRegionSize = " + codeRegionSize + + ", methodsPerRegion = " + defaultMethodsPerGroup + + ", nmethod size = " + nmethod.size + + ". One code region does not have enough space to hold " + defaultMethodsPerGroup + " nmethods."); + } + + final var codeHeapSize = nmethod.code_blob_type.getSize(); + final var neededSpace = groupCount * codeRegionSize; + if (neededSpace > codeHeapSize) { + throw new IllegalArgumentException(nmethod.code_blob_type.sizeOptionName + " = " + codeHeapSize + + ". Not enough space to hold " + groupCount + " groups " + + "of code region size " + codeRegionSize + "."); + } + + int j = 1; + for (; j < defaultMethodsPerGroup; ++j) { + methods[j] = new TestMethod(); + methods[j].profile(num1, num2, result); + methods[j].compileWithC2(); + } + + int methodsPerGroup = defaultMethodsPerGroup; + int remainingMethods = activeMethodCount % groupCount; + for (int i = 1; i < groupCount; ++i) { + getWhiteBox().lockCompilation(); + var firstNmethodInPrevGroup = methods[j - methodsPerGroup].getNMethod(); + var regionStart = firstNmethodInPrevGroup.address & ~(codeRegionSize - 1); + var regionEnd = regionStart + codeRegionSize; + var lastNmethodInPrevGroup = methods[j - 1].getNMethod(); + + // We have disabled code cache flushing. This should guarantee our just compiled + // not yet used code will not be flushed. + // Besides our test methods, we don't use a lot of Java methods in this benchmark. + // This should guarantee that most of code in the code cache is our test methods. + // If C2 occasionally compiles other methods, it should not affect test methods code placement much. + // We don't expect a lot of deoptimizations in this benchmark. So we don't expect + // CodeCache to be fragmented. + // We assume addresses of our compiled methods and dummy code blobs are in increasing order. + // Methods compiled during the same iteration are in the same code region. + if ((lastNmethodInPrevGroup.address + lastNmethodInPrevGroup.size) < regionEnd) { + var dummyBlob = getWhiteBox().allocateCodeBlob(regionEnd - lastNmethodInPrevGroup.address - lastNmethodInPrevGroup.size, + lastNmethodInPrevGroup.code_blob_type.id); + if (dummyBlob == 0) { + throw new IllegalStateException("Failed to allocate dummy blob."); + } + } + getWhiteBox().unlockCompilation(); + + methodsPerGroup = defaultMethodsPerGroup; + if (remainingMethods > 0) { + ++methodsPerGroup; + --remainingMethods; + } + + for (int k = 0; k < methodsPerGroup; ++k, ++j) { + methods[j] = new TestMethod(); + methods[j].profile(num1, num2, result); + methods[j].compileWithC2(); + } + } + + allocateDummyBlobs(DUMMY_BLOB_COUNT, DUMMY_BLOB_SIZE, methods[j - 1].getNMethod().code_blob_type.id); + compileCallMethods(); + } + + private void compileCallMethods() throws Exception { + var threadState = new ThreadState(); + threadState.setup(); + callMethods(threadState); + Method method = SparseCodeCache.class.getDeclaredMethod("callMethods", ThreadState.class); + getWhiteBox().markMethodProfiled(method); + getWhiteBox().enqueueMethodForCompilation(method, C2_LEVEL); + while (getWhiteBox().isMethodQueuedForCompilation(method)) { + Thread.onSpinWait(); + } + if (getWhiteBox().getMethodCompilationLevel(method) != C2_LEVEL) { + throw new IllegalStateException("Method SparseCodeCache::callMethods is not compiled by C2."); + } + getWhiteBox().testSetDontInlineMethod(method, true); + } + + @Setup(Level.Trial) + public void setupCodeCache() throws Exception { + initWhiteBox(); + generateCode(); + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + private void callMethods(ThreadState s) throws Exception { + for (var m : methods) { + m.invoke(num1, num2, s.result); + } + } + + @Benchmark + @Warmup(iterations = 2) + public void runMethodsWithReflection(ThreadState s) throws Exception { + callMethods(s); + } +} From 97ed536125645304aed03a4afbc3ded627de0bb0 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Mon, 7 Apr 2025 05:21:44 +0000 Subject: [PATCH 0409/1101] 8346989: C2: deoptimization and re-execution cycle with Math.*Exact in case of frequent overflow Reviewed-by: thartmann, vlivanov --- src/hotspot/share/opto/graphKit.cpp | 155 ++++--- src/hotspot/share/opto/graphKit.hpp | 10 + src/hotspot/share/opto/library_call.cpp | 18 +- src/hotspot/share/opto/library_call.hpp | 2 +- .../intrinsics/mathexact/OverflowTest.java | 274 ++++++++++++ .../openjdk/bench/vm/compiler/MathExact.java | 403 ++++++++++++++++++ 6 files changed, 786 insertions(+), 76 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/intrinsics/mathexact/OverflowTest.java create mode 100644 test/micro/org/openjdk/bench/vm/compiler/MathExact.java diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index e10a87171fc1c..df9177a493833 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -527,71 +527,29 @@ void GraphKit::uncommon_trap_if_should_post_on_exceptions(Deoptimization::DeoptR //------------------------------builtin_throw---------------------------------- void GraphKit::builtin_throw(Deoptimization::DeoptReason reason) { - bool must_throw = true; - - // If this particular condition has not yet happened at this - // bytecode, then use the uncommon trap mechanism, and allow for - // a future recompilation if several traps occur here. - // If the throw is hot, try to use a more complicated inline mechanism - // which keeps execution inside the compiled code. - bool treat_throw_as_hot = false; - ciMethodData* md = method()->method_data(); - - if (ProfileTraps) { - if (too_many_traps(reason)) { - treat_throw_as_hot = true; - } - // (If there is no MDO at all, assume it is early in - // execution, and that any deopts are part of the - // startup transient, and don't need to be remembered.) - - // Also, if there is a local exception handler, treat all throws - // as hot if there has been at least one in this method. - if (C->trap_count(reason) != 0 - && method()->method_data()->trap_count(reason) != 0 - && has_exception_handler()) { - treat_throw_as_hot = true; - } - } + builtin_throw(reason, builtin_throw_exception(reason), /*allow_too_many_traps*/ true); +} +void GraphKit::builtin_throw(Deoptimization::DeoptReason reason, + ciInstance* ex_obj, + bool allow_too_many_traps) { // If this throw happens frequently, an uncommon trap might cause // a performance pothole. If there is a local exception handler, // and if this particular bytecode appears to be deoptimizing often, // let us handle the throw inline, with a preconstructed instance. // Note: If the deopt count has blown up, the uncommon trap // runtime is going to flush this nmethod, not matter what. - if (treat_throw_as_hot && method()->can_omit_stack_trace()) { - // If the throw is local, we use a pre-existing instance and - // punt on the backtrace. This would lead to a missing backtrace - // (a repeat of 4292742) if the backtrace object is ever asked - // for its backtrace. - // Fixing this remaining case of 4292742 requires some flavor of - // escape analysis. Leave that for the future. - ciInstance* ex_obj = nullptr; - switch (reason) { - case Deoptimization::Reason_null_check: - ex_obj = env()->NullPointerException_instance(); - break; - case Deoptimization::Reason_div0_check: - ex_obj = env()->ArithmeticException_instance(); - break; - case Deoptimization::Reason_range_check: - ex_obj = env()->ArrayIndexOutOfBoundsException_instance(); - break; - case Deoptimization::Reason_class_check: - ex_obj = env()->ClassCastException_instance(); - break; - case Deoptimization::Reason_array_check: - ex_obj = env()->ArrayStoreException_instance(); - break; - default: - break; - } - // If we have a preconstructed exception object, use it. - if (ex_obj != nullptr) { + if (is_builtin_throw_hot(reason)) { + if (method()->can_omit_stack_trace() && ex_obj != nullptr) { + // If the throw is local, we use a pre-existing instance and + // punt on the backtrace. This would lead to a missing backtrace + // (a repeat of 4292742) if the backtrace object is ever asked + // for its backtrace. + // Fixing this remaining case of 4292742 requires some flavor of + // escape analysis. Leave that for the future. if (env()->jvmti_can_post_on_exceptions()) { // check if we must post exception events, take uncommon trap if so - uncommon_trap_if_should_post_on_exceptions(reason, must_throw); + uncommon_trap_if_should_post_on_exceptions(reason, true /*must_throw*/); // here if should_post_on_exceptions is false // continue on with the normal codegen } @@ -622,6 +580,18 @@ void GraphKit::builtin_throw(Deoptimization::DeoptReason reason) { add_exception_state(make_exception_state(ex_node)); return; + } else if (builtin_throw_too_many_traps(reason, ex_obj)) { + // We cannot afford to take too many traps here. Suffer in the interpreter instead. + assert(allow_too_many_traps, "not allowed"); + if (C->log() != nullptr) { + C->log()->elem("hot_throw preallocated='0' reason='%s' mcount='%d'", + Deoptimization::trap_reason_name(reason), + C->trap_count(reason)); + } + uncommon_trap(reason, Deoptimization::Action_none, + (ciKlass*) nullptr, (char*) nullptr, + true /*must_throw*/); + return; } } @@ -633,27 +603,72 @@ void GraphKit::builtin_throw(Deoptimization::DeoptReason reason) { // Usual case: Bail to interpreter. // Reserve the right to recompile if we haven't seen anything yet. - ciMethod* m = Deoptimization::reason_is_speculate(reason) ? C->method() : nullptr; - Deoptimization::DeoptAction action = Deoptimization::Action_maybe_recompile; - if (treat_throw_as_hot - && (method()->method_data()->trap_recompiled_at(bci(), m) - || C->too_many_traps(reason))) { - // We cannot afford to take more traps here. Suffer in the interpreter. - if (C->log() != nullptr) - C->log()->elem("hot_throw preallocated='0' reason='%s' mcount='%d'", - Deoptimization::trap_reason_name(reason), - C->trap_count(reason)); - action = Deoptimization::Action_none; - } - // "must_throw" prunes the JVM state to include only the stack, if there // are no local exception handlers. This should cut down on register // allocation time and code size, by drastically reducing the number // of in-edges on the call to the uncommon trap. + uncommon_trap(reason, Deoptimization::Action_maybe_recompile, + (ciKlass*) nullptr, (char*) nullptr, + true /*must_throw*/); +} + +bool GraphKit::is_builtin_throw_hot(Deoptimization::DeoptReason reason) { + // If this particular condition has not yet happened at this + // bytecode, then use the uncommon trap mechanism, and allow for + // a future recompilation if several traps occur here. + // If the throw is hot, try to use a more complicated inline mechanism + // which keeps execution inside the compiled code. + if (ProfileTraps) { + if (too_many_traps(reason)) { + return true; + } + // (If there is no MDO at all, assume it is early in + // execution, and that any deopts are part of the + // startup transient, and don't need to be remembered.) + + // Also, if there is a local exception handler, treat all throws + // as hot if there has been at least one in this method. + if (C->trap_count(reason) != 0 && + method()->method_data()->trap_count(reason) != 0 && + has_exception_handler()) { + return true; + } + } + return false; +} - uncommon_trap(reason, action, (ciKlass*)nullptr, (char*)nullptr, must_throw); +bool GraphKit::builtin_throw_too_many_traps(Deoptimization::DeoptReason reason, + ciInstance* ex_obj) { + if (is_builtin_throw_hot(reason)) { + if (method()->can_omit_stack_trace() && ex_obj != nullptr) { + return false; // no traps; throws preallocated exception instead + } + ciMethod* m = Deoptimization::reason_is_speculate(reason) ? C->method() : nullptr; + if (method()->method_data()->trap_recompiled_at(bci(), m) || + C->too_many_traps(reason)) { + return true; + } + } + return false; } +ciInstance* GraphKit::builtin_throw_exception(Deoptimization::DeoptReason reason) const { + // Preallocated exception objects to use when we don't need the backtrace. + switch (reason) { + case Deoptimization::Reason_null_check: + return env()->NullPointerException_instance(); + case Deoptimization::Reason_div0_check: + return env()->ArithmeticException_instance(); + case Deoptimization::Reason_range_check: + return env()->ArrayIndexOutOfBoundsException_instance(); + case Deoptimization::Reason_class_check: + return env()->ClassCastException_instance(); + case Deoptimization::Reason_array_check: + return env()->ArrayStoreException_instance(); + default: + return nullptr; + } +} //----------------------------PreserveJVMState--------------------------------- PreserveJVMState::PreserveJVMState(GraphKit* kit, bool clone_map) { diff --git a/src/hotspot/share/opto/graphKit.hpp b/src/hotspot/share/opto/graphKit.hpp index d9a725fc10c0c..d1b58526a6dc1 100644 --- a/src/hotspot/share/opto/graphKit.hpp +++ b/src/hotspot/share/opto/graphKit.hpp @@ -276,6 +276,16 @@ class GraphKit : public Phase { // Helper to throw a built-in exception. // The JVMS must allow the bytecode to be re-executed via an uncommon trap. void builtin_throw(Deoptimization::DeoptReason reason); + void builtin_throw(Deoptimization::DeoptReason reason, + ciInstance* exception_object, + bool allow_too_many_traps); + bool builtin_throw_too_many_traps(Deoptimization::DeoptReason reason, + ciInstance* exception_object); + private: + bool is_builtin_throw_hot(Deoptimization::DeoptReason reason); + ciInstance* builtin_throw_exception(Deoptimization::DeoptReason reason) const; + + public: // Helper to check the JavaThread::_should_post_on_exceptions flag // and branch to an uncommon_trap if it is true (with the specified reason and must_throw) diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 3bb432ac6077b..708225ba3aa9f 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -2003,7 +2003,14 @@ bool LibraryCallKit::inline_min_max(vmIntrinsics::ID id) { return true; } -void LibraryCallKit::inline_math_mathExact(Node* math, Node *test) { +bool LibraryCallKit::inline_math_mathExact(Node* math, Node* test) { + if (builtin_throw_too_many_traps(Deoptimization::Reason_intrinsic, + env()->ArithmeticException_instance())) { + // It has been already too many times, but we cannot use builtin_throw (e.g. we care about backtraces), + // so let's bail out intrinsic rather than risking deopting again. + return false; + } + Node* bol = _gvn.transform( new BoolNode(test, BoolTest::overflow) ); IfNode* check = create_and_map_if(control(), bol, PROB_UNLIKELY_MAG(3), COUNT_UNKNOWN); Node* fast_path = _gvn.transform( new IfFalseNode(check)); @@ -2017,12 +2024,14 @@ void LibraryCallKit::inline_math_mathExact(Node* math, Node *test) { set_control(slow_path); set_i_o(i_o()); - uncommon_trap(Deoptimization::Reason_intrinsic, - Deoptimization::Action_none); + builtin_throw(Deoptimization::Reason_intrinsic, + env()->ArithmeticException_instance(), + /*allow_too_many_traps*/ false); } set_control(fast_path); set_result(math); + return true; } template @@ -2032,8 +2041,7 @@ bool LibraryCallKit::inline_math_overflow(Node* arg1, Node* arg2) { MathOp* mathOp = new MathOp(arg1, arg2); Node* operation = _gvn.transform( mathOp ); Node* ofcheck = _gvn.transform( new OverflowOp(arg1, arg2) ); - inline_math_mathExact(operation, ofcheck); - return true; + return inline_math_mathExact(operation, ofcheck); } bool LibraryCallKit::inline_math_addExactI(bool is_increment) { diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index 1f83e28932b70..ad1ce71c374bf 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -209,7 +209,7 @@ class LibraryCallKit : public GraphKit { bool inline_math_pow(); template bool inline_math_overflow(Node* arg1, Node* arg2); - void inline_math_mathExact(Node* math, Node* test); + bool inline_math_mathExact(Node* math, Node* test); bool inline_math_addExactI(bool is_increment); bool inline_math_addExactL(bool is_increment); bool inline_math_multiplyExactI(); diff --git a/test/hotspot/jtreg/compiler/intrinsics/mathexact/OverflowTest.java b/test/hotspot/jtreg/compiler/intrinsics/mathexact/OverflowTest.java new file mode 100644 index 0000000000000..eba6686ee4746 --- /dev/null +++ b/test/hotspot/jtreg/compiler/intrinsics/mathexact/OverflowTest.java @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Math.*Exact intrinsics, especially in case of overflow + * The base case + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm + * -XX:+UnlockDiagnosticVMOptions -Xbootclasspath/a:. -XX:+WhiteBoxAPI + * -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.intrinsics.mathexact.OverflowTest::comp_* + * -XX:CompileCommand=dontinline,compiler.intrinsics.mathexact.OverflowTest::* + * compiler.intrinsics.mathexact.OverflowTest + */ + +/* + * @test + * @summary Math.*Exact intrinsics, especially in case of overflow + * With ProfileTraps enabled to allow builtin_throw to work + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -Xbootclasspath/a:. -XX:+WhiteBoxAPI + * -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.intrinsics.mathexact.OverflowTest::comp_* + * -XX:CompileCommand=dontinline,compiler.intrinsics.mathexact.OverflowTest::* + * -XX:+ProfileTraps -XX:+StackTraceInThrowable -XX:+OmitStackTraceInFastThrow + * compiler.intrinsics.mathexact.OverflowTest + */ + +/* + * @test + * @summary Math.*Exact intrinsics, especially in case of overflow + * ProfileTraps off => throw will never be hot for builtin_throw + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -Xbootclasspath/a:. -XX:+WhiteBoxAPI + * -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.intrinsics.mathexact.OverflowTest::comp_* + * -XX:CompileCommand=dontinline,compiler.intrinsics.mathexact.OverflowTest::* + * -XX:-ProfileTraps + * compiler.intrinsics.mathexact.OverflowTest + */ + +/* + * @test + * @summary Math.*Exact intrinsics, especially in case of overflow + * OmitStackTraceInFastThrow off => can_omit_stack_trace is false => no builtin_throw + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -Xbootclasspath/a:. -XX:+WhiteBoxAPI + * -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.intrinsics.mathexact.OverflowTest::comp_* + * -XX:CompileCommand=dontinline,compiler.intrinsics.mathexact.OverflowTest::* + * -XX:+ProfileTraps -XX:+StackTraceInThrowable -XX:-OmitStackTraceInFastThrow + * compiler.intrinsics.mathexact.OverflowTest + */ + +/* + * @test + * @summary Math.*Exact intrinsics, especially in case of overflow + * StackTraceInThrowable off => can_omit_stack_trace is true => yes builtin_throw + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -Xbootclasspath/a:. -XX:+WhiteBoxAPI + * -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.intrinsics.mathexact.OverflowTest::comp_* + * -XX:CompileCommand=dontinline,compiler.intrinsics.mathexact.OverflowTest::* + * -XX:+ProfileTraps -XX:-StackTraceInThrowable -XX:+OmitStackTraceInFastThrow + * compiler.intrinsics.mathexact.OverflowTest + */ + +/* + * @test + * @summary Math.*Exact intrinsics, especially in case of overflow + * StackTraceInThrowable off && OmitStackTraceInFastThrow off => can_omit_stack_trace is true => yes builtin_throw + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -Xbootclasspath/a:. -XX:+WhiteBoxAPI + * -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.intrinsics.mathexact.OverflowTest::comp_* + * -XX:CompileCommand=dontinline,compiler.intrinsics.mathexact.OverflowTest::* + * -XX:+ProfileTraps -XX:-StackTraceInThrowable -XX:-OmitStackTraceInFastThrow + * compiler.intrinsics.mathexact.OverflowTest + */ + +/* + * @test + * @summary Math.*Exact intrinsics, especially in case of overflow + * Without intrinsics + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm + * -XX:+UnlockDiagnosticVMOptions -Xbootclasspath/a:. -XX:+WhiteBoxAPI + * -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.intrinsics.mathexact.OverflowTest::comp_* + * -XX:CompileCommand=dontinline,compiler.intrinsics.mathexact.OverflowTest::* + * -XX:DisableIntrinsic=_addExactI,_incrementExactI,_addExactL,_incrementExactL,_subtractExactI,_decrementExactI,_subtractExactL,_decrementExactL,_negateExactI,_negateExactL,_multiplyExactI,_multiplyExactL + * compiler.intrinsics.mathexact.OverflowTest + */ + +package compiler.intrinsics.mathexact; + +import java.lang.reflect.Method; + +import compiler.lib.generators.RestrictableGenerator; +import jdk.test.lib.Asserts; +import jdk.test.whitebox.WhiteBox; + +import static compiler.lib.generators.Generators.G; + +public class OverflowTest { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static final RestrictableGenerator int_gen = G.ints(); + private static final int LIMIT = 10_000; + + public static void main(String... args) throws NoSuchMethodException { + OverflowTest t = new OverflowTest(); + t.run(); + } + + void run() throws NoSuchMethodException { + check_compilation(); + check_multiplyI(); + } + + void check_compilation() throws NoSuchMethodException { + // Force Math loading + Math.min(2, 3); + comp_multiplyI(0, 0); + comp_multiplyI_no_catch(0, 0); + int_multiplyI(0, 0); + + Method comp_multiplyI_meth = OverflowTest.class.getDeclaredMethod("comp_multiplyI", int.class, int.class); + Asserts.assertTrue(WHITE_BOX.isMethodCompiled(comp_multiplyI_meth), "comp_multiplyI(int, int) is not compiled"); + + Method comp_multiplyI_no_catch_meth = OverflowTest.class.getDeclaredMethod("comp_multiplyI_no_catch", int.class, int.class); + Asserts.assertTrue(WHITE_BOX.isMethodCompiled(comp_multiplyI_no_catch_meth), "comp_multiplyI_no_catch(int, int) is not compiled"); + + Method int_multiplyI_meth = OverflowTest.class.getDeclaredMethod("int_multiplyI", int.class, int.class); + Asserts.assertFalse(WHITE_BOX.isMethodCompiled(int_multiplyI_meth), "int_multiplyI(int, int) is compiled"); + } + + void assert_consistent(Integer comp_res, Integer int_res) { + if (int_res == null) { + Asserts.assertNull(comp_res); + } else { + Asserts.assertNotNull(comp_res); + Asserts.assertEquals(comp_res, int_res); + } + } + + Integer comp_multiplyI(int a, int b) { + try { + return Math.multiplyExact(a, b); + } catch (ArithmeticException e) { + return null; + } + } + + int comp_multiplyI_no_catch(int a, int b) { + return Math.multiplyExact(a, b); + } + + Integer int_multiplyI(int a, int b) { + try { + return Math.multiplyExact(a, b); + } catch (ArithmeticException e) { + return null; + } + } + + void check_multiplyI() { + // 46_340 < 2 ^ 15.5 < 46_341 => + // 46_340^2 < 2 ^ 31 < 46_341^2 + int limit_square_do_not_overflow = 46_340; + + // In bound cases + for (int i = 0; i < LIMIT; i++) { + int a = limit_square_do_not_overflow - i; + Integer comp_res = comp_multiplyI(a, a); + Integer int_res = int_multiplyI(a, a); + Asserts.assertNotNull(int_res); + assert_consistent(comp_res, int_res); + } + for (int i = 0; i < LIMIT; i++) { + int a = limit_square_do_not_overflow - i; + Integer comp_res; + try { + comp_res = comp_multiplyI_no_catch(a, a); + } catch (ArithmeticException _) { + comp_res = null; + } + Integer int_res = int_multiplyI(a, a); + Asserts.assertNotNull(int_res); + assert_consistent(comp_res, int_res); + } + + // Out of bound cases + for (int i = 0; i < LIMIT; i++) { + int a = limit_square_do_not_overflow + 1 + i; + Integer comp_res = comp_multiplyI(a, a); + Integer int_res = int_multiplyI(a, a); + Asserts.assertNull(int_res); + assert_consistent(comp_res, int_res); + } + for (int i = 0; i < LIMIT; i++) { + int a = limit_square_do_not_overflow + 1 + i; + Integer comp_res; + try { + comp_res = comp_multiplyI_no_catch(a, a); + } catch (ArithmeticException _) { + comp_res = null; + } + Integer int_res = int_multiplyI(a, a); + Asserts.assertNull(int_res); + assert_consistent(comp_res, int_res); + } + + // Random slice + int lhs = int_gen.next(); + int rhs_start = int_gen.next() & 0xff_ff_00_00; + for (int i = 0; i < 0x1_00_00; i++) { + int rhs = rhs_start | i; + Integer comp_res = comp_multiplyI(lhs, rhs); + Integer int_res = int_multiplyI(lhs, rhs); + assert_consistent(comp_res, int_res); + } + for (int i = 0; i < 0x1_00_00; i++) { + int rhs = rhs_start | i; + Integer comp_res; + try { + comp_res = comp_multiplyI_no_catch(lhs, rhs); + } catch (ArithmeticException _) { + comp_res = null; + } + Integer int_res = int_multiplyI(lhs, rhs); + assert_consistent(comp_res, int_res); + } + } +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/MathExact.java b/test/micro/org/openjdk/bench/vm/compiler/MathExact.java new file mode 100644 index 0000000000000..5558af08722f1 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/MathExact.java @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.*; + +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Thread) +@Warmup(iterations = 2, time = 1, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.MILLISECONDS) +public abstract class MathExact { + @Param({"1000000"}) + public int SIZE; + + + // === multiplyExact(int, int) === + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public int testMultiplyI(int i) { + try { + return Math.multiplyExact(i, i); + } catch (ArithmeticException e) { + return 0; + } + } + + @Benchmark + public void loopMultiplyIOverflow() { + for (int i = 0; i < SIZE; i++) { + testMultiplyI(i); + } + } + + @Benchmark + public void loopMultiplyIInBounds() { + for (int i = 0; i < SIZE; i++) { + // 46_340 < 2 ^ 15.5 (< 46_341, but that's not important) + // so + // 46_340 ^ 2 < 2 ^ 31 + testMultiplyI(i % 46_341); + } + } + + + // === multiplyExact(long, long) === + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public long testMultiplyL(long i) { + try { + return Math.multiplyExact(i, i); + } catch (ArithmeticException e) { + return 0L; + } + } + + @Benchmark + public void loopMultiplyLOverflow() { + for (long i = 0L; i < (long)SIZE; i++) { + // (2 ^ 63 - 1)^0.5 ~= 3_037_000_499.9761 + // Starting at 3_037_000_000 so that almost all computations overflow + testMultiplyL(3_037_000_000L + i); + } + } + + @Benchmark + public void loopMultiplyLInBounds() { + for (long i = 0L; i < (long)SIZE; i++) { + testMultiplyL(i); + } + } + + + // === negateExact(int) === + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public int testNegateI(int i) { + try { + return Math.negateExact(i); + } catch (ArithmeticException e) { + return 0; + } + } + + @Benchmark + public void loopNegateIOverflow() { + for (int i = 0; i < SIZE; i++) { + testNegateI(i); + } + for (int i = 0; i < SIZE; i++) { + testNegateI(Integer.MIN_VALUE); + } + } + + @Benchmark + public void loopNegateIInBounds() { + for (int i = 0; i < SIZE; i++) { + testNegateI(i); + } + for (int i = 0; i < SIZE; i++) { + testNegateI(Integer.MAX_VALUE); + } + } + + + // === negateExact(long) === + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public long testNegateL(long i) { + try { + return Math.negateExact(i); + } catch (ArithmeticException e) { + return 0L; + } + } + + @Benchmark + public void loopNegateLOverflow() { + for (long i = 0L; i < (long)SIZE; i++) { + testNegateL(i); + } + for (long i = 0L; i < (long)SIZE; i++) { + testNegateL(Long.MIN_VALUE); + } + } + + @Benchmark + public void loopNegateLInBounds() { + for (long i = 0L; i < (long)SIZE; i++) { + testNegateL(i); + } + for (long i = 0L; i < (long)SIZE; i++) { + testNegateL(Long.MAX_VALUE); + } + } + + + // === incrementExact(int) === + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public int testIncrementI(int i) { + try { + return Math.incrementExact(i); + } catch (ArithmeticException e) { + return 0; + } + } + + @Benchmark + public void loopIncrementIOverflow() { + for (int i = 0; i < SIZE; i++) { + testIncrementI(i); + } + for (int i = 0; i < SIZE; i++) { + testIncrementI(Integer.MAX_VALUE); + } + } + + @Benchmark + public void loopIncrementIInBounds() { + for (int i = 0; i < SIZE; i++) { + testIncrementI(i); + } + for (int i = 0; i < SIZE; i++) { + testIncrementI(Integer.MIN_VALUE + i); + } + } + + + // === incrementExact(long) === + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public long testIncrementL(long i) { + try { + return Math.incrementExact(i); + } catch (ArithmeticException e) { + return 0L; + } + } + + @Benchmark + public void loopIncrementLOverflow() { + for (long i = 0L; i < (long)SIZE; i++) { + testIncrementL(i); + } + for (long i = 0L; i < (long)SIZE; i++) { + testIncrementL(Long.MAX_VALUE); + } + } + + @Benchmark + public void loopIncrementLInBounds() { + for (long i = 0L; i < (long)SIZE; i++) { + testIncrementL(i); + } + for (long i = 0L; i < (long)SIZE; i++) { + testIncrementL(Long.MIN_VALUE + i); + } + } + + + // === decrementExact(int) === + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public int testDecrementI(int i) { + try { + return Math.decrementExact(i); + } catch (ArithmeticException e) { + return 0; + } + } + + @Benchmark + public void loopDecrementIOverflow() { + for (int i = 0; i < SIZE; i++) { + testDecrementI(i); + } + for (int i = 0; i < SIZE; i++) { + testDecrementI(Integer.MIN_VALUE); + } + } + + @Benchmark + public void loopDecrementIInBounds() { + for (int i = 0; i < SIZE; i++) { + testDecrementI(i); + } + for (int i = 0; i < SIZE; i++) { + testDecrementI(Integer.MAX_VALUE - i); + } + } + + + // === decrementExact(long) === + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public long testDecrementL(long i) { + try { + return Math.decrementExact(i); + } catch (ArithmeticException e) { + return 0L; + } + } + + @Benchmark + public void loopDecrementLOverflow() { + for (long i = 0L; i < (long)SIZE; i++) { + testDecrementL(i); + } + for (long i = 0L; i < (long)SIZE; i++) { + testDecrementL(Long.MIN_VALUE); + } + } + + @Benchmark + public void loopDecrementLInBounds() { + for (long i = 0L; i < (long)SIZE; i++) { + testDecrementL(i); + } + for (long i = 0L; i < (long)SIZE; i++) { + testDecrementL(Long.MAX_VALUE - i); + } + } + + + // === addExact(int) === + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public int testAddI(int l, int r) { + try { + return Math.addExact(l, r); + } catch (ArithmeticException e) { + return 0; + } + } + + @Benchmark + public void loopAddIOverflow() { + for (int i = 0; i < SIZE; i++) { + testAddI(Integer.MAX_VALUE - 1_000, i); + } + } + + @Benchmark + public void loopAddIInBounds() { + for (int i = 0; i < SIZE; i++) { + testAddI(i * 5, i); + } + } + + + // === addExact(long) === + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public long testAddL(long l, long r) { + try { + return Math.addExact(l, r); + } catch (ArithmeticException e) { + return 0L; + } + } + + @Benchmark + public void loopAddLOverflow() { + for (long i = 0L; i < (long)SIZE; i++) { + testAddL(Long.MAX_VALUE - 1_000L, i); + } + } + + @Benchmark + public void loopAddLInBounds() { + for (long i = 0L; i < (long)SIZE; i++) { + testAddL(i * 5L, i); + } + } + + + // === subtractExact(int) === + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public int testSubtractI(int l, int r) { + try { + return Math.subtractExact(l, r); + } catch (ArithmeticException e) { + return 0; + } + } + + @Benchmark + public void loopSubtractIOverflow() { + for (int i = 0; i < SIZE; i++) { + testSubtractI(Integer.MIN_VALUE + 1_000, i); + } + } + + @Benchmark + public void loopSubtractIInBounds() { + for (int i = 0; i < SIZE; i++) { + testSubtractI(i * 5, i); + } + } + + + // === subtractExact(long) === + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public long testSubtractL(long l, long r) { + try { + return Math.subtractExact(l, r); + } catch (ArithmeticException e) { + return 0L; + } + } + + @Benchmark + public void loopSubtractLOverflow() { + for (long i = 0L; i < (long)SIZE; i++) { + testSubtractL(Long.MIN_VALUE + 1_000L, i); + } + } + + @Benchmark + public void loopSubtractLInBounds() { + for (long i = 0L; i < (long)SIZE; i++) { + testSubtractL(i * 5L, i); + } + } + + + + @Fork(value = 1, jvmArgs = {"-XX:TieredStopAtLevel=1"}) + public static class C1_1 extends MathExact {} + + @Fork(value = 1, jvmArgs = {"-XX:TieredStopAtLevel=2"}) + public static class C1_2 extends MathExact {} + + @Fork(value = 1, jvmArgs = {"-XX:TieredStopAtLevel=3"}) + public static class C1_3 extends MathExact {} + + @Fork(value = 1) + public static class C2 extends MathExact {} + + @Fork(value = 1, + jvmArgs = { + "-XX:+UnlockDiagnosticVMOptions", + "-XX:DisableIntrinsic=_addExactI,_incrementExactI,_addExactL,_incrementExactL,_subtractExactI,_decrementExactI,_subtractExactL,_decrementExactL,_negateExactI,_negateExactL,_multiplyExactI,_multiplyExactL", + }) + public static class C2_no_intrinsics extends MathExact {} + + @Fork(value = 1, jvmArgs = {"-XX:-OmitStackTraceInFastThrow"}) + public static class C2_no_builtin_throw extends MathExact {} +} From 6d9ece73a96dd32fccf4a740205407a76dcd907a Mon Sep 17 00:00:00 2001 From: Robbin Ehn Date: Mon, 7 Apr 2025 07:09:51 +0000 Subject: [PATCH 0410/1101] 8351949: RISC-V: Cleanup and enable store-load peephole for membars Reviewed-by: fyang, fjiang, mli --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 4 +- .../cpu/riscv/macroAssembler_riscv.cpp | 24 ++-- .../cpu/riscv/macroAssembler_riscv.hpp | 32 ++--- src/hotspot/cpu/riscv/riscv.ad | 136 ++++++++++++------ 4 files changed, 120 insertions(+), 76 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 3c19673f1e749..e036cb6b1ec60 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -815,7 +815,7 @@ class Assembler : public AbstractAssembler { emit(insn); } - public: + protected: enum barrier { i = 0b1000, o = 0b0100, r = 0b0010, w = 0b0001, @@ -846,6 +846,8 @@ class Assembler : public AbstractAssembler { emit(insn); } + public: + #define INSN(NAME, op, funct3, funct7) \ void NAME() { \ unsigned insn = 0; \ diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 1916fbdeb18b3..71481565fc73d 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -183,7 +183,6 @@ void MacroAssembler::set_membar_kind(address addr, uint32_t order_kind) { Assembler::sd_instr(membar, insn); } - static void pass_arg0(MacroAssembler* masm, Register arg) { if (c_rarg0 != arg) { masm->mv(c_rarg0, arg); @@ -3556,6 +3555,14 @@ void MacroAssembler::lookup_virtual_method(Register recv_klass, } void MacroAssembler::membar(uint32_t order_constraint) { + if (UseZtso && ((order_constraint & StoreLoad) != StoreLoad)) { + // TSO allows for stores to be reordered after loads. When the compiler + // generates a fence to disallow that, we are required to generate the + // fence for correctness. + BLOCK_COMMENT("elided tso membar"); + return; + } + address prev = pc() - MacroAssembler::instruction_size; address last = code()->last_insn(); @@ -3564,15 +3571,14 @@ void MacroAssembler::membar(uint32_t order_constraint) { // can do this simply by ORing them together. set_membar_kind(prev, get_membar_kind(prev) | order_constraint); BLOCK_COMMENT("merged membar"); - } else { - code()->set_last_insn(pc()); - - uint32_t predecessor = 0; - uint32_t successor = 0; - - membar_mask_to_pred_succ(order_constraint, predecessor, successor); - fence(predecessor, successor); + return; } + + code()->set_last_insn(pc()); + uint32_t predecessor = 0; + uint32_t successor = 0; + membar_mask_to_pred_succ(order_constraint, predecessor, successor); + fence(predecessor, successor); } void MacroAssembler::cmodx_fence() { diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 5d36a5f6fcd91..153b6d77f9937 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -417,15 +417,17 @@ class MacroAssembler: public Assembler { // We used four bit to indicate the read and write bits in the predecessors and successors, // and extended i for r, o for w if UseConservativeFence enabled. enum Membar_mask_bits { - StoreStore = 0b0101, // (pred = ow + succ = ow) - LoadStore = 0b1001, // (pred = ir + succ = ow) - StoreLoad = 0b0110, // (pred = ow + succ = ir) - LoadLoad = 0b1010, // (pred = ir + succ = ir) - AnyAny = LoadStore | StoreLoad // (pred = iorw + succ = iorw) + StoreStore = 0b0101, // (pred = w + succ = w) + LoadStore = 0b1001, // (pred = r + succ = w) + StoreLoad = 0b0110, // (pred = w + succ = r) + LoadLoad = 0b1010, // (pred = r + succ = r) + AnyAny = LoadStore | StoreLoad // (pred = rw + succ = rw) }; void membar(uint32_t order_constraint); + private: + static void membar_mask_to_pred_succ(uint32_t order_constraint, uint32_t& predecessor, uint32_t& successor) { predecessor = (order_constraint >> 2) & 0x3; @@ -437,7 +439,7 @@ class MacroAssembler: public Assembler { // 11(rw)-> 1111(iorw) if (UseConservativeFence) { predecessor |= predecessor << 2; - successor |= successor << 2; + successor |= successor << 2; } } @@ -445,25 +447,13 @@ class MacroAssembler: public Assembler { return ((predecessor & 0x3) << 2) | (successor & 0x3); } - void fence(uint32_t predecessor, uint32_t successor) { - if (UseZtso) { - if ((pred_succ_to_membar_mask(predecessor, successor) & StoreLoad) == StoreLoad) { - // TSO allows for stores to be reordered after loads. When the compiler - // generates a fence to disallow that, we are required to generate the - // fence for correctness. - Assembler::fence(predecessor, successor); - } else { - // TSO guarantees other fences already. - } - } else { - // always generate fence for RVWMO - Assembler::fence(predecessor, successor); - } - } + public: void cmodx_fence(); void pause() { + // Zihintpause + // PAUSE is encoded as a FENCE instruction with pred=W, succ=0, fm=0, rd=x0, and rs1=x0. Assembler::fence(w, 0); } diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 59171d84c9b80..4ebfdf9f16c42 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -4397,6 +4397,12 @@ pipe_class pipe_slow() LDST : MEM; %} +// The real do-nothing guy +pipe_class real_empty() +%{ + instruction_count(0); +%} + // Empty pipeline class pipe_class pipe_class_empty() %{ @@ -7902,78 +7908,102 @@ instruct xorL_reg_imm(iRegLNoSp dst, iRegL src1, immLAdd src2) %{ // ============================================================================ // MemBar Instruction -instruct load_fence() %{ +// RVTSO + +instruct unnecessary_membar_rvtso() %{ + predicate(UseZtso); match(LoadFence); - ins_cost(ALU_COST); + match(StoreFence); + match(StoreStoreFence); + match(MemBarAcquire); + match(MemBarRelease); + match(MemBarStoreStore); + match(MemBarAcquireLock); + match(MemBarReleaseLock); - format %{ "#@load_fence" %} + ins_cost(0); + + size(0); + format %{ "#@unnecessary_membar_rvtso elided/tso (empty encoding)" %} ins_encode %{ - __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + __ block_comment("unnecessary_membar_rvtso"); %} - ins_pipe(pipe_serial); + ins_pipe(real_empty); %} -instruct membar_acquire() %{ - match(MemBarAcquire); - ins_cost(ALU_COST); +instruct membar_volatile_rvtso() %{ + predicate(UseZtso); + match(MemBarVolatile); + ins_cost(VOLATILE_REF_COST); - format %{ "#@membar_acquire\n\t" - "fence ir iorw" %} + format %{ "#@membar_volatile_rvtso\n\t" + "fence w, r"%} ins_encode %{ - __ block_comment("membar_acquire"); - __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + __ block_comment("membar_volatile_rvtso"); + __ membar(MacroAssembler::StoreLoad); %} - ins_pipe(pipe_serial); + ins_pipe(pipe_slow); %} -instruct membar_acquire_lock() %{ - match(MemBarAcquireLock); +instruct unnecessary_membar_volatile_rvtso() %{ + predicate(UseZtso && Matcher::post_store_load_barrier(n)); + match(MemBarVolatile); ins_cost(0); - format %{ "#@membar_acquire_lock (elided)" %} - + size(0); + + format %{ "#@unnecessary_membar_volatile_rvtso (unnecessary so empty encoding)" %} ins_encode %{ - __ block_comment("membar_acquire_lock (elided)"); + __ block_comment("unnecessary_membar_volatile_rvtso"); %} - - ins_pipe(pipe_serial); + ins_pipe(real_empty); %} -instruct store_fence() %{ - match(StoreFence); - ins_cost(ALU_COST); +// RVWMO + +instruct membar_aqcuire_rvwmo() %{ + predicate(!UseZtso); + match(LoadFence); + match(MemBarAcquire); + ins_cost(VOLATILE_REF_COST); - format %{ "#@store_fence" %} + format %{ "#@membar_aqcuire_rvwmo\n\t" + "fence r, rw" %} ins_encode %{ - __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + __ block_comment("membar_aqcuire_rvwmo"); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); %} ins_pipe(pipe_serial); %} -instruct membar_release() %{ +instruct membar_release_rvwmo() %{ + predicate(!UseZtso); + match(StoreFence); match(MemBarRelease); - ins_cost(ALU_COST); + ins_cost(VOLATILE_REF_COST); - format %{ "#@membar_release\n\t" - "fence iorw ow" %} + format %{ "#@membar_release_rvwmo\n\t" + "fence rw, w" %} ins_encode %{ - __ block_comment("membar_release"); + __ block_comment("membar_release_rvwmo"); __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); %} ins_pipe(pipe_serial); %} -instruct membar_storestore() %{ +instruct membar_storestore_rvwmo() %{ + predicate(!UseZtso); match(MemBarStoreStore); match(StoreStoreFence); - ins_cost(ALU_COST); + ins_cost(VOLATILE_REF_COST); - format %{ "MEMBAR-store-store\t#@membar_storestore" %} + format %{ "#@membar_storestore_rvwmo\n\t" + "fence w, w" %} ins_encode %{ __ membar(MacroAssembler::StoreStore); @@ -7981,34 +8011,50 @@ instruct membar_storestore() %{ ins_pipe(pipe_serial); %} -instruct membar_release_lock() %{ - match(MemBarReleaseLock); - ins_cost(0); +instruct membar_volatile_rvwmo() %{ + predicate(!UseZtso); + match(MemBarVolatile); + ins_cost(VOLATILE_REF_COST); - format %{ "#@membar_release_lock (elided)" %} + format %{ "#@membar_volatile_rvwmo\n\t" + "fence w, r"%} ins_encode %{ - __ block_comment("membar_release_lock (elided)"); + __ block_comment("membar_volatile_rvwmo"); + __ membar(MacroAssembler::StoreLoad); %} ins_pipe(pipe_serial); %} -instruct membar_volatile() %{ - match(MemBarVolatile); - ins_cost(ALU_COST); +instruct membar_lock_rvwmo() %{ + predicate(!UseZtso); + match(MemBarAcquireLock); + match(MemBarReleaseLock); + ins_cost(0); - format %{ "#@membar_volatile\n\t" - "fence iorw iorw"%} + format %{ "#@membar_lock_rvwmo (elided)" %} ins_encode %{ - __ block_comment("membar_volatile"); - __ membar(MacroAssembler::StoreLoad); + __ block_comment("membar_lock_rvwmo (elided)"); %} ins_pipe(pipe_serial); %} +instruct unnecessary_membar_volatile_rvwmo() %{ + predicate(!UseZtso && Matcher::post_store_load_barrier(n)); + match(MemBarVolatile); + ins_cost(0); + + size(0); + format %{ "#@unnecessary_membar_volatile_rvwmo (unnecessary so empty encoding)" %} + ins_encode %{ + __ block_comment("unnecessary_membar_volatile_rvwmo"); + %} + ins_pipe(real_empty); +%} + instruct spin_wait() %{ predicate(UseZihintpause); match(OnSpinWait); From 6abf4e6d4d9f948b8ae51aec731b94ba7acd022e Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 7 Apr 2025 07:14:32 +0000 Subject: [PATCH 0411/1101] 8353568: SEGV_BNDERR signal code adjust definition Reviewed-by: stuefe --- src/hotspot/os/posix/signals_posix.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index 5f5a2ccfa4a71..555ac832aae7f 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -49,8 +49,12 @@ #include -#if !defined(SEGV_BNDERR) -#define SEGV_BNDERR 3 +#define SEGV_BNDERR_value 3 + +#if defined(SEGV_BNDERR) +STATIC_ASSERT(SEGV_BNDERR == SEGV_BNDERR_value); +#else +#define SEGV_BNDERR SEGV_BNDERR_value #endif static const char* get_signal_name(int sig, char* out, size_t outlen); From d1e91fcd620ce7e5527363dfa44543872f419c73 Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Mon, 7 Apr 2025 07:21:15 +0000 Subject: [PATCH 0412/1101] 8353344: RISC-V: Detect and enable several extensions for debug builds Reviewed-by: mli, fjiang, rehn --- .../os_cpu/linux_riscv/riscv_hwprobe.cpp | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp index 5b427693a8dfd..8572d54716bc3 100644 --- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp @@ -187,18 +187,43 @@ void RiscvHwprobe::add_features_from_query_result() { if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBS)) { VM_Version::ext_Zbs.enable_feature(); } +#ifndef PRODUCT + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBKB)) { + VM_Version::ext_Zbkb.enable_feature(); + } +#endif if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZFH)) { VM_Version::ext_Zfh.enable_feature(); } if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZFHMIN)) { VM_Version::ext_Zfhmin.enable_feature(); } +#ifndef PRODUCT + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVBB)) { + VM_Version::ext_Zvbb.enable_feature(); + } +#endif +#ifndef PRODUCT if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVBC)) { VM_Version::ext_Zvbc.enable_feature(); } +#endif +#ifndef PRODUCT + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVKNED) && + is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVKNHB) && + is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVKB) && + is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVKT)) { + VM_Version::ext_Zvkn.enable_feature(); + } +#endif if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVFH)) { VM_Version::ext_Zvfh.enable_feature(); } +#ifndef PRODUCT + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZFA)) { + VM_Version::ext_Zfa.enable_feature(); + } +#endif if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZICOND)) { VM_Version::ext_Zicond.enable_feature(); } From d63b561fffd42d76f14771c47951dd1d08efe3a7 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 7 Apr 2025 07:39:17 +0000 Subject: [PATCH 0413/1101] 8353188: C1: Clean up x86 backend after 32-bit x86 removal Reviewed-by: kvn, vlivanov --- src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp | 56 +-- src/hotspot/cpu/x86/c1_Defs_x86.hpp | 12 +- src/hotspot/cpu/x86/c1_FrameMap_x86.cpp | 43 +- src/hotspot/cpu/x86/c1_FrameMap_x86.hpp | 18 - src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp | 450 +----------------- src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp | 4 +- src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp | 190 +------- src/hotspot/cpu/x86/c1_LIR_x86.cpp | 7 - src/hotspot/cpu/x86/c1_LinearScan_x86.hpp | 12 - src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp | 26 +- src/hotspot/cpu/x86/c1_Runtime1_x86.cpp | 310 +----------- 11 files changed, 47 insertions(+), 1081 deletions(-) diff --git a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp index 80365878061d0..73262b213655e 100644 --- a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp +++ b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp @@ -37,66 +37,12 @@ #define __ ce->masm()-> -#ifndef _LP64 -float ConversionStub::float_zero = 0.0; -double ConversionStub::double_zero = 0.0; - -void ConversionStub::emit_code(LIR_Assembler* ce) { - __ bind(_entry); - assert(bytecode() == Bytecodes::_f2i || bytecode() == Bytecodes::_d2i, "other conversions do not require stub"); - - - if (input()->is_single_xmm()) { - __ comiss(input()->as_xmm_float_reg(), - ExternalAddress((address)&float_zero)); - } else if (input()->is_double_xmm()) { - __ comisd(input()->as_xmm_double_reg(), - ExternalAddress((address)&double_zero)); - } else { - __ push(rax); - __ ftst(); - __ fnstsw_ax(); - __ sahf(); - __ pop(rax); - } - - Label NaN, do_return; - __ jccb(Assembler::parity, NaN); - __ jccb(Assembler::below, do_return); - - // input is > 0 -> return maxInt - // result register already contains 0x80000000, so subtracting 1 gives 0x7fffffff - __ decrement(result()->as_register()); - __ jmpb(do_return); - - // input is NaN -> return 0 - __ bind(NaN); - __ xorptr(result()->as_register(), result()->as_register()); - - __ bind(do_return); - __ jmp(_continuation); -} -#endif // !_LP64 - void C1SafepointPollStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); InternalAddress safepoint_pc(ce->masm()->pc() - ce->masm()->offset() + safepoint_offset()); -#ifdef _LP64 __ lea(rscratch1, safepoint_pc); __ movptr(Address(r15_thread, JavaThread::saved_exception_pc_offset()), rscratch1); -#else - const Register tmp1 = rcx; - const Register tmp2 = rdx; - __ push(tmp1); - __ push(tmp2); - - __ lea(tmp1, safepoint_pc); - __ get_thread(tmp2); - __ movptr(Address(tmp2, JavaThread::saved_exception_pc_offset()), tmp1); - - __ pop(tmp2); - __ pop(tmp1); -#endif /* _LP64 */ + assert(SharedRuntime::polling_page_return_handler_blob() != nullptr, "polling page return stub not created yet"); diff --git a/src/hotspot/cpu/x86/c1_Defs_x86.hpp b/src/hotspot/cpu/x86/c1_Defs_x86.hpp index 1637789e79884..bfb885a1b7301 100644 --- a/src/hotspot/cpu/x86/c1_Defs_x86.hpp +++ b/src/hotspot/cpu/x86/c1_Defs_x86.hpp @@ -33,15 +33,11 @@ enum { // registers enum { - pd_nof_cpu_regs_frame_map = NOT_LP64(8) LP64_ONLY(16), // number of registers used during code emission + pd_nof_cpu_regs_frame_map = 16, // number of registers used during code emission pd_nof_fpu_regs_frame_map = FloatRegister::number_of_registers, // number of registers used during code emission pd_nof_xmm_regs_frame_map = XMMRegister::number_of_registers, // number of registers used during code emission -#ifdef _LP64 #define UNALLOCATED 4 // rsp, rbp, r15, r10 -#else - #define UNALLOCATED 2 // rsp, rbp -#endif // LP64 pd_nof_caller_save_cpu_regs_frame_map = pd_nof_cpu_regs_frame_map - UNALLOCATED, // number of registers killed by calls pd_nof_caller_save_fpu_regs_frame_map = pd_nof_fpu_regs_frame_map, // number of registers killed by calls @@ -54,9 +50,9 @@ enum { pd_nof_fpu_regs_linearscan = pd_nof_fpu_regs_frame_map, // number of registers visible to linear scan pd_nof_xmm_regs_linearscan = pd_nof_xmm_regs_frame_map, // number of registers visible to linear scan pd_first_cpu_reg = 0, - pd_last_cpu_reg = NOT_LP64(5) LP64_ONLY(11), - pd_first_byte_reg = NOT_LP64(2) LP64_ONLY(0), - pd_last_byte_reg = NOT_LP64(5) LP64_ONLY(11), + pd_last_cpu_reg = 11, + pd_first_byte_reg = 0, + pd_last_byte_reg = 11, pd_first_fpu_reg = pd_nof_cpu_regs_frame_map, pd_last_fpu_reg = pd_first_fpu_reg + 7, pd_first_xmm_reg = pd_nof_cpu_regs_frame_map + pd_nof_fpu_regs_frame_map, diff --git a/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp b/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp index e3c7879260266..bdbab432180bd 100644 --- a/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp +++ b/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp @@ -32,7 +32,6 @@ const int FrameMap::pd_c_runtime_reserved_arg_size = 0; LIR_Opr FrameMap::map_to_opr(BasicType type, VMRegPair* reg, bool) { LIR_Opr opr = LIR_OprFact::illegalOpr; VMReg r_1 = reg->first(); - VMReg r_2 = reg->second(); if (r_1->is_stack()) { // Convert stack slot to an SP offset // The calling convention does not count the SharedRuntime::out_preserve_stack_slots() value @@ -41,14 +40,8 @@ LIR_Opr FrameMap::map_to_opr(BasicType type, VMRegPair* reg, bool) { opr = LIR_OprFact::address(new LIR_Address(rsp_opr, st_off, type)); } else if (r_1->is_Register()) { Register reg = r_1->as_Register(); - if (r_2->is_Register() && (type == T_LONG || type == T_DOUBLE)) { - Register reg2 = r_2->as_Register(); -#ifdef _LP64 - assert(reg2 == reg, "must be same register"); + if (type == T_LONG || type == T_DOUBLE) { opr = as_long_opr(reg); -#else - opr = as_long_opr(reg2, reg); -#endif // _LP64 } else if (is_reference_type(type)) { opr = as_oop_opr(reg); } else if (type == T_METADATA) { @@ -111,8 +104,6 @@ LIR_Opr FrameMap::long1_opr; LIR_Opr FrameMap::xmm0_float_opr; LIR_Opr FrameMap::xmm0_double_opr; -#ifdef _LP64 - LIR_Opr FrameMap::r8_opr; LIR_Opr FrameMap::r9_opr; LIR_Opr FrameMap::r10_opr; @@ -137,7 +128,6 @@ LIR_Opr FrameMap::r11_metadata_opr; LIR_Opr FrameMap::r12_metadata_opr; LIR_Opr FrameMap::r13_metadata_opr; LIR_Opr FrameMap::r14_metadata_opr; -#endif // _LP64 LIR_Opr FrameMap::_caller_save_cpu_regs[] = {}; LIR_Opr FrameMap::_caller_save_fpu_regs[] = {}; @@ -157,23 +147,17 @@ XMMRegister FrameMap::nr2xmmreg(int rnr) { void FrameMap::initialize() { assert(!_init_done, "once"); - assert(nof_cpu_regs == LP64_ONLY(16) NOT_LP64(8), "wrong number of CPU registers"); + assert(nof_cpu_regs == 16, "wrong number of CPU registers"); map_register(0, rsi); rsi_opr = LIR_OprFact::single_cpu(0); map_register(1, rdi); rdi_opr = LIR_OprFact::single_cpu(1); map_register(2, rbx); rbx_opr = LIR_OprFact::single_cpu(2); map_register(3, rax); rax_opr = LIR_OprFact::single_cpu(3); map_register(4, rdx); rdx_opr = LIR_OprFact::single_cpu(4); map_register(5, rcx); rcx_opr = LIR_OprFact::single_cpu(5); - -#ifndef _LP64 - // The unallocatable registers are at the end - map_register(6, rsp); - map_register(7, rbp); -#else - map_register( 6, r8); r8_opr = LIR_OprFact::single_cpu(6); - map_register( 7, r9); r9_opr = LIR_OprFact::single_cpu(7); - map_register( 8, r11); r11_opr = LIR_OprFact::single_cpu(8); - map_register( 9, r13); r13_opr = LIR_OprFact::single_cpu(9); + map_register(6, r8); r8_opr = LIR_OprFact::single_cpu(6); + map_register(7, r9); r9_opr = LIR_OprFact::single_cpu(7); + map_register(8, r11); r11_opr = LIR_OprFact::single_cpu(8); + map_register(9, r13); r13_opr = LIR_OprFact::single_cpu(9); map_register(10, r14); r14_opr = LIR_OprFact::single_cpu(10); // r12 is allocated conditionally. With compressed oops it holds // the heapbase value and is not visible to the allocator. @@ -183,15 +167,9 @@ void FrameMap::initialize() { map_register(13, r15); r15_opr = LIR_OprFact::single_cpu(13); map_register(14, rsp); map_register(15, rbp); -#endif // _LP64 -#ifdef _LP64 long0_opr = LIR_OprFact::double_cpu(3 /*eax*/, 3 /*eax*/); long1_opr = LIR_OprFact::double_cpu(2 /*ebx*/, 2 /*ebx*/); -#else - long0_opr = LIR_OprFact::double_cpu(3 /*eax*/, 4 /*edx*/); - long1_opr = LIR_OprFact::double_cpu(2 /*ebx*/, 5 /*ecx*/); -#endif // _LP64 xmm0_float_opr = LIR_OprFact::single_xmm(0); xmm0_double_opr = LIR_OprFact::double_xmm(0); @@ -201,16 +179,12 @@ void FrameMap::initialize() { _caller_save_cpu_regs[3] = rax_opr; _caller_save_cpu_regs[4] = rdx_opr; _caller_save_cpu_regs[5] = rcx_opr; - -#ifdef _LP64 _caller_save_cpu_regs[6] = r8_opr; _caller_save_cpu_regs[7] = r9_opr; _caller_save_cpu_regs[8] = r11_opr; _caller_save_cpu_regs[9] = r13_opr; _caller_save_cpu_regs[10] = r14_opr; _caller_save_cpu_regs[11] = r12_opr; -#endif // _LP64 - _xmm_regs[0] = xmm0; _xmm_regs[1] = xmm1; @@ -220,8 +194,6 @@ void FrameMap::initialize() { _xmm_regs[5] = xmm5; _xmm_regs[6] = xmm6; _xmm_regs[7] = xmm7; - -#ifdef _LP64 _xmm_regs[8] = xmm8; _xmm_regs[9] = xmm9; _xmm_regs[10] = xmm10; @@ -246,7 +218,6 @@ void FrameMap::initialize() { _xmm_regs[29] = xmm29; _xmm_regs[30] = xmm30; _xmm_regs[31] = xmm31; -#endif // _LP64 for (int i = 0; i < 8; i++) { _caller_save_fpu_regs[i] = LIR_OprFact::single_fpu(i); @@ -276,7 +247,6 @@ void FrameMap::initialize() { rsp_opr = as_pointer_opr(rsp); rbp_opr = as_pointer_opr(rbp); -#ifdef _LP64 r8_oop_opr = as_oop_opr(r8); r9_oop_opr = as_oop_opr(r9); r11_oop_opr = as_oop_opr(r11); @@ -290,7 +260,6 @@ void FrameMap::initialize() { r12_metadata_opr = as_metadata_opr(r12); r13_metadata_opr = as_metadata_opr(r13); r14_metadata_opr = as_metadata_opr(r14); -#endif // _LP64 VMRegPair regs; BasicType sig_bt = T_OBJECT; diff --git a/src/hotspot/cpu/x86/c1_FrameMap_x86.hpp b/src/hotspot/cpu/x86/c1_FrameMap_x86.hpp index ce892efbed243..08b872cb0951d 100644 --- a/src/hotspot/cpu/x86/c1_FrameMap_x86.hpp +++ b/src/hotspot/cpu/x86/c1_FrameMap_x86.hpp @@ -41,13 +41,8 @@ nof_xmm_regs = pd_nof_xmm_regs_frame_map, nof_caller_save_xmm_regs = pd_nof_caller_save_xmm_regs_frame_map, first_available_sp_in_frame = 0, -#ifndef _LP64 - frame_pad_in_bytes = 8, - nof_reg_args = 2 -#else frame_pad_in_bytes = 16, nof_reg_args = 6 -#endif // _LP64 }; private: @@ -81,8 +76,6 @@ static LIR_Opr rdx_metadata_opr; static LIR_Opr rcx_metadata_opr; -#ifdef _LP64 - static LIR_Opr r8_opr; static LIR_Opr r9_opr; static LIR_Opr r10_opr; @@ -108,28 +101,17 @@ static LIR_Opr r13_metadata_opr; static LIR_Opr r14_metadata_opr; -#endif // _LP64 - static LIR_Opr long0_opr; static LIR_Opr long1_opr; static LIR_Opr xmm0_float_opr; static LIR_Opr xmm0_double_opr; -#ifdef _LP64 static LIR_Opr as_long_opr(Register r) { return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r)); } static LIR_Opr as_pointer_opr(Register r) { return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r)); } -#else - static LIR_Opr as_long_opr(Register r, Register r2) { - return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r2)); - } - static LIR_Opr as_pointer_opr(Register r) { - return LIR_OprFact::single_cpu(cpu_reg2rnr(r)); - } -#endif // _LP64 // VMReg name for spilled physical FPU stack slot n static VMReg fpu_regname (int n); diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index ed16f81cba18a..fa1bfaa71dbac 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -169,7 +169,6 @@ void LIR_Assembler::push(LIR_Opr opr) { if (opr->is_single_cpu()) { __ push_reg(opr->as_register()); } else if (opr->is_double_cpu()) { - NOT_LP64(__ push_reg(opr->as_register_hi())); __ push_reg(opr->as_register_lo()); } else if (opr->is_stack()) { __ push_addr(frame_map()->address_for_slot(opr->single_stack_ix())); @@ -325,11 +324,9 @@ void LIR_Assembler::clinit_barrier(ciMethod* method) { Label L_skip_barrier; Register klass = rscratch1; - Register thread = LP64_ONLY( r15_thread ) NOT_LP64( noreg ); - assert(thread != noreg, "x86_32 not implemented"); __ mov_metadata(klass, method->holder()->constant_encoding()); - __ clinit_barrier(klass, thread, &L_skip_barrier /*L_fast_path*/); + __ clinit_barrier(klass, r15_thread, &L_skip_barrier /*L_fast_path*/); __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); @@ -401,11 +398,9 @@ int LIR_Assembler::emit_unwind_handler() { int offset = code_offset(); // Fetch the exception from TLS and clear out exception related thread state - Register thread = NOT_LP64(rsi) LP64_ONLY(r15_thread); - NOT_LP64(__ get_thread(thread)); - __ movptr(rax, Address(thread, JavaThread::exception_oop_offset())); - __ movptr(Address(thread, JavaThread::exception_oop_offset()), NULL_WORD); - __ movptr(Address(thread, JavaThread::exception_pc_offset()), NULL_WORD); + __ movptr(rax, Address(r15_thread, JavaThread::exception_oop_offset())); + __ movptr(Address(r15_thread, JavaThread::exception_oop_offset()), NULL_WORD); + __ movptr(Address(r15_thread, JavaThread::exception_pc_offset()), NULL_WORD); __ bind(_unwind_handler_entry); __ verify_not_null_oop(rax); @@ -427,14 +422,8 @@ int LIR_Assembler::emit_unwind_handler() { } if (compilation()->env()->dtrace_method_probes()) { -#ifdef _LP64 __ mov(rdi, r15_thread); __ mov_metadata(rsi, method()->constant_encoding()); -#else - __ get_thread(rax); - __ movptr(Address(rsp, 0), rax); - __ mov_metadata(Address(rsp, sizeof(void*)), method()->constant_encoding(), noreg); -#endif __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit))); } @@ -491,15 +480,9 @@ void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) { // Note: we do not need to round double result; float result has the right precision // the poll sets the condition code, but no data registers -#ifdef _LP64 - const Register thread = r15_thread; -#else - const Register thread = rbx; - __ get_thread(thread); -#endif code_stub->set_safepoint_offset(__ offset()); __ relocate(relocInfo::poll_return_type); - __ safepoint_poll(*code_stub->entry(), thread, true /* at_return */, true /* in_nmethod */); + __ safepoint_poll(*code_stub->entry(), r15_thread, true /* at_return */, true /* in_nmethod */); __ ret(0); } @@ -507,21 +490,14 @@ void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) { int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) { guarantee(info != nullptr, "Shouldn't be null"); int offset = __ offset(); -#ifdef _LP64 const Register poll_addr = rscratch1; __ movptr(poll_addr, Address(r15_thread, JavaThread::polling_page_offset())); -#else - assert(tmp->is_cpu_register(), "needed"); - const Register poll_addr = tmp->as_register(); - __ get_thread(poll_addr); - __ movptr(poll_addr, Address(poll_addr, in_bytes(JavaThread::polling_page_offset()))); -#endif add_debug_info_for_branch(info); __ relocate(relocInfo::poll_type); address pre_pc = __ pc(); __ testl(rax, Address(poll_addr, 0)); address post_pc = __ pc(); - guarantee(pointer_delta(post_pc, pre_pc, 1) == 2 LP64_ONLY(+1), "must be exact length"); + guarantee(pointer_delta(post_pc, pre_pc, 1) == 3, "must be exact length"); return offset; } @@ -555,12 +531,7 @@ void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_cod case T_LONG: { assert(patch_code == lir_patch_none, "no patching handled here"); -#ifdef _LP64 __ movptr(dest->as_register_lo(), (intptr_t)c->as_jlong()); -#else - __ movptr(dest->as_register_lo(), c->as_jint_lo()); - __ movptr(dest->as_register_hi(), c->as_jint_hi()); -#endif // _LP64 break; } @@ -636,17 +607,10 @@ void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) { case T_LONG: // fall through case T_DOUBLE: -#ifdef _LP64 __ movptr(frame_map()->address_for_slot(dest->double_stack_ix(), lo_word_offset_in_bytes), (intptr_t)c->as_jlong_bits(), rscratch1); -#else - __ movptr(frame_map()->address_for_slot(dest->double_stack_ix(), - lo_word_offset_in_bytes), c->as_jint_lo_bits()); - __ movptr(frame_map()->address_for_slot(dest->double_stack_ix(), - hi_word_offset_in_bytes), c->as_jint_hi_bits()); -#endif // _LP64 break; default: @@ -677,20 +641,15 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi if (UseCompressedOops && !wide) { __ movl(as_Address(addr), NULL_WORD); } else { -#ifdef _LP64 __ xorptr(rscratch1, rscratch1); null_check_here = code_offset(); __ movptr(as_Address(addr), rscratch1); -#else - __ movptr(as_Address(addr), NULL_WORD); -#endif } } else { if (is_literal_address(addr)) { ShouldNotReachHere(); __ movoop(as_Address(addr, noreg), c->as_jobject(), rscratch1); } else { -#ifdef _LP64 __ movoop(rscratch1, c->as_jobject()); if (UseCompressedOops && !wide) { __ encode_heap_oop(rscratch1); @@ -700,16 +659,12 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi null_check_here = code_offset(); __ movptr(as_Address_lo(addr), rscratch1); } -#else - __ movoop(as_Address(addr), c->as_jobject(), noreg); -#endif } } break; case T_LONG: // fall through case T_DOUBLE: -#ifdef _LP64 if (is_literal_address(addr)) { ShouldNotReachHere(); __ movptr(as_Address(addr, r15_thread), (intptr_t)c->as_jlong_bits()); @@ -718,11 +673,6 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi null_check_here = code_offset(); __ movptr(as_Address_lo(addr), r10); } -#else - // Always reachable in 32bit so this doesn't produce useless move literal - __ movptr(as_Address_hi(addr), c->as_jint_hi_bits()); - __ movptr(as_Address_lo(addr), c->as_jint_lo_bits()); -#endif // _LP64 break; case T_BOOLEAN: // fall through @@ -751,13 +701,11 @@ void LIR_Assembler::reg2reg(LIR_Opr src, LIR_Opr dest) { // move between cpu-registers if (dest->is_single_cpu()) { -#ifdef _LP64 if (src->type() == T_LONG) { // Can do LONG -> OBJECT move_regs(src->as_register_lo(), dest->as_register()); return; } -#endif assert(src->is_single_cpu(), "must match"); if (src->type() == T_OBJECT) { __ verify_oop(src->as_register()); @@ -765,39 +713,20 @@ void LIR_Assembler::reg2reg(LIR_Opr src, LIR_Opr dest) { move_regs(src->as_register(), dest->as_register()); } else if (dest->is_double_cpu()) { -#ifdef _LP64 if (is_reference_type(src->type())) { // Surprising to me but we can see move of a long to t_object __ verify_oop(src->as_register()); move_regs(src->as_register(), dest->as_register_lo()); return; } -#endif assert(src->is_double_cpu(), "must match"); Register f_lo = src->as_register_lo(); Register f_hi = src->as_register_hi(); Register t_lo = dest->as_register_lo(); Register t_hi = dest->as_register_hi(); -#ifdef _LP64 assert(f_hi == f_lo, "must be same"); assert(t_hi == t_lo, "must be same"); move_regs(f_lo, t_lo); -#else - assert(f_lo != f_hi && t_lo != t_hi, "invalid register allocation"); - - - if (f_lo == t_hi && f_hi == t_lo) { - swap_reg(f_lo, f_hi); - } else if (f_hi == t_lo) { - assert(f_lo != t_hi, "overwriting register"); - move_regs(f_hi, t_hi); - move_regs(f_lo, t_lo); - } else { - assert(f_hi != t_lo, "overwriting register"); - move_regs(f_lo, t_lo); - move_regs(f_hi, t_hi); - } -#endif // LP64 // move between xmm-registers } else if (dest->is_single_xmm()) { @@ -831,7 +760,6 @@ void LIR_Assembler::reg2stack(LIR_Opr src, LIR_Opr dest, BasicType type) { Address dstLO = frame_map()->address_for_slot(dest->double_stack_ix(), lo_word_offset_in_bytes); Address dstHI = frame_map()->address_for_slot(dest->double_stack_ix(), hi_word_offset_in_bytes); __ movptr (dstLO, src->as_register_lo()); - NOT_LP64(__ movptr (dstHI, src->as_register_hi())); } else if (src->is_single_xmm()) { Address dst_addr = frame_map()->address_for_slot(dest->single_stack_ix()); @@ -854,7 +782,6 @@ void LIR_Assembler::reg2mem(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch if (is_reference_type(type)) { __ verify_oop(src->as_register()); -#ifdef _LP64 if (UseCompressedOops && !wide) { __ movptr(compressed_src, src->as_register()); __ encode_heap_oop(compressed_src); @@ -862,7 +789,6 @@ void LIR_Assembler::reg2mem(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch info->oop_map()->set_narrowoop(compressed_src->as_VMReg()); } } -#endif } if (patch_code != lir_patch_none) { @@ -893,14 +819,6 @@ void LIR_Assembler::reg2mem(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch __ movptr(as_Address(to_addr), src->as_register()); } break; - case T_METADATA: - // We get here to store a method pointer to the stack to pass to - // a dtrace runtime call. This can't work on 64 bit with - // compressed klass ptrs: T_METADATA can be a compressed klass - // ptr or a 64 bit method pointer. - LP64_ONLY(ShouldNotReachHere()); - __ movptr(as_Address(to_addr), src->as_register()); - break; case T_ADDRESS: __ movptr(as_Address(to_addr), src->as_register()); break; @@ -911,35 +829,7 @@ void LIR_Assembler::reg2mem(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch case T_LONG: { Register from_lo = src->as_register_lo(); Register from_hi = src->as_register_hi(); -#ifdef _LP64 __ movptr(as_Address_lo(to_addr), from_lo); -#else - Register base = to_addr->base()->as_register(); - Register index = noreg; - if (to_addr->index()->is_register()) { - index = to_addr->index()->as_register(); - } - if (base == from_lo || index == from_lo) { - assert(base != from_hi, "can't be"); - assert(index == noreg || (index != base && index != from_hi), "can't handle this"); - __ movl(as_Address_hi(to_addr), from_hi); - if (patch != nullptr) { - patching_epilog(patch, lir_patch_high, base, info); - patch = new PatchingStub(_masm, PatchingStub::access_field_id); - patch_code = lir_patch_low; - } - __ movl(as_Address_lo(to_addr), from_lo); - } else { - assert(index == noreg || (index != base && index != from_lo), "can't handle this"); - __ movl(as_Address_lo(to_addr), from_lo); - if (patch != nullptr) { - patching_epilog(patch, lir_patch_low, base, info); - patch = new PatchingStub(_masm, PatchingStub::access_field_id); - patch_code = lir_patch_high; - } - __ movl(as_Address_hi(to_addr), from_hi); - } -#endif // _LP64 break; } @@ -988,7 +878,6 @@ void LIR_Assembler::stack2reg(LIR_Opr src, LIR_Opr dest, BasicType type) { Address src_addr_LO = frame_map()->address_for_slot(src->double_stack_ix(), lo_word_offset_in_bytes); Address src_addr_HI = frame_map()->address_for_slot(src->double_stack_ix(), hi_word_offset_in_bytes); __ movptr(dest->as_register_lo(), src_addr_LO); - NOT_LP64(__ movptr(dest->as_register_hi(), src_addr_HI)); } else if (dest->is_single_xmm()) { Address src_addr = frame_map()->address_for_slot(src->single_stack_ix()); @@ -1010,27 +899,14 @@ void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) { __ pushptr(frame_map()->address_for_slot(src ->single_stack_ix())); __ popptr (frame_map()->address_for_slot(dest->single_stack_ix())); } else { -#ifndef _LP64 - __ pushl(frame_map()->address_for_slot(src ->single_stack_ix())); - __ popl (frame_map()->address_for_slot(dest->single_stack_ix())); -#else //no pushl on 64bits __ movl(rscratch1, frame_map()->address_for_slot(src ->single_stack_ix())); __ movl(frame_map()->address_for_slot(dest->single_stack_ix()), rscratch1); -#endif } } else if (src->is_double_stack()) { -#ifdef _LP64 __ pushptr(frame_map()->address_for_slot(src ->double_stack_ix())); __ popptr (frame_map()->address_for_slot(dest->double_stack_ix())); -#else - __ pushl(frame_map()->address_for_slot(src ->double_stack_ix(), 0)); - // push and pop the part at src + wordSize, adding wordSize for the previous push - __ pushl(frame_map()->address_for_slot(src ->double_stack_ix(), 2 * wordSize)); - __ popl (frame_map()->address_for_slot(dest->double_stack_ix(), 2 * wordSize)); - __ popl (frame_map()->address_for_slot(dest->double_stack_ix(), 0)); -#endif // _LP64 } else { ShouldNotReachHere(); @@ -1113,44 +989,7 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch case T_LONG: { Register to_lo = dest->as_register_lo(); Register to_hi = dest->as_register_hi(); -#ifdef _LP64 __ movptr(to_lo, as_Address_lo(addr)); -#else - Register base = addr->base()->as_register(); - Register index = noreg; - if (addr->index()->is_register()) { - index = addr->index()->as_register(); - } - if ((base == to_lo && index == to_hi) || - (base == to_hi && index == to_lo)) { - // addresses with 2 registers are only formed as a result of - // array access so this code will never have to deal with - // patches or null checks. - assert(info == nullptr && patch == nullptr, "must be"); - __ lea(to_hi, as_Address(addr)); - __ movl(to_lo, Address(to_hi, 0)); - __ movl(to_hi, Address(to_hi, BytesPerWord)); - } else if (base == to_lo || index == to_lo) { - assert(base != to_hi, "can't be"); - assert(index == noreg || (index != base && index != to_hi), "can't handle this"); - __ movl(to_hi, as_Address_hi(addr)); - if (patch != nullptr) { - patching_epilog(patch, lir_patch_high, base, info); - patch = new PatchingStub(_masm, PatchingStub::access_field_id); - patch_code = lir_patch_low; - } - __ movl(to_lo, as_Address_lo(addr)); - } else { - assert(index == noreg || (index != base && index != to_lo), "can't handle this"); - __ movl(to_lo, as_Address_lo(addr)); - if (patch != nullptr) { - patching_epilog(patch, lir_patch_low, base, info); - patch = new PatchingStub(_masm, PatchingStub::access_field_id); - patch_code = lir_patch_high; - } - __ movl(to_hi, as_Address_hi(addr)); - } -#endif // _LP64 break; } @@ -1200,11 +1039,9 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch } if (is_reference_type(type)) { -#ifdef _LP64 if (UseCompressedOops && !wide) { __ decode_heap_oop(dest->as_register()); } -#endif __ verify_oop(dest->as_register()); } @@ -1299,21 +1136,11 @@ void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) { switch (op->bytecode()) { case Bytecodes::_i2l: -#ifdef _LP64 __ movl2ptr(dest->as_register_lo(), src->as_register()); -#else - move_regs(src->as_register(), dest->as_register_lo()); - move_regs(src->as_register(), dest->as_register_hi()); - __ sarl(dest->as_register_hi(), 31); -#endif // LP64 break; case Bytecodes::_l2i: -#ifdef _LP64 __ movl(dest->as_register(), src->as_register_lo()); -#else - move_regs(src->as_register_lo(), dest->as_register()); -#endif break; case Bytecodes::_i2b: @@ -1396,7 +1223,7 @@ void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) { Register len = op->len()->as_register(); - LP64_ONLY( __ movslq(len, len); ) + __ movslq(len, len); if (UseSlowPath || (!UseFastNewObjectArray && is_reference_type(op->type())) || @@ -1464,7 +1291,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L Register dst = op->result_opr()->as_register(); ciKlass* k = op->klass(); Register Rtmp1 = noreg; - Register tmp_load_klass = LP64_ONLY(rscratch1) NOT_LP64(noreg); + Register tmp_load_klass = rscratch1; // check if it needs to be profiled ciMethodData* md = nullptr; @@ -1526,29 +1353,19 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L if (!k->is_loaded()) { klass2reg_with_patching(k_RInfo, op->info_for_patch()); } else { -#ifdef _LP64 __ mov_metadata(k_RInfo, k->constant_encoding()); -#endif // _LP64 } __ verify_oop(obj); if (op->fast_check()) { // get object class // not a safepoint as obj null check happens earlier -#ifdef _LP64 if (UseCompressedClassPointers) { __ load_klass(Rtmp1, obj, tmp_load_klass); __ cmpptr(k_RInfo, Rtmp1); } else { __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); } -#else - if (k->is_loaded()) { - __ cmpklass(Address(obj, oopDesc::klass_offset_in_bytes()), k->constant_encoding()); - } else { - __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); - } -#endif __ jcc(Assembler::notEqual, *failure_target); // successful cast, fall through to profile or jump } else { @@ -1557,11 +1374,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L __ load_klass(klass_RInfo, obj, tmp_load_klass); if (k->is_loaded()) { // See if we get an immediate positive hit -#ifdef _LP64 __ cmpptr(k_RInfo, Address(klass_RInfo, k->super_check_offset())); -#else - __ cmpklass(Address(klass_RInfo, k->super_check_offset()), k->constant_encoding()); -#endif // _LP64 if ((juint)in_bytes(Klass::secondary_super_cache_offset()) != k->super_check_offset()) { __ jcc(Assembler::notEqual, *failure_target); // successful cast, fall through to profile or jump @@ -1569,19 +1382,11 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L // See if we get an immediate positive hit __ jcc(Assembler::equal, *success_target); // check for self -#ifdef _LP64 __ cmpptr(klass_RInfo, k_RInfo); -#else - __ cmpklass(klass_RInfo, k->constant_encoding()); -#endif // _LP64 __ jcc(Assembler::equal, *success_target); __ push(klass_RInfo); -#ifdef _LP64 __ push(k_RInfo); -#else - __ pushklass(k->constant_encoding(), noreg); -#endif // _LP64 __ call(RuntimeAddress(Runtime1::entry_for(C1StubId::slow_subtype_check_id))); __ pop(klass_RInfo); __ pop(klass_RInfo); @@ -1610,7 +1415,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { - Register tmp_load_klass = LP64_ONLY(rscratch1) NOT_LP64(noreg); + Register tmp_load_klass = rscratch1; LIR_Code code = op->code(); if (code == lir_store_check) { Register value = op->object()->as_register(); @@ -1714,17 +1519,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { - if (LP64_ONLY(false &&) op->code() == lir_cas_long) { - assert(op->cmp_value()->as_register_lo() == rax, "wrong register"); - assert(op->cmp_value()->as_register_hi() == rdx, "wrong register"); - assert(op->new_value()->as_register_lo() == rbx, "wrong register"); - assert(op->new_value()->as_register_hi() == rcx, "wrong register"); - Register addr = op->addr()->as_register(); - __ lock(); - NOT_LP64(__ cmpxchg8(Address(addr, 0))); - - } else if (op->code() == lir_cas_int || op->code() == lir_cas_obj ) { - NOT_LP64(assert(op->addr()->is_single_cpu(), "must be single");) + if (op->code() == lir_cas_int || op->code() == lir_cas_obj) { Register addr = (op->addr()->is_single_cpu() ? op->addr()->as_register() : op->addr()->as_register_lo()); Register newval = op->new_value()->as_register(); Register cmpval = op->cmp_value()->as_register(); @@ -1734,8 +1529,7 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { assert(cmpval != addr, "cmp and addr must be in different registers"); assert(newval != addr, "new value and addr must be in different registers"); - if ( op->code() == lir_cas_obj) { -#ifdef _LP64 + if (op->code() == lir_cas_obj) { if (UseCompressedOops) { __ encode_heap_oop(cmpval); __ mov(rscratch1, newval); @@ -1743,9 +1537,7 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { __ lock(); // cmpval (rax) is implicitly used by this instruction __ cmpxchgl(rscratch1, Address(addr, 0)); - } else -#endif - { + } else { __ lock(); __ cmpxchgptr(newval, Address(addr, 0)); } @@ -1754,7 +1546,6 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { __ lock(); __ cmpxchgl(newval, Address(addr, 0)); } -#ifdef _LP64 } else if (op->code() == lir_cas_long) { Register addr = (op->addr()->is_single_cpu() ? op->addr()->as_register() : op->addr()->as_register_lo()); Register newval = op->new_value()->as_register_lo(); @@ -1766,7 +1557,6 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { assert(newval != addr, "new value and addr must be in different registers"); __ lock(); __ cmpxchgq(newval, Address(addr, 0)); -#endif // _LP64 } else { Unimplemented(); } @@ -1809,12 +1599,10 @@ void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, L assert(opr2->cpu_regnrLo() != result->cpu_regnrLo() && opr2->cpu_regnrLo() != result->cpu_regnrHi(), "opr2 already overwritten by previous move"); assert(opr2->cpu_regnrHi() != result->cpu_regnrLo() && opr2->cpu_regnrHi() != result->cpu_regnrHi(), "opr2 already overwritten by previous move"); __ cmovptr(ncond, result->as_register_lo(), opr2->as_register_lo()); - NOT_LP64(__ cmovptr(ncond, result->as_register_hi(), opr2->as_register_hi());) } else if (opr2->is_single_stack()) { __ cmovl(ncond, result->as_register(), frame_map()->address_for_slot(opr2->single_stack_ix())); } else if (opr2->is_double_stack()) { __ cmovptr(ncond, result->as_register_lo(), frame_map()->address_for_slot(opr2->double_stack_ix(), lo_word_offset_in_bytes)); - NOT_LP64(__ cmovptr(ncond, result->as_register_hi(), frame_map()->address_for_slot(opr2->double_stack_ix(), hi_word_offset_in_bytes));) } else { ShouldNotReachHere(); } @@ -1890,28 +1678,16 @@ void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr // cpu register - cpu register Register rreg_lo = right->as_register_lo(); Register rreg_hi = right->as_register_hi(); - NOT_LP64(assert_different_registers(lreg_lo, lreg_hi, rreg_lo, rreg_hi)); - LP64_ONLY(assert_different_registers(lreg_lo, rreg_lo)); + assert_different_registers(lreg_lo, rreg_lo); switch (code) { case lir_add: __ addptr(lreg_lo, rreg_lo); - NOT_LP64(__ adcl(lreg_hi, rreg_hi)); break; case lir_sub: __ subptr(lreg_lo, rreg_lo); - NOT_LP64(__ sbbl(lreg_hi, rreg_hi)); break; case lir_mul: -#ifdef _LP64 __ imulq(lreg_lo, rreg_lo); -#else - assert(lreg_lo == rax && lreg_hi == rdx, "must be"); - __ imull(lreg_hi, rreg_lo); - __ imull(rreg_hi, lreg_lo); - __ addl (rreg_hi, lreg_hi); - __ mull (rreg_lo); - __ addl (lreg_hi, rreg_hi); -#endif // _LP64 break; default: ShouldNotReachHere(); @@ -1919,7 +1695,6 @@ void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr } else if (right->is_constant()) { // cpu register - constant -#ifdef _LP64 jlong c = right->as_constant_ptr()->as_jlong_bits(); __ movptr(r10, (intptr_t) c); switch (code) { @@ -1932,22 +1707,6 @@ void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr default: ShouldNotReachHere(); } -#else - jint c_lo = right->as_constant_ptr()->as_jint_lo(); - jint c_hi = right->as_constant_ptr()->as_jint_hi(); - switch (code) { - case lir_add: - __ addptr(lreg_lo, c_lo); - __ adcl(lreg_hi, c_hi); - break; - case lir_sub: - __ subptr(lreg_lo, c_lo); - __ sbbl(lreg_hi, c_hi); - break; - default: - ShouldNotReachHere(); - } -#endif // _LP64 } else { ShouldNotReachHere(); @@ -2123,7 +1882,6 @@ void LIR_Assembler::logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr Register l_lo = left->as_register_lo(); Register l_hi = left->as_register_hi(); if (right->is_constant()) { -#ifdef _LP64 __ mov64(rscratch1, right->as_constant_ptr()->as_jlong()); switch (code) { case lir_logic_and: @@ -2137,50 +1895,22 @@ void LIR_Assembler::logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr break; default: ShouldNotReachHere(); } -#else - int r_lo = right->as_constant_ptr()->as_jint_lo(); - int r_hi = right->as_constant_ptr()->as_jint_hi(); - switch (code) { - case lir_logic_and: - __ andl(l_lo, r_lo); - __ andl(l_hi, r_hi); - break; - case lir_logic_or: - __ orl(l_lo, r_lo); - __ orl(l_hi, r_hi); - break; - case lir_logic_xor: - __ xorl(l_lo, r_lo); - __ xorl(l_hi, r_hi); - break; - default: ShouldNotReachHere(); - } -#endif // _LP64 } else { -#ifdef _LP64 Register r_lo; if (is_reference_type(right->type())) { r_lo = right->as_register(); } else { r_lo = right->as_register_lo(); } -#else - Register r_lo = right->as_register_lo(); - Register r_hi = right->as_register_hi(); - assert(l_lo != r_hi, "overwriting registers"); -#endif switch (code) { case lir_logic_and: __ andptr(l_lo, r_lo); - NOT_LP64(__ andptr(l_hi, r_hi);) break; case lir_logic_or: __ orptr(l_lo, r_lo); - NOT_LP64(__ orptr(l_hi, r_hi);) break; case lir_logic_xor: __ xorptr(l_lo, r_lo); - NOT_LP64(__ xorptr(l_hi, r_hi);) break; default: ShouldNotReachHere(); } @@ -2189,19 +1919,7 @@ void LIR_Assembler::logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr Register dst_lo = dst->as_register_lo(); Register dst_hi = dst->as_register_hi(); -#ifdef _LP64 move_regs(l_lo, dst_lo); -#else - if (dst_lo == l_hi) { - assert(dst_hi != l_lo, "overwriting registers"); - move_regs(l_hi, dst_hi); - move_regs(l_lo, dst_lo); - } else { - assert(dst_lo != l_hi, "overwriting registers"); - move_regs(l_lo, dst_lo); - move_regs(l_hi, dst_hi); - } -#endif // _LP64 } } @@ -2329,27 +2047,11 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, Register xlo = opr1->as_register_lo(); Register xhi = opr1->as_register_hi(); if (opr2->is_double_cpu()) { -#ifdef _LP64 __ cmpptr(xlo, opr2->as_register_lo()); -#else - // cpu register - cpu register - Register ylo = opr2->as_register_lo(); - Register yhi = opr2->as_register_hi(); - __ subl(xlo, ylo); - __ sbbl(xhi, yhi); - if (condition == lir_cond_equal || condition == lir_cond_notEqual) { - __ orl(xhi, xlo); - } -#endif // _LP64 } else if (opr2->is_constant()) { // cpu register - constant 0 assert(opr2->as_jlong() == (jlong)0, "only handles zero"); -#ifdef _LP64 __ cmpptr(xlo, (int32_t)opr2->as_jlong()); -#else - assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "only handles equals case"); - __ orl(xhi, xlo); -#endif // _LP64 } else { ShouldNotReachHere(); } @@ -2398,12 +2100,10 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, } else if (opr1->is_address() && opr2->is_constant()) { LIR_Const* c = opr2->as_constant_ptr(); -#ifdef _LP64 if (is_reference_type(c->type())) { assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "need to reverse"); __ movoop(rscratch1, c->as_jobject()); } -#endif // LP64 if (op->info() != nullptr) { add_debug_info_for_null_check_here(op->info()); } @@ -2412,13 +2112,9 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, if (c->type() == T_INT) { __ cmpl(as_Address(addr), c->as_jint()); } else if (is_reference_type(c->type())) { -#ifdef _LP64 // %%% Make this explode if addr isn't reachable until we figure out a // better strategy by giving noreg as the temp for as_Address __ cmpoop(rscratch1, as_Address(addr, noreg)); -#else - __ cmpoop(as_Address(addr), c->as_jobject()); -#endif // _LP64 } else { ShouldNotReachHere(); } @@ -2442,7 +2138,6 @@ void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Op } } else { assert(code == lir_cmp_l2i, "check"); -#ifdef _LP64 Label done; Register dest = dst->as_register(); __ cmpptr(left->as_register_lo(), right->as_register_lo()); @@ -2451,13 +2146,6 @@ void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Op __ setb(Assembler::notZero, dest); __ movzbl(dest, dest); __ bind(done); -#else - __ lcmp2int(left->as_register_hi(), - left->as_register_lo(), - right->as_register_hi(), - right->as_register_lo()); - move_regs(left->as_register_hi(), dst->as_register()); -#endif // _LP64 } } @@ -2583,22 +2271,12 @@ void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, LIR_Opr count, LIR_Opr Register lo = left->as_register_lo(); Register hi = left->as_register_hi(); assert(lo != SHIFT_count && hi != SHIFT_count, "left cannot be ECX"); -#ifdef _LP64 switch (code) { case lir_shl: __ shlptr(lo); break; case lir_shr: __ sarptr(lo); break; case lir_ushr: __ shrptr(lo); break; default: ShouldNotReachHere(); } -#else - - switch (code) { - case lir_shl: __ lshl(hi, lo); break; - case lir_shr: __ lshr(hi, lo, true); break; - case lir_ushr: __ lshr(hi, lo, false); break; - default: ShouldNotReachHere(); - } -#endif // LP64 } else { ShouldNotReachHere(); } @@ -2619,9 +2297,6 @@ void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, jint count, LIR_Opr de default: ShouldNotReachHere(); } } else if (dest->is_double_cpu()) { -#ifndef _LP64 - Unimplemented(); -#else // first move left into dest so that left is not destroyed by the shift Register value = dest->as_register_lo(); count = count & 0x1F; // Java spec @@ -2633,7 +2308,6 @@ void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, jint count, LIR_Opr de case lir_ushr: __ shrptr(value, count); break; default: ShouldNotReachHere(); } -#endif // _LP64 } else { ShouldNotReachHere(); } @@ -2683,7 +2357,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { Register dst_pos = op->dst_pos()->as_register(); Register length = op->length()->as_register(); Register tmp = op->tmp()->as_register(); - Register tmp_load_klass = LP64_ONLY(rscratch1) NOT_LP64(noreg); + Register tmp_load_klass = rscratch1; Register tmp2 = UseCompactObjectHeaders ? rscratch2 : noreg; CodeStub* stub = op->stub(); @@ -2708,13 +2382,11 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { // these are just temporary placements until we need to reload store_parameter(src_pos, 3); store_parameter(src, 4); - NOT_LP64(assert(src == rcx && src_pos == rdx, "mismatch in calling convention");) address copyfunc_addr = StubRoutines::generic_arraycopy(); assert(copyfunc_addr != nullptr, "generic arraycopy stub required"); // pass arguments: may push as this is not a safepoint; SP must be fix at each safepoint -#ifdef _LP64 // The arguments are in java calling convention so we can trivially shift them to C // convention assert_different_registers(c_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4); @@ -2745,21 +2417,6 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { #endif __ call(RuntimeAddress(copyfunc_addr)); #endif // _WIN64 -#else - __ push(length); - __ push(dst_pos); - __ push(dst); - __ push(src_pos); - __ push(src); - -#ifndef PRODUCT - if (PrintC1Statistics) { - __ incrementl(ExternalAddress((address)&Runtime1::_generic_arraycopystub_cnt), rscratch1); - } -#endif - __ call_VM_leaf(copyfunc_addr, 5); // removes pushed parameter from the stack - -#endif // _LP64 __ testl(rax, rax); __ jcc(Assembler::equal, *stub->continuation()); @@ -2865,10 +2522,8 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { __ jcc(Assembler::less, *stub->entry()); } -#ifdef _LP64 __ movl2ptr(src_pos, src_pos); //higher 32bits must be null __ movl2ptr(dst_pos, dst_pos); //higher 32bits must be null -#endif if (flags & LIR_OpArrayCopy::type_check) { // We don't know the array types are compatible @@ -2932,21 +2587,6 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { store_parameter(src_pos, 3); store_parameter(src, 4); -#ifndef _LP64 - Address dst_klass_addr = Address(dst, oopDesc::klass_offset_in_bytes()); - __ movptr(tmp, dst_klass_addr); - __ movptr(tmp, Address(tmp, ObjArrayKlass::element_klass_offset())); - __ push(tmp); - __ movl(tmp, Address(tmp, Klass::super_check_offset_offset())); - __ push(tmp); - __ push(length); - __ lea(tmp, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); - __ push(tmp); - __ lea(tmp, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); - __ push(tmp); - - __ call_VM_leaf(copyfunc_addr, 5); -#else __ movl2ptr(length, length); //higher 32bits must be null __ lea(c_rarg0, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); @@ -2973,8 +2613,6 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { __ call(RuntimeAddress(copyfunc_addr)); #endif -#endif - #ifndef PRODUCT if (PrintC1Statistics) { Label failed; @@ -3030,11 +2668,9 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { // but not necessarily exactly of type default_type. Label known_ok, halt; __ mov_metadata(tmp, default_type->constant_encoding()); -#ifdef _LP64 if (UseCompressedClassPointers) { __ encode_klass_not_null(tmp, rscratch1); } -#endif if (basic_type != T_OBJECT) { __ cmp_klass(tmp, dst, tmp2); @@ -3059,21 +2695,12 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { } #endif -#ifdef _LP64 assert_different_registers(c_rarg0, dst, dst_pos, length); __ lea(c_rarg0, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); assert_different_registers(c_rarg1, length); __ lea(c_rarg1, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); __ mov(c_rarg2, length); -#else - __ lea(tmp, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); - store_parameter(tmp, 0); - __ lea(tmp, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); - store_parameter(tmp, 1); - store_parameter(length, 2); -#endif // _LP64 - bool disjoint = (flags & LIR_OpArrayCopy::overlapping) == 0; bool aligned = (flags & LIR_OpArrayCopy::unaligned) == 0; const char *name; @@ -3146,7 +2773,7 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { ciMethod* method = op->profiled_method(); int bci = op->profiled_bci(); ciMethod* callee = op->profiled_callee(); - Register tmp_load_klass = LP64_ONLY(rscratch1) NOT_LP64(noreg); + Register tmp_load_klass = rscratch1; // Update counter for all call types ciMethodData* md = method->method_data_or_null(); @@ -3217,7 +2844,7 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { Register obj = op->obj()->as_register(); Register tmp = op->tmp()->as_pointer_register(); - Register tmp_load_klass = LP64_ONLY(rscratch1) NOT_LP64(noreg); + Register tmp_load_klass = rscratch1; Address mdo_addr = as_Address(op->mdp()->as_address_ptr()); ciKlass* exact_klass = op->exact_klass(); intptr_t current_klass = op->current_klass(); @@ -3237,17 +2864,9 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { #ifdef ASSERT if (obj == tmp) { -#ifdef _LP64 assert_different_registers(obj, rscratch1, mdo_addr.base(), mdo_addr.index()); -#else - assert_different_registers(obj, mdo_addr.base(), mdo_addr.index()); -#endif } else { -#ifdef _LP64 assert_different_registers(obj, tmp, rscratch1, mdo_addr.base(), mdo_addr.index()); -#else - assert_different_registers(obj, tmp, mdo_addr.base(), mdo_addr.index()); -#endif } #endif if (do_null) { @@ -3301,9 +2920,7 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { } else { __ load_klass(tmp, obj, tmp_load_klass); } -#ifdef _LP64 __ mov(rscratch1, tmp); // save original value before XOR -#endif __ xorptr(tmp, mdo_addr); __ testptr(tmp, TypeEntries::type_klass_mask); // klass seen before, nothing to do. The unknown bit may have been @@ -3316,7 +2933,6 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { if (TypeEntries::is_type_none(current_klass)) { __ testptr(mdo_addr, TypeEntries::type_mask); __ jccb(Assembler::zero, none); -#ifdef _LP64 // There is a chance that the checks above (re-reading profiling // data from memory) fail if another thread has just set the // profiling to this obj's klass @@ -3324,7 +2940,6 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { __ xorptr(tmp, mdo_addr); __ testptr(tmp, TypeEntries::type_klass_mask); __ jccb(Assembler::zero, next); -#endif } } else { assert(ciTypeEntries::valid_ciklass(current_klass) != nullptr && @@ -3418,22 +3033,9 @@ void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) { } else if (left->is_double_cpu()) { Register lo = left->as_register_lo(); -#ifdef _LP64 Register dst = dest->as_register_lo(); __ movptr(dst, lo); __ negptr(dst); -#else - Register hi = left->as_register_hi(); - __ lneg(hi, lo); - if (dest->as_register_lo() == hi) { - assert(dest->as_register_hi() != lo, "destroying register"); - move_regs(hi, dest->as_register_hi()); - move_regs(lo, dest->as_register_lo()); - } else { - move_regs(lo, dest->as_register_lo()); - move_regs(hi, dest->as_register_hi()); - } -#endif // _LP64 } else if (dest->is_single_xmm()) { assert(!tmp->is_valid(), "do not need temporary"); @@ -3496,13 +3098,7 @@ void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, if (src->is_double_xmm()) { if (dest->is_double_cpu()) { -#ifdef _LP64 __ movdq(dest->as_register_lo(), src->as_xmm_double_reg()); -#else - __ movdl(dest->as_register_lo(), src->as_xmm_double_reg()); - __ psrlq(src->as_xmm_double_reg(), 32); - __ movdl(dest->as_register_hi(), src->as_xmm_double_reg()); -#endif // _LP64 } else if (dest->is_double_stack()) { __ movdbl(frame_map()->address_for_slot(dest->double_stack_ix()), src->as_xmm_double_reg()); } else if (dest->is_address()) { @@ -3519,6 +3115,7 @@ void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, } else { ShouldNotReachHere(); } + } else { ShouldNotReachHere(); } @@ -3601,12 +3198,7 @@ void LIR_Assembler::on_spin_wait() { void LIR_Assembler::get_thread(LIR_Opr result_reg) { assert(result_reg->is_register(), "check"); -#ifdef _LP64 - // __ get_thread(result_reg->as_register_lo()); __ mov(result_reg->as_register(), r15_thread); -#else - __ get_thread(result_reg->as_register()); -#endif // _LP64 } @@ -3627,7 +3219,6 @@ void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr } else if (data->is_oop()) { assert (code == lir_xchg, "xadd for oops"); Register obj = data->as_register(); -#ifdef _LP64 if (UseCompressedOops) { __ encode_heap_oop(obj); __ xchgl(obj, as_Address(src->as_address_ptr())); @@ -3635,11 +3226,7 @@ void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr } else { __ xchgptr(obj, as_Address(src->as_address_ptr())); } -#else - __ xchgl(obj, as_Address(src->as_address_ptr())); -#endif } else if (data->type() == T_LONG) { -#ifdef _LP64 assert(data->as_register_lo() == data->as_register_hi(), "should be a single register"); if (code == lir_xadd) { __ lock(); @@ -3647,9 +3234,6 @@ void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr } else { __ xchgq(data->as_register_lo(), as_Address(src->as_address_ptr())); } -#else - ShouldNotReachHere(); -#endif } else { ShouldNotReachHere(); } diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp index c8f97cece6d8b..8524dc90276f0 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp @@ -46,9 +46,9 @@ Register recv, Label* update_done); enum { - _call_stub_size = NOT_LP64(15) LP64_ONLY(28), + _call_stub_size = 28, _exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175), - _deopt_handler_size = NOT_LP64(10) LP64_ONLY(17) + _deopt_handler_size = 17 }; public: diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index fe6d6a58b00dd..60ce3419dfb42 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -142,7 +142,6 @@ bool LIRGenerator::can_inline_as_constant(LIR_Const* c) const { LIR_Opr LIRGenerator::safepoint_poll_register() { - NOT_LP64( return new_register(T_ADDRESS); ) return LIR_OprFact::illegalOpr; } @@ -152,7 +151,6 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, assert(base->is_register(), "must be"); if (index->is_constant()) { LIR_Const *constant = index->as_constant_ptr(); -#ifdef _LP64 jlong c; if (constant->type() == T_INT) { c = (jlong(index->as_jint()) << shift) + disp; @@ -167,11 +165,6 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, __ move(index, tmp); return new LIR_Address(base, tmp, type); } -#else - return new LIR_Address(base, - ((intx)(constant->as_jint()) << shift) + disp, - type); -#endif } else { return new LIR_Address(base, index, (LIR_Address::Scale)shift, disp, type); } @@ -185,7 +178,6 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o LIR_Address* addr; if (index_opr->is_constant()) { int elem_size = type2aelembytes(type); -#ifdef _LP64 jint index = index_opr->as_jint(); jlong disp = offset_in_bytes + (jlong)(index) * elem_size; if (disp > max_jint) { @@ -197,28 +189,12 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o } else { addr = new LIR_Address(array_opr, (intx)disp, type); } -#else - // A displacement overflow can also occur for x86 but that is not a problem due to the 32-bit address range! - // Let's assume an array 'a' and an access with displacement 'disp'. When disp overflows, then "a + disp" will - // always be negative (i.e. underflows the 32-bit address range): - // Let N = 2^32: a + signed_overflow(disp) = a + disp - N. - // "a + disp" is always smaller than N. If an index was chosen which would point to an address beyond N, then - // range checks would catch that and throw an exception. Thus, a + disp < 0 holds which means that it always - // underflows the 32-bit address range: - // unsigned_underflow(a + signed_overflow(disp)) = unsigned_underflow(a + disp - N) - // = (a + disp - N) + N = a + disp - // This shows that we still end up at the correct address with a displacement overflow due to the 32-bit address - // range limitation. This overflow only needs to be handled if addresses can be larger as on 64-bit platforms. - addr = new LIR_Address(array_opr, offset_in_bytes + (intx)(index_opr->as_jint()) * elem_size, type); -#endif // _LP64 } else { -#ifdef _LP64 if (index_opr->type() == T_INT) { LIR_Opr tmp = new_register(T_LONG); __ convert(Bytecodes::_i2l, index_opr, tmp); index_opr = tmp; } -#endif // _LP64 addr = new LIR_Address(array_opr, index_opr, LIR_Address::scale(type), @@ -358,34 +334,12 @@ void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) { left.dont_load_item(); } -#ifndef _LP64 - // do not load right operand if it is a constant. only 0 and 1 are - // loaded because there are special instructions for loading them - // without memory access (not needed for SSE2 instructions) - bool must_load_right = false; - if (right.is_constant()) { - LIR_Const* c = right.result()->as_constant_ptr(); - assert(c != nullptr, "invalid constant"); - assert(c->type() == T_FLOAT || c->type() == T_DOUBLE, "invalid type"); - - if (c->type() == T_FLOAT) { - must_load_right = UseSSE < 1 && (c->is_one_float() || c->is_zero_float()); - } else { - must_load_right = UseSSE < 2 && (c->is_one_double() || c->is_zero_double()); - } - } -#endif // !LP64 - if (must_load_both) { // frem and drem destroy also right operand, so move it to a new register right.set_destroys_register(); right.load_item(); } else if (right.is_register()) { right.load_item(); -#ifndef _LP64 - } else if (must_load_right) { - right.load_item(); -#endif // !LP64 } else { right.dont_load_item(); } @@ -395,7 +349,6 @@ void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) { tmp = new_register(T_DOUBLE); } -#ifdef _LP64 if (x->op() == Bytecodes::_frem || x->op() == Bytecodes::_drem) { // frem and drem are implemented as a direct call into the runtime. LIRItem left(x->x(), this); @@ -430,27 +383,6 @@ void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) { arithmetic_op_fpu(x->op(), reg, left.result(), right.result(), tmp); set_result(x, reg); } -#else - if ((UseSSE >= 1 && x->op() == Bytecodes::_frem) || (UseSSE >= 2 && x->op() == Bytecodes::_drem)) { - // special handling for frem and drem: no SSE instruction, so must use FPU with temporary fpu stack slots - LIR_Opr fpu0, fpu1; - if (x->op() == Bytecodes::_frem) { - fpu0 = LIR_OprFact::single_fpu(0); - fpu1 = LIR_OprFact::single_fpu(1); - } else { - fpu0 = LIR_OprFact::double_fpu(0); - fpu1 = LIR_OprFact::double_fpu(1); - } - __ move(right.result(), fpu1); // order of left and right operand is important! - __ move(left.result(), fpu0); - __ rem (fpu0, fpu1, fpu0); - __ move(fpu0, reg); - - } else { - arithmetic_op_fpu(x->op(), reg, left.result(), right.result(), tmp); - } - set_result(x, reg); -#endif // _LP64 } @@ -740,7 +672,7 @@ LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) value.load_item(); // Because we want a 2-arg form of xchg and xadd __ move(value.result(), result); - assert(type == T_INT || is_oop LP64_ONLY( || type == T_LONG ), "unexpected type"); + assert(type == T_INT || is_oop || type == T_LONG, "unexpected type"); __ xchg(addr, result, result, LIR_OprFact::illegalOpr); return result; } @@ -750,7 +682,7 @@ LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) { value.load_item(); // Because we want a 2-arg form of xchg and xadd __ move(value.result(), result); - assert(type == T_INT LP64_ONLY( || type == T_LONG ), "unexpected type"); + assert(type == T_INT || type == T_LONG, "unexpected type"); __ xadd(addr, result, result, LIR_OprFact::illegalOpr); return result; } @@ -788,10 +720,7 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { if (x->id() == vmIntrinsics::_dexp || x->id() == vmIntrinsics::_dlog || x->id() == vmIntrinsics::_dpow || x->id() == vmIntrinsics::_dcos || x->id() == vmIntrinsics::_dsin || x->id() == vmIntrinsics::_dtan || - x->id() == vmIntrinsics::_dlog10 -#ifdef _LP64 - || x->id() == vmIntrinsics::_dtanh -#endif + x->id() == vmIntrinsics::_dlog10 || x->id() == vmIntrinsics::_dtanh ) { do_LibmIntrinsic(x); return; @@ -799,12 +728,6 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { LIRItem value(x->argument_at(0), this); - bool use_fpu = false; -#ifndef _LP64 - if (UseSSE < 2) { - value.set_destroys_register(); - } -#endif // !LP64 value.load_item(); LIR_Opr calc_input = value.result(); @@ -832,10 +755,6 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { default: ShouldNotReachHere(); } - - if (use_fpu) { - __ move(calc_result, x->operand()); - } } void LIRGenerator::do_LibmIntrinsic(Intrinsic* x) { @@ -956,20 +875,6 @@ void LIRGenerator::do_ArrayCopy(Intrinsic* x) { flags = 0; } -#ifndef _LP64 - src.load_item_force (FrameMap::rcx_oop_opr); - src_pos.load_item_force (FrameMap::rdx_opr); - dst.load_item_force (FrameMap::rax_oop_opr); - dst_pos.load_item_force (FrameMap::rbx_opr); - length.load_item_force (FrameMap::rdi_opr); - LIR_Opr tmp = (FrameMap::rsi_opr); - - if (expected_type != nullptr && flags == 0) { - FrameMap* f = Compilation::current()->frame_map(); - f->update_reserved_argument_area_size(3 * BytesPerWord); - } -#else - // The java calling convention will give us enough registers // so that on the stub side the args will be perfect already. // On the other slow/special case side we call C and the arg @@ -985,7 +890,6 @@ void LIRGenerator::do_ArrayCopy(Intrinsic* x) { length.load_item_force (FrameMap::as_opr(j_rarg4)); LIR_Opr tmp = FrameMap::as_opr(j_rarg5); -#endif // LP64 set_no_result(x); @@ -1027,18 +931,11 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) { } LIR_Opr base_op = buf.result(); -#ifndef _LP64 - if (!is_updateBytes) { // long b raw address - base_op = new_register(T_INT); - __ convert(Bytecodes::_l2i, buf.result(), base_op); - } -#else if (index->is_valid()) { LIR_Opr tmp = new_register(T_LONG); __ convert(Bytecodes::_i2l, index, tmp); index = tmp; } -#endif LIR_Address* a = new LIR_Address(base_op, index, @@ -1172,14 +1069,6 @@ void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) { } LIR_Opr result_b = b.result(); -#ifndef _LP64 - result_a = new_register(T_INT); - __ convert(Bytecodes::_l2i, a.result(), result_a); - result_b = new_register(T_INT); - __ convert(Bytecodes::_l2i, b.result(), result_b); -#endif - - LIR_Address* addr_a = new LIR_Address(result_a, result_aOffset, constant_aOffset, @@ -1214,7 +1103,6 @@ void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) { } void LIRGenerator::do_Convert(Convert* x) { -#ifdef _LP64 LIRItem value(x->value(), this); value.load_item(); LIR_Opr input = value.result(); @@ -1222,66 +1110,6 @@ void LIRGenerator::do_Convert(Convert* x) { __ convert(x->op(), input, result); assert(result->is_virtual(), "result must be virtual register"); set_result(x, result); -#else - // flags that vary for the different operations and different SSE-settings - bool fixed_input = false, fixed_result = false, round_result = false, needs_stub = false; - - switch (x->op()) { - case Bytecodes::_i2l: // fall through - case Bytecodes::_l2i: // fall through - case Bytecodes::_i2b: // fall through - case Bytecodes::_i2c: // fall through - case Bytecodes::_i2s: fixed_input = false; fixed_result = false; round_result = false; needs_stub = false; break; - - case Bytecodes::_f2d: fixed_input = UseSSE == 1; fixed_result = false; round_result = false; needs_stub = false; break; - case Bytecodes::_d2f: fixed_input = false; fixed_result = UseSSE == 1; round_result = UseSSE < 1; needs_stub = false; break; - case Bytecodes::_i2f: fixed_input = false; fixed_result = false; round_result = UseSSE < 1; needs_stub = false; break; - case Bytecodes::_i2d: fixed_input = false; fixed_result = false; round_result = false; needs_stub = false; break; - case Bytecodes::_f2i: fixed_input = false; fixed_result = false; round_result = false; needs_stub = true; break; - case Bytecodes::_d2i: fixed_input = false; fixed_result = false; round_result = false; needs_stub = true; break; - case Bytecodes::_l2f: fixed_input = false; fixed_result = UseSSE >= 1; round_result = UseSSE < 1; needs_stub = false; break; - case Bytecodes::_l2d: fixed_input = false; fixed_result = UseSSE >= 2; round_result = UseSSE < 2; needs_stub = false; break; - case Bytecodes::_f2l: fixed_input = true; fixed_result = true; round_result = false; needs_stub = false; break; - case Bytecodes::_d2l: fixed_input = true; fixed_result = true; round_result = false; needs_stub = false; break; - default: ShouldNotReachHere(); - } - - LIRItem value(x->value(), this); - value.load_item(); - LIR_Opr input = value.result(); - LIR_Opr result = rlock(x); - - // arguments of lir_convert - LIR_Opr conv_input = input; - LIR_Opr conv_result = result; - ConversionStub* stub = nullptr; - - if (fixed_input) { - conv_input = fixed_register_for(input->type()); - __ move(input, conv_input); - } - - assert(fixed_result == false || round_result == false, "cannot set both"); - if (fixed_result) { - conv_result = fixed_register_for(result->type()); - } else if (round_result) { - result = new_register(result->type()); - set_vreg_flag(result, must_start_in_memory); - } - - if (needs_stub) { - stub = new ConversionStub(x->op(), conv_input, conv_result); - } - - __ convert(x->op(), conv_input, conv_result, stub); - - if (result != conv_result) { - __ move(conv_result, result); - } - - assert(result->is_virtual(), "result must be virtual register"); - set_result(x, result); -#endif // _LP64 } @@ -1547,13 +1375,7 @@ void LIRGenerator::do_If(If* x) { LIR_Opr LIRGenerator::getThreadPointer() { -#ifdef _LP64 return FrameMap::as_pointer_opr(r15_thread); -#else - LIR_Opr result = new_register(T_INT); - __ get_thread(result); - return result; -#endif // } void LIRGenerator::trace_block_entry(BlockBegin* block) { @@ -1598,12 +1420,6 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, LIR_Opr temp_double = new_register(T_DOUBLE); __ volatile_move(LIR_OprFact::address(address), temp_double, T_LONG, info); __ volatile_move(temp_double, result, T_LONG); -#ifndef _LP64 - if (UseSSE < 2) { - // no spill slot needed in SSE2 mode because xmm->cpu register move is possible - set_vreg_flag(result, must_start_in_memory); - } -#endif // !LP64 } else { __ load(address, result, info); } diff --git a/src/hotspot/cpu/x86/c1_LIR_x86.cpp b/src/hotspot/cpu/x86/c1_LIR_x86.cpp index adcc53c44ce14..ce831c5f95649 100644 --- a/src/hotspot/cpu/x86/c1_LIR_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIR_x86.cpp @@ -58,16 +58,9 @@ LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) { #ifndef PRODUCT void LIR_Address::verify() const { -#ifdef _LP64 assert(base()->is_cpu_register(), "wrong base operand"); assert(index()->is_illegal() || index()->is_double_cpu(), "wrong index operand"); assert(base()->type() == T_ADDRESS || base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA, "wrong type for addresses"); -#else - assert(base()->is_single_cpu(), "wrong base operand"); - assert(index()->is_illegal() || index()->is_single_cpu(), "wrong index operand"); - assert(base()->type() == T_ADDRESS || base()->type() == T_OBJECT || base()->type() == T_INT || base()->type() == T_METADATA, - "wrong type for addresses"); -#endif } #endif // PRODUCT diff --git a/src/hotspot/cpu/x86/c1_LinearScan_x86.hpp b/src/hotspot/cpu/x86/c1_LinearScan_x86.hpp index 8669c9ab8a10b..62a1bd6510e41 100644 --- a/src/hotspot/cpu/x86/c1_LinearScan_x86.hpp +++ b/src/hotspot/cpu/x86/c1_LinearScan_x86.hpp @@ -26,12 +26,6 @@ #define CPU_X86_C1_LINEARSCAN_X86_HPP inline bool LinearScan::is_processed_reg_num(int reg_num) { -#ifndef _LP64 - // rsp and rbp (numbers 6 ancd 7) are ignored - assert(FrameMap::rsp_opr->cpu_regnr() == 6, "wrong assumption below"); - assert(FrameMap::rbp_opr->cpu_regnr() == 7, "wrong assumption below"); - assert(reg_num >= 0, "invalid reg_num"); -#else // rsp and rbp, r10, r15 (numbers [12,15]) are ignored // r12 (number 11) is conditional on compressed oops. assert(FrameMap::r12_opr->cpu_regnr() == 11, "wrong assumption below"); @@ -40,16 +34,10 @@ inline bool LinearScan::is_processed_reg_num(int reg_num) { assert(FrameMap::rsp_opr->cpu_regnrLo() == 14, "wrong assumption below"); assert(FrameMap::rbp_opr->cpu_regnrLo() == 15, "wrong assumption below"); assert(reg_num >= 0, "invalid reg_num"); -#endif // _LP64 return reg_num <= FrameMap::last_cpu_reg() || reg_num >= pd_nof_cpu_regs_frame_map; } inline int LinearScan::num_physical_regs(BasicType type) { - // Intel requires two cpu registers for long, - // but requires only one fpu register for double - if (LP64_ONLY(false &&) type == T_LONG) { - return 2; - } return 1; } diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index 238a1bd048a9f..7ffa6d9bdd4fd 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -62,15 +62,8 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr } if (LockingMode == LM_LIGHTWEIGHT) { -#ifdef _LP64 const Register thread = r15_thread; lightweight_lock(disp_hdr, obj, hdr, thread, tmp, slow_case); -#else - // Implicit null check. - movptr(hdr, Address(obj, oopDesc::mark_offset_in_bytes())); - // Lacking registers and thread on x86_32. Always take slow path. - jmp(slow_case); -#endif } else if (LockingMode == LM_LEGACY) { Label done; // Load object header @@ -135,12 +128,7 @@ void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_ verify_oop(obj); if (LockingMode == LM_LIGHTWEIGHT) { -#ifdef _LP64 lightweight_unlock(obj, disp_hdr, r15_thread, hdr, slow_case); -#else - // Lacking registers and thread on x86_32. Always take slow path. - jmp(slow_case); -#endif } else if (LockingMode == LM_LEGACY) { // test if object header is pointing to the displaced header, and if so, restore // the displaced header in the object - if the object header is not pointing to @@ -169,7 +157,6 @@ void C1_MacroAssembler::try_allocate(Register obj, Register var_size_in_bytes, i void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register t1, Register t2) { assert_different_registers(obj, klass, len, t1, t2); -#ifdef _LP64 if (UseCompactObjectHeaders) { movptr(t1, Address(klass, Klass::prototype_header_offset())); movptr(Address(obj, oopDesc::mark_offset_in_bytes()), t1); @@ -178,16 +165,13 @@ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register movptr(t1, klass); encode_klass_not_null(t1, rscratch1); movl(Address(obj, oopDesc::klass_offset_in_bytes()), t1); - } else -#endif - { + } else { movptr(Address(obj, oopDesc::mark_offset_in_bytes()), checked_cast(markWord::prototype().value())); movptr(Address(obj, oopDesc::klass_offset_in_bytes()), klass); } if (len->is_valid()) { movl(Address(obj, arrayOopDesc::length_offset_in_bytes()), len); -#ifdef _LP64 int base_offset = arrayOopDesc::length_offset_in_bytes() + BytesPerInt; if (!is_aligned(base_offset, BytesPerWord)) { assert(is_aligned(base_offset, BytesPerInt), "must be 4-byte aligned"); @@ -195,14 +179,10 @@ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register xorl(t1, t1); movl(Address(obj, base_offset), t1); } -#endif - } -#ifdef _LP64 - else if (UseCompressedClassPointers && !UseCompactObjectHeaders) { + } else if (UseCompressedClassPointers && !UseCompactObjectHeaders) { xorptr(t1, t1); store_klass_gap(obj, t1); } -#endif } @@ -265,8 +245,6 @@ void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register bind(loop); movptr(Address(obj, index, Address::times_8, hdr_size_in_bytes - (1*BytesPerWord)), t1_zero); - NOT_LP64(movptr(Address(obj, index, Address::times_8, hdr_size_in_bytes - (2*BytesPerWord)), - t1_zero);) decrement(index); jcc(Assembler::notZero, loop); } diff --git a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp index cb4cb3af8c3d4..bb5111fa65236 100644 --- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp +++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp @@ -51,27 +51,18 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, int args_size) { // setup registers - const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread); // is callee-saved register (Visual C++ calling conventions) + const Register thread = r15_thread; // is callee-saved register (Visual C++ calling conventions) assert(!(oop_result1->is_valid() || metadata_result->is_valid()) || oop_result1 != metadata_result, "registers must be different"); assert(oop_result1 != thread && metadata_result != thread, "registers must be different"); assert(args_size >= 0, "illegal args_size"); bool align_stack = false; -#ifdef _LP64 + // At a method handle call, the stack may not be properly aligned // when returning with an exception. align_stack = (stub_id() == (int)C1StubId::handle_exception_from_callee_id); -#endif -#ifdef _LP64 mov(c_rarg0, thread); set_num_rt_args(0); // Nothing on stack -#else - set_num_rt_args(1 + args_size); - - // push java thread (becomes first argument of C function) - get_thread(thread); - push(thread); -#endif // _LP64 int call_offset = -1; if (!align_stack) { @@ -104,9 +95,6 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre #endif reset_last_Java_frame(thread, true); - // discard thread and arguments - NOT_LP64(addptr(rsp, num_rt_args()*BytesPerWord)); - // check for pending exceptions { Label L; cmpptr(Address(thread, Thread::pending_exception_offset()), NULL_WORD); @@ -144,17 +132,12 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1) { -#ifdef _LP64 mov(c_rarg1, arg1); -#else - push(arg1); -#endif // _LP64 return call_RT(oop_result1, metadata_result, entry, 1); } int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2) { -#ifdef _LP64 if (c_rarg1 == arg2) { if (c_rarg2 == arg1) { xchgq(arg1, arg2); @@ -166,16 +149,11 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre mov(c_rarg1, arg1); mov(c_rarg2, arg2); } -#else - push(arg2); - push(arg1); -#endif // _LP64 return call_RT(oop_result1, metadata_result, entry, 2); } int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3) { -#ifdef _LP64 // if there is any conflict use the stack if (arg1 == c_rarg2 || arg1 == c_rarg3 || arg2 == c_rarg1 || arg2 == c_rarg3 || @@ -191,11 +169,6 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre mov(c_rarg2, arg2); mov(c_rarg3, arg3); } -#else - push(arg3); - push(arg2); - push(arg1); -#endif // _LP64 return call_RT(oop_result1, metadata_result, entry, 3); } @@ -262,20 +235,13 @@ const int xmm_regs_as_doubles_size_in_slots = FrameMap::nof_xmm_regs * 2; // but the code in save_live_registers will take the argument count into // account. // -#ifdef _LP64 - #define SLOT2(x) x, - #define SLOT_PER_WORD 2 -#else - #define SLOT2(x) - #define SLOT_PER_WORD 1 -#endif // _LP64 +#define SLOT2(x) x, +#define SLOT_PER_WORD 2 enum reg_save_layout { // 64bit needs to keep stack 16 byte aligned. So we add some alignment dummies to make that // happen and will assert if the stack size we create is misaligned -#ifdef _LP64 align_dummy_0, align_dummy_1, -#endif // _LP64 #ifdef _WIN64 // Windows always allocates space for it's argument registers (see // frame::arg_reg_save_area_bytes). @@ -291,7 +257,6 @@ enum reg_save_layout { fpu_state_end_off = fpu_state_off + (FPUStateSizeInWords / SLOT_PER_WORD), // 352 marker = fpu_state_end_off, SLOT2(markerH) // 352, 356 extra_space_offset, // 360 -#ifdef _LP64 r15_off = extra_space_offset, r15H_off, // 360, 364 r14_off, r14H_off, // 368, 372 r13_off, r13H_off, // 376, 380 @@ -301,9 +266,6 @@ enum reg_save_layout { r9_off, r9H_off, // 408, 412 r8_off, r8H_off, // 416, 420 rdi_off, rdiH_off, // 424, 428 -#else - rdi_off = extra_space_offset, -#endif // _LP64 rsi_off, SLOT2(rsiH_off) // 432, 436 rbp_off, SLOT2(rbpH_off) // 440, 444 rsp_off, SLOT2(rspH_off) // 448, 452 @@ -329,8 +291,8 @@ static OopMap* generate_oop_map(StubAssembler* sasm, int num_rt_args, bool save_fpu_registers = true) { // In 64bit all the args are in regs so there are no additional stack slots - LP64_ONLY(num_rt_args = 0); - LP64_ONLY(assert((reg_save_frame_size * VMRegImpl::stack_slot_size) % 16 == 0, "must be 16 byte aligned");) + num_rt_args = 0; + assert((reg_save_frame_size * VMRegImpl::stack_slot_size) % 16 == 0, "must be 16 byte aligned"); int frame_size_in_slots = reg_save_frame_size + num_rt_args; // args + thread sasm->set_frame_size(frame_size_in_slots / VMRegImpl::slots_per_word); @@ -343,7 +305,6 @@ static OopMap* generate_oop_map(StubAssembler* sasm, int num_rt_args, map->set_callee_saved(VMRegImpl::stack2reg(rbx_off + num_rt_args), rbx->as_VMReg()); map->set_callee_saved(VMRegImpl::stack2reg(rsi_off + num_rt_args), rsi->as_VMReg()); map->set_callee_saved(VMRegImpl::stack2reg(rdi_off + num_rt_args), rdi->as_VMReg()); -#ifdef _LP64 map->set_callee_saved(VMRegImpl::stack2reg(r8_off + num_rt_args), r8->as_VMReg()); map->set_callee_saved(VMRegImpl::stack2reg(r9_off + num_rt_args), r9->as_VMReg()); map->set_callee_saved(VMRegImpl::stack2reg(r10_off + num_rt_args), r10->as_VMReg()); @@ -369,37 +330,10 @@ static OopMap* generate_oop_map(StubAssembler* sasm, int num_rt_args, map->set_callee_saved(VMRegImpl::stack2reg(r13H_off + num_rt_args), r13->as_VMReg()->next()); map->set_callee_saved(VMRegImpl::stack2reg(r14H_off + num_rt_args), r14->as_VMReg()->next()); map->set_callee_saved(VMRegImpl::stack2reg(r15H_off + num_rt_args), r15->as_VMReg()->next()); -#endif // _LP64 int xmm_bypass_limit = FrameMap::get_num_caller_save_xmms(); if (save_fpu_registers) { -#ifndef _LP64 - if (UseSSE < 2) { - int fpu_off = float_regs_as_doubles_off; - for (int n = 0; n < FrameMap::nof_fpu_regs; n++) { - VMReg fpu_name_0 = FrameMap::fpu_regname(n); - map->set_callee_saved(VMRegImpl::stack2reg(fpu_off + num_rt_args), fpu_name_0); - // %%% This is really a waste but we'll keep things as they were for now - if (true) { - map->set_callee_saved(VMRegImpl::stack2reg(fpu_off + 1 + num_rt_args), fpu_name_0->next()); - } - fpu_off += 2; - } - assert(fpu_off == fpu_state_off, "incorrect number of fpu stack slots"); - - if (UseSSE == 1) { - int xmm_off = xmm_regs_as_doubles_off; - for (int n = 0; n < FrameMap::nof_fpu_regs; n++) { - VMReg xmm_name_0 = as_XMMRegister(n)->as_VMReg(); - map->set_callee_saved(VMRegImpl::stack2reg(xmm_off + num_rt_args), xmm_name_0); - xmm_off += 2; - } - assert(xmm_off == float_regs_as_doubles_off, "incorrect number of xmm registers"); - } - } -#endif // !LP64 - if (UseSSE >= 2) { int xmm_off = xmm_regs_as_doubles_off; for (int n = 0; n < FrameMap::nof_xmm_regs; n++) { @@ -426,14 +360,7 @@ void C1_MacroAssembler::save_live_registers_no_oop_map(bool save_fpu_registers) __ block_comment("save_live_registers"); // Push CPU state in multiple of 16 bytes -#ifdef _LP64 __ save_legacy_gprs(); -#else - __ pusha(); -#endif - - // assert(float_regs_as_doubles_off % 2 == 0, "misaligned offset"); - // assert(xmm_regs_as_doubles_off % 2 == 0, "misaligned offset"); __ subptr(rsp, extra_space_offset * VMRegImpl::stack_slot_size); @@ -442,46 +369,6 @@ void C1_MacroAssembler::save_live_registers_no_oop_map(bool save_fpu_registers) #endif if (save_fpu_registers) { -#ifndef _LP64 - if (UseSSE < 2) { - // save FPU stack - __ fnsave(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size)); - __ fwait(); - -#ifdef ASSERT - Label ok; - __ cmpw(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size), StubRoutines::x86::fpu_cntrl_wrd_std()); - __ jccb(Assembler::equal, ok); - __ stop("corrupted control word detected"); - __ bind(ok); -#endif - - // Reset the control word to guard against exceptions being unmasked - // since fstp_d can cause FPU stack underflow exceptions. Write it - // into the on stack copy and then reload that to make sure that the - // current and future values are correct. - __ movw(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size), StubRoutines::x86::fpu_cntrl_wrd_std()); - __ frstor(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size)); - - // Save the FPU registers in de-opt-able form - int offset = 0; - for (int n = 0; n < FrameMap::nof_fpu_regs; n++) { - __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + offset)); - offset += 8; - } - - if (UseSSE == 1) { - // save XMM registers as float because double not supported without SSE2(num MMX == num fpu) - int offset = 0; - for (int n = 0; n < FrameMap::nof_fpu_regs; n++) { - XMMRegister xmm_name = as_XMMRegister(n); - __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + offset), xmm_name); - offset += 8; - } - } - } -#endif // !_LP64 - if (UseSSE >= 2) { // save XMM registers // XMM registers can contain float or double values, but this is not known here, @@ -497,16 +384,12 @@ void C1_MacroAssembler::save_live_registers_no_oop_map(bool save_fpu_registers) } } } - - // FPU stack must be empty now - NOT_LP64( __ verify_FPU(0, "save_live_registers"); ) } #undef __ #define __ sasm-> static void restore_fpu(C1_MacroAssembler* sasm, bool restore_fpu_registers) { -#ifdef _LP64 if (restore_fpu_registers) { // restore XMM registers int xmm_bypass_limit = FrameMap::get_num_caller_save_xmms(); @@ -517,38 +400,6 @@ static void restore_fpu(C1_MacroAssembler* sasm, bool restore_fpu_registers) { offset += 8; } } -#else - if (restore_fpu_registers) { - if (UseSSE >= 2) { - // restore XMM registers - int xmm_bypass_limit = FrameMap::nof_xmm_regs; - int offset = 0; - for (int n = 0; n < xmm_bypass_limit; n++) { - XMMRegister xmm_name = as_XMMRegister(n); - __ movdbl(xmm_name, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + offset)); - offset += 8; - } - } else if (UseSSE == 1) { - // restore XMM registers(num MMX == num fpu) - int offset = 0; - for (int n = 0; n < FrameMap::nof_fpu_regs; n++) { - XMMRegister xmm_name = as_XMMRegister(n); - __ movflt(xmm_name, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + offset)); - offset += 8; - } - } - - if (UseSSE < 2) { - __ frstor(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size)); - } else { - // check that FPU stack is really empty - __ verify_FPU(0, "restore_live_registers"); - } - } else { - // check that FPU stack is really empty - __ verify_FPU(0, "restore_live_registers"); - } -#endif // _LP64 #ifdef ASSERT { @@ -570,12 +421,7 @@ void C1_MacroAssembler::restore_live_registers(bool restore_fpu_registers) { __ block_comment("restore_live_registers"); restore_fpu(this, restore_fpu_registers); -#ifdef _LP64 __ restore_legacy_gprs(); -#else - __ popa(); -#endif - } @@ -584,7 +430,6 @@ void C1_MacroAssembler::restore_live_registers_except_rax(bool restore_fpu_regis restore_fpu(this, restore_fpu_registers); -#ifdef _LP64 __ movptr(r15, Address(rsp, 0)); __ movptr(r14, Address(rsp, wordSize)); __ movptr(r13, Address(rsp, 2 * wordSize)); @@ -602,17 +447,6 @@ void C1_MacroAssembler::restore_live_registers_except_rax(bool restore_fpu_regis __ movptr(rcx, Address(rsp, 14 * wordSize)); __ addptr(rsp, 16 * wordSize); -#else - - __ pop(rdi); - __ pop(rsi); - __ pop(rbp); - __ pop(rbx); // skip this value - __ pop(rbx); - __ pop(rdx); - __ pop(rcx); - __ addptr(rsp, BytesPerWord); -#endif // _LP64 } #undef __ @@ -639,12 +473,7 @@ void Runtime1::initialize_pd() { // return: offset in 64-bit words. uint Runtime1::runtime_blob_current_thread_offset(frame f) { -#ifdef _LP64 return r15_off / 2; // rsp offsets are in halfwords -#else - Unimplemented(); - return 0; -#endif } // Target: the entry point of the method that creates and posts the exception oop. @@ -664,15 +493,8 @@ OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address targe // Load arguments for exception that are passed as arguments into the stub. if (has_argument) { -#ifdef _LP64 __ movptr(c_rarg1, Address(rbp, 2*BytesPerWord)); __ movptr(c_rarg2, Address(rbp, 3*BytesPerWord)); -#else - __ movptr(temp_reg, Address(rbp, 3*BytesPerWord)); - __ push(temp_reg); - __ movptr(temp_reg, Address(rbp, 2*BytesPerWord)); - __ push(temp_reg); -#endif // _LP64 } int call_offset = __ call_RT(noreg, noreg, target, num_rt_args - 1); @@ -692,7 +514,7 @@ OopMapSet* Runtime1::generate_handle_exception(C1StubId id, StubAssembler *sasm) const Register exception_oop = rax; const Register exception_pc = rdx; // other registers used in this stub - const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread); + const Register thread = r15_thread; // Save registers, if required. OopMapSet* oop_maps = new OopMapSet(); @@ -725,7 +547,7 @@ OopMapSet* Runtime1::generate_handle_exception(C1StubId id, StubAssembler *sasm) case C1StubId::handle_exception_from_callee_id: { // At this point all registers except exception oop (RAX) and // exception pc (RDX) are dead. - const int frame_size = 2 /*BP, return address*/ NOT_LP64(+ 1 /*thread*/) WIN64_ONLY(+ frame::arg_reg_save_area_bytes / BytesPerWord); + const int frame_size = 2 /*BP, return address*/ WIN64_ONLY(+ frame::arg_reg_save_area_bytes / BytesPerWord); oop_map = new OopMap(frame_size * VMRegImpl::slots_per_word, 0); sasm->set_frame_size(frame_size); WIN64_ONLY(__ subq(rsp, frame::arg_reg_save_area_bytes)); @@ -734,21 +556,11 @@ OopMapSet* Runtime1::generate_handle_exception(C1StubId id, StubAssembler *sasm) default: ShouldNotReachHere(); } -#if !defined(_LP64) && defined(COMPILER2) - if (UseSSE < 2 && !CompilerConfig::is_c1_only_no_jvmci()) { - // C2 can leave the fpu stack dirty - __ empty_FPU_stack(); - } -#endif // !_LP64 && COMPILER2 - // verify that only rax, and rdx is valid at this time __ invalidate_registers(false, true, true, false, true, true); // verify that rax, contains a valid exception __ verify_not_null_oop(exception_oop); - // load address of JavaThread object for thread-local data - NOT_LP64(__ get_thread(thread);) - #ifdef ASSERT // check that fields in JavaThread for exception oop and issuing pc are // empty before writing to them @@ -815,11 +627,11 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) { // incoming parameters const Register exception_oop = rax; // callee-saved copy of exception_oop during runtime call - const Register exception_oop_callee_saved = NOT_LP64(rsi) LP64_ONLY(r14); + const Register exception_oop_callee_saved = r14; // other registers used in this stub const Register exception_pc = rdx; const Register handler_addr = rbx; - const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread); + const Register thread = r15_thread; if (AbortVMOnException) { __ enter(); @@ -834,7 +646,6 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) { #ifdef ASSERT // check that fields in JavaThread for exception oop and issuing pc are empty - NOT_LP64(__ get_thread(thread);) Label oop_empty; __ cmpptr(Address(thread, JavaThread::exception_oop_offset()), 0); __ jcc(Assembler::equal, oop_empty); @@ -848,14 +659,10 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) { __ bind(pc_empty); #endif - // clear the FPU stack in case any FPU results are left behind - NOT_LP64( __ empty_FPU_stack(); ) - // save exception_oop in callee-saved register to preserve it during runtime calls __ verify_not_null_oop(exception_oop); __ movptr(exception_oop_callee_saved, exception_oop); - NOT_LP64(__ get_thread(thread);) // Get return address (is on top of stack after leave). __ movptr(exception_pc, Address(rsp, 0)); @@ -905,18 +712,10 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) { OopMap* oop_map = save_live_registers(sasm, num_rt_args); -#ifdef _LP64 const Register thread = r15_thread; // No need to worry about dummy __ mov(c_rarg0, thread); -#else - __ push(rax); // push dummy - - const Register thread = rdi; // is callee-saved register (Visual C++ calling conventions) - // push java thread (becomes first argument of C function) - __ get_thread(thread); - __ push(thread); -#endif // _LP64 + __ set_last_Java_frame(thread, noreg, rbp, nullptr, rscratch1); // do the call __ call(RuntimeAddress(target)); @@ -936,10 +735,6 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) { __ pop(rax); #endif __ reset_last_Java_frame(thread, true); -#ifndef _LP64 - __ pop(rcx); // discard thread arg - __ pop(rcx); // discard dummy -#endif // _LP64 // check for pending exceptions { Label L; @@ -1166,15 +961,8 @@ OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) { // This is called via call_runtime so the arguments // will be place in C abi locations -#ifdef _LP64 __ verify_oop(c_rarg0); __ mov(rax, c_rarg0); -#else - // The object is passed on the stack and we haven't pushed a - // frame yet so it's one work away from top of stack. - __ movptr(rax, Address(rsp, 1 * BytesPerWord)); - __ verify_oop(rax); -#endif // _LP64 // load the klass and check the has finalizer flag Label register_finalizer; @@ -1467,9 +1255,8 @@ OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) { // the live registers get saved. save_live_registers(sasm, 1); - __ NOT_LP64(push(rax)) LP64_ONLY(mov(c_rarg0, rax)); + __ mov(c_rarg0, rax); __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, static_cast(SharedRuntime::dtrace_object_alloc)))); - NOT_LP64(__ pop(rax)); restore_live_registers(sasm); } @@ -1477,7 +1264,6 @@ OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) { case C1StubId::fpu2long_stub_id: { -#ifdef _LP64 Label done; __ cvttsd2siq(rax, Address(rsp, wordSize)); __ cmp64(rax, ExternalAddress((address) StubRoutines::x86::double_sign_flip())); @@ -1489,78 +1275,6 @@ OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) { __ pop(rax); __ bind(done); __ ret(0); -#else - // rax, and rdx are destroyed, but should be free since the result is returned there - // preserve rsi,ecx - __ push(rsi); - __ push(rcx); - - // check for NaN - Label return0, do_return, return_min_jlong, do_convert; - - Address value_high_word(rsp, wordSize + 4); - Address value_low_word(rsp, wordSize); - Address result_high_word(rsp, 3*wordSize + 4); - Address result_low_word(rsp, 3*wordSize); - - __ subptr(rsp, 32); // more than enough on 32bit - __ fst_d(value_low_word); - __ movl(rax, value_high_word); - __ andl(rax, 0x7ff00000); - __ cmpl(rax, 0x7ff00000); - __ jcc(Assembler::notEqual, do_convert); - __ movl(rax, value_high_word); - __ andl(rax, 0xfffff); - __ orl(rax, value_low_word); - __ jcc(Assembler::notZero, return0); - - __ bind(do_convert); - __ fnstcw(Address(rsp, 0)); - __ movzwl(rax, Address(rsp, 0)); - __ orl(rax, 0xc00); - __ movw(Address(rsp, 2), rax); - __ fldcw(Address(rsp, 2)); - __ fwait(); - __ fistp_d(result_low_word); - __ fldcw(Address(rsp, 0)); - __ fwait(); - // This gets the entire long in rax on 64bit - __ movptr(rax, result_low_word); - // testing of high bits - __ movl(rdx, result_high_word); - __ mov(rcx, rax); - // What the heck is the point of the next instruction??? - __ xorl(rcx, 0x0); - __ movl(rsi, 0x80000000); - __ xorl(rsi, rdx); - __ orl(rcx, rsi); - __ jcc(Assembler::notEqual, do_return); - __ fldz(); - __ fcomp_d(value_low_word); - __ fnstsw_ax(); - __ sahf(); - __ jcc(Assembler::above, return_min_jlong); - // return max_jlong - __ movl(rdx, 0x7fffffff); - __ movl(rax, 0xffffffff); - __ jmp(do_return); - - __ bind(return_min_jlong); - __ movl(rdx, 0x80000000); - __ xorl(rax, rax); - __ jmp(do_return); - - __ bind(return0); - __ fpop(); - __ xorptr(rdx,rdx); - __ xorptr(rax,rax); - - __ bind(do_return); - __ addptr(rsp, 32); - __ pop(rcx); - __ pop(rsi); - __ ret(0); -#endif // _LP64 } break; From 39549f89905019fa90dd20ff8b6822c1351cbaa6 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 7 Apr 2025 09:13:43 +0000 Subject: [PATCH 0414/1101] 8352116: Deadlock with GCLocker and JVMTI after JDK-8192647 Reviewed-by: kbarrett, tschatzl, eosterlund --- src/hotspot/share/gc/shared/gcLocker.cpp | 9 ++++---- .../share/gc/shared/gcVMOperations.cpp | 21 +++++++++++++------ src/hotspot/share/runtime/mutexLocker.cpp | 4 +++- src/hotspot/share/runtime/mutexLocker.hpp | 1 + 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcLocker.cpp b/src/hotspot/share/gc/shared/gcLocker.cpp index aa13209a37a02..caf752f70c8d9 100644 --- a/src/hotspot/share/gc/shared/gcLocker.cpp +++ b/src/hotspot/share/gc/shared/gcLocker.cpp @@ -65,8 +65,8 @@ volatile bool GCLocker::_is_gc_request_pending; DEBUG_ONLY(uint64_t GCLocker::_verify_in_cr_count;) void GCLocker::initialize() { - assert(Heap_lock != nullptr, "inv"); - _lock = Heap_lock; + assert(JNICritical_lock != nullptr, "inv"); + _lock = JNICritical_lock; _is_gc_request_pending = false; DEBUG_ONLY(_verify_in_cr_count = 0;) @@ -82,7 +82,8 @@ bool GCLocker::is_active() { } void GCLocker::block() { - assert(_lock->is_locked(), "precondition"); + // _lock is held from the beginning of block() to the end of of unblock(). + _lock->lock(); assert(Atomic::load(&_is_gc_request_pending) == false, "precondition"); GCLockerTimingDebugLogger logger("Thread blocked to start GC."); @@ -116,10 +117,10 @@ void GCLocker::block() { } void GCLocker::unblock() { - assert(_lock->is_locked(), "precondition"); assert(Atomic::load(&_is_gc_request_pending) == true, "precondition"); Atomic::store(&_is_gc_request_pending, false); + _lock->unlock(); } void GCLocker::enter_slow(JavaThread* current_thread) { diff --git a/src/hotspot/share/gc/shared/gcVMOperations.cpp b/src/hotspot/share/gc/shared/gcVMOperations.cpp index b28007962d3e2..8e5768ce6a98c 100644 --- a/src/hotspot/share/gc/shared/gcVMOperations.cpp +++ b/src/hotspot/share/gc/shared/gcVMOperations.cpp @@ -93,6 +93,11 @@ bool VM_GC_Operation::skip_operation() const { return skip; } +static bool should_use_gclocker() { + // Only Serial and Parallel use GCLocker to synchronize with threads in JNI critical-sections, in order to handle pinned objects. + return UseSerialGC || UseParallelGC; +} + bool VM_GC_Operation::doit_prologue() { assert(((_gc_cause != GCCause::_no_gc) && (_gc_cause != GCCause::_no_cause_specified)), "Illegal GCCause"); @@ -106,17 +111,21 @@ bool VM_GC_Operation::doit_prologue() { proper_unit_for_byte_size(NewSize))); } + + if (should_use_gclocker()) { + GCLocker::block(); + } VM_GC_Sync_Operation::doit_prologue(); // Check invocations if (skip_operation()) { // skip collection Heap_lock->unlock(); + if (should_use_gclocker()) { + GCLocker::unblock(); + } _prologue_succeeded = false; } else { - if (UseSerialGC || UseParallelGC) { - GCLocker::block(); - } _prologue_succeeded = true; } return _prologue_succeeded; @@ -124,9 +133,6 @@ bool VM_GC_Operation::doit_prologue() { void VM_GC_Operation::doit_epilogue() { - if (UseSerialGC || UseParallelGC) { - GCLocker::unblock(); - } // GC thread root traversal likely used OopMapCache a lot, which // might have created lots of old entries. Trigger the cleanup now. OopMapCache::try_trigger_cleanup(); @@ -134,6 +140,9 @@ void VM_GC_Operation::doit_epilogue() { Heap_lock->notify_all(); } VM_GC_Sync_Operation::doit_epilogue(); + if (should_use_gclocker()) { + GCLocker::unblock(); + } } bool VM_GC_HeapInspection::doit_prologue() { diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 2733cbcb14c2f..3db53d038b669 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -46,6 +46,7 @@ Mutex* CompiledIC_lock = nullptr; Mutex* VMStatistic_lock = nullptr; Mutex* JmethodIdCreation_lock = nullptr; Mutex* JfieldIdCreation_lock = nullptr; +Monitor* JNICritical_lock = nullptr; Mutex* JvmtiThreadState_lock = nullptr; Monitor* EscapeBarrier_lock = nullptr; Monitor* JvmtiVTMSTransition_lock = nullptr; @@ -318,7 +319,8 @@ void mutex_init() { MUTEX_DEFL(Threads_lock , PaddedMonitor, CompileThread_lock, true); MUTEX_DEFL(Compile_lock , PaddedMutex , MethodCompileQueue_lock); - MUTEX_DEFL(Heap_lock , PaddedMonitor, AdapterHandlerLibrary_lock); + MUTEX_DEFL(JNICritical_lock , PaddedMonitor, AdapterHandlerLibrary_lock); // used for JNI critical regions + MUTEX_DEFL(Heap_lock , PaddedMonitor, JNICritical_lock); MUTEX_DEFL(PerfDataMemAlloc_lock , PaddedMutex , Heap_lock); MUTEX_DEFL(PerfDataManager_lock , PaddedMutex , Heap_lock); diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index 1913c64d6a621..bd2073dfe882b 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -44,6 +44,7 @@ extern Mutex* CompiledIC_lock; // a lock used to guard compile extern Mutex* VMStatistic_lock; // a lock used to guard statistics count increment extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers +extern Monitor* JNICritical_lock; // a lock used while synchronizing with threads entering/leaving JNI critical regions extern Mutex* JvmtiThreadState_lock; // a lock on modification of JVMTI thread data extern Monitor* EscapeBarrier_lock; // a lock to sync reallocating and relocking objects because of JVMTI access extern Monitor* JvmtiVTMSTransition_lock; // a lock for Virtual Thread Mount State transition (VTMS transition) management From 32d6d031514be9cfee5b0fd778cb738b7ff9d770 Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Mon, 7 Apr 2025 09:57:12 +0000 Subject: [PATCH 0415/1101] 8349348: Refactor ClassLoaderDeadlock.sh and Deadlock.sh to run fully in java Reviewed-by: jpai, mullan --- .../ClassLoaderDeadlock.java | 11 +- .../ClassLoaderDeadlock.sh | 106 ------------------ .../ClassLoaderDeadlock/Deadlock.java | 11 +- .../Security/ClassLoaderDeadlock/Deadlock.sh | 66 ----------- 4 files changed, 17 insertions(+), 177 deletions(-) delete mode 100644 test/jdk/java/security/Security/ClassLoaderDeadlock/ClassLoaderDeadlock.sh delete mode 100644 test/jdk/java/security/Security/ClassLoaderDeadlock/Deadlock.sh diff --git a/test/jdk/java/security/Security/ClassLoaderDeadlock/ClassLoaderDeadlock.java b/test/jdk/java/security/Security/ClassLoaderDeadlock/ClassLoaderDeadlock.java index f5af071654c61..d2794e70a2d9e 100644 --- a/test/jdk/java/security/Security/ClassLoaderDeadlock/ClassLoaderDeadlock.java +++ b/test/jdk/java/security/Security/ClassLoaderDeadlock/ClassLoaderDeadlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,7 +21,14 @@ * questions. */ -// See bug 5094825 / ClassLoadDeadlock.sh +/* +* @test +* @bug 5094825 +* @summary verify no deadlock if crypto provider in other classloader is used to verify signed jars +* @library ./Deadlock.jar +* @compile provider/HashProvider.java +* @run main/othervm/timeout=30 ClassLoaderDeadlock +*/ import java.net.*; diff --git a/test/jdk/java/security/Security/ClassLoaderDeadlock/ClassLoaderDeadlock.sh b/test/jdk/java/security/Security/ClassLoaderDeadlock/ClassLoaderDeadlock.sh deleted file mode 100644 index e2e573928535e..0000000000000 --- a/test/jdk/java/security/Security/ClassLoaderDeadlock/ClassLoaderDeadlock.sh +++ /dev/null @@ -1,106 +0,0 @@ -# -# Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# @test -# @bug 5094825 -# @summary verify no deadlock if crypto provider in other classloader is used to verify signed jars -# -# @run shell/timeout=30 ClassLoaderDeadlock.sh - -# set a few environment variables so that the shell-script can run stand-alone -# in the source directory -if [ "${TESTSRC}" = "" ] ; then - TESTSRC="." -fi - -if [ "${TESTCLASSES}" = "" ] ; then - TESTCLASSES="." -fi - -if [ "${TESTJAVA}" = "" ] ; then - echo "TESTJAVA not set. Test cannot execute." - echo "FAILED!!!" - exit 1 -fi - -if [ "${COMPILEJAVA}" = "" ]; then - COMPILEJAVA="${TESTJAVA}" -fi - -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - Linux ) - PATHSEP=":" - FILESEP="/" - ;; - Darwin ) - PATHSEP=":" - FILESEP="/" - ;; - AIX ) - PATHSEP=":" - FILESEP="/" - ;; - CYGWIN* ) - PATHSEP=";" - FILESEP="/" - ;; - Windows* ) - PATHSEP=";" - FILESEP="\\" - ;; - * ) - echo "Unrecognized system!" - exit 1; - ;; -esac - -cd ${TESTCLASSES}${FILESEP} -if [ ! -d provider ] ; then - mkdir provider -fi - -# compile the test program -${COMPILEJAVA}${FILESEP}bin${FILESEP}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ - -d ${TESTCLASSES}${FILESEP} \ - ${TESTSRC}${FILESEP}ClassLoaderDeadlock.java - -${COMPILEJAVA}${FILESEP}bin${FILESEP}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ - -d ${TESTCLASSES}${FILESEP}provider${FILESEP} \ - ${TESTSRC}${FILESEP}provider${FILESEP}HashProvider.java - -# run the test -${TESTJAVA}${FILESEP}bin${FILESEP}java ${TESTVMOPTS} ${TESTJAVAOPTS} \ - -classpath "${TESTCLASSES}${PATHSEP}${TESTSRC}${FILESEP}Deadlock.jar" \ - -Djava.awt.headless=true \ - ClassLoaderDeadlock - -STATUS=$? - -# clean up -rm -f 'ClassLoaderDeadlock.class' 'ClassLoaderDeadlock$1.class' \ -'ClassLoaderDeadlock$DelayClassLoader.class' \ -provider${FILESEP}HashProvider.class - -exit $STATUS diff --git a/test/jdk/java/security/Security/ClassLoaderDeadlock/Deadlock.java b/test/jdk/java/security/Security/ClassLoaderDeadlock/Deadlock.java index 5693f4933aa96..0d46b5c8660a8 100644 --- a/test/jdk/java/security/Security/ClassLoaderDeadlock/Deadlock.java +++ b/test/jdk/java/security/Security/ClassLoaderDeadlock/Deadlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,8 +21,13 @@ * questions. */ - -// see Deadlock.sh +/* + * @test + * @bug 4944382 + * @summary make sure we do not deadlock loading signed JAR with getInstance() + * @library ./Deadlock.jar + * @run main/othervm/timeout=30 Deadlock + */ import java.security.*; diff --git a/test/jdk/java/security/Security/ClassLoaderDeadlock/Deadlock.sh b/test/jdk/java/security/Security/ClassLoaderDeadlock/Deadlock.sh deleted file mode 100644 index 7013c4cc33a1a..0000000000000 --- a/test/jdk/java/security/Security/ClassLoaderDeadlock/Deadlock.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/sh - -# -# Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - - -# @test -# @bug 4944382 -# @summary make sure we do not deadlock loading signed JAR with getInstance() -# @author Andreas Sterbenz -# @build Deadlock -# @run shell/timeout=30 Deadlock.sh - -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - Linux ) - PATHSEP=":" - FILESEP="/" - ;; - Darwin ) - PATHSEP=":" - FILESEP="/" - ;; - AIX ) - PATHSEP=":" - FILESEP="/" - ;; - CYGWIN* ) - PATHSEP=";" - FILESEP="/" - ;; - Windows* ) - PATHSEP=";" - FILESEP="\\" - ;; - * ) - echo "Unrecognized system!" - exit 1; - ;; -esac - -JAVA="${TESTJAVA}${FILESEP}bin${FILESEP}java" - -${JAVA} ${TESTVMOPTS} ${TESTJAVAOPTS} -cp "${TESTCLASSES}${PATHSEP}${TESTSRC}${FILESEP}Deadlock.jar" Deadlock - From c494a00a66d21d2e403fd9ce253eb132c34e455d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Mon, 7 Apr 2025 11:31:06 +0000 Subject: [PATCH 0416/1101] 8353559: Restructure CollectedHeap error printing Reviewed-by: stefank, eosterlund, ayang --- src/hotspot/share/gc/epsilon/epsilonHeap.cpp | 10 ++++++ src/hotspot/share/gc/epsilon/epsilonHeap.hpp | 3 +- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 8 ++++- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 2 +- .../gc/parallel/parallelScavengeHeap.cpp | 8 ++++- src/hotspot/share/gc/serial/serialHeap.cpp | 10 ++++++ src/hotspot/share/gc/serial/serialHeap.hpp | 3 +- src/hotspot/share/gc/shared/collectedHeap.cpp | 11 ------- src/hotspot/share/gc/shared/collectedHeap.hpp | 12 ++----- .../share/gc/shenandoah/shenandoahHeap.cpp | 12 +++---- .../share/gc/shenandoah/shenandoahHeap.hpp | 4 +-- src/hotspot/share/gc/z/zCollectedHeap.cpp | 28 +--------------- src/hotspot/share/gc/z/zCollectedHeap.hpp | 3 +- src/hotspot/share/gc/z/zHeap.cpp | 33 ++++++++++++++++++- src/hotspot/share/gc/z/zHeap.hpp | 6 ++-- src/hotspot/share/utilities/vmError.cpp | 2 ++ 16 files changed, 89 insertions(+), 66 deletions(-) diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp index 8bc98835844ed..d5ee7835fea0d 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp @@ -310,6 +310,16 @@ void EpsilonHeap::print_on(outputStream *st) const { MetaspaceUtils::print_on(st); } +void EpsilonHeap::print_on_error(outputStream *st) const { + print_on(st); + st->cr(); + + BarrierSet* bs = BarrierSet::barrier_set(); + if (bs != nullptr) { + bs->print_on(st); + } +} + bool EpsilonHeap::print_location(outputStream* st, void* addr) const { return BlockLocationPrinter::print_location(st, addr); } diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp index b2b522c1435e6..81bcd61916fe6 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2022, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -132,6 +132,7 @@ class EpsilonHeap : public CollectedHeap { HeapWord* allocate_loaded_archive_space(size_t size) override; void print_on(outputStream* st) const override; + void print_on_error(outputStream* st) const override; void print_tracing_info() const override; bool print_location(outputStream* st, void* addr) const override; diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 4c0436ad1e224..31f0cc12aa5ee 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2161,7 +2161,13 @@ void G1CollectedHeap::print_extended_on(outputStream* st) const { } void G1CollectedHeap::print_on_error(outputStream* st) const { - this->CollectedHeap::print_on_error(st); + print_extended_on(st); + st->cr(); + + BarrierSet* bs = BarrierSet::barrier_set(); + if (bs != nullptr) { + bs->print_on(st); + } if (_cm != nullptr) { st->cr(); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index d1e81205cefb7..8d449ceedc6d1 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -1313,7 +1313,7 @@ class G1CollectedHeap : public CollectedHeap { public: void print_on(outputStream* st) const override; - void print_extended_on(outputStream* st) const override; + void print_extended_on(outputStream* st) const; void print_on_error(outputStream* st) const override; void gc_threads_do(ThreadClosure* tc) const override; diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 24cc30e191811..244094f1acc78 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -673,7 +673,13 @@ void ParallelScavengeHeap::print_on(outputStream* st) const { } void ParallelScavengeHeap::print_on_error(outputStream* st) const { - this->CollectedHeap::print_on_error(st); + print_on(st); + st->cr(); + + BarrierSet* bs = BarrierSet::barrier_set(); + if (bs != nullptr) { + bs->print_on(st); + } st->cr(); PSParallelCompact::print_on_error(st); diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index fcf57909a032e..ea2b656d4bd01 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -810,6 +810,16 @@ void SerialHeap::print_on(outputStream* st) const { MetaspaceUtils::print_on(st); } +void SerialHeap::print_on_error(outputStream* st) const { + print_on(st); + st->cr(); + + BarrierSet* bs = BarrierSet::barrier_set(); + if (bs != nullptr) { + bs->print_on(st); + } +} + void SerialHeap::gc_threads_do(ThreadClosure* tc) const { } diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index 754f6741cfec3..2ec50814daf55 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -207,6 +207,7 @@ class SerialHeap : public CollectedHeap { void verify(VerifyOption option) override; void print_on(outputStream* st) const override; + void print_on_error(outputStream* st) const override; void gc_threads_do(ThreadClosure* tc) const override; void print_tracing_info() const override; diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index 2175b58b694d3..9c55a894ee702 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -188,17 +188,6 @@ void CollectedHeap::print_heap_after_gc() { void CollectedHeap::print() const { print_on(tty); } -void CollectedHeap::print_on_error(outputStream* st) const { - st->print_cr("Heap:"); - print_extended_on(st); - st->cr(); - - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs != nullptr) { - bs->print_on(st); - } -} - void CollectedHeap::trace_heap(GCWhen::Type when, const GCTracer* gc_tracer) { const GCHeapSummary& heap_summary = create_heap_summary(); gc_tracer->report_gc_heap_summary(when, heap_summary); diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index 31a224597a048..7b3fbd1a1c483 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -440,15 +440,7 @@ class CollectedHeap : public CHeapObj { // The default behavior is to call print_on() on tty. virtual void print() const; - // Print more detailed heap information on the given - // outputStream. The default behavior is to call print_on(). It is - // up to each subclass to override it and add any additional output - // it needs. - virtual void print_extended_on(outputStream* st) const { - print_on(st); - } - - virtual void print_on_error(outputStream* st) const; + virtual void print_on_error(outputStream* st) const = 0; // Used to print information about locations in the hs_err file. virtual bool print_location(outputStream* st, void* addr) const = 0; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 32acb42c76538..c055a3f9b5a9d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -649,6 +649,12 @@ void ShenandoahHeap::print_on(outputStream* st) const { } } +void ShenandoahHeap::print_on_error(outputStream* st) const { + print_on(st); + st->cr(); + print_heap_regions_on(st); +} + class ShenandoahInitWorkerGCLABClosure : public ThreadClosure { public: void do_thread(Thread* thread) { @@ -2582,12 +2588,6 @@ void ShenandoahHeap::rebuild_free_set(bool concurrent) { } } -void ShenandoahHeap::print_extended_on(outputStream *st) const { - print_on(st); - st->cr(); - print_heap_regions_on(st); -} - bool ShenandoahHeap::is_bitmap_slice_committed(ShenandoahHeapRegion* r, bool skip_self) { size_t slice = r->index() / _bitmap_regions_per_slice; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index d9508beac202c..2bbb590f3552d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2021, Red Hat, Inc. All rights reserved. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -203,7 +203,7 @@ class ShenandoahHeap : public CollectedHeap { void initialize_serviceability() override; void print_on(outputStream* st) const override; - void print_extended_on(outputStream *st) const override; + void print_on_error(outputStream *st) const override; void print_tracing_info() const override; void print_heap_regions_on(outputStream* st) const; diff --git a/src/hotspot/share/gc/z/zCollectedHeap.cpp b/src/hotspot/share/gc/z/zCollectedHeap.cpp index 2911106252913..828e3c9d033b2 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.cpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp @@ -359,33 +359,7 @@ void ZCollectedHeap::print_on(outputStream* st) const { } void ZCollectedHeap::print_on_error(outputStream* st) const { - st->print_cr("ZGC Globals:"); - st->print_cr(" Young Collection: %s/%u", ZGeneration::young()->phase_to_string(), ZGeneration::young()->seqnum()); - st->print_cr(" Old Collection: %s/%u", ZGeneration::old()->phase_to_string(), ZGeneration::old()->seqnum()); - st->print_cr(" Offset Max: " EXACTFMT " (" PTR_FORMAT ")", EXACTFMTARGS(ZAddressOffsetMax), ZAddressOffsetMax); - st->print_cr(" Page Size Small: %zuM", ZPageSizeSmall / M); - st->print_cr(" Page Size Medium: %zuM", ZPageSizeMedium / M); - st->cr(); - st->print_cr("ZGC Metadata Bits:"); - st->print_cr(" LoadGood: " PTR_FORMAT, ZPointerLoadGoodMask); - st->print_cr(" LoadBad: " PTR_FORMAT, ZPointerLoadBadMask); - st->print_cr(" MarkGood: " PTR_FORMAT, ZPointerMarkGoodMask); - st->print_cr(" MarkBad: " PTR_FORMAT, ZPointerMarkBadMask); - st->print_cr(" StoreGood: " PTR_FORMAT, ZPointerStoreGoodMask); - st->print_cr(" StoreBad: " PTR_FORMAT, ZPointerStoreBadMask); - st->print_cr(" ------------------- "); - st->print_cr(" Remapped: " PTR_FORMAT, ZPointerRemapped); - st->print_cr(" RemappedYoung: " PTR_FORMAT, ZPointerRemappedYoungMask); - st->print_cr(" RemappedOld: " PTR_FORMAT, ZPointerRemappedOldMask); - st->print_cr(" MarkedYoung: " PTR_FORMAT, ZPointerMarkedYoung); - st->print_cr(" MarkedOld: " PTR_FORMAT, ZPointerMarkedOld); - st->print_cr(" Remembered: " PTR_FORMAT, ZPointerRemembered); - st->cr(); - CollectedHeap::print_on_error(st); -} - -void ZCollectedHeap::print_extended_on(outputStream* st) const { - _heap.print_extended_on(st); + _heap.print_on_error(st); } void ZCollectedHeap::print_tracing_info() const { diff --git a/src/hotspot/share/gc/z/zCollectedHeap.hpp b/src/hotspot/share/gc/z/zCollectedHeap.hpp index 434204e16b80d..08aa7d40a3f9d 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.hpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,7 +117,6 @@ class ZCollectedHeap : public CollectedHeap { void print_on(outputStream* st) const override; void print_on_error(outputStream* st) const override; - void print_extended_on(outputStream* st) const override; void print_tracing_info() const override; bool print_location(outputStream* st, void* addr) const override; diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index bca9e2f8c4156..e0f4cb6530370 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -326,10 +326,41 @@ void ZHeap::print_on(outputStream* st) const { MetaspaceUtils::print_on(st); } -void ZHeap::print_extended_on(outputStream* st) const { +void ZHeap::print_on_error(outputStream* st) const { print_on(st); st->cr(); + print_globals_on(st); + st->cr(); + + print_page_table_on(st); +} + +void ZHeap::print_globals_on(outputStream* st) const { + st->print_cr("ZGC Globals:"); + st->print_cr(" Young Collection: %s/%u", ZGeneration::young()->phase_to_string(), ZGeneration::young()->seqnum()); + st->print_cr(" Old Collection: %s/%u", ZGeneration::old()->phase_to_string(), ZGeneration::old()->seqnum()); + st->print_cr(" Offset Max: " EXACTFMT " (" PTR_FORMAT ")", EXACTFMTARGS(ZAddressOffsetMax), ZAddressOffsetMax); + st->print_cr(" Page Size Small: %zuM", ZPageSizeSmall / M); + st->print_cr(" Page Size Medium: %zuM", ZPageSizeMedium / M); + st->cr(); + st->print_cr("ZGC Metadata Bits:"); + st->print_cr(" LoadGood: " PTR_FORMAT, ZPointerLoadGoodMask); + st->print_cr(" LoadBad: " PTR_FORMAT, ZPointerLoadBadMask); + st->print_cr(" MarkGood: " PTR_FORMAT, ZPointerMarkGoodMask); + st->print_cr(" MarkBad: " PTR_FORMAT, ZPointerMarkBadMask); + st->print_cr(" StoreGood: " PTR_FORMAT, ZPointerStoreGoodMask); + st->print_cr(" StoreBad: " PTR_FORMAT, ZPointerStoreBadMask); + st->print_cr(" ------------------- "); + st->print_cr(" Remapped: " PTR_FORMAT, ZPointerRemapped); + st->print_cr(" RemappedYoung: " PTR_FORMAT, ZPointerRemappedYoungMask); + st->print_cr(" RemappedOld: " PTR_FORMAT, ZPointerRemappedOldMask); + st->print_cr(" MarkedYoung: " PTR_FORMAT, ZPointerMarkedYoung); + st->print_cr(" MarkedOld: " PTR_FORMAT, ZPointerMarkedOld); + st->print_cr(" Remembered: " PTR_FORMAT, ZPointerRemembered); +} + +void ZHeap::print_page_table_on(outputStream* st) const { // Do not allow pages to be deleted _page_allocator.enable_safe_destroy(); diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index 4bf4727c3e35c..25cd22090030e 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,7 +132,9 @@ class ZHeap { // Printing void print_on(outputStream* st) const; - void print_extended_on(outputStream* st) const; + void print_on_error(outputStream* st) const; + void print_globals_on(outputStream* st) const; + void print_page_table_on(outputStream* st) const; bool print_location(outputStream* st, uintptr_t addr) const; bool print_location(outputStream* st, zaddress addr) const; bool print_location(outputStream* st, zpointer ptr) const; diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index bbf1fcf9d6f49..ef04d69ee995c 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1191,6 +1191,7 @@ void VMError::report(outputStream* st, bool _verbose) { GCLogPrecious::print_on_error(st); if (Universe::heap() != nullptr) { + st->print_cr("Heap:"); Universe::heap()->print_on_error(st); st->cr(); } @@ -1374,6 +1375,7 @@ void VMError::print_vm_info(outputStream* st) { if (Universe::is_fully_initialized()) { MutexLocker hl(Heap_lock); GCLogPrecious::print_on_error(st); + st->print_cr("Heap:"); Universe::heap()->print_on_error(st); st->cr(); st->print_cr("Polling page: " PTR_FORMAT, p2i(SafepointMechanism::get_polling_page())); From 6ab1647af2d83427215f3a704671f113ba9845e2 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Mon, 7 Apr 2025 11:32:16 +0000 Subject: [PATCH 0417/1101] 8353637: ZGC: Discontiguous memory reservation is broken on Windows Co-authored-by: Axel Boldt-Christmas Reviewed-by: jsikstro, aboldtch, eosterlund --- .../os/posix/gc/z/zVirtualMemory_posix.cpp | 2 +- .../windows/gc/z/zVirtualMemory_windows.cpp | 132 ++++----- src/hotspot/share/gc/z/zArguments.hpp | 2 + src/hotspot/share/gc/z/zInitialize.hpp | 2 + src/hotspot/share/gc/z/zMemory.cpp | 147 ++++++---- src/hotspot/share/gc/z/zMemory.hpp | 27 +- src/hotspot/share/gc/z/zMemory.inline.hpp | 12 + src/hotspot/share/gc/z/zNMT.cpp | 20 ++ src/hotspot/share/gc/z/zNMT.hpp | 2 + src/hotspot/share/gc/z/zPhysicalMemory.cpp | 2 +- src/hotspot/share/gc/z/zVirtualMemory.cpp | 27 +- src/hotspot/share/gc/z/zVirtualMemory.hpp | 7 +- .../gtest/gc/z/test_zMapper_windows.cpp | 153 ++-------- test/hotspot/gtest/gc/z/test_zMemory.cpp | 24 +- .../gtest/gc/z/test_zVirtualMemory.cpp | 4 +- .../gtest/gc/z/test_zVirtualMemoryManager.cpp | 269 ++++++++++++++++++ test/hotspot/gtest/gc/z/zunittest.hpp | 82 ++++++ 17 files changed, 625 insertions(+), 289 deletions(-) create mode 100644 test/hotspot/gtest/gc/z/test_zVirtualMemoryManager.cpp create mode 100644 test/hotspot/gtest/gc/z/zunittest.hpp diff --git a/src/hotspot/os/posix/gc/z/zVirtualMemory_posix.cpp b/src/hotspot/os/posix/gc/z/zVirtualMemory_posix.cpp index a177fe2b63647..a103f764c9891 100644 --- a/src/hotspot/os/posix/gc/z/zVirtualMemory_posix.cpp +++ b/src/hotspot/os/posix/gc/z/zVirtualMemory_posix.cpp @@ -32,7 +32,7 @@ void ZVirtualMemoryManager::pd_initialize_before_reserve() { // Does nothing } -void ZVirtualMemoryManager::pd_initialize_after_reserve() { +void ZVirtualMemoryManager::pd_register_callbacks(ZMemoryManager* manager) { // Does nothing } diff --git a/src/hotspot/os/windows/gc/z/zVirtualMemory_windows.cpp b/src/hotspot/os/windows/gc/z/zVirtualMemory_windows.cpp index 392b16e38a308..ac5be56a0c0df 100644 --- a/src/hotspot/os/windows/gc/z/zVirtualMemory_windows.cpp +++ b/src/hotspot/os/windows/gc/z/zVirtualMemory_windows.cpp @@ -33,7 +33,7 @@ class ZVirtualMemoryManagerImpl : public CHeapObj { public: virtual void initialize_before_reserve() {} - virtual void initialize_after_reserve(ZMemoryManager* manager) {} + virtual void register_callbacks(ZMemoryManager* manager) {} virtual bool reserve(zaddress_unsafe addr, size_t size) = 0; virtual void unreserve(zaddress_unsafe addr, size_t size) = 0; }; @@ -47,7 +47,7 @@ class ZVirtualMemoryManagerImpl : public CHeapObj { class ZVirtualMemoryManagerSmallPages : public ZVirtualMemoryManagerImpl { private: class PlaceholderCallbacks : public AllStatic { - public: + private: static void split_placeholder(zoffset start, size_t size) { ZMapper::split_placeholder(ZOffset::address_unsafe(start), size); } @@ -79,99 +79,93 @@ class ZVirtualMemoryManagerSmallPages : public ZVirtualMemoryManagerImpl { } } - // Called when a memory area is returned to the memory manager but can't - // be merged with an already existing area. Make sure this area is covered - // by a single placeholder. - static void create_callback(const ZMemory* area) { - assert(is_aligned(area->size(), ZGranuleSize), "Must be granule aligned"); - - coalesce_into_one_placeholder(area->start(), area->size()); - } + // Callback implementations - // Called when a complete memory area in the memory manager is allocated. - // Create granule sized placeholders for the entire area. - static void destroy_callback(const ZMemory* area) { - assert(is_aligned(area->size(), ZGranuleSize), "Must be granule aligned"); + // Called when a memory area is going to be handed out to be used. + // + // Splits the memory area into granule-sized placeholders. + static void prepare_for_hand_out_callback(const ZMemory& area) { + assert(is_aligned(area.size(), ZGranuleSize), "Must be granule aligned"); - split_into_granule_sized_placeholders(area->start(), area->size()); + split_into_granule_sized_placeholders(area.start(), area.size()); } - // Called when a memory area is allocated at the front of an exising memory area. - // Turn the first part of the memory area into granule sized placeholders. - static void shrink_from_front_callback(const ZMemory* area, size_t size) { - assert(area->size() > size, "Must be larger than what we try to split out"); - assert(is_aligned(size, ZGranuleSize), "Must be granule aligned"); + // Called when a memory area is handed back to the memory manager. + // + // Combines the granule-sized placeholders into one placeholder. + static void prepare_for_hand_back_callback(const ZMemory& area) { + assert(is_aligned(area.size(), ZGranuleSize), "Must be granule aligned"); - // Split the area into two placeholders - split_placeholder(area->start(), size); - - // Split the first part into granule sized placeholders - split_into_granule_sized_placeholders(area->start(), size); + coalesce_into_one_placeholder(area.start(), area.size()); } - // Called when a memory area is allocated at the end of an existing memory area. - // Turn the second part of the memory area into granule sized placeholders. - static void shrink_from_back_callback(const ZMemory* area, size_t size) { - assert(area->size() > size, "Must be larger than what we try to split out"); - assert(is_aligned(size, ZGranuleSize), "Must be granule aligned"); - - // Split the area into two placeholders - const zoffset start = to_zoffset(area->end() - size); - split_placeholder(start, size); - - // Split the second part into granule sized placeholders - split_into_granule_sized_placeholders(start, size); - } - - // Called when freeing a memory area and it can be merged at the start of an - // existing area. Coalesce the underlying placeholders into one. - static void grow_from_front_callback(const ZMemory* area, size_t size) { - assert(is_aligned(area->size(), ZGranuleSize), "Must be granule aligned"); - - const zoffset start = area->start() - size; - coalesce_into_one_placeholder(start, area->size() + size); + // Called when inserting a memory area and it can be merged with an + // existing, adjacent memory area. + // + // Coalesces the underlying placeholders into one. + static void grow_callback(const ZMemory& from, const ZMemory& to) { + assert(is_aligned(from.size(), ZGranuleSize), "Must be granule aligned"); + assert(is_aligned(to.size(), ZGranuleSize), "Must be granule aligned"); + assert(from != to, "Must have grown"); + assert(to.contains(from), "Must be within"); + + coalesce_into_one_placeholder(to.start(), to.size()); } - // Called when freeing a memory area and it can be merged at the end of an - // existing area. Coalesce the underlying placeholders into one. - static void grow_from_back_callback(const ZMemory* area, size_t size) { - assert(is_aligned(area->size(), ZGranuleSize), "Must be granule aligned"); + // Called when a memory area is removed from the front or back of an existing + // memory area. + // + // Splits the memory into two placeholders. + static void shrink_callback(const ZMemory& from, const ZMemory& to) { + assert(is_aligned(from.size(), ZGranuleSize), "Must be granule aligned"); + assert(is_aligned(to.size(), ZGranuleSize), "Must be granule aligned"); + assert(from != to, "Must have shrunk"); + assert(from.contains(to), "Must be larger than what we try to split out"); + assert(from.start() == to.start() || from.end() == to.end(), + "Only verified to work if we split a placeholder into two placeholders"); - coalesce_into_one_placeholder(area->start(), area->size() + size); + // Split the area into two placeholders + split_placeholder(to.start(), to.size()); } - static void register_with(ZMemoryManager* manager) { + public: + static ZMemoryManager::Callbacks callbacks() { // Each reserved virtual memory address area registered in _manager is // exactly covered by a single placeholder. Callbacks are installed so // that whenever a memory area changes, the corresponding placeholder // is adjusted. // - // The create and grow callbacks are called when virtual memory is - // returned to the memory manager. The new memory area is then covered - // by a new single placeholder. + // The prepare_for_hand_out callback is called when virtual memory is + // handed out to callers. The memory area is split into granule-sized + // placeholders. + // + // The prepare_for_hand_back callback is called when previously handed + // out virtual memory is handed back to the memory manager. The + // returned memory area is then covered by a new single placeholder. + // + // The grow callback is called when a virtual memory area grows. The + // resulting memory area is then covered by a single placeholder. // - // The destroy and shrink callbacks are called when virtual memory is - // allocated from the memory manager. The memory area is then is split - // into granule-sized placeholders. + // The shrink callback is called when a virtual memory area is split into + // two parts. The two resulting memory areas are then covered by two + // separate placeholders. // // See comment in zMapper_windows.cpp explaining why placeholders are // split into ZGranuleSize sized placeholders. ZMemoryManager::Callbacks callbacks; - callbacks._create = &create_callback; - callbacks._destroy = &destroy_callback; - callbacks._shrink_from_front = &shrink_from_front_callback; - callbacks._shrink_from_back = &shrink_from_back_callback; - callbacks._grow_from_front = &grow_from_front_callback; - callbacks._grow_from_back = &grow_from_back_callback; + callbacks._prepare_for_hand_out = &prepare_for_hand_out_callback; + callbacks._prepare_for_hand_back = &prepare_for_hand_back_callback; + callbacks._grow = &grow_callback; + callbacks._shrink = &shrink_callback; - manager->register_callbacks(callbacks); + return callbacks; } }; - virtual void initialize_after_reserve(ZMemoryManager* manager) { - PlaceholderCallbacks::register_with(manager); + virtual void register_callbacks(ZMemoryManager* manager) { + manager->register_callbacks(PlaceholderCallbacks::callbacks()); } virtual bool reserve(zaddress_unsafe addr, size_t size) { @@ -220,8 +214,8 @@ void ZVirtualMemoryManager::pd_initialize_before_reserve() { _impl->initialize_before_reserve(); } -void ZVirtualMemoryManager::pd_initialize_after_reserve() { - _impl->initialize_after_reserve(&_manager); +void ZVirtualMemoryManager::pd_register_callbacks(ZMemoryManager* manager) { + _impl->register_callbacks(manager); } bool ZVirtualMemoryManager::pd_reserve(zaddress_unsafe addr, size_t size) { diff --git a/src/hotspot/share/gc/z/zArguments.hpp b/src/hotspot/share/gc/z/zArguments.hpp index 3ed1c8e212e83..8bbd88f357cbf 100644 --- a/src/hotspot/share/gc/z/zArguments.hpp +++ b/src/hotspot/share/gc/z/zArguments.hpp @@ -29,6 +29,8 @@ class CollectedHeap; class ZArguments : public GCArguments { + friend class ZTest; + private: static void select_max_gc_threads(); diff --git a/src/hotspot/share/gc/z/zInitialize.hpp b/src/hotspot/share/gc/z/zInitialize.hpp index ce31912586eec..44a286f2182fd 100644 --- a/src/hotspot/share/gc/z/zInitialize.hpp +++ b/src/hotspot/share/gc/z/zInitialize.hpp @@ -37,6 +37,8 @@ class ZInitializer { }; class ZInitialize : public AllStatic { + friend class ZTest; + private: static constexpr size_t ErrorMessageLength = 256; diff --git a/src/hotspot/share/gc/z/zMemory.cpp b/src/hotspot/share/gc/z/zMemory.cpp index 8ccde9f45a288..35e95888d4d67 100644 --- a/src/hotspot/share/gc/z/zMemory.cpp +++ b/src/hotspot/share/gc/z/zMemory.cpp @@ -25,56 +25,47 @@ #include "gc/z/zLock.inline.hpp" #include "gc/z/zMemory.inline.hpp" -ZMemory* ZMemoryManager::create(zoffset start, size_t size) { - ZMemory* const area = new ZMemory(start, size); - if (_callbacks._create != nullptr) { - _callbacks._create(area); - } - return area; -} - -void ZMemoryManager::destroy(ZMemory* area) { - if (_callbacks._destroy != nullptr) { - _callbacks._destroy(area); - } - delete area; -} - void ZMemoryManager::shrink_from_front(ZMemory* area, size_t size) { - if (_callbacks._shrink_from_front != nullptr) { - _callbacks._shrink_from_front(area, size); + if (_callbacks._shrink != nullptr) { + const ZMemory* from = area; + const ZMemory to(area->start() + size, area->size() - size); + _callbacks._shrink(*from, to); } area->shrink_from_front(size); } void ZMemoryManager::shrink_from_back(ZMemory* area, size_t size) { - if (_callbacks._shrink_from_back != nullptr) { - _callbacks._shrink_from_back(area, size); + if (_callbacks._shrink != nullptr) { + const ZMemory* from = area; + const ZMemory to(area->start(), area->size() - size); + _callbacks._shrink(*from, to); } area->shrink_from_back(size); } void ZMemoryManager::grow_from_front(ZMemory* area, size_t size) { - if (_callbacks._grow_from_front != nullptr) { - _callbacks._grow_from_front(area, size); + if (_callbacks._grow != nullptr) { + const ZMemory* from = area; + const ZMemory to(area->start() - size, area->size() + size); + _callbacks._grow(*from, to); } area->grow_from_front(size); } void ZMemoryManager::grow_from_back(ZMemory* area, size_t size) { - if (_callbacks._grow_from_back != nullptr) { - _callbacks._grow_from_back(area, size); + if (_callbacks._grow != nullptr) { + const ZMemory* from = area; + const ZMemory to(area->start(), area->size() + size); + _callbacks._grow(*from, to); } area->grow_from_back(size); } ZMemoryManager::Callbacks::Callbacks() - : _create(nullptr), - _destroy(nullptr), - _shrink_from_front(nullptr), - _shrink_from_back(nullptr), - _grow_from_front(nullptr), - _grow_from_back(nullptr) {} + : _prepare_for_hand_out(nullptr), + _prepare_for_hand_back(nullptr), + _grow(nullptr), + _shrink(nullptr) {} ZMemoryManager::ZMemoryManager() : _freelist(), @@ -118,18 +109,24 @@ zoffset ZMemoryManager::alloc_low_address(size_t size) { ZListIterator iter(&_freelist); for (ZMemory* area; iter.next(&area);) { if (area->size() >= size) { + zoffset start; + if (area->size() == size) { // Exact match, remove area - const zoffset start = area->start(); + start = area->start(); _freelist.remove(area); - destroy(area); - return start; + delete area; } else { // Larger than requested, shrink area - const zoffset start = area->start(); + start = area->start(); shrink_from_front(area, size); - return start; } + + if (_callbacks._prepare_for_hand_out != nullptr) { + _callbacks._prepare_for_hand_out(ZMemory(start, size)); + } + + return start; } } @@ -142,20 +139,24 @@ zoffset ZMemoryManager::alloc_low_address_at_most(size_t size, size_t* allocated ZMemory* const area = _freelist.first(); if (area != nullptr) { + const zoffset start = area->start(); + if (area->size() <= size) { // Smaller than or equal to requested, remove area - const zoffset start = area->start(); - *allocated = area->size(); _freelist.remove(area); - destroy(area); - return start; + *allocated = area->size(); + delete area; } else { // Larger than requested, shrink area - const zoffset start = area->start(); shrink_from_front(area, size); *allocated = size; - return start; } + + if (_callbacks._prepare_for_hand_out != nullptr) { + _callbacks._prepare_for_hand_out(ZMemory(start, *allocated)); + } + + return start; } // Out of memory @@ -169,17 +170,24 @@ zoffset ZMemoryManager::alloc_high_address(size_t size) { ZListReverseIterator iter(&_freelist); for (ZMemory* area; iter.next(&area);) { if (area->size() >= size) { + zoffset start; + if (area->size() == size) { // Exact match, remove area - const zoffset start = area->start(); + start = area->start(); _freelist.remove(area); - destroy(area); - return start; + delete area; } else { // Larger than requested, shrink area shrink_from_back(area, size); - return to_zoffset(area->end()); + start = to_zoffset(area->end()); + } + + if (_callbacks._prepare_for_hand_out != nullptr) { + _callbacks._prepare_for_hand_out(ZMemory(start, size)); } + + return start; } } @@ -187,12 +195,10 @@ zoffset ZMemoryManager::alloc_high_address(size_t size) { return zoffset(UINTPTR_MAX); } -void ZMemoryManager::free(zoffset start, size_t size) { +void ZMemoryManager::move_into(zoffset start, size_t size) { assert(start != zoffset(UINTPTR_MAX), "Invalid address"); const zoffset_end end = to_zoffset_end(start, size); - ZLocker locker(&_lock); - ZListIterator iter(&_freelist); for (ZMemory* area; iter.next(&area);) { if (start < area->start()) { @@ -213,7 +219,7 @@ void ZMemoryManager::free(zoffset start, size_t size) { } else { // Insert new area before current area assert(end < area->start(), "Areas must not overlap"); - ZMemory* const new_area = create(start, size); + ZMemory* const new_area = new ZMemory(start, size); _freelist.insert_before(area, new_area); } @@ -229,7 +235,50 @@ void ZMemoryManager::free(zoffset start, size_t size) { grow_from_back(last, size); } else { // Insert new area last - ZMemory* const new_area = create(start, size); + ZMemory* const new_area = new ZMemory(start, size); _freelist.insert_last(new_area); } } + +void ZMemoryManager::free(zoffset start, size_t size) { + ZLocker locker(&_lock); + + if (_callbacks._prepare_for_hand_back != nullptr) { + _callbacks._prepare_for_hand_back(ZMemory(start, size)); + } + + move_into(start, size); +} + +void ZMemoryManager::register_range(zoffset start, size_t size) { + // Note that there's no need to call the _prepare_for_hand_back when memory + // is added the first time. We don't have to undo the effects of a previous + // _prepare_for_hand_out callback. + + // No need to lock during initialization. + + move_into(start, size); +} + +bool ZMemoryManager::unregister_first(zoffset* start_out, size_t* size_out) { + // Note that this doesn't hand out memory to be used, so we don't call the + // _prepare_for_hand_out callback. + + ZLocker locker(&_lock); + + if (_freelist.is_empty()) { + return false; + } + + // Don't invoke the _prepare_for_hand_out callback + + ZMemory* const area = _freelist.remove_first(); + + // Return the range + *start_out = area->start(); + *size_out = area->size(); + + delete area; + + return true; +} diff --git a/src/hotspot/share/gc/z/zMemory.hpp b/src/hotspot/share/gc/z/zMemory.hpp index 229d5a7c50c4a..da37596c1c7b2 100644 --- a/src/hotspot/share/gc/z/zMemory.hpp +++ b/src/hotspot/share/gc/z/zMemory.hpp @@ -44,6 +44,11 @@ class ZMemory : public CHeapObj { zoffset_end end() const; size_t size() const; + bool operator==(const ZMemory& other) const; + bool operator!=(const ZMemory& other) const; + + bool contains(const ZMemory& other) const; + void shrink_from_front(size_t size); void shrink_from_back(size_t size); void grow_from_front(size_t size); @@ -51,17 +56,17 @@ class ZMemory : public CHeapObj { }; class ZMemoryManager { + friend class ZVirtualMemoryManagerTest; + public: - typedef void (*CreateDestroyCallback)(const ZMemory* area); - typedef void (*ResizeCallback)(const ZMemory* area, size_t size); + typedef void (*CallbackPrepare)(const ZMemory& area); + typedef void (*CallbackResize)(const ZMemory& from, const ZMemory& to); struct Callbacks { - CreateDestroyCallback _create; - CreateDestroyCallback _destroy; - ResizeCallback _shrink_from_front; - ResizeCallback _shrink_from_back; - ResizeCallback _grow_from_front; - ResizeCallback _grow_from_back; + CallbackPrepare _prepare_for_hand_out; + CallbackPrepare _prepare_for_hand_back; + CallbackResize _grow; + CallbackResize _shrink; Callbacks(); }; @@ -71,13 +76,13 @@ class ZMemoryManager { ZList _freelist; Callbacks _callbacks; - ZMemory* create(zoffset start, size_t size); - void destroy(ZMemory* area); void shrink_from_front(ZMemory* area, size_t size); void shrink_from_back(ZMemory* area, size_t size); void grow_from_front(ZMemory* area, size_t size); void grow_from_back(ZMemory* area, size_t size); + void move_into(zoffset start, size_t size); + public: ZMemoryManager(); @@ -92,6 +97,8 @@ class ZMemoryManager { zoffset alloc_high_address(size_t size); void free(zoffset start, size_t size); + void register_range(zoffset start, size_t size); + bool unregister_first(zoffset* start_out, size_t* size_out); }; #endif // SHARE_GC_Z_ZMEMORY_HPP diff --git a/src/hotspot/share/gc/z/zMemory.inline.hpp b/src/hotspot/share/gc/z/zMemory.inline.hpp index 154ac6d69f25f..39e5b26d85696 100644 --- a/src/hotspot/share/gc/z/zMemory.inline.hpp +++ b/src/hotspot/share/gc/z/zMemory.inline.hpp @@ -46,6 +46,18 @@ inline size_t ZMemory::size() const { return end() - start(); } +inline bool ZMemory::operator==(const ZMemory& other) const { + return _start == other._start && _end == other._end; +} + +inline bool ZMemory::operator!=(const ZMemory& other) const { + return !operator==(other); +} + +inline bool ZMemory::contains(const ZMemory& other) const { + return _start <= other._start && other.end() <= end(); +} + inline void ZMemory::shrink_from_front(size_t size) { assert(this->size() > size, "Too small"); _start += size; diff --git a/src/hotspot/share/gc/z/zNMT.cpp b/src/hotspot/share/gc/z/zNMT.cpp index 07ea8df13252f..4e1efbf9cafe9 100644 --- a/src/hotspot/share/gc/z/zNMT.cpp +++ b/src/hotspot/share/gc/z/zNMT.cpp @@ -40,6 +40,26 @@ void ZNMT::reserve(zaddress_unsafe start, size_t size) { MemTracker::record_virtual_memory_reserve((address)untype(start), size, CALLER_PC, mtJavaHeap); } +void ZNMT::unreserve(zaddress_unsafe start, size_t size) { + precond(is_aligned(untype(start), ZGranuleSize)); + precond(is_aligned(size, ZGranuleSize)); + + if (MemTracker::enabled()) { + // We are the owner of the reserved memory, and any failure to unreserve + // are fatal, so so we don't need to hold a lock while unreserving memory. + + MemTracker::NmtVirtualMemoryLocker nvml; + + // The current NMT implementation does not support unreserving a memory + // region that was built up from smaller memory reservations. Workaround + // this problem by splitting the work up into granule-sized chunks, which + // is the smallest unit we ever reserve. + for (size_t i = 0; i < size; i += ZGranuleSize) { + MemTracker::record_virtual_memory_release((address)untype(start + i), ZGranuleSize); + } + } +} + void ZNMT::commit(zoffset offset, size_t size) { MemTracker::allocate_memory_in(ZNMT::_device, untype(offset), size, CALLER_PC, mtJavaHeap); } diff --git a/src/hotspot/share/gc/z/zNMT.hpp b/src/hotspot/share/gc/z/zNMT.hpp index d75b48808d44c..bea6a6b62ac12 100644 --- a/src/hotspot/share/gc/z/zNMT.hpp +++ b/src/hotspot/share/gc/z/zNMT.hpp @@ -42,6 +42,8 @@ class ZNMT : public AllStatic { static void initialize(); static void reserve(zaddress_unsafe start, size_t size); + static void unreserve(zaddress_unsafe start, size_t size); + static void commit(zoffset offset, size_t size); static void uncommit(zoffset offset, size_t size); diff --git a/src/hotspot/share/gc/z/zPhysicalMemory.cpp b/src/hotspot/share/gc/z/zPhysicalMemory.cpp index 541e60051c312..5b209a4c01c36 100644 --- a/src/hotspot/share/gc/z/zPhysicalMemory.cpp +++ b/src/hotspot/share/gc/z/zPhysicalMemory.cpp @@ -238,7 +238,7 @@ ZPhysicalMemory ZPhysicalMemory::split_committed() { ZPhysicalMemoryManager::ZPhysicalMemoryManager(size_t max_capacity) : _backing(max_capacity) { // Make the whole range free - _manager.free(zoffset(0), max_capacity); + _manager.register_range(zoffset(0), max_capacity); } bool ZPhysicalMemoryManager::is_initialized() const { diff --git a/src/hotspot/share/gc/z/zVirtualMemory.cpp b/src/hotspot/share/gc/z/zVirtualMemory.cpp index 21152cf4db6b3..471fc6f505e5e 100644 --- a/src/hotspot/share/gc/z/zVirtualMemory.cpp +++ b/src/hotspot/share/gc/z/zVirtualMemory.cpp @@ -42,6 +42,9 @@ ZVirtualMemoryManager::ZVirtualMemoryManager(size_t max_capacity) // Initialize platform specific parts before reserving address space pd_initialize_before_reserve(); + // Register the Windows callbacks + pd_register_callbacks(&_manager); + // Reserve address space if (!reserve(max_capacity)) { ZInitialize::error_d("Failed to reserve enough address space for Java heap"); @@ -51,9 +54,6 @@ ZVirtualMemoryManager::ZVirtualMemoryManager(size_t max_capacity) // Set ZAddressOffsetMax to the highest address end available after reservation ZAddressOffsetMax = untype(highest_available_address_end()); - // Initialize platform specific parts after reserving address space - pd_initialize_after_reserve(); - // Successfully initialized _initialized = true; } @@ -154,7 +154,7 @@ bool ZVirtualMemoryManager::reserve_contiguous(zoffset start, size_t size) { ZNMT::reserve(addr, size); // Make the address range free - _manager.free(start, size); + _manager.register_range(start, size); return true; } @@ -211,6 +211,25 @@ bool ZVirtualMemoryManager::reserve(size_t max_capacity) { return reserved >= max_capacity; } +void ZVirtualMemoryManager::unreserve(zoffset start, size_t size) { + const zaddress_unsafe addr = ZOffset::address_unsafe(start); + + // Unregister the reserved memory from NMT + ZNMT::unreserve(addr, size); + + // Unreserve address space + pd_unreserve(addr, size); +} + +void ZVirtualMemoryManager::unreserve_all() { + zoffset start; + size_t size; + + while (_manager.unregister_first(&start, &size)) { + unreserve(start, size); + } +} + bool ZVirtualMemoryManager::is_initialized() const { return _initialized; } diff --git a/src/hotspot/share/gc/z/zVirtualMemory.hpp b/src/hotspot/share/gc/z/zVirtualMemory.hpp index 57a377ab61b9e..f5185549e8a53 100644 --- a/src/hotspot/share/gc/z/zVirtualMemory.hpp +++ b/src/hotspot/share/gc/z/zVirtualMemory.hpp @@ -48,6 +48,7 @@ class ZVirtualMemory { class ZVirtualMemoryManager { friend class ZMapperTest; + friend class ZVirtualMemoryManagerTest; private: static size_t calculate_min_range(size_t size); @@ -58,7 +59,7 @@ class ZVirtualMemoryManager { // Platform specific implementation void pd_initialize_before_reserve(); - void pd_initialize_after_reserve(); + void pd_register_callbacks(ZMemoryManager* manager); bool pd_reserve(zaddress_unsafe addr, size_t size); void pd_unreserve(zaddress_unsafe addr, size_t size); @@ -68,6 +69,8 @@ class ZVirtualMemoryManager { size_t reserve_discontiguous(size_t size); bool reserve(size_t max_capacity); + void unreserve(zoffset start, size_t size); + DEBUG_ONLY(size_t force_reserve_discontiguous(size_t size);) public: @@ -81,6 +84,8 @@ class ZVirtualMemoryManager { ZVirtualMemory alloc(size_t size, bool force_low_address); void free(const ZVirtualMemory& vmem); + + void unreserve_all(); }; #endif // SHARE_GC_Z_ZVIRTUALMEMORY_HPP diff --git a/test/hotspot/gtest/gc/z/test_zMapper_windows.cpp b/test/hotspot/gtest/gc/z/test_zMapper_windows.cpp index 79ad840b50b7c..c66bb04668a8d 100644 --- a/test/hotspot/gtest/gc/z/test_zMapper_windows.cpp +++ b/test/hotspot/gtest/gc/z/test_zMapper_windows.cpp @@ -29,182 +29,71 @@ #include "gc/z/zMapper_windows.hpp" #include "gc/z/zMemory.inline.hpp" #include "gc/z/zSyscall_windows.hpp" -#include "gc/z/zVirtualMemory.hpp" +#include "gc/z/zVirtualMemory.inline.hpp" #include "runtime/os.hpp" -#include "unittest.hpp" +#include "zunittest.hpp" using namespace testing; -#define EXPECT_ALLOC_OK(offset) EXPECT_NE(offset, zoffset(UINTPTR_MAX)) - -class ZMapperTest : public Test { +class ZMapperTest : public ZTest { private: - static constexpr size_t ZMapperTestReservationSize = 32 * M; - - static bool _initialized; - static ZMemoryManager* _va; - - static ZVirtualMemoryManager* _vmm; + static constexpr size_t ReservationSize = 32 * M; - static bool _has_unreserved; + ZVirtualMemoryManager* _vmm; + ZMemoryManager* _va; public: - bool reserve_for_test() { - // Initialize platform specific parts before reserving address space - _vmm->pd_initialize_before_reserve(); - - // Reserve address space - if (!_vmm->pd_reserve(ZOffset::address_unsafe(zoffset(0)), ZMapperTestReservationSize)) { - return false; - } - - // Make the address range free before setting up callbacks below - _va->free(zoffset(0), ZMapperTestReservationSize); - - // Initialize platform specific parts after reserving address space - _vmm->pd_initialize_after_reserve(); - - return true; - } - virtual void SetUp() { // Only run test on supported Windows versions - if (!ZSyscall::is_supported()) { + if (!is_os_supported()) { GTEST_SKIP() << "Requires Windows version 1803 or later"; - return; } - ZSyscall::initialize(); - ZGlobalsPointers::initialize(); - // Fake a ZVirtualMemoryManager _vmm = (ZVirtualMemoryManager*)os::malloc(sizeof(ZVirtualMemoryManager), mtTest); + _vmm = ::new (_vmm) ZVirtualMemoryManager(ReservationSize); // Construct its internal ZMemoryManager _va = new (&_vmm->_manager) ZMemoryManager(); // Reserve address space for the test - if (!reserve_for_test()) { + if (_vmm->reserved() != ReservationSize) { GTEST_SKIP() << "Failed to reserve address space"; - return; } - - _initialized = true; - _has_unreserved = false; } virtual void TearDown() { - if (!ZSyscall::is_supported()) { + if (!is_os_supported()) { // Test skipped, nothing to cleanup return; } - if (_initialized && !_has_unreserved) { - _vmm->pd_unreserve(ZOffset::address_unsafe(zoffset(0)), 0); - } + // Best-effort cleanup + _vmm->unreserve_all(); + _vmm->~ZVirtualMemoryManager(); os::free(_vmm); } - static void test_unreserve() { + void test_unreserve() { zoffset bottom = _va->alloc_low_address(ZGranuleSize); - zoffset top = _va->alloc_high_address(ZGranuleSize); + zoffset middle = _va->alloc_low_address(ZGranuleSize); + zoffset top = _va->alloc_low_address(ZGranuleSize); + + ASSERT_EQ(bottom, zoffset(0)); + ASSERT_EQ(middle, bottom + 1 * ZGranuleSize); + ASSERT_EQ(top, bottom + 2 * ZGranuleSize); // Unreserve the middle part - ZMapper::unreserve(ZOffset::address_unsafe(bottom + ZGranuleSize), ZGranuleSize); + ZMapper::unreserve(ZOffset::address_unsafe(middle), ZGranuleSize); // Make sure that we still can unreserve the memory before and after ZMapper::unreserve(ZOffset::address_unsafe(bottom), ZGranuleSize); ZMapper::unreserve(ZOffset::address_unsafe(top), ZGranuleSize); - - _has_unreserved = true; - } - - static void test_alloc_low_address() { - // Verify that we get placeholder for first granule - zoffset bottom = _va->alloc_low_address(ZGranuleSize); - EXPECT_ALLOC_OK(bottom); - - _va->free(bottom, ZGranuleSize); - - // Alloc something larger than a granule and free it - bottom = _va->alloc_low_address(ZGranuleSize * 3); - EXPECT_ALLOC_OK(bottom); - - _va->free(bottom, ZGranuleSize * 3); - - // Free with more memory allocated - bottom = _va->alloc_low_address(ZGranuleSize); - EXPECT_ALLOC_OK(bottom); - - zoffset next = _va->alloc_low_address(ZGranuleSize); - EXPECT_ALLOC_OK(next); - - _va->free(bottom, ZGranuleSize); - _va->free(next, ZGranuleSize); - } - - static void test_alloc_high_address() { - // Verify that we get placeholder for last granule - zoffset high = _va->alloc_high_address(ZGranuleSize); - EXPECT_ALLOC_OK(high); - - zoffset prev = _va->alloc_high_address(ZGranuleSize); - EXPECT_ALLOC_OK(prev); - - _va->free(high, ZGranuleSize); - _va->free(prev, ZGranuleSize); - - // Alloc something larger than a granule and return it - high = _va->alloc_high_address(ZGranuleSize * 2); - EXPECT_ALLOC_OK(high); - - _va->free(high, ZGranuleSize * 2); - } - - static void test_alloc_whole_area() { - // Alloc the whole reservation - zoffset bottom = _va->alloc_low_address(ZMapperTestReservationSize); - EXPECT_ALLOC_OK(bottom); - - // Free two chunks and then allocate them again - _va->free(bottom, ZGranuleSize * 4); - _va->free(bottom + ZGranuleSize * 6, ZGranuleSize * 6); - - zoffset offset = _va->alloc_low_address(ZGranuleSize * 4); - EXPECT_ALLOC_OK(offset); - - offset = _va->alloc_low_address(ZGranuleSize * 6); - EXPECT_ALLOC_OK(offset); - - // Now free it all, and verify it can be re-allocated - _va->free(bottom, ZMapperTestReservationSize); - - bottom = _va->alloc_low_address(ZMapperTestReservationSize); - EXPECT_ALLOC_OK(bottom); - - _va->free(bottom, ZMapperTestReservationSize); } }; -bool ZMapperTest::_initialized = false; -ZMemoryManager* ZMapperTest::_va = nullptr; -ZVirtualMemoryManager* ZMapperTest::_vmm = nullptr; -bool ZMapperTest::_has_unreserved; - TEST_VM_F(ZMapperTest, test_unreserve) { test_unreserve(); } -TEST_VM_F(ZMapperTest, test_alloc_low_address) { - test_alloc_low_address(); -} - -TEST_VM_F(ZMapperTest, test_alloc_high_address) { - test_alloc_high_address(); -} - -TEST_VM_F(ZMapperTest, test_alloc_whole_area) { - test_alloc_whole_area(); -} - #endif // _WINDOWS diff --git a/test/hotspot/gtest/gc/z/test_zMemory.cpp b/test/hotspot/gtest/gc/z/test_zMemory.cpp index 39b0cc31db132..786a8b3fe32d2 100644 --- a/test/hotspot/gtest/gc/z/test_zMemory.cpp +++ b/test/hotspot/gtest/gc/z/test_zMemory.cpp @@ -23,28 +23,10 @@ #include "gc/z/zGlobals.hpp" #include "gc/z/zMemory.inline.hpp" -#include "unittest.hpp" - -class ZAddressOffsetMaxSetter { -private: - const size_t _old_max; - const size_t _old_mask; - -public: - ZAddressOffsetMaxSetter() - : _old_max(ZAddressOffsetMax), - _old_mask(ZAddressOffsetMask) { - ZAddressOffsetMax = size_t(16) * G * 1024; - ZAddressOffsetMask = ZAddressOffsetMax - 1; - } - ~ZAddressOffsetMaxSetter() { - ZAddressOffsetMax = _old_max; - ZAddressOffsetMask = _old_mask; - } -}; +#include "zunittest.hpp" TEST(ZMemory, accessors) { - ZAddressOffsetMaxSetter setter; + ZAddressOffsetMaxSetter setter(size_t(16) * G * 1024); { ZMemory mem(zoffset(0), ZGranuleSize); @@ -74,7 +56,7 @@ TEST(ZMemory, accessors) { } TEST(ZMemory, resize) { - ZAddressOffsetMaxSetter setter; + ZAddressOffsetMaxSetter setter(size_t(16) * G * 1024); ZMemory mem(zoffset(ZGranuleSize * 2), ZGranuleSize * 2) ; diff --git a/test/hotspot/gtest/gc/z/test_zVirtualMemory.cpp b/test/hotspot/gtest/gc/z/test_zVirtualMemory.cpp index d09d79f8b1c44..facbb14e8a07f 100644 --- a/test/hotspot/gtest/gc/z/test_zVirtualMemory.cpp +++ b/test/hotspot/gtest/gc/z/test_zVirtualMemory.cpp @@ -22,9 +22,11 @@ */ #include "gc/z/zVirtualMemory.inline.hpp" -#include "unittest.hpp" +#include "zunittest.hpp" TEST(ZVirtualMemory, split) { + ZAddressOffsetMaxSetter setter(size_t(16) * G * 1024); + ZVirtualMemory vmem(zoffset(0), 10); ZVirtualMemory vmem0 = vmem.split(0); diff --git a/test/hotspot/gtest/gc/z/test_zVirtualMemoryManager.cpp b/test/hotspot/gtest/gc/z/test_zVirtualMemoryManager.cpp new file mode 100644 index 0000000000000..1100b1e005ecf --- /dev/null +++ b/test/hotspot/gtest/gc/z/test_zVirtualMemoryManager.cpp @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "gc/z/zAddress.inline.hpp" +#include "gc/z/zArguments.hpp" +#include "gc/z/zGlobals.hpp" +#include "gc/z/zInitialize.hpp" +#include "gc/z/zList.inline.hpp" +#include "gc/z/zMemory.inline.hpp" +#include "gc/z/zNUMA.inline.hpp" +#include "gc/z/zValue.inline.hpp" +#include "gc/z/zVirtualMemory.hpp" +#include "runtime/os.hpp" +#include "zunittest.hpp" + +using namespace testing; + +#define ASSERT_ALLOC_OK(offset) ASSERT_NE(offset, zoffset(UINTPTR_MAX)) + +class ZCallbacksResetter { +private: + ZMemoryManager::Callbacks* _callbacks; + ZMemoryManager::Callbacks _saved; + +public: + ZCallbacksResetter(ZMemoryManager::Callbacks* callbacks) + : _callbacks(callbacks), + _saved(*callbacks) { + *_callbacks = {}; + } + ~ZCallbacksResetter() { + *_callbacks = _saved; + } +}; + +class ZVirtualMemoryManagerTest : public ZTest { +private: + static constexpr size_t ReservationSize = 32 * M; + + ZMemoryManager* _va; + ZVirtualMemoryManager* _vmm; + +public: + virtual void SetUp() { + // Only run test on supported Windows versions + if (!is_os_supported()) { + GTEST_SKIP() << "OS not supported"; + } + + void* vmr_mem = os::malloc(sizeof(ZVirtualMemoryManager), mtTest); + _vmm = ::new (vmr_mem) ZVirtualMemoryManager(ReservationSize); + _va = &_vmm->_manager; + } + + virtual void TearDown() { + if (!is_os_supported()) { + // Test skipped, nothing to cleanup + return; + } + + // Best-effort cleanup + _vmm->unreserve_all(); + _vmm->~ZVirtualMemoryManager(); + os::free(_vmm); + } + + void test_reserve_discontiguous_and_coalesce() { + // Start by ensuring that we have 3 unreserved granules, and then let the + // fourth granule be pre-reserved and therefore blocking subsequent requests + // to reserve memory. + // + // +----+----+----+----+ + // ----- pre-reserved - to block contiguous reservation + // --------------- unreserved - to allow reservation of 3 granules + // + // If we then asks for 4 granules starting at the first granule above, + // then we won't be able to allocate 4 consecutive granules and the code + // reverts into the discontiguous mode. This mode uses interval halving + // to find the limits of memory areas that have already been reserved. + // This will lead to the first 2 granules being reserved, then the third + // granule will be reserved. + // + // The problem we had with this is that this would yield two separate + // placeholder reservations, even though they are adjacent. The callbacks + // are supposed to fix that by coalescing the placeholders, *but* the + // callbacks used to be only turned on *after* the reservation call. So, + // we end up with one 3 granule large memory area in the manager, which + // unexpectedly was covered by two placeholders (instead of the expected + // one placeholder). + // + // Later when the callbacks had been installed and we tried to fetch memory + // from the manager, the callbacks would try to split off the placeholder + // to separate the fetched memory from the memory left in the manager. This + // used to fail because the memory was already split into two placeholders. + + if (_vmm->reserved() < 4 * ZGranuleSize || !_va->free_is_contiguous()) { + GTEST_SKIP() << "Fixture failed to reserve adequate memory, reserved " + << (_vmm->reserved() >> ZGranuleSizeShift) << " * ZGranuleSize"; + } + + // Start at the offset we reserved. + const zoffset base_offset = _vmm->lowest_available_address(); + + // Empty the reserved memory in preparation for the rest of the test. + _vmm->unreserve_all(); + + const zaddress_unsafe base = ZOffset::address_unsafe(base_offset); + const zaddress_unsafe blocked = base + 3 * ZGranuleSize; + + // Reserve the memory that is acting as a blocking reservation. + { + char* const result = os::attempt_reserve_memory_at((char*)untype(blocked), ZGranuleSize, !ExecMem, mtTest); + if (uintptr_t(result) != untype(blocked)) { + GTEST_SKIP() << "Failed to reserve requested memory at " << untype(blocked); + } + } + + { + // This ends up reserving 2 granules and then 1 granule adjacent to the + // first. In previous implementations this resulted in two separate + // placeholders (4MB and 2MB). This was a bug, because the manager is + // designed to have one placeholder per memory area. This in turn would + // lead to a subsequent failure when _vmm->alloc tried to split off the + // 4MB that is already covered by its own placeholder. You can't place + // a placeholder over an already existing placeholder. + + // To reproduce this, the test needed to mimic the initializing memory + // reservation code which had the placeholders turned off. This was done + // with this helper: + // + // ZCallbacksResetter resetter(&_va->_callbacks); + // + // After the fix, we always have the callbacks turned on, so we don't + // need this to mimic the initializing memory reservation. + + const size_t reserved = _vmm->reserve_discontiguous(base_offset, 4 * ZGranuleSize, ZGranuleSize); + ASSERT_LE(reserved, 3 * ZGranuleSize); + if (reserved < 3 * ZGranuleSize) { + GTEST_SKIP() << "Failed reserve_discontiguous" + ", expected 3 * ZGranuleSize, got " << (reserved >> ZGranuleSizeShift) + << " * ZGranuleSize"; + } + } + + { + // The test used to crash here because the 3 granule memory area was + // inadvertently covered by two place holders (2 granules + 1 granule). + const ZVirtualMemory vmem = _vmm->alloc(2 * ZGranuleSize, true); + ASSERT_EQ(vmem.start(), base_offset); + ASSERT_EQ(vmem.size(), 2 * ZGranuleSize); + + // Cleanup - Must happen in granule-sizes because of how Windows hands + // out memory in granule-sized placeholder reservations. + _vmm->unreserve(base_offset, ZGranuleSize); + _vmm->unreserve(base_offset + ZGranuleSize, ZGranuleSize); + } + + // Final cleanup + const ZVirtualMemory vmem = _vmm->alloc(ZGranuleSize, true); + ASSERT_EQ(vmem.start(), base_offset + 2 * ZGranuleSize); + ASSERT_EQ(vmem.size(), ZGranuleSize); + _vmm->unreserve(vmem.start(), vmem.size()); + + const bool released = os::release_memory((char*)untype(blocked), ZGranuleSize); + ASSERT_TRUE(released); + } + + void test_alloc_low_address() { + // Verify that we get a placeholder for the first granule + zoffset bottom = _va->alloc_low_address(ZGranuleSize); + ASSERT_ALLOC_OK(bottom); + + _va->free(bottom, ZGranuleSize); + + // Alloc something larger than a granule and free it + bottom = _va->alloc_low_address(ZGranuleSize * 3); + ASSERT_ALLOC_OK(bottom); + + _va->free(bottom, ZGranuleSize * 3); + + // Free with more memory allocated + bottom = _va->alloc_low_address(ZGranuleSize); + ASSERT_ALLOC_OK(bottom); + + zoffset next = _va->alloc_low_address(ZGranuleSize); + ASSERT_ALLOC_OK(next); + + _va->free(bottom, ZGranuleSize); + _va->free(next, ZGranuleSize); + } + + void test_alloc_high_address() { + // Verify that we get a placeholder for the last granule + zoffset high = _va->alloc_high_address(ZGranuleSize); + ASSERT_ALLOC_OK(high); + + zoffset prev = _va->alloc_high_address(ZGranuleSize); + ASSERT_ALLOC_OK(prev); + + _va->free(high, ZGranuleSize); + _va->free(prev, ZGranuleSize); + + // Alloc something larger than a granule and return it + high = _va->alloc_high_address(ZGranuleSize * 2); + ASSERT_ALLOC_OK(high); + + _va->free(high, ZGranuleSize * 2); + } + + void test_alloc_whole_area() { + // Alloc the whole reservation + zoffset bottom = _va->alloc_low_address(ReservationSize); + ASSERT_ALLOC_OK(bottom); + + // Free two chunks and then allocate them again + _va->free(bottom, ZGranuleSize * 4); + _va->free(bottom + ZGranuleSize * 6, ZGranuleSize * 6); + + zoffset offset = _va->alloc_low_address(ZGranuleSize * 4); + ASSERT_ALLOC_OK(offset); + + offset = _va->alloc_low_address(ZGranuleSize * 6); + ASSERT_ALLOC_OK(offset); + + // Now free it all, and verify it can be re-allocated + _va->free(bottom, ReservationSize); + + bottom = _va->alloc_low_address(ReservationSize); + ASSERT_ALLOC_OK(bottom); + + _va->free(bottom, ReservationSize); + } +}; + +TEST_VM_F(ZVirtualMemoryManagerTest, test_reserve_discontiguous_and_coalesce) { + test_reserve_discontiguous_and_coalesce(); +} + +TEST_VM_F(ZVirtualMemoryManagerTest, test_alloc_low_address) { + test_alloc_low_address(); +} + +TEST_VM_F(ZVirtualMemoryManagerTest, test_alloc_high_address) { + test_alloc_high_address(); +} + +TEST_VM_F(ZVirtualMemoryManagerTest, test_alloc_whole_area) { + test_alloc_whole_area(); +} diff --git a/test/hotspot/gtest/gc/z/zunittest.hpp b/test/hotspot/gtest/gc/z/zunittest.hpp new file mode 100644 index 0000000000000..610d158c89da8 --- /dev/null +++ b/test/hotspot/gtest/gc/z/zunittest.hpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef ZUNITTEST_HPP +#define ZUNITTEST_HPP + +#include "gc/z/zAddress.hpp" +#include "gc/z/zArguments.hpp" +#include "gc/z/zInitialize.hpp" +#include "unittest.hpp" + +class ZAddressOffsetMaxSetter { + friend class ZTest; + +private: + size_t _old_max; + size_t _old_mask; + +public: + ZAddressOffsetMaxSetter(size_t zaddress_offset_max) + : _old_max(ZAddressOffsetMax), + _old_mask(ZAddressOffsetMask) { + ZAddressOffsetMax = zaddress_offset_max; + ZAddressOffsetMask = ZAddressOffsetMax - 1; + } + ~ZAddressOffsetMaxSetter() { + ZAddressOffsetMax = _old_max; + ZAddressOffsetMask = _old_mask; + } +}; + +class ZTest : public testing::Test { +private: + ZAddressOffsetMaxSetter _zaddress_offset_max_setter; + +protected: + ZTest() + : _zaddress_offset_max_setter(ZAddressOffsetMax) { + if (!is_os_supported()) { + // If the OS does not support ZGC do not run initialization, as it may crash the VM. + return; + } + + // Initialize ZGC subsystems for gtests, may only be called once per process. + static bool runs_once = [&]() { + ZInitialize::pd_initialize(); + ZGlobalsPointers::initialize(); + + // ZGlobalsPointers::initialize() sets ZAddressOffsetMax, make sure the + // first test fixture invocation has a correct ZAddressOffsetMaxSetter. + _zaddress_offset_max_setter._old_max = ZAddressOffsetMax; + _zaddress_offset_max_setter._old_mask = ZAddressOffsetMask; + return true; + }(); + } + + bool is_os_supported() { + return ZArguments::is_os_supported(); + } +}; + +#endif // ZUNITTEST_HPP From e8c9e5c6cd3c844765c27c068022a018914fdf4e Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Mon, 7 Apr 2025 11:34:23 +0000 Subject: [PATCH 0418/1101] 8353231: Test com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad still fails intermittently Reviewed-by: dholmes --- .../OperatingSystemMXBean/TEST.properties | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 test/jdk/com/sun/management/OperatingSystemMXBean/TEST.properties diff --git a/test/jdk/com/sun/management/OperatingSystemMXBean/TEST.properties b/test/jdk/com/sun/management/OperatingSystemMXBean/TEST.properties new file mode 100644 index 0000000000000..9ddb06fbbcb9b --- /dev/null +++ b/test/jdk/com/sun/management/OperatingSystemMXBean/TEST.properties @@ -0,0 +1,24 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +exclusiveAccess.dirs=. From 26bb18378737809542b1153f8f34d55d409ea4e2 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 7 Apr 2025 11:56:53 +0000 Subject: [PATCH 0419/1101] 8352621: MatchException from backwards incompatible change to switch expressions Reviewed-by: abimpoudis --- .../sun/tools/javac/comp/TransPatterns.java | 9 +- .../com/sun/tools/javac/jvm/Target.java | 9 +- .../NoPrimitivesAsCaseLabelsFor21.java | 166 ++++++++++++++++++ 3 files changed, 181 insertions(+), 3 deletions(-) create mode 100644 test/langtools/tools/javac/patterns/NoPrimitivesAsCaseLabelsFor21.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java index 93c4eaa03ee01..58c36a5cf7c27 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1041,7 +1041,12 @@ private Type principalType(JCTree p) { private LoadableConstant toLoadableConstant(JCCaseLabel l, Type selector) { if (l.hasTag(Tag.PATTERNCASELABEL)) { Type principalType = principalType(((JCPatternCaseLabel) l).pat); - if (((JCPatternCaseLabel) l).pat.type.isReference()) { + + if (target.switchBootstrapOnlyAllowsReferenceTypesAsCaseLabels()) { + principalType = types.boxedTypeOrType(principalType); + } + + if (principalType.isReference()) { if (types.isSubtype(selector, principalType)) { return (LoadableConstant) selector; } else { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java index 5b207352e6e34..eeca1dadc1b42 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -245,4 +245,11 @@ public boolean usesReferenceOnlySelectorTypes() { public boolean nullCheckOuterThisByDefault() { return compareTo(JDK1_25) >= 0; } + + /** Releases prior to JDK 23 don't allow primitive types as case labels in + * SwitchBootstrap.typeSwitch + */ + public boolean switchBootstrapOnlyAllowsReferenceTypesAsCaseLabels() { + return compareTo(Target.JDK1_23) < 0; + } } diff --git a/test/langtools/tools/javac/patterns/NoPrimitivesAsCaseLabelsFor21.java b/test/langtools/tools/javac/patterns/NoPrimitivesAsCaseLabelsFor21.java new file mode 100644 index 0000000000000..bd5f51b644e98 --- /dev/null +++ b/test/langtools/tools/javac/patterns/NoPrimitivesAsCaseLabelsFor21.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8352621 + * @summary Verify javac does not use primitive types in SwitchBootstraps.typeSwitch + * when compiling with target older than JDK 23 + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavacTask + * @run main NoPrimitivesAsCaseLabelsFor21 +*/ + +import java.io.IOException; +import java.lang.classfile.Attributes; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassModel; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.LoadableConstantEntry; +import java.lang.classfile.constantpool.MethodHandleEntry; +import java.lang.constant.DirectMethodHandleDesc; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.atomic.AtomicBoolean; + +import toolbox.JavacTask; +import toolbox.TestRunner; +import toolbox.ToolBox; + +public class NoPrimitivesAsCaseLabelsFor21 extends TestRunner { + + ToolBox tb; + + public static void main(String... args) throws Exception { + new NoPrimitivesAsCaseLabelsFor21().runTests(); + } + + NoPrimitivesAsCaseLabelsFor21() { + super(System.err); + tb = new ToolBox(); + } + + public void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test + public void testExhaustiveSealedClasses(Path base) throws Exception { + Path current = base.resolve("."); + Path src = current.resolve("src"); + + tb.writeJavaFiles(src, + """ + package test; + public class Test { + private int test(Object obj) { + return switch (obj) { + case R1(String s1, String s2) when s1.isEmpty() -> 0; + case R1(String s1, String s2) -> 1; + case R2(int i1, int i2) when i1 == 0 -> 2; + case R2(int i1, int i2) -> 3; + default -> 4; + }; + } + record R1(String s1, String s2) {} + record R2(int i1, int i2) {} + } + """); + + Path classes = current.resolve("classes"); + + Files.createDirectories(classes); + + for (String version : new String[] {"23", System.getProperty("java.specification.version")}) { + new JavacTask(tb) + .options("--release", version) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run() + .writeAll(); + + Path testClassFile = classes.resolve("test").resolve("Test.class"); + String primitivesInBoostrapArgsForNewer = + findPrimitiveBootstrapArguments(testClassFile); + + if (!primitivesInBoostrapArgsForNewer.contains("I-Ljava/lang/Class")) { + throw new AssertionError("Expected primitive types in switch bootstrap arguments: " + primitivesInBoostrapArgsForNewer); + } + } + + for (String version : new String[] {"21", "22"}) { + new JavacTask(tb) + .options("--release", version) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run() + .writeAll(); + + Path testClassFile = classes.resolve("test").resolve("Test.class"); + String primitivesInBoostrapArgsForOlder = + findPrimitiveBootstrapArguments(testClassFile); + + + if (!primitivesInBoostrapArgsForOlder.isEmpty()) { + throw new AssertionError("Unexpected primitive types in switch bootstrap arguments: " + primitivesInBoostrapArgsForOlder); + } + } + } + + private String findPrimitiveBootstrapArguments(Path forFile) throws IOException { + AtomicBoolean hasTypeSwitchBootStrap = new AtomicBoolean(); + StringBuilder nonClassInTypeSwitchBootStrap = new StringBuilder(); + ClassModel testClassFileModel = ClassFile.of().parse(forFile); + + testClassFileModel.findAttribute(Attributes.bootstrapMethods()) + .orElseThrow() + .bootstrapMethods() + .stream() + .filter(bme -> isTypeSwitchBoostrap(bme.bootstrapMethod())) + .forEach(bme -> { + hasTypeSwitchBootStrap.set(true); + for (LoadableConstantEntry e : bme.arguments()) { + if (!(e instanceof ClassEntry)) { + nonClassInTypeSwitchBootStrap.append(String.valueOf(e)); + } + } + }); + + if (!hasTypeSwitchBootStrap.get()) { + throw new AssertionError("Didn't find any typeSwitch bootstraps!"); + } + + return nonClassInTypeSwitchBootStrap.toString(); + } + + private static boolean isTypeSwitchBoostrap(MethodHandleEntry entry) { + DirectMethodHandleDesc desc = entry.asSymbol(); + return "Ljava/lang/runtime/SwitchBootstraps;".equals(desc.owner().descriptorString()) && + "typeSwitch".equals(desc.methodName()) && + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;".equals(desc.lookupDescriptor()); + } +} From 353e1738f6eb9965571e1de881d209b698492e6e Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Mon, 7 Apr 2025 11:58:17 +0000 Subject: [PATCH 0420/1101] 8219408: Tests should handle ${} in the view of jtreg "smart action" Reviewed-by: mullan --- test/jdk/com/sun/security/auth/login/ConfigFile/TEST.properties | 2 -- .../jdk/java/security/Security/SecurityPropFile/TEST.properties | 2 -- test/jdk/javax/security/auth/login/TEST.properties | 2 -- test/jdk/sun/security/util/Resources/TEST.properties | 2 -- 4 files changed, 8 deletions(-) delete mode 100644 test/jdk/com/sun/security/auth/login/ConfigFile/TEST.properties delete mode 100644 test/jdk/java/security/Security/SecurityPropFile/TEST.properties delete mode 100644 test/jdk/javax/security/auth/login/TEST.properties delete mode 100644 test/jdk/sun/security/util/Resources/TEST.properties diff --git a/test/jdk/com/sun/security/auth/login/ConfigFile/TEST.properties b/test/jdk/com/sun/security/auth/login/ConfigFile/TEST.properties deleted file mode 100644 index 908b451f8ea69..0000000000000 --- a/test/jdk/com/sun/security/auth/login/ConfigFile/TEST.properties +++ /dev/null @@ -1,2 +0,0 @@ -# disabled till JDK-8219408 is fixed -allowSmartActionArgs=false diff --git a/test/jdk/java/security/Security/SecurityPropFile/TEST.properties b/test/jdk/java/security/Security/SecurityPropFile/TEST.properties deleted file mode 100644 index 908b451f8ea69..0000000000000 --- a/test/jdk/java/security/Security/SecurityPropFile/TEST.properties +++ /dev/null @@ -1,2 +0,0 @@ -# disabled till JDK-8219408 is fixed -allowSmartActionArgs=false diff --git a/test/jdk/javax/security/auth/login/TEST.properties b/test/jdk/javax/security/auth/login/TEST.properties deleted file mode 100644 index 908b451f8ea69..0000000000000 --- a/test/jdk/javax/security/auth/login/TEST.properties +++ /dev/null @@ -1,2 +0,0 @@ -# disabled till JDK-8219408 is fixed -allowSmartActionArgs=false diff --git a/test/jdk/sun/security/util/Resources/TEST.properties b/test/jdk/sun/security/util/Resources/TEST.properties deleted file mode 100644 index 908b451f8ea69..0000000000000 --- a/test/jdk/sun/security/util/Resources/TEST.properties +++ /dev/null @@ -1,2 +0,0 @@ -# disabled till JDK-8219408 is fixed -allowSmartActionArgs=false From 66435c27b3e0a89e4350caf6207e36f5a9b82b7f Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Mon, 7 Apr 2025 12:28:41 +0000 Subject: [PATCH 0421/1101] 8352684: Opensource JInternalFrame tests - series1 Reviewed-by: azvegint --- .../swing/JInternalFrame/bug4131008.java | 86 +++++++++++++++++++ .../swing/JInternalFrame/bug4176136.java | 70 +++++++++++++++ .../swing/JInternalFrame/bug4244536.java | 75 ++++++++++++++++ .../swing/JInternalFrame/bug4305284.java | 73 ++++++++++++++++ 4 files changed, 304 insertions(+) create mode 100644 test/jdk/javax/swing/JInternalFrame/bug4131008.java create mode 100644 test/jdk/javax/swing/JInternalFrame/bug4176136.java create mode 100644 test/jdk/javax/swing/JInternalFrame/bug4244536.java create mode 100644 test/jdk/javax/swing/JInternalFrame/bug4305284.java diff --git a/test/jdk/javax/swing/JInternalFrame/bug4131008.java b/test/jdk/javax/swing/JInternalFrame/bug4131008.java new file mode 100644 index 0000000000000..9f45175a7857d --- /dev/null +++ b/test/jdk/javax/swing/JInternalFrame/bug4131008.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4131008 + * @summary JInternalFrame should refresh title after it changing + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4131008 +*/ + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.UIManager; + +public class bug4131008 { + + private static final String INSTRUCTIONS = """ + Press button "Change title" at the internal frame "Old". + If title of this frame will replaced by "New", + then test passed, else test fails."""; + + public static void main(String[] args) throws Exception { + + UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); + + PassFailJFrame.builder() + .title("bug4131008 Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4131008::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("bug4131008"); + JInternalFrame jif = new JInternalFrame("Old"); + JDesktopPane jdp = new JDesktopPane(); + frame.setContentPane(jdp); + + jif.setSize(150, 100); + jif.setVisible(true); + JButton bt = new JButton("Change title"); + bt.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + jif.setTitle("New"); + } + }); + jif.getContentPane().add(bt); + jdp.add(jif); + try { + jif.setSelected(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + frame.setSize(300, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JInternalFrame/bug4176136.java b/test/jdk/javax/swing/JInternalFrame/bug4176136.java new file mode 100644 index 0000000000000..019e453750c64 --- /dev/null +++ b/test/jdk/javax/swing/JInternalFrame/bug4176136.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4176136 + * @summary Default close operation JInternalFrame.DO_NOTHING_ON_CLOSE works correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4176136 + */ + + +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; + +public class bug4176136 { + + private static final String INSTRUCTIONS = """ + Click the close button of the internal frame. + You will see the close button activate, + but nothing else should happen. + If the internal frame closes, the test fails. + If it doesn't close, the test passes."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4176136 Instructions") + .instructions(INSTRUCTIONS) + .columns(25) + .testUI(bug4176136::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("bug4176136"); + JDesktopPane dp = new JDesktopPane(); + frame.add(dp); + JInternalFrame inf = new JInternalFrame(); + dp.add(inf); + inf.setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE); + inf.setSize(100, 100); + inf.setClosable(true); + inf.setVisible(true); + frame.setSize(200, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JInternalFrame/bug4244536.java b/test/jdk/javax/swing/JInternalFrame/bug4244536.java new file mode 100644 index 0000000000000..85acb833d2aa8 --- /dev/null +++ b/test/jdk/javax/swing/JInternalFrame/bug4244536.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4244536 + * @summary Tests that Motif JInternalFrame can be maximized + * after it was iconified. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4244536 + */ + +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.UIManager; + +public class bug4244536 { + + private static final String INSTRUCTIONS = """ + Minimize the internal frame using the minimize button. + Then double-click on it to restore its size. + Then press the maximize button. + If the frame gets maximized, test passes. + If its size don't change, test fails."""; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel( + "com.sun.java.swing.plaf.motif.MotifLookAndFeel"); + + PassFailJFrame.builder() + .title("bug4244536 Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4244536::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("bug4244536"); + JDesktopPane desktop = new JDesktopPane(); + JInternalFrame jif = new JInternalFrame("Internal Frame"); + jif.setSize(150, 150); + jif.setMaximizable(true); + jif.setIconifiable(true); + jif.setVisible(true); + desktop.add(jif); + frame.add("Center", desktop); + frame.setSize(300, 300); + return frame; + } + +} diff --git a/test/jdk/javax/swing/JInternalFrame/bug4305284.java b/test/jdk/javax/swing/JInternalFrame/bug4305284.java new file mode 100644 index 0000000000000..8801c8c678c6f --- /dev/null +++ b/test/jdk/javax/swing/JInternalFrame/bug4305284.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4305284 + * @summary JInternalFrames can't be sized off of the desktop + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4305284 + */ + +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; + +public class bug4305284 { + + private static final String INSTRUCTIONS = """ + Try to resize the shown internal frame. + If it can't be sized of the desktop bounds, + then test passes, else test fails."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4305284 Instructions") + .instructions(INSTRUCTIONS) + .columns(25) + .testUI(bug4305284::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("bug4305284"); + JInternalFrame jif = new JInternalFrame("Test", + true, true, true, true); + JDesktopPane dp = new JDesktopPane(); + frame.setContentPane(dp); + dp.add(jif); + + try { + jif.setBounds(50, 50, 200, 200); + jif.setMaximum(false); + jif.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + frame.setSize(300, 300); + return frame; + } + +} From 27c8d9d635eaa0aac722c1b1eba8591fd291c077 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Mon, 7 Apr 2025 12:30:55 +0000 Subject: [PATCH 0422/1101] 8352686: Opensource JInternalFrame tests - series3 Reviewed-by: azvegint --- .../swing/JInternalFrame/bug4151444.java | 84 ++++++++++++ .../swing/JInternalFrame/bug4215380.java | 109 +++++++++++++++ .../swing/JInternalFrame/bug4321312.java | 126 ++++++++++++++++++ .../swing/JInternalFrame/bug4322726.java | 109 +++++++++++++++ 4 files changed, 428 insertions(+) create mode 100644 test/jdk/javax/swing/JInternalFrame/bug4151444.java create mode 100644 test/jdk/javax/swing/JInternalFrame/bug4215380.java create mode 100644 test/jdk/javax/swing/JInternalFrame/bug4321312.java create mode 100644 test/jdk/javax/swing/JInternalFrame/bug4322726.java diff --git a/test/jdk/javax/swing/JInternalFrame/bug4151444.java b/test/jdk/javax/swing/JInternalFrame/bug4151444.java new file mode 100644 index 0000000000000..26b64142e28df --- /dev/null +++ b/test/jdk/javax/swing/JInternalFrame/bug4151444.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4151444 + * @summary The maximize button acts like the restore button + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4151444 +*/ + +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.JLayeredPane; +import javax.swing.UIManager; + + +public class bug4151444 { + + private static JFrame frame; + private static JInternalFrame interFrame; + + private static final String INSTRUCTIONS = """ + - maximize the internal frame + - then minimize the internal frame + - then maximize the internal frame again + - Check whether internal frame is maximized + - Test will fail automatically even if "Pass" is pressed + if internal frame is not maximized."""; + + public static void main(String[] args) throws Exception { + + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + + PassFailJFrame pfj = PassFailJFrame.builder() + .title("bug4151444 Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(bug4151444::createTestUI) + .build(); + try { + pfj.awaitAndCheck(); + } finally { + if (!interFrame.isMaximum()) { + throw new RuntimeException ("Test failed. The maximize button acts like the restore button"); + } + } + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("bug4151444 frame"); + JDesktopPane desktop = new JDesktopPane(); + frame.setContentPane(desktop); + interFrame = new JInternalFrame( + "Internal frame", true, true, true, true); + desktop.add(interFrame, JLayeredPane.DEFAULT_LAYER); + interFrame.setBounds(0, 0, 200, 100); + interFrame.setVisible(true); + frame.setSize(300, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JInternalFrame/bug4215380.java b/test/jdk/javax/swing/JInternalFrame/bug4215380.java new file mode 100644 index 0000000000000..f9cd18dfb752f --- /dev/null +++ b/test/jdk/javax/swing/JInternalFrame/bug4215380.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4215380 + * @summary Internal Frame should get focus + * @key headful + * @run main bug4215380 + */ + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.InputEvent; +import java.awt.Point; +import java.awt.Robot; + +import javax.swing.JButton; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.JLayeredPane; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +public class bug4215380 { + + private static String button; + private static JButton b; + private static JFrame frame; + private static JInternalFrame jif; + private static volatile Point loc; + private static volatile Dimension size; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + try { + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("bug4215380"); + JDesktopPane desktop = new JDesktopPane(); + frame.add(desktop, BorderLayout.CENTER); + + jif = iFrame(1); + desktop.add(jif, JLayeredPane.DEFAULT_LAYER); + desktop.add(iFrame(2), JLayeredPane.DEFAULT_LAYER); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(1000); + SwingUtilities.invokeAndWait(() -> { + loc = b.getLocationOnScreen(); + size = b.getSize(); + }); + robot.mouseMove(loc.x + size.width / 2, loc.y + size.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(500); + if (!(jif.isSelected()) && !button.equals("Frame 1")) { + throw new RuntimeException("Internal frame \"Frame 1\" should be selected..."); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static JInternalFrame iFrame(int i) { + JInternalFrame frame = new JInternalFrame("Frame " + i); + JPanel panel = new JPanel(); + JButton bt = new JButton("Button " + i); + if (i == 1) { + b = bt; + } + bt.addActionListener(e -> button = ((JButton)e.getSource()).getText()); + + panel.add(bt); + + frame.getContentPane().add(panel); + frame.setBounds(10, i * 80 - 70, 120, 90); + frame.setVisible(true); + return frame; + } +} diff --git a/test/jdk/javax/swing/JInternalFrame/bug4321312.java b/test/jdk/javax/swing/JInternalFrame/bug4321312.java new file mode 100644 index 0000000000000..1b527acf74584 --- /dev/null +++ b/test/jdk/javax/swing/JInternalFrame/bug4321312.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4321312 + * @summary Verifies no Exception thrown from BasicInternalFrameUI$BorderListener + * @key headful + * @run main bug4321312 + */ + +import java.awt.Dimension; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.Point; +import java.awt.Robot; + +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +public class bug4321312 { + + private static JFrame frame; + private static MyInternalFrame jif; + private static volatile Point loc; + private static volatile Dimension size; + + static boolean fails; + static Exception exc; + + private static synchronized boolean isFails() { + return fails; + } + + private static synchronized void setFails(Exception e) { + fails = true; + exc = e; + } + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + try { + SwingUtilities.invokeAndWait(() -> { + try { + UIManager.setLookAndFeel( + "com.sun.java.swing.plaf.motif.MotifLookAndFeel"); + } catch (ClassNotFoundException | InstantiationException + | UnsupportedLookAndFeelException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + + frame = new JFrame("bug4321312"); + JDesktopPane jdp = new JDesktopPane(); + frame.add(jdp); + + jif = new MyInternalFrame("Internal Frame", true); + jdp.add(jif); + jif.setSize(150, 150); + jif.setVisible(true); + + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(1000); + SwingUtilities.invokeAndWait(() -> { + loc = jif.getLocationOnScreen(); + size = jif.getSize(); + }); + robot.mouseMove(loc.x + size.width / 2, loc.y + size.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(200); + if (isFails()) { + throw new RuntimeException(exc); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + static class MyInternalFrame extends JInternalFrame { + MyInternalFrame(String str, boolean b) { + super(str, b); + } + + protected void processMouseEvent(MouseEvent e) { + try { + super.processMouseEvent(e); + } catch (Exception exc) { + setFails(exc); + } + } + } +} diff --git a/test/jdk/javax/swing/JInternalFrame/bug4322726.java b/test/jdk/javax/swing/JInternalFrame/bug4322726.java new file mode 100644 index 0000000000000..861f9357fba6c --- /dev/null +++ b/test/jdk/javax/swing/JInternalFrame/bug4322726.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4322726 + * @summary Tests that JInternalFrame throws ArrayIndexOutOfBoundsException when Control-F4 pressed + * @key headful + * @run main bug4322726 + */ + +import java.awt.event.KeyEvent; +import java.awt.Robot; + +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +import java.beans.PropertyVetoException; + +public class bug4322726 { + + private static JFrame frame; + private static JInternalFrame internalFrame; + private static volatile boolean failed; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + try { + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("bug4322726"); + frame.setSize(600, 400); + TestDesktopPane desktopPane = new TestDesktopPane(); + frame.setContentPane(desktopPane); + internalFrame = new JInternalFrame(); + internalFrame.setClosable(true); + internalFrame.setMaximizable(true); + internalFrame.setIconifiable(true); + internalFrame.setResizable(true); + internalFrame.setTitle("Internal Frame"); + internalFrame.setSize(300, 200); + internalFrame.setVisible(true); + desktopPane.add(internalFrame); + + frame.setSize(400, 400); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(1000); + SwingUtilities.invokeAndWait(() -> { + try { + internalFrame.setSelected(true); + } catch (PropertyVetoException e) { + throw new RuntimeException("PropertyVetoException thrown"); + } + }); + robot.waitForIdle(); + robot.delay(200); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.keyPress(KeyEvent.VK_F4); + robot.keyRelease(KeyEvent.VK_F4); + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.waitForIdle(); + robot.delay(200); + if (failed) { + throw new RuntimeException("Failed: index is out of bounds"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + static class TestDesktopPane extends JDesktopPane { + protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) { + try { + return super.processKeyBinding(ks, e, condition, pressed); + } catch (ArrayIndexOutOfBoundsException ex) { + failed = true; + } + return failed; + } + } +} From 9128ec61df430a2eb352f58ec9799d332f7b1a10 Mon Sep 17 00:00:00 2001 From: Joachim Kern Date: Mon, 7 Apr 2025 12:50:43 +0000 Subject: [PATCH 0423/1101] 8352935: Launcher should not add $JDK/../lib to LD_LIBRARY_PATH Reviewed-by: clanger, ihse, jpai --- src/java.base/unix/native/libjli/java_md.c | 7 ++-- .../tools/launcher/ExecutionEnvironment.java | 1 - test/jdk/tools/launcher/Test7029048.java | 32 ++++++------------- 3 files changed, 11 insertions(+), 29 deletions(-) diff --git a/src/java.base/unix/native/libjli/java_md.c b/src/java.base/unix/native/libjli/java_md.c index 2c25a7668c396..0a61971b080c9 100644 --- a/src/java.base/unix/native/libjli/java_md.c +++ b/src/java.base/unix/native/libjli/java_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -348,7 +348,6 @@ CreateExecutionEnvironment(int *pargc, char ***pargv, * * o $JVMPATH (directory portion only) * o $JDK/lib - * o $JDK/../lib * * followed by the user's previous effective LD_LIBRARY_PATH, if * any. @@ -377,10 +376,8 @@ CreateExecutionEnvironment(int *pargc, char ***pargv, snprintf(new_runpath, new_runpath_size, LD_LIBRARY_PATH "=" "%s:" - "%s/lib:" - "%s/../lib", + "%s/lib", new_jvmpath, - jdkroot, jdkroot ); diff --git a/test/jdk/tools/launcher/ExecutionEnvironment.java b/test/jdk/tools/launcher/ExecutionEnvironment.java index 8a10756021eb9..dbf20fc5bb9c4 100644 --- a/test/jdk/tools/launcher/ExecutionEnvironment.java +++ b/test/jdk/tools/launcher/ExecutionEnvironment.java @@ -141,7 +141,6 @@ void testEcoFriendly() { String libPath = LD_LIBRARY_PATH + "=" + jvmroot + "/lib/server" + System.getProperty("path.separator") + jvmroot + "/lib" + System.getProperty("path.separator") + - jvmroot + "/../lib" + System.getProperty("path.separator") + LD_LIBRARY_PATH_VALUE; if (!tr.matches(libPath)) { flagError(tr, "FAIL: did not get <" + libPath + ">"); diff --git a/test/jdk/tools/launcher/Test7029048.java b/test/jdk/tools/launcher/Test7029048.java index 4aab158cfc13e..f92867044a16e 100644 --- a/test/jdk/tools/launcher/Test7029048.java +++ b/test/jdk/tools/launcher/Test7029048.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,21 +26,10 @@ * @bug 7029048 8217340 8217216 * @summary Ensure that the launcher defends against user settings of the * LD_LIBRARY_PATH environment variable on Unixes - * @requires os.family != "windows" & os.family != "mac" & !vm.musl & os.family != "aix" + * @requires os.family != "windows" & os.family != "mac" * @library /test/lib - * @compile -XDignore.symbol.file ExecutionEnvironment.java Test7029048.java - * @run main/othervm -DexpandedLdLibraryPath=false Test7029048 - */ - -/** - * @test - * @bug 7029048 8217340 8217216 - * @summary Ensure that the launcher defends against user settings of the - * LD_LIBRARY_PATH environment variable on Unixes - * @requires os.family == "aix" | vm.musl - * @library /test/lib - * @compile -XDignore.symbol.file ExecutionEnvironment.java Test7029048.java - * @run main/othervm -DexpandedLdLibraryPath=true Test7029048 + * @compile ExecutionEnvironment.java Test7029048.java + * @run main/othervm Test7029048 */ import java.io.File; @@ -51,13 +40,13 @@ import java.util.List; import java.util.Map; +import jdk.test.lib.Platform; + public class Test7029048 extends TestHelper { private static final String LIBJVM = ExecutionEnvironment.LIBJVM; private static final String LD_LIBRARY_PATH = ExecutionEnvironment.LD_LIBRARY_PATH; - private static final String LD_LIBRARY_PATH_64 = - ExecutionEnvironment.LD_LIBRARY_PATH_64; private static final File libDir = new File(System.getProperty("sun.boot.library.path")); @@ -71,9 +60,6 @@ public class Test7029048 extends TestHelper { private static final File dstClientDir = new File(dstLibDir, "client"); private static final File dstClientLibjvm = new File(dstClientDir, LIBJVM); - static final boolean IS_EXPANDED_LD_LIBRARY_PATH = - Boolean.getBoolean("expandedLdLibraryPath"); - static String getValue(String name, List in) { for (String x : in) { String[] s = x.split("="); @@ -134,7 +120,7 @@ static int getLLPComponents(TestResult tr) { private static enum TestCase { NO_DIR(0), // Directory does not exist NO_LIBJVM(0), // Directory exists, but no libjvm.so - LIBJVM(3); // Directory exists, with a libjvm.so + LIBJVM(2); // Directory exists, with a libjvm.so private final int value; TestCase(int i) { this.value = i; @@ -170,7 +156,7 @@ static boolean runTest() throws IOException { } desc = "LD_LIBRARY_PATH should not be set (no libjvm.so)"; - if (IS_EXPANDED_LD_LIBRARY_PATH) { + if (Platform.isAix() || Platform.isMusl()) { printSkipMessage(desc); continue; } @@ -180,7 +166,7 @@ static boolean runTest() throws IOException { recursiveDelete(dstLibDir); } desc = "LD_LIBRARY_PATH should not be set (no directory)"; - if (IS_EXPANDED_LD_LIBRARY_PATH) { + if (Platform.isAix() || Platform.isMusl()) { printSkipMessage(desc); continue; } From 77fff61b864054b0029ee5d38f6293534db10ce1 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Mon, 7 Apr 2025 13:04:47 +0000 Subject: [PATCH 0424/1101] 8341095: Possible overflow in os::Posix::print_uptime_info Reviewed-by: dholmes --- src/hotspot/os/posix/os_posix.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 6f756fbf64831..a36d6b87641e5 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -551,7 +551,7 @@ void os::Posix::print_uptime_info(outputStream* st) { setutxent(); while ((ent = getutxent())) { if (!strcmp("system boot", ent->ut_line)) { - bootsec = ent->ut_tv.tv_sec; + bootsec = (int)ent->ut_tv.tv_sec; break; } } From 60fbf73fc492ad9fff83fb4540e2d01311406287 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Mon, 7 Apr 2025 13:27:21 +0000 Subject: [PATCH 0425/1101] 8353709: Debug symbols bundle should contain full debug files when building --with-external-symbols-in-bundles=public Reviewed-by: erikj, mbaesken --- make/Bundles.gmk | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/make/Bundles.gmk b/make/Bundles.gmk index 58950b5fb1f71..8962b596278bd 100644 --- a/make/Bundles.gmk +++ b/make/Bundles.gmk @@ -242,7 +242,10 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), ) ) JDK_SYMBOLS_BUNDLE_FILES := \ - $(call FindFiles, $(SYMBOLS_IMAGE_DIR)) + $(filter-out \ + %.stripped.pdb, \ + $(call FindFiles, $(SYMBOLS_IMAGE_DIR)) \ + ) TEST_DEMOS_BUNDLE_FILES := $(filter $(JDK_DEMOS_IMAGE_HOMEDIR)/demo/%, \ $(ALL_JDK_DEMOS_FILES)) From 402103331bcdb1055f89c938fdd6b1df772993b6 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Mon, 7 Apr 2025 15:03:30 +0000 Subject: [PATCH 0426/1101] 8353659: SubmissionPublisherTest::testCap1Submit times out Reviewed-by: dl, alanb --- .../classes/java/util/concurrent/ForkJoinPool.java | 13 ++++++------- .../util/concurrent/tck/ForkJoinPool20Test.java | 7 +++---- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java index ec46f61291d27..5c74e653431b6 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -1278,8 +1278,7 @@ final int queueSize() { * @param internal if caller owns this queue * @throws RejectedExecutionException if array could not be resized */ - final void push(ForkJoinTask task, ForkJoinPool pool, - boolean internal) { + final void push(ForkJoinTask task, ForkJoinPool pool, boolean internal) { int s = top, b = base, m, cap, room; ForkJoinTask[] a; if ((a = array) != null && (cap = a.length) > 0 && // else disabled task != null) { @@ -1383,8 +1382,7 @@ final boolean tryUnpush(ForkJoinTask task, boolean internal) { if (a != null && (cap = a.length) > 0 && U.getReference(a, k = slotOffset((cap - 1) & s)) == task && (internal || tryLockPhase())) { - if (top == p && - U.compareAndSetReference(a, k, task, null)) { + if (top == p && U.compareAndSetReference(a, k, task, null)) { taken = true; updateTop(s); } @@ -2061,8 +2059,9 @@ private int deactivate(WorkQueue w, int phase) { ((e & SHUTDOWN) != 0L && ac == 0 && quiescent() > 0) || (qs = queues) == null || (n = qs.length) <= 0) return IDLE; // terminating - int k = Math.max(n << 2, SPIN_WAITS << 1); - for (int prechecks = k / n;;) { // reactivation threshold + + for (int prechecks = Math.min(ac, 2), // reactivation threshold + k = Math.max(n + (n << 1), SPIN_WAITS << 1);;) { WorkQueue q; int cap; ForkJoinTask[] a; long c; if (w.phase == activePhase) return activePhase; @@ -2071,7 +2070,7 @@ private int deactivate(WorkQueue w, int phase) { if ((q = qs[k & (n - 1)]) == null) Thread.onSpinWait(); else if ((a = q.array) != null && (cap = a.length) > 0 && - a[q.base & (cap - 1)] != null && --prechecks <= 0 && + a[q.base & (cap - 1)] != null && --prechecks < 0 && (int)(c = ctl) == activePhase && compareAndSetCtl(c, (sp & LMASK) | ((c + RC_UNIT) & UMASK))) return w.phase = activePhase; // reactivate diff --git a/test/jdk/java/util/concurrent/tck/ForkJoinPool20Test.java b/test/jdk/java/util/concurrent/tck/ForkJoinPool20Test.java index 41dd82300e210..9b60bbae484d8 100644 --- a/test/jdk/java/util/concurrent/tck/ForkJoinPool20Test.java +++ b/test/jdk/java/util/concurrent/tck/ForkJoinPool20Test.java @@ -528,6 +528,7 @@ public void testScheduleWithFixedDelay_overflow() throws Exception { final CountDownLatch delayedDone = new CountDownLatch(1); final CountDownLatch immediateDone = new CountDownLatch(1); final ForkJoinPool p = new ForkJoinPool(2); + p.cancelDelayedTasksOnShutdown(); try (PoolCleaner cleaner = cleaner(p)) { final Runnable delayed = () -> { delayedDone.countDown(); @@ -568,8 +569,8 @@ public void testSubmitWithTimeoutCancels() throws InterruptedException { public Boolean call() throws Exception { Thread.sleep(LONGER_DELAY_MS); return Boolean.TRUE; }}; ForkJoinTask task = p.submitWithTimeout(c, 1, NANOSECONDS, null); - Thread.sleep(timeoutMillis()); - assertTrue(task.isCancelled()); + while(!task.isCancelled()) + Thread.sleep(timeoutMillis()); } static final class SubmitWithTimeoutException extends RuntimeException {} @@ -586,7 +587,6 @@ public Item call() throws Exception { c, 1, NANOSECONDS, (ForkJoinTask t) -> t.complete(two)); - Thread.sleep(timeoutMillis()); assertEquals(task.join(), two); } @@ -602,7 +602,6 @@ public Boolean call() throws Exception { c, 1, NANOSECONDS, (ForkJoinTask t) -> t.completeExceptionally(new SubmitWithTimeoutException())); - Thread.sleep(timeoutMillis()); try { task.join(); shouldThrow(); From 9a391f44e038d6c15a7872164bd3099edad93c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Mon, 7 Apr 2025 15:23:18 +0000 Subject: [PATCH 0427/1101] 8353278: Consolidate local file URL checks in jar: and file: URL schemes Reviewed-by: dfuchs, jpai --- .../share/classes/sun/net/www/ParseUtil.java | 18 +++++++++++++++++- .../net/www/protocol/jar/JarFileFactory.java | 12 +++++++----- .../sun/net/www/protocol/jar/URLJarFile.java | 18 ++---------------- .../sun/net/www/protocol/file/Handler.java | 5 ++--- .../sun/net/www/protocol/file/Handler.java | 6 ++---- 5 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/java.base/share/classes/sun/net/www/ParseUtil.java b/src/java.base/share/classes/sun/net/www/ParseUtil.java index 628eeb948ad88..51d1b8398b6f4 100644 --- a/src/java.base/share/classes/sun/net/www/ParseUtil.java +++ b/src/java.base/share/classes/sun/net/www/ParseUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -507,6 +507,22 @@ private static void checkPath(String s, String scheme, String path) } } + /** + * {@return true if the url is a file: URL for a 'local file' as defined by RFC 8089, Section 2} + * + * For unknown historical reasons, this method deviates from RFC 8089 + * by allowing "~" as an alias for 'localhost' + * + * @param url the URL which may be a local file URL + */ + public static boolean isLocalFileURL(URL url) { + if (url.getProtocol().equalsIgnoreCase("file")) { + String host = url.getHost(); + return host == null || host.isEmpty() || host.equals("~") || + host.equalsIgnoreCase("localhost"); + } + return false; + } // -- Character classes for parsing -- diff --git a/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java b/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java index 9afbea8bf76e8..4d695c8d4e83c 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java +++ b/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import jdk.internal.util.OperatingSystem; import sun.net.util.URLUtil; +import sun.net.www.ParseUtil; /* A factory for cached JAR file. This class is used to both retrieve * and cache Jar files. @@ -92,7 +93,7 @@ JarFile getOrCreate(URL url, boolean useCaches) throws IOException { return get(url, false); } URL patched = urlFor(url); - if (!URLJarFile.isFileURL(patched)) { + if (!ParseUtil.isLocalFileURL(patched)) { // A temporary file will be created, we can prepopulate // the cache in this case. return get(url, useCaches); @@ -158,9 +159,10 @@ private URL urlFor(URL url) throws IOException { // Deal with UNC pathnames specially. See 4180841 String host = url.getHost(); - if (host != null && !host.isEmpty() && - !host.equalsIgnoreCase("localhost")) { - + // Subtly different from ParseUtil.isLocalFileURL, for historical reasons + boolean isLocalFile = ParseUtil.isLocalFileURL(url) && !"~".equals(host); + // For remote hosts, change 'file://host/folder/data.xml' to 'file:////host/folder/data.xml' + if (!isLocalFile) { @SuppressWarnings("deprecation") var _unused = url = new URL("file", "", "//" + host + url.getPath()); } diff --git a/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java b/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java index b3d4a2231964b..d30d18df9d6cf 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java +++ b/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,7 @@ public class URLJarFile extends JarFile { private Map superEntries; static JarFile getJarFile(URL url, URLJarFileCloseController closeController) throws IOException { - if (isFileURL(url)) { + if (ParseUtil.isLocalFileURL(url)) { Runtime.Version version = "runtime".equals(url.getRef()) ? JarFile.runtimeVersion() : JarFile.baseVersion(); @@ -71,20 +71,6 @@ private URLJarFile(URL url, URLJarFileCloseController closeController, Runtime.V this.closeController = closeController; } - static boolean isFileURL(URL url) { - if (url.getProtocol().equalsIgnoreCase("file")) { - /* - * Consider this a 'file' only if it's a LOCAL file, because - * 'file:' URLs can be accessible through ftp. - */ - String host = url.getHost(); - if (host == null || host.isEmpty() || host.equals("~") || - host.equalsIgnoreCase("localhost")) - return true; - } - return false; - } - /** * Returns the ZipEntry for the given entry name or * null if not found. diff --git a/src/java.base/unix/classes/sun/net/www/protocol/file/Handler.java b/src/java.base/unix/classes/sun/net/www/protocol/file/Handler.java index 4b2c110b3e1df..efde6a809e928 100644 --- a/src/java.base/unix/classes/sun/net/www/protocol/file/Handler.java +++ b/src/java.base/unix/classes/sun/net/www/protocol/file/Handler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,8 +64,7 @@ public URLConnection openConnection(URL u) public URLConnection openConnection(URL u, Proxy p) throws IOException { String host = u.getHost(); - if (host == null || host.isEmpty() || host.equals("~") || - host.equalsIgnoreCase("localhost")) { + if (ParseUtil.isLocalFileURL(u)) { File file = new File(ParseUtil.decode(u.getPath())); return createFileURLConnection(u, file); } diff --git a/src/java.base/windows/classes/sun/net/www/protocol/file/Handler.java b/src/java.base/windows/classes/sun/net/www/protocol/file/Handler.java index 2865aa32a95ff..38ad16267e790 100644 --- a/src/java.base/windows/classes/sun/net/www/protocol/file/Handler.java +++ b/src/java.base/windows/classes/sun/net/www/protocol/file/Handler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,9 +72,7 @@ public URLConnection openConnection(URL url, Proxy p) path = path.replace('/', '\\'); path = path.replace('|', ':'); - if ((host == null) || host.isEmpty() || - host.equalsIgnoreCase("localhost") || - host.equals("~")) { + if (ParseUtil.isLocalFileURL(url)) { return createFileURLConnection(url, new File(path)); } From 867a0301893cbf3d5434e4966d27d7f4913afb98 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Mon, 7 Apr 2025 16:15:51 +0000 Subject: [PATCH 0428/1101] 8352971: Increase maximum number of hold counts for ReentrantReadWriteLock Reviewed-by: alanb --- .../locks/ReentrantReadWriteLock.java | 72 +++++++------ .../util/concurrent/tck/JSR166TestCase.java | 1 + .../tck/ReentrantReadWriteLock20Test.java | 100 ++++++++++++++++++ .../tck/ReentrantReadWriteLockTest.java | 2 +- 4 files changed, 140 insertions(+), 35 deletions(-) create mode 100644 test/jdk/java/util/concurrent/tck/ReentrantReadWriteLock20Test.java diff --git a/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java b/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java index cc9b75a7e37e3..a45043e48ee4b 100644 --- a/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java +++ b/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java @@ -251,25 +251,25 @@ public ReentrantReadWriteLock(boolean fair) { * Synchronization implementation for ReentrantReadWriteLock. * Subclassed into fair and nonfair versions. */ - abstract static class Sync extends AbstractQueuedSynchronizer { + abstract static class Sync extends AbstractQueuedLongSynchronizer { private static final long serialVersionUID = 6317671515068378041L; /* * Read vs write count extraction constants and functions. - * Lock state is logically divided into two unsigned shorts: + * Lock state is logically divided into two ints: * The lower one representing the exclusive (writer) lock hold count, * and the upper the shared (reader) hold count. */ - static final int SHARED_SHIFT = 16; - static final int SHARED_UNIT = (1 << SHARED_SHIFT); - static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; - static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; + static final int SHARED_SHIFT = 32; + static final long SHARED_UNIT = (1L << SHARED_SHIFT); + static final long MAX_COUNT = Integer.MAX_VALUE; + static final long EXCLUSIVE_MASK = (1L << SHARED_SHIFT) - 1; /** Returns the number of shared holds represented in count. */ - static int sharedCount(int c) { return c >>> SHARED_SHIFT; } + static int sharedCount(long c) { return (int)(c >>> SHARED_SHIFT); } /** Returns the number of exclusive holds represented in count. */ - static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; } + static int exclusiveCount(long c) { return (int)(c & EXCLUSIVE_MASK); } /** * A counter for per-thread read hold counts. @@ -367,11 +367,12 @@ public HoldCounter initialValue() { * both read and write holds that are all released during a * condition wait and re-established in tryAcquire. */ + @Override @ReservedStackAccess - protected final boolean tryRelease(int releases) { + protected final boolean tryRelease(long releases) { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); - int nextc = getState() - releases; + long nextc = getState() - releases; boolean free = exclusiveCount(nextc) == 0; if (free) setExclusiveOwnerThread(null); @@ -379,8 +380,9 @@ protected final boolean tryRelease(int releases) { return free; } + @Override @ReservedStackAccess - protected final boolean tryAcquire(int acquires) { + protected final boolean tryAcquire(long acquires) { /* * Walkthrough: * 1. If read count nonzero or write count nonzero @@ -393,8 +395,8 @@ protected final boolean tryAcquire(int acquires) { * and set owner. */ Thread current = Thread.currentThread(); - int c = getState(); - int w = exclusiveCount(c); + long c = getState(); + long w = exclusiveCount(c); if (c != 0) { // (Note: if c != 0 and w == 0 then shared count != 0) if (w == 0 || current != getExclusiveOwnerThread()) @@ -412,8 +414,9 @@ protected final boolean tryAcquire(int acquires) { return true; } + @Override @ReservedStackAccess - protected final boolean tryReleaseShared(int unused) { + protected final boolean tryReleaseShared(long unused) { Thread current = Thread.currentThread(); if (firstReader == current) { // assert firstReaderHoldCount > 0; @@ -435,8 +438,8 @@ protected final boolean tryReleaseShared(int unused) { --rh.count; } for (;;) { - int c = getState(); - int nextc = c - SHARED_UNIT; + long c = getState(); + long nextc = c - SHARED_UNIT; if (compareAndSetState(c, nextc)) // Releasing the read lock has no effect on readers, // but it may allow waiting writers to proceed if @@ -450,8 +453,9 @@ private static IllegalMonitorStateException unmatchedUnlockException() { "attempt to unlock read lock, not locked by current thread"); } + @Override @ReservedStackAccess - protected final int tryAcquireShared(int unused) { + protected final long tryAcquireShared(long unused) { /* * Walkthrough: * 1. If write lock held by another thread, fail. @@ -468,10 +472,10 @@ protected final int tryAcquireShared(int unused) { * saturated, chain to version with full retry loop. */ Thread current = Thread.currentThread(); - int c = getState(); + long c = getState(); if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) - return -1; + return -1L; int r = sharedCount(c); if (!readerShouldBlock() && r < MAX_COUNT && @@ -490,7 +494,7 @@ else if (rh.count == 0) readHolds.set(rh); rh.count++; } - return 1; + return 1L; } return fullTryAcquireShared(current); } @@ -499,7 +503,7 @@ else if (rh.count == 0) * Full version of acquire for reads, that handles CAS misses * and reentrant reads not dealt with in tryAcquireShared. */ - final int fullTryAcquireShared(Thread current) { + final long fullTryAcquireShared(Thread current) { /* * This code is in part redundant with that in * tryAcquireShared but is simpler overall by not @@ -508,7 +512,7 @@ final int fullTryAcquireShared(Thread current) { */ HoldCounter rh = null; for (;;) { - int c = getState(); + long c = getState(); if (exclusiveCount(c) != 0) { if (getExclusiveOwnerThread() != current) return -1; @@ -529,7 +533,7 @@ final int fullTryAcquireShared(Thread current) { } } if (rh.count == 0) - return -1; + return -1L; } } if (sharedCount(c) == MAX_COUNT) @@ -551,7 +555,7 @@ else if (rh.count == 0) rh.count++; cachedHoldCounter = rh; // cache for release } - return 1; + return 1L; } } } @@ -564,7 +568,7 @@ else if (rh.count == 0) @ReservedStackAccess final boolean tryWriteLock() { Thread current = Thread.currentThread(); - int c = getState(); + long c = getState(); if (c != 0) { int w = exclusiveCount(c); if (w == 0 || current != getExclusiveOwnerThread()) @@ -587,7 +591,7 @@ final boolean tryWriteLock() { final boolean tryReadLock() { Thread current = Thread.currentThread(); for (;;) { - int c = getState(); + long c = getState(); if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) return false; @@ -672,7 +676,7 @@ private void readObject(java.io.ObjectInputStream s) setState(0); // reset to unlocked state } - final int getCount() { return getState(); } + final long getCount() { return getState(); } } /** @@ -1431,9 +1435,9 @@ protected Collection getQueuedThreads() { public boolean hasWaiters(Condition condition) { if (condition == null) throw new NullPointerException(); - if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) + if (!(condition instanceof AbstractQueuedLongSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); - return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition); + return sync.hasWaiters((AbstractQueuedLongSynchronizer.ConditionObject)condition); } /** @@ -1454,9 +1458,9 @@ public boolean hasWaiters(Condition condition) { public int getWaitQueueLength(Condition condition) { if (condition == null) throw new NullPointerException(); - if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) + if (!(condition instanceof AbstractQueuedLongSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); - return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition); + return sync.getWaitQueueLength((AbstractQueuedLongSynchronizer.ConditionObject)condition); } /** @@ -1479,9 +1483,9 @@ public int getWaitQueueLength(Condition condition) { protected Collection getWaitingThreads(Condition condition) { if (condition == null) throw new NullPointerException(); - if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) + if (!(condition instanceof AbstractQueuedLongSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); - return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition); + return sync.getWaitingThreads((AbstractQueuedLongSynchronizer.ConditionObject)condition); } /** @@ -1494,7 +1498,7 @@ protected Collection getWaitingThreads(Condition condition) { * @return a string identifying this lock, as well as its lock state */ public String toString() { - int c = sync.getCount(); + long c = sync.getCount(); int w = Sync.exclusiveCount(c); int r = Sync.sharedCount(c); diff --git a/test/jdk/java/util/concurrent/tck/JSR166TestCase.java b/test/jdk/java/util/concurrent/tck/JSR166TestCase.java index 92e2e82362ae4..18007f72ca8f5 100644 --- a/test/jdk/java/util/concurrent/tck/JSR166TestCase.java +++ b/test/jdk/java/util/concurrent/tck/JSR166TestCase.java @@ -622,6 +622,7 @@ public static Test suite() { String[] java20TestClassNames = { "ForkJoinPool20Test", "SynchronousQueue20Test", + "ReentrantReadWriteLock20Test" }; addNamedTestClasses(suite, java20TestClassNames); } diff --git a/test/jdk/java/util/concurrent/tck/ReentrantReadWriteLock20Test.java b/test/jdk/java/util/concurrent/tck/ReentrantReadWriteLock20Test.java new file mode 100644 index 0000000000000..730e162e7fc4d --- /dev/null +++ b/test/jdk/java/util/concurrent/tck/ReentrantReadWriteLock20Test.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; + +import java.util.ArrayDeque; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class ReentrantReadWriteLock20Test extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ReentrantReadWriteLock20Test.class); + } + public void test66kReadersFair() throws InterruptedException { test66kReaders(true); } + public void test66kReadersUnfair() throws InterruptedException { test66kReaders(false); } + + private void test66kReaders(boolean fairness) throws InterruptedException { + final var failure = new AtomicReference(); + final var lock = new ReentrantReadWriteLock(fairness); + final var numThreads = 0x10000; + final var threads = new ArrayDeque(numThreads); + final var latch = new CountDownLatch(1); + try { + for(int i = 0; i < numThreads && failure.get() == null;++i) { + var t = Thread.ofVirtual().unstarted(() -> { + + try { + lock.readLock().lock(); + } catch (Throwable ex) { + failure.compareAndSet(null, ex); + return; + } + + try { + while (latch.getCount() > 0) { + try { + latch.await(); + } catch (InterruptedException ie) { + failure.compareAndSet(null, ie); + } + } + } + finally { + lock.readLock().unlock(); + } + }); + + threads.addLast(t); + t.start(); + } + } finally { + latch.countDown(); // Make sure waiters are signalled + Thread next; + while ((next = threads.pollFirst()) != null) { + while (next.isAlive()) { + next.join(); + } + } + } + + assertEquals(null, failure.get()); + } +} diff --git a/test/jdk/java/util/concurrent/tck/ReentrantReadWriteLockTest.java b/test/jdk/java/util/concurrent/tck/ReentrantReadWriteLockTest.java index ccbff0d29ce43..64f3d2c58e334 100644 --- a/test/jdk/java/util/concurrent/tck/ReentrantReadWriteLockTest.java +++ b/test/jdk/java/util/concurrent/tck/ReentrantReadWriteLockTest.java @@ -1720,7 +1720,7 @@ public void testBlockers() { ? "ReentrantReadWriteLock$FairSync" : "ReentrantReadWriteLock$NonfairSync"; final String conditionClassName - = "AbstractQueuedSynchronizer$ConditionObject"; + = "AbstractQueuedLongSynchronizer$ConditionObject"; final Thread.State expectedAcquireState = timedAcquire ? Thread.State.TIMED_WAITING : Thread.State.WAITING; From e08441c03352543f800aef166afabec1dacaf4bf Mon Sep 17 00:00:00 2001 From: Phil Race Date: Mon, 7 Apr 2025 16:40:36 +0000 Subject: [PATCH 0429/1101] 8353475: Open source two Swing DefaultCaret tests Reviewed-by: honkar --- .../swing/text/DefaultCaret/PaintTest.java | 63 ++++++++++++++++ .../swing/text/DefaultCaret/bug4785160.java | 71 +++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 test/jdk/javax/swing/text/DefaultCaret/PaintTest.java create mode 100644 test/jdk/javax/swing/text/DefaultCaret/bug4785160.java diff --git a/test/jdk/javax/swing/text/DefaultCaret/PaintTest.java b/test/jdk/javax/swing/text/DefaultCaret/PaintTest.java new file mode 100644 index 0000000000000..c554764527eaa --- /dev/null +++ b/test/jdk/javax/swing/text/DefaultCaret/PaintTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4193062 + * @summary Tests that when a TextField first gets focus, if modelToView fails + * (null is returned) that the caret will start to blink again. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PaintTest +*/ + +import java.awt.FlowLayout; +import javax.swing.JFrame; +import javax.swing.JTextField; + +public class PaintTest { + + static final String INSTRUCTIONS = """ + If the test window displays with the text caret flashing (do wait at + least several second for it to start) the test PASSES, otherwise it FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("PaintTest Test Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(PaintTest::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("PaintTest"); + JTextField tf = new JTextField(20); + frame.setLayout(new FlowLayout()); + frame.add(tf); + frame.setSize(300, 300); + return frame; + } +} diff --git a/test/jdk/javax/swing/text/DefaultCaret/bug4785160.java b/test/jdk/javax/swing/text/DefaultCaret/bug4785160.java new file mode 100644 index 0000000000000..644becf8ae6ac --- /dev/null +++ b/test/jdk/javax/swing/text/DefaultCaret/bug4785160.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4785160 + * @summary Test that the cursor is always visible when typing in JTextArea with JScrollBar + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4785160 +*/ + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; + +public class bug4785160 { + + static final String INSTRUCTIONS = """ + Ensure that the horizontal scrollbar is visible in the JTextArea. + If necessary, reduce the width of the window so that the scrollbar becomes visible. + Scroll all the way to the right so the end of the line is visible. + If necessary, move the text caret in the text area to the end of line. + The test PASSES if the caret is visible at the end of the line. + The test FAILS if the caret disappears when moved to the end of the line. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4785160 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4785160::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("bug4785160"); + JTextArea area = new JTextArea(); + String s = ""; + for (int i = 0; i < 80; i++) { + s += "m"; + } + area.setText(s); + area.getCaret().setDot(area.getText().length() + 1); + frame.add(new JScrollPane(area)); + frame.setSize(300, 300); + return frame; + } +} From 0d4d1558164bb352aa4f7be1fffb7eb2da506944 Mon Sep 17 00:00:00 2001 From: Koushik Thirupattur Date: Mon, 7 Apr 2025 17:29:13 +0000 Subject: [PATCH 0430/1101] 8349890: Option -Djava.security.debug=x509,ava breaks special chars Reviewed-by: mullan --- .../share/classes/sun/security/x509/AVA.java | 22 ++----- ...X500PrincipalInDebugModeWithAvaOption.java | 61 +++++++++++++++++++ 2 files changed, 65 insertions(+), 18 deletions(-) create mode 100644 test/jdk/sun/security/x509/X500Name/PrintX500PrincipalInDebugModeWithAvaOption.java diff --git a/src/java.base/share/classes/sun/security/x509/AVA.java b/src/java.base/share/classes/sun/security/x509/AVA.java index f5d8008fbb09c..915421c76f2f4 100644 --- a/src/java.base/share/classes/sun/security/x509/AVA.java +++ b/src/java.base/share/classes/sun/security/x509/AVA.java @@ -640,7 +640,7 @@ private String toKeyword(int format, Map oidMap) { */ public String toString() { return toKeywordValueString - (toKeyword(DEFAULT, Collections.emptyMap())); + (toKeyword(DEFAULT, Collections.emptyMap()), true); } /** @@ -659,7 +659,7 @@ public String toRFC1779String() { * OID/keyword map. */ public String toRFC1779String(Map oidMap) { - return toKeywordValueString(toKeyword(RFC1779, oidMap)); + return toKeywordValueString(toKeyword(RFC1779, oidMap), false); } /** @@ -758,12 +758,6 @@ public String toRFC2253String(Map oidMap) { // escape null character sbuffer.append("\\00"); - } else if (debug != null && Debug.isOn("ava")) { - - // embed non-printable/non-escaped char - // as escaped hex pairs for debugging - byte[] valueBytes = Character.toString(c).getBytes(UTF_8); - HexFormat.of().withPrefix("\\").withUpperCase().formatHex(sbuffer, valueBytes); } else { // append non-printable/non-escaped char @@ -888,14 +882,6 @@ public String toRFC2253CanonicalString() { } } - } else if (debug != null && Debug.isOn("ava")) { - - // embed non-printable/non-escaped char - // as escaped hex pairs for debugging - - previousWhite = false; - byte[] valueBytes = Character.toString(c).getBytes(UTF_8); - HexFormat.of().withPrefix("\\").withUpperCase().formatHex(sbuffer, valueBytes); } else { // append non-printable/non-escaped char @@ -945,7 +931,7 @@ boolean hasRFC2253Keyword() { return AVAKeyword.hasKeyword(oid, RFC2253); } - private String toKeywordValueString(String keyword) { + private String toKeywordValueString(String keyword, Boolean isFromToString) { /* * Construct the value with as little copying and garbage * production as practical. First the keyword (mandatory), @@ -1019,7 +1005,7 @@ private String toKeywordValueString(String keyword) { sbuffer.append(c); - } else if (debug != null && Debug.isOn("ava")) { + } else if (debug != null && isFromToString && Debug.isOn("ava")) { // embed non-printable/non-escaped char // as escaped hex pairs for debugging diff --git a/test/jdk/sun/security/x509/X500Name/PrintX500PrincipalInDebugModeWithAvaOption.java b/test/jdk/sun/security/x509/X500Name/PrintX500PrincipalInDebugModeWithAvaOption.java new file mode 100644 index 0000000000000..88f0b6d15a8d5 --- /dev/null +++ b/test/jdk/sun/security/x509/X500Name/PrintX500PrincipalInDebugModeWithAvaOption.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8349890 + * @summary Make sure debug with AVA option does not interfere with parsing special characters. + * @library /test/lib + * @run main/othervm -Djava.security.debug=x509:ava PrintX500PrincipalInDebugModeWithAvaOption + */ + +import jdk.test.lib.Asserts; +import javax.security.auth.x500.X500Principal; + +public class PrintX500PrincipalInDebugModeWithAvaOption { + + public static void main(String[] args) throws Exception { + + X500Principal name = new X500Principal("cn=john doe + l=ca\\+lifornia + l =sf, O=Ñ"); + + //Test the name in default String format. This will perform the hex conversion to + //"\\C3\\91" for special character "Ñ" + Asserts.assertTrue(name.toString().contains("\\C3\\91"), + "String does not contain expected value"); + + //Test the name in RFC2253 format. This should skip the hex conversion to return + //"\u00d1" for special character "Ñ" + Asserts.assertTrue(name.getName().contains("\u00d1"), + "String does not contain expected value"); + + //Test the name in canonical name in RFC2253 format. This should skip the hex conversion to return + //"n\u0303" for special character "Ñ" + Asserts.assertTrue(name.getName(X500Principal.CANONICAL).contains("n\u0303"), + "String does not contain expected value"); + + + //Test to print name in RFC1779 format. This should skip the hex conversion to print + //"\u00d1" for special character "Ñ" + Asserts.assertTrue(name.getName(X500Principal.RFC1779).contains("\u00d1"), + "String does not contain expected value"); + } +} From 1b6f6946ae1fa0657d6bd1f63b25a0008ab2acdd Mon Sep 17 00:00:00 2001 From: Phil Race Date: Mon, 7 Apr 2025 18:16:15 +0000 Subject: [PATCH 0431/1101] 8353304: Open source two JTabbedPane tests Reviewed-by: kizune --- test/jdk/ProblemList.txt | 1 + .../javax/swing/JTabbedPane/bug4499556.java | 280 ++++++++++++++++++ .../javax/swing/JTabbedPane/bug6259533.java | 82 +++++ 3 files changed, 363 insertions(+) create mode 100644 test/jdk/javax/swing/JTabbedPane/bug4499556.java create mode 100644 test/jdk/javax/swing/JTabbedPane/bug6259533.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index b7f1d68a45186..ef2c698f19844 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -774,6 +774,7 @@ jdk/jfr/jvm/TestWaste.java 8282427 generic- javax/swing/JFileChooser/6698013/bug6698013.java 8024419 macosx-all javax/swing/JColorChooser/8065098/bug8065098.java 8065647 macosx-all +javax/swing/JTabbedPane/bug4499556.java 8267500 macosx-all javax/swing/JTabbedPane/4666224/bug4666224.java 8144124 macosx-all javax/swing/JTabbedPane/TestJTabbedPaneOpaqueColor.java 8345090 windows-all,linux-all javax/swing/SwingUtilities/TestTextPosInPrint.java 8227025 windows-all diff --git a/test/jdk/javax/swing/JTabbedPane/bug4499556.java b/test/jdk/javax/swing/JTabbedPane/bug4499556.java new file mode 100644 index 0000000000000..fe9d7dbbfde1f --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/bug4499556.java @@ -0,0 +1,280 @@ +/* + Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4499556 + * @summary Use arbitrary (J)Components as JTabbedPane tab labels. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4499556 +*/ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.BorderFactory; +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JTabbedPane; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class bug4499556 { + + static final String INSTRUCTIONS = """ + The test window contains a tabbedPane with 4 tabs. + + Tab #0 without any tabComponent, just a title. + Tab #1 with a JLabel and a little JButton wrapped into JPanel + Tab #2 with a JButton (Delete #1) as a tabComponent + Tab #3 with a JTextField as a tabComponent + + Check that tabbedPane and all tabComponents are shown properly + for different tabLayout and tabPlacement policies, + (you can change them with help of settings in the right panel), + and for different looks and feels (you can change L&F by using the L&F menu) + + Remove tab #1 by clicking the Button labeled Delete #1 and then re-insert it + by clicking "Insert #1". Check that it works - ie Delete #1 is restored. + + If everything displays and behaves as described, the test PASSES, otherwise it FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4499556::createUI) + .build() + .awaitAndCheck(); + } + + static volatile JTabbedPane pane; + + static JFrame createUI() { + JFrame frame = new JFrame("bug4499556"); + pane = getTabbedPane(); + frame.add(pane); + frame.add(getRightPanel(), BorderLayout.EAST); + JMenu menu = new JMenu("L&F Menu"); + JMenuItem platformItem = new JMenuItem("Platform L&F"); + JMenuItem nimbusItem = new JMenuItem("Nimbus L&F"); + JMenuItem metalItem = new JMenuItem("Metal L&F"); + menu.add(platformItem); + menu.add(nimbusItem); + menu.add(metalItem); + JMenuBar menuBar = new JMenuBar(); + menuBar.add(menu); + frame.setJMenuBar(menuBar); + platformItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + setPlatformLAF(); + } + }); + metalItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + setMetalLAF(); + } + }); + + nimbusItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + setNimbusLAF(); + } + }); + frame.setSize(500, 500); + return frame; + } + + static JTabbedPane getTabbedPane() { + final JTabbedPane pane = new JTabbedPane(); + + pane.add("Title", new JLabel("")); + + addCompoundTab(pane); + + pane.add("Title", new JLabel("")); + pane.add("Title", new JLabel("")); + + final JButton button = new JButton("Delete #1"); + pane.setTabComponentAt(2, button); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (pane.getTabCount() == 4) { + pane.remove(1); + button.setText("Insert #1"); + } else { + addCompoundTab(pane); + button.setText("Delete #1"); + } + } + }); + + JTextField tf = new JTextField("JTextField", 7); + pane.setTabComponentAt(3, tf); + + return pane; + } + + static JComponent getRightPanel() { + JComponent ret = new Box(BoxLayout.Y_AXIS); + ret.setBorder(BorderFactory.createTitledBorder("Properties")); + ret.setPreferredSize(new Dimension(100, 0)); + final JCheckBox checkBox = new JCheckBox(); + JPanel temp = new JPanel(); + temp.add(new JLabel("Scrollable")); + temp.add(checkBox); + pane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT); + checkBox.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if (checkBox.isSelected()) { + pane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); + } else { + pane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT); + } + } + }); + checkBox.doClick(); + ret.add(temp); + ButtonGroup group = new ButtonGroup(); + temp = new JPanel(); + JRadioButton topRadio = new JRadioButton("Top"); + temp.add(topRadio); + topRadio.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + pane.setTabPlacement(JTabbedPane.TOP); + } + }); + ret.add(temp); + temp = new JPanel(); + JRadioButton bottomRadio = new JRadioButton("Bottom"); + temp.add(bottomRadio); + bottomRadio.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + pane.setTabPlacement(JTabbedPane.BOTTOM); + } + }); + ret.add(temp); + temp = new JPanel(); + JRadioButton leftRadio = new JRadioButton("Left"); + temp.add(leftRadio); + leftRadio.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + pane.setTabPlacement(JTabbedPane.LEFT); + } + }); + ret.add(temp); + temp = new JPanel(); + JRadioButton rightRadio = new JRadioButton("Right"); + temp.add(rightRadio); + rightRadio.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + pane.setTabPlacement(JTabbedPane.RIGHT); + } + }); + ret.add(temp); + group.add(topRadio); + group.add(bottomRadio); + group.add(leftRadio); + group.add(rightRadio); + return ret; + } + + + + static void addCompoundTab(final JTabbedPane pane) { + JLabel label = new JLabel("JLabel"); + label.setOpaque(true); + JPanel testPanel = new JPanel(); + JLabel comp = new JLabel("JLabel"); + testPanel.add(comp); + JButton closeButton = new CloseButton(); + closeButton.setPreferredSize(new Dimension(10, 10)); + testPanel.add(closeButton); + testPanel.setOpaque(false); + pane.insertTab("Test", null, new JLabel(""), "", 1); + pane.setTabComponentAt(1, testPanel); + } + + static class CloseButton extends JButton { + public CloseButton() { + final Object[] options = {"Fine"}; + addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + JOptionPane.showOptionDialog(null, + "How are you ?", "Hello !", JOptionPane.YES_OPTION, + JOptionPane.QUESTION_MESSAGE, null, options, null); + } + }); + } + + protected void paintComponent(Graphics g) { + super.paintComponent(g); + g.setColor(Color.black); + g.drawLine(0, 0, getWidth()-1, getHeight()-1); + g.drawLine(0, getHeight()-1, getWidth()-1, 0); + } + } + + static boolean setLAF(String laf) { + try { + UIManager.setLookAndFeel(laf); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + SwingUtilities.updateComponentTreeUI(pane); + return true; + } + + static final boolean setPlatformLAF() { + return setLAF(UIManager.getSystemLookAndFeelClassName()); + } + + static final boolean setNimbusLAF() { + return setLAF("javax.swing.plaf.nimbus.NimbusLookAndFeel"); + } + + static final boolean setMetalLAF() { + return setLAF("javax.swing.plaf.metal.MetalLookAndFeel"); + } +} diff --git a/test/jdk/javax/swing/JTabbedPane/bug6259533.java b/test/jdk/javax/swing/JTabbedPane/bug6259533.java new file mode 100644 index 0000000000000..7aaa3e591ce35 --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/bug6259533.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6259533 + * @requires (os.family == "windows") + * @summary Win L&F : JTabbedPane should move upwards the tabComponent of the selected tab. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug6259533 +*/ + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JTabbedPane; +import javax.swing.UIManager; + +public class bug6259533 { + + static final String INSTRUCTIONS = """ + This test is for the Windows LaF only. + + You should see a JTabbedPane with two tabs. + The first tab uses a string and the second tab has a JLabel as a tabComponent + + Select each tab and notice that on selection the tab title + is moved upwards slightly in comparison with the unselected tab + + If that is the observed behaviour, press PASS, press FAIL otherwise. + + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug6259533::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + try { + UIManager.setLookAndFeel( + "com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel"); + } catch (Exception e) { + throw new RuntimeException(e); + } + + JFrame frame = new JFrame("bug6259533"); + JTabbedPane pane = new JTabbedPane(); + pane.add("String Tab", null); + pane.add("Tab 2", null); + JLabel label = new JLabel("JLabel Tab"); + pane.setTabComponentAt(1, label); + frame.add(pane); + frame.setSize(400, 200); + return frame; + } + +} From 885cf0ff8d1e7816bf409136234d63373d576f9e Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Mon, 7 Apr 2025 18:44:04 +0000 Subject: [PATCH 0432/1101] 8353671: Remove dead code missed in JDK-8350459 Reviewed-by: sviswanathan, mullan --- .../MontgomeryIntegerPolynomialP256.java | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/src/java.base/share/classes/sun/security/util/math/intpoly/MontgomeryIntegerPolynomialP256.java b/src/java.base/share/classes/sun/security/util/math/intpoly/MontgomeryIntegerPolynomialP256.java index 954713bea5fe1..1910746fe448f 100644 --- a/src/java.base/share/classes/sun/security/util/math/intpoly/MontgomeryIntegerPolynomialP256.java +++ b/src/java.base/share/classes/sun/security/util/math/intpoly/MontgomeryIntegerPolynomialP256.java @@ -547,27 +547,4 @@ protected void reduceIn(long[] limbs, long v, int i) { limbs[i - 5] += (v << 4) & LIMB_MASK; limbs[i - 4] += v >> 48; } - - // Used when limbs a could overflow by one modulus. - @ForceInline - protected void reducePositive(long[] a) { - long aa0 = a[0]; - long aa1 = a[1] + (aa0>>BITS_PER_LIMB); - long aa2 = a[2] + (aa1>>BITS_PER_LIMB); - long aa3 = a[3] + (aa2>>BITS_PER_LIMB); - long aa4 = a[4] + (aa3>>BITS_PER_LIMB); - - long c0 = a[0] - modulus[0]; - long c1 = a[1] - modulus[1] + (c0 >> BITS_PER_LIMB); - long c2 = a[2] - modulus[2] + (c1 >> BITS_PER_LIMB); - long c3 = a[3] - modulus[3] + (c2 >> BITS_PER_LIMB); - long c4 = a[4] - modulus[4] + (c3 >> BITS_PER_LIMB); - long mask = c4 >> BITS_PER_LIMB; // Signed shift! - - a[0] = ((aa0 & mask) | (c0 & ~mask)) & LIMB_MASK; - a[1] = ((aa1 & mask) | (c1 & ~mask)) & LIMB_MASK; - a[2] = ((aa2 & mask) | (c2 & ~mask)) & LIMB_MASK; - a[3] = ((aa3 & mask) | (c3 & ~mask)) & LIMB_MASK; - a[4] = ((aa4 & mask) | (c4 & ~mask)); - } } From 5481021ee64fd457279ea7083be0f977c7ce3e3c Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Mon, 7 Apr 2025 18:46:04 +0000 Subject: [PATCH 0433/1101] 8321591: (fs) Improve String -> Path conversion performance (win) Reviewed-by: alanb --- .../classes/sun/nio/fs/WindowsPathParser.java | 116 +++++++++--------- .../bench/java/nio/file/PathOfString.java | 52 ++++++++ 2 files changed, 113 insertions(+), 55 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/nio/file/PathOfString.java diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsPathParser.java b/src/java.base/windows/classes/sun/nio/fs/WindowsPathParser.java index 6198fbfd5b596..b9986d41f422f 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsPathParser.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsPathParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,38 +37,7 @@ private WindowsPathParser() { } /** * The result of a parse operation */ - static class Result { - private final WindowsPathType type; - private final String root; - private final String path; - - Result(WindowsPathType type, String root, String path) { - this.type = type; - this.root = root; - this.path = path; - } - - /** - * The path type - */ - WindowsPathType type() { - return type; - } - - /** - * The root component - */ - String root() { - return root; - } - - /** - * The normalized path (includes root) - */ - String path() { - return path; - } - } + record Result(WindowsPathType type, String root, String path) {}; /** * Parses the given input as a Windows path @@ -117,7 +86,7 @@ private static Result parse(String input, boolean requireToNormalize) { char c = 0; int next = 2; if (isSlash(c0) && isSlash(c1)) { - // UNC: We keep the first two slash, collapse all the + // UNC: We keep the first two slashes, collapse all the // following, then take the hostname and share name out, // meanwhile collapsing all the redundant slashes. type = WindowsPathType.UNC; @@ -170,9 +139,7 @@ private static Result parse(String input, boolean requireToNormalize) { } if (requireToNormalize) { - StringBuilder sb = new StringBuilder(input.length()); - sb.append(root); - return new Result(type, root, normalize(sb, input, off)); + return new Result(type, root, normalize(root, input, off)); } else { return new Result(type, root, input); } @@ -182,40 +149,62 @@ private static Result parse(String input, boolean requireToNormalize) { * Remove redundant slashes from the rest of the path, forcing all slashes * into the preferred slash. */ - private static String normalize(StringBuilder sb, String path, int off) { - int len = path.length(); - off = nextNonSlash(path, off, len); - int start = off; + private static String normalize(String root, String path, int pathOff) { + + int rootLen = root.length(); + int pathLen = path.length(); + + // the result array will initally contain the characters of root in + // the first rootLen elements followed by the chanacters of path from + // position index pathOff to the end of path + char[] result = new char[rootLen + pathLen - pathOff]; + root.getChars(0, rootLen, result, 0); + path.getChars(pathOff, pathLen, result, rootLen); + + // the portion of array derived from path is normalized by copying + // from position srcPos to position dstPos, and as the invariant + // dstPos <= srcPos holds, no characters can be overwritten + int dstPos = rootLen; + int srcPos = nextNonSlash(result, rootLen, result.length); + + // pathPos is the position in array which is being tested as to + // whether the element at that position is a slash + int pathPos = srcPos; + char lastC = 0; - while (off < len) { - char c = path.charAt(off); + while (pathPos < result.length) { + char c = result[pathPos]; if (isSlash(c)) { if (lastC == ' ') throw new InvalidPathException(path, "Trailing char <" + lastC + ">", - off - 1); - sb.append(path, start, off); - off = nextNonSlash(path, off, len); - if (off != len) //no slash at the end of normalized path - sb.append('\\'); - start = off; + pathPos - 1); + int nchars = pathPos - srcPos; + System.arraycopy(result, srcPos, result, dstPos, nchars); + dstPos += nchars; + pathPos = nextNonSlash(result, pathPos, result.length); + if (pathPos != result.length) //no slash at the end of normalized path + result[dstPos++] = '\\'; + srcPos = pathPos; } else { if (isInvalidPathChar(c)) throw new InvalidPathException(path, "Illegal char <" + c + ">", - off); + pathPos); lastC = c; - off++; + pathPos++; } } - if (start != off) { + if (srcPos != pathPos) { if (lastC == ' ') throw new InvalidPathException(path, "Trailing char <" + lastC + ">", - off - 1); - sb.append(path, start, off); + pathPos - 1); + int nchars = pathPos - srcPos; + System.arraycopy(result, srcPos, result, dstPos, nchars); + dstPos += nchars; } - return sb.toString(); + return new String(result, 0, dstPos); } private static final boolean isSlash(char c) { @@ -227,6 +216,11 @@ private static final int nextNonSlash(String path, int off, int end) { return off; } + private static final int nextNonSlash(char[] path, int off, int end) { + while (off < end && isSlash(path[off])) { off++; } + return off; + } + private static final int nextSlash(String path, int off, int end) { char c; while (off < end && !isSlash(c=path.charAt(off))) { @@ -239,6 +233,18 @@ private static final int nextSlash(String path, int off, int end) { return off; } + private static final int nextSlash(char[] path, int off, int end) { + char c; + while (off < end && !isSlash(c=path[off])) { + if (isInvalidPathChar(c)) + throw new InvalidPathException(new String(path), + "Illegal character [" + c + "] in path", + off); + off++; + } + return off; + } + private static final boolean isLetter(char c) { return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')); } diff --git a/test/micro/org/openjdk/bench/java/nio/file/PathOfString.java b/test/micro/org/openjdk/bench/java/nio/file/PathOfString.java new file mode 100644 index 0000000000000..662bc0f25e64e --- /dev/null +++ b/test/micro/org/openjdk/bench/java/nio/file/PathOfString.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.nio.file; + +import java.nio.file.Path; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; + +@State(Scope.Benchmark) +public class PathOfString { + @Param({"C:\\Users\\foo\\bar\\gus.txt", // absolute + "C:\\Users\\\\foo\\\\bar\\gus.txt", // ... with extra '\\'s + "\\\\.\\UNC\\localhost\\C$\\Users\\foo", // UNC + "\\\\.\\UNC\\localhost\\C$\\\\Users\\\\foo", // ... with extra '\\'s + "\\\\?\\C:\\Users\\foo\\bar\\gus.txt", // long path prefix + "\\\\?\\C:\\Users\\\\foo\\bar\\\\gus.txt", // ... with extra '\\'s + ".\\foo\\bar\\gus.txt", // relative + ".\\foo\\\\bar\\\\gus.txt", // ... with extra '\\'s + "\\foo\\bar\\gus.txt", // current drive-relative + "\\foo\\\\bar\\\\gus.txt", // ... with extra '\\'s + "C:foo\\bar\\gus.txt", // drive's current directory-relative + "C:foo\\\\bar\\\\gus.txt"}) // ... with extra '\\'s + + public String path; + + @Benchmark + public Path parse() { + return Path.of(path); + } +} From 05ff557dee6adc679d85bfe8fb49f69053a6aaba Mon Sep 17 00:00:00 2001 From: Renjith Kannath Pariyangad Date: Mon, 7 Apr 2025 19:52:39 +0000 Subject: [PATCH 0434/1101] 8353138: Screen capture for test TaskbarPositionTest.java, failure case Reviewed-by: aivanov, serb --- .../swing/Popup/TaskbarPositionTest.java | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/test/jdk/javax/swing/Popup/TaskbarPositionTest.java b/test/jdk/javax/swing/Popup/TaskbarPositionTest.java index 5378f61c96f77..a649956748360 100644 --- a/test/jdk/javax/swing/Popup/TaskbarPositionTest.java +++ b/test/jdk/javax/swing/Popup/TaskbarPositionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,11 @@ import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; import javax.swing.AbstractAction; import javax.swing.JComboBox; import javax.swing.JFrame; @@ -337,11 +341,11 @@ public static void main(String[] args) throws Throwable { } } - try { - // Use Robot to automate the test - Robot robot = new Robot(); - robot.setAutoDelay(50); + // Use Robot to automate the test + Robot robot = new Robot(); + robot.setAutoDelay(50); + try { SwingUtilities.invokeAndWait(TaskbarPositionTest::new); robot.waitForIdle(); @@ -442,6 +446,9 @@ public static void main(String[] args) throws Throwable { hidePopup(robot); robot.waitForIdle(); + } catch (Throwable t) { + saveScreenCapture(robot, screens); + throw t; } finally { SwingUtilities.invokeAndWait(() -> { if (frame != null) { @@ -450,4 +457,17 @@ public static void main(String[] args) throws Throwable { }); } } + + private static void saveScreenCapture(Robot robot, GraphicsDevice[] screens) { + for (int i = 0; i < screens.length; i++) { + Rectangle bounds = screens[i].getDefaultConfiguration() + .getBounds(); + BufferedImage image = robot.createScreenCapture(bounds); + try { + ImageIO.write(image, "png", new File("Screenshot.png")); + } catch (IOException e) { + e.printStackTrace(); + } + } + } } From 3757f660f237408e843584c224f03a64657f7b31 Mon Sep 17 00:00:00 2001 From: Daniel Gredler Date: Mon, 7 Apr 2025 19:53:36 +0000 Subject: [PATCH 0435/1101] 8353002: Remove unnecessary Windows version check in WTaskbarPeer Reviewed-by: prr, serb, aivanov --- .../classes/sun/awt/windows/WTaskbarPeer.java | 7 +-- .../java/awt/Dialog/TaskbarFeatureTest.java | 50 +++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 test/jdk/java/awt/Dialog/TaskbarFeatureTest.java diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WTaskbarPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WTaskbarPeer.java index 98abeff562f17..09cafc3bed9a9 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WTaskbarPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WTaskbarPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,6 @@ import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; import sun.awt.AWTAccessor; -import sun.awt.OSInfo; import sun.awt.shell.ShellFolder; final class WTaskbarPeer implements TaskbarPeer { @@ -44,9 +43,7 @@ final class WTaskbarPeer implements TaskbarPeer { private static synchronized void init() { if (!initExecuted) { - supported = OSInfo.getWindowsVersion() - .compareTo(OSInfo.WINDOWS_7) >= 0 - && ShellFolder.invoke(() -> nativeInit()); + supported = ShellFolder.invoke(() -> nativeInit()); } initExecuted = true; } diff --git a/test/jdk/java/awt/Dialog/TaskbarFeatureTest.java b/test/jdk/java/awt/Dialog/TaskbarFeatureTest.java new file mode 100644 index 0000000000000..5392019d5a362 --- /dev/null +++ b/test/jdk/java/awt/Dialog/TaskbarFeatureTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Taskbar; +import java.awt.Taskbar.Feature; + +/* + * @test + * @bug 8353002 + * @key headful + * @requires (os.family == "windows") + * @summary Verifies that expected taskbar features are supported on Windows. + */ + +public class TaskbarFeatureTest { + + public static void main(String[] args) throws Exception { + Taskbar taskbar = Taskbar.getTaskbar(); + testFeature(taskbar, Feature.ICON_BADGE_IMAGE_WINDOW); + testFeature(taskbar, Feature.PROGRESS_STATE_WINDOW); + testFeature(taskbar, Feature.PROGRESS_VALUE_WINDOW); + testFeature(taskbar, Feature.USER_ATTENTION_WINDOW); + } + + private static void testFeature(Taskbar taskbar, Feature feature) { + if (!taskbar.isSupported(feature)) { + throw new RuntimeException("Feature not supported: " + feature); + } + } +} From cebda921dd49cf05b521f9ab3f731dd44719b027 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 7 Apr 2025 20:32:26 +0000 Subject: [PATCH 0436/1101] 8311227: Add .editorconfig Co-authored-by: David Briemann Reviewed-by: erikj --- .editorconfig | 7 +++++++ src/hotspot/.editorconfig | 3 +++ 2 files changed, 10 insertions(+) create mode 100644 .editorconfig create mode 100644 src/hotspot/.editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000000..0e6c17e76740d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +root = true + +[*.{cpp,hpp,c,h,java,cc,hh,m,mm,S,md,properties,gmk,m4,ac}] +trim_trailing_whitespace = true + +[Makefile] +trim_trailing_whitespace = true diff --git a/src/hotspot/.editorconfig b/src/hotspot/.editorconfig new file mode 100644 index 0000000000000..48e63362b542e --- /dev/null +++ b/src/hotspot/.editorconfig @@ -0,0 +1,3 @@ +[*.{cpp,hpp,c,h}] +indent_style = space +indent_size = 2 From 42dc99eac16c46f1b403cce1dd14c6bda50eae70 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 7 Apr 2025 20:34:30 +0000 Subject: [PATCH 0437/1101] 8301197: Make sure use of printf is correct and actually needed Reviewed-by: erikj --- make/Docs.gmk | 2 +- make/Init.gmk | 10 +- make/InitSupport.gmk | 23 ++-- make/MainSupport.gmk | 58 ++++---- make/RunTests.gmk | 9 +- make/SourceRevision.gmk | 2 +- make/autoconf/help.m4 | 130 +++++++++--------- make/common/FindTests.gmk | 6 +- make/common/JarArchive.gmk | 2 +- make/common/Modules.gmk | 4 +- make/common/modules/GensrcCommon.gmk | 4 +- make/modules/java.base/Copy.gmk | 2 +- .../modules/java.base/gensrc/GensrcBuffer.gmk | 2 +- .../gensrc/GensrcScopedMemoryAccess.gmk | 2 +- make/scripts/compare.sh | 8 +- test/make/autoconf/test.m4 | 10 +- 16 files changed, 145 insertions(+), 129 deletions(-) diff --git a/make/Docs.gmk b/make/Docs.gmk index 49c97946f7531..0948f8ff76cf1 100644 --- a/make/Docs.gmk +++ b/make/Docs.gmk @@ -264,7 +264,7 @@ define create_overview_file $$($1_OVERVIEW): $$($1_OVERVIEW_VARDEPS_FILE) $$(call LogInfo, Creating overview.html for $1) $$(call MakeDir, $$(@D)) - $$(PRINTF) > $$@ '$$($1_OVERVIEW_TEXT)' + $$(ECHO) -n '$$($1_OVERVIEW_TEXT)' > $$@ endef ################################################################################ diff --git a/make/Init.gmk b/make/Init.gmk index 2a8f6399a184a..5dd1a71dd9a45 100644 --- a/make/Init.gmk +++ b/make/Init.gmk @@ -137,7 +137,7 @@ main: MAKEOVERRIDES := main: $(INIT_TARGETS) ifneq ($(SEQUENTIAL_TARGETS)$(PARALLEL_TARGETS), ) $(call RotateLogFiles) - $(PRINTF) "Building $(TARGET_DESCRIPTION)\n" $(BUILD_LOG_PIPE_SIMPLE) + $(ECHO) "Building $(TARGET_DESCRIPTION)" $(BUILD_LOG_PIPE_SIMPLE) ifneq ($(SEQUENTIAL_TARGETS), ) # Don't touch build output dir since we might be cleaning. That # means no log pipe. @@ -158,7 +158,8 @@ main: $(INIT_TARGETS) -f make/Main.gmk $(USER_MAKE_VARS) \ $(PARALLEL_TARGETS) $(COMPARE_BUILD_MAKE) $(BUILD_LOG_PIPE) || \ ( exitcode=$$? && \ - $(PRINTF) "\nERROR: Build failed for $(TARGET_DESCRIPTION) (exit code $$exitcode) \n" \ + $(ECHO) "" $(BUILD_LOG_PIPE_SIMPLE) && \ + $(ECHO) "ERROR: Build failed for $(TARGET_DESCRIPTION) (exit code $$exitcode)" \ $(BUILD_LOG_PIPE_SIMPLE) && \ cd $(TOPDIR) && $(MAKE) $(MAKE_ARGS) -j 1 -f make/Init.gmk \ on-failure ; \ @@ -170,7 +171,7 @@ main: $(INIT_TARGETS) if test -f $(MAKESUPPORT_OUTPUTDIR)/exit-with-error ; then \ exit 1 ; \ fi - $(PRINTF) "Finished building $(TARGET_DESCRIPTION)\n" $(BUILD_LOG_PIPE_SIMPLE) + $(ECHO) "Finished building $(TARGET_DESCRIPTION)" $(BUILD_LOG_PIPE_SIMPLE) $(call ReportProfileTimes) endif @@ -181,7 +182,8 @@ on-failure: $(call PrintFailureReports) $(call PrintBuildLogFailures) $(call ReportProfileTimes) - $(PRINTF) "HELP: Run 'make doctor' to diagnose build problems.\n\n" + $(ECHO) "HELP: Run 'make doctor' to diagnose build problems." + $(ECHO) "" ifneq ($(COMPARE_BUILD), ) $(call CleanupCompareBuild) endif diff --git a/make/InitSupport.gmk b/make/InitSupport.gmk index a9af44e4225b1..809d1128692a9 100644 --- a/make/InitSupport.gmk +++ b/make/InitSupport.gmk @@ -173,9 +173,10 @@ define PrintFailureReports $(RM) $(MAKESUPPORT_OUTPUTDIR)/failure-summary.log ; \ $(if $(wildcard $(MAKESUPPORT_OUTPUTDIR)/failure-logs/*.log), \ ( \ - $(PRINTF) "\n=== Output from failing command(s) repeated here ===\n" ; \ + $(ECHO) "" ; \ + $(ECHO) "=== Output from failing command(s) repeated here ===" ; \ $(foreach logfile, $(sort $(wildcard $(MAKESUPPORT_OUTPUTDIR)/failure-logs/*.log)), \ - $(PRINTF) "* For target $(notdir $(basename $(logfile))):\n" ; \ + $(ECHO) "* For target $(notdir $(basename $(logfile))):" ; \ $(if $(filter all, $(LOG_REPORT)), \ $(GREP) -v -e "^Note: including file:" < $(logfile) || true ; \ , \ @@ -185,8 +186,9 @@ define PrintFailureReports fi ; \ ) \ ) \ - $(PRINTF) "\n* All command lines available in $(MAKESUPPORT_OUTPUTDIR)/failure-logs.\n" ; \ - $(PRINTF) "=== End of repeated output ===\n" ; \ + $(ECHO) "" ; \ + $(ECHO) "* All command lines available in $(MAKESUPPORT_OUTPUTDIR)/failure-logs." ; \ + $(ECHO) "=== End of repeated output ===" ; \ ) >> $(MAKESUPPORT_OUTPUTDIR)/failure-summary.log \ ) \ ) @@ -195,13 +197,16 @@ endef define PrintBuildLogFailures $(if $(filter none, $(LOG_REPORT)), , \ if $(GREP) -q "recipe for target .* failed" $(BUILD_LOG) 2> /dev/null; then \ - $(PRINTF) "\n=== Make failed targets repeated here ===\n" ; \ + $(ECHO) "" ; \ + $(ECHO) "=== Make failed targets repeated here ===" ; \ $(GREP) "recipe for target .* failed" $(BUILD_LOG) ; \ - $(PRINTF) "=== End of repeated output ===\n" ; \ - $(PRINTF) "\nHELP: Try searching the build log for the name of the first failed target.\n" ; \ + $(ECHO) "=== End of repeated output ===" ; \ + $(ECHO) "" ; \ + $(ECHO) "HELP: Try searching the build log for the name of the first failed target." ; \ else \ - $(PRINTF) "\nNo indication of failed target found.\n" ; \ - $(PRINTF) "HELP: Try searching the build log for '] Error'.\n" ; \ + $(ECHO) "" ; \ + $(ECHO) "No indication of failed target found." ; \ + $(ECHO) "HELP: Try searching the build log for '] Error'." ; \ fi >> $(MAKESUPPORT_OUTPUTDIR)/failure-summary.log ; \ $(CAT) $(MAKESUPPORT_OUTPUTDIR)/failure-summary.log \ ) diff --git a/make/MainSupport.gmk b/make/MainSupport.gmk index f7ba4de2d53c5..ae4858c35afec 100644 --- a/make/MainSupport.gmk +++ b/make/MainSupport.gmk @@ -57,77 +57,77 @@ define SetupTargetBody endef define CleanDocs - @$(PRINTF) "Cleaning docs ..." - @$(PRINTF) "\n" $(LOG_DEBUG) + @$(ECHO) -n "Cleaning docs ..." + @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(SUPPORT_OUTPUTDIR)/docs $(RM) -r $(SUPPORT_OUTPUTDIR)/javadoc $(RM) -r $(IMAGES_OUTPUTDIR)/docs - @$(PRINTF) " done\n" + @$(ECHO) " done" endef # Cleans the dir given as $1 define CleanDir - @$(PRINTF) "Cleaning $(strip $1) build artifacts ..." - @$(PRINTF) "\n" $(LOG_DEBUG) + @$(ECHO) -n "Cleaning $(strip $1) build artifacts ..." + @$(ECHO) "" $(LOG_DEBUG) ($(CD) $(OUTPUTDIR) && $(RM) -r $1) - @$(PRINTF) " done\n" + @$(ECHO) " done" endef define CleanSupportDir - @$(PRINTF) "Cleaning $(strip $1) build artifacts ..." - @$(PRINTF) "\n" $(LOG_DEBUG) + @$(ECHO) -n "Cleaning$(strip $1) build artifacts ..." + @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(SUPPORT_OUTPUTDIR)/$(strip $1) - @$(PRINTF) " done\n" + @$(ECHO) " done" endef define CleanMakeSupportDir - @$(PRINTF) "Cleaning $(strip $1) make support artifacts ..." - @$(PRINTF) "\n" $(LOG_DEBUG) + @$(ECHO) -n "Cleaning $(strip $1) make support artifacts ..." + @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(MAKESUPPORT_OUTPUTDIR)/$(strip $1) - @$(PRINTF) " done\n" + @$(ECHO) " done" endef define CleanTest - @$(PRINTF) "Cleaning test $(strip $1) ..." - @$(PRINTF) "\n" $(LOG_DEBUG) + @$(ECHO) -n "Cleaning test $(strip $1) ..." + @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(SUPPORT_OUTPUTDIR)/test/$(strip $(subst -,/,$1)) # Remove as much of the test directory structure as is empty $(RMDIR) -p $(dir $(SUPPORT_OUTPUTDIR)/test/$(strip $(subst -,/,$1))) 2> /dev/null || true - @$(PRINTF) " done\n" + @$(ECHO) " done" endef define Clean-gensrc - @$(PRINTF) "Cleaning gensrc $(if $1,for $(strip $1) )..." - @$(PRINTF) "\n" $(LOG_DEBUG) + @$(ECHO) -n "Cleaning gensrc $(if $1,for $(strip $1) )..." + @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(SUPPORT_OUTPUTDIR)/gensrc/$(strip $1) - @$(PRINTF) " done\n" + @$(ECHO) " done" endef define Clean-java - @$(PRINTF) "Cleaning java $(if $1,for $(strip $1) )..." - @$(PRINTF) "\n" $(LOG_DEBUG) + @$(ECHO) -n "Cleaning java $(if $1,for $(strip $1) )..." + @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(JDK_OUTPUTDIR)/modules/$(strip $1) $(RM) -r $(SUPPORT_OUTPUTDIR)/special_classes/$(strip $1) - $(PRINTF) " done\n" - $(PRINTF) "Cleaning headers $(if $1,for $(strip $1)) ..." + $(ECHO) " done" + $(ECHO) -n "Cleaning headers $(if $1,for $(strip $1) )..." $(RM) -r $(SUPPORT_OUTPUTDIR)/headers/$(strip $1) - @$(PRINTF) " done\n" + @$(ECHO) " done" endef define Clean-native - @$(PRINTF) "Cleaning native $(if $1,for $(strip $1) )..." - @$(PRINTF) "\n" $(LOG_DEBUG) + @$(ECHO) -n "Cleaning native $(if $1,for $(strip $1) )..." + @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(SUPPORT_OUTPUTDIR)/native/$(strip $1) $(RM) -r $(SUPPORT_OUTPUTDIR)/modules_libs/$(strip $1) $(RM) -r $(SUPPORT_OUTPUTDIR)/modules_cmds/$(strip $1) - @$(PRINTF) " done\n" + @$(ECHO) " done" endef define Clean-include - @$(PRINTF) "Cleaning include $(if $1,for $(strip $1) )..." - @$(PRINTF) "\n" $(LOG_DEBUG) + @$(ECHO) -n "Cleaning include $(if $1,for $(strip $1) )..." + @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(SUPPORT_OUTPUTDIR)/modules_include/$(strip $1) - @$(PRINTF) " done\n" + @$(ECHO) " done" endef define CleanModule diff --git a/make/RunTests.gmk b/make/RunTests.gmk index b9fd3e755d179..7aa0082e0ae81 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -1017,7 +1017,8 @@ define SetupRunJtregTestBody $1_COMMAND_LINE := \ for i in {0..$$(JTREG_RETRY_COUNT)}; do \ if [ "$$$$i" != 0 ]; then \ - $$(PRINTF) "\nRetrying Jtreg run. Attempt: $$$$i\n"; \ + $$(ECHO) ""; \ + $$(ECHO) "Retrying Jtreg run. Attempt: $$$$i"; \ fi; \ $$($1_COMMAND_LINE); \ if [ "`$$(CAT) $$($1_EXITCODE)`" = "0" ]; then \ @@ -1030,10 +1031,12 @@ define SetupRunJtregTestBody ifneq ($$(JTREG_REPEAT_COUNT), 0) $1_COMMAND_LINE := \ for i in {1..$$(JTREG_REPEAT_COUNT)}; do \ - $$(PRINTF) "\nRepeating Jtreg run: $$$$i out of $$(JTREG_REPEAT_COUNT)\n"; \ + $$(ECHO) ""; \ + $$(ECHO) "Repeating Jtreg run: $$$$i out of $$(JTREG_REPEAT_COUNT)"; \ $$($1_COMMAND_LINE); \ if [ "`$$(CAT) $$($1_EXITCODE)`" != "0" ]; then \ - $$(PRINTF) "\nFailures detected, no more repeats.\n"; \ + $$(ECHO) ""; \ + $$(ECHO) "Failures detected, no more repeats."; \ break; \ fi; \ done diff --git a/make/SourceRevision.gmk b/make/SourceRevision.gmk index 285aaae17b591..15399527e6a94 100644 --- a/make/SourceRevision.gmk +++ b/make/SourceRevision.gmk @@ -55,7 +55,7 @@ ifneq ($(and $(GIT), $(wildcard $(TOPDIR)/.git)), ) SCM_DIR := .git ID_COMMAND := $(PRINTF) "git:%s%s\n" \ "$$($(GIT) log -n1 --format=%H | cut -c1-12)" \ - "$$(if test -n "$$($(GIT) status --porcelain)"; then printf '+'; fi)" + "$$(if test -n "$$($(GIT) status --porcelain)"; then $(PRINTF) '+'; fi)" endif ifeq ($(USE_SCM), true) diff --git a/make/autoconf/help.m4 b/make/autoconf/help.m4 index 400acf11a6329..93796d27f06c9 100644 --- a/make/autoconf/help.m4 +++ b/make/autoconf/help.m4 @@ -228,19 +228,19 @@ AC_DEFUN_ONCE([HELP_PRINT_ADDITIONAL_HELP_AND_EXIT], if test "x$CONFIGURE_PRINT_ADDITIONAL_HELP" != x; then # Print available toolchains - $PRINTF "The following toolchains are valid as arguments to --with-toolchain-type.\n" - $PRINTF "Which are available to use depends on the build platform.\n" + $ECHO "The following toolchains are valid as arguments to --with-toolchain-type." + $ECHO "Which are available to use depends on the build platform." for toolchain in $VALID_TOOLCHAINS_all; do # Use indirect variable referencing toolchain_var_name=TOOLCHAIN_DESCRIPTION_$toolchain TOOLCHAIN_DESCRIPTION=${!toolchain_var_name} $PRINTF " %-22s %s\n" $toolchain "$TOOLCHAIN_DESCRIPTION" done - $PRINTF "\n" + $ECHO "" # Print available JVM features - $PRINTF "The following JVM features are valid as arguments to --with-jvm-features.\n" - $PRINTF "Which are available to use depends on the environment and JVM variant.\n" + $ECHO "The following JVM features are valid as arguments to --with-jvm-features." + $ECHO "Which are available to use depends on the environment and JVM variant." m4_foreach(FEATURE, m4_split(jvm_features_valid), [ # Create an m4 variable containing the description for FEATURE. m4_define(FEATURE_DESCRIPTION, [jvm_feature_desc_]m4_translit(FEATURE, -, _)) @@ -257,115 +257,117 @@ AC_DEFUN_ONCE([HELP_PRINT_SUMMARY_AND_WARNINGS], [ # Finally output some useful information to the user - printf "\n" - printf "====================================================\n" + $ECHO "" + $ECHO "====================================================" if test "x$no_create" != "xyes"; then if test "x$IS_RECONFIGURE" != "xyes"; then - printf "A new configuration has been successfully created in\n%s\n" "$OUTPUTDIR" + $ECHO "A new configuration has been successfully created in" + $ECHO "$OUTPUTDIR" else - printf "The existing configuration has been successfully updated in\n%s\n" "$OUTPUTDIR" + $ECHO "The existing configuration has been successfully updated in" + $ECHO "$OUTPUTDIR" fi else if test "x$IS_RECONFIGURE" != "xyes"; then - printf "A configuration has been successfully checked but not created\n" + $ECHO "A configuration has been successfully checked but not created" else - printf "The existing configuration has been successfully checked in\n%s\n" "$OUTPUTDIR" + $ECHO "The existing configuration has been successfully checked in" + $ECHO "$OUTPUTDIR" fi fi if test "x$CONFIGURE_COMMAND_LINE" != x; then - printf "using configure arguments '$CONFIGURE_COMMAND_LINE'.\n" + $ECHO "using configure arguments '$CONFIGURE_COMMAND_LINE'." else - printf "using default settings.\n" + $ECHO "using default settings." fi if test "x$REAL_CONFIGURE_COMMAND_EXEC_FULL" != x; then - printf "\n" - printf "The original configure invocation was '$REAL_CONFIGURE_COMMAND_EXEC_SHORT $REAL_CONFIGURE_COMMAND_LINE'.\n" + $ECHO "" + $ECHO "The original configure invocation was '$REAL_CONFIGURE_COMMAND_EXEC_SHORT $REAL_CONFIGURE_COMMAND_LINE'." fi - printf "\n" - printf "Configuration summary:\n" - printf "* Name: $CONF_NAME\n" - printf "* Debug level: $DEBUG_LEVEL\n" - printf "* HS debug level: $HOTSPOT_DEBUG_LEVEL\n" - printf "* JVM variants: $JVM_VARIANTS\n" - printf "* JVM features: " + $ECHO "" + $ECHO "Configuration summary:" + $ECHO "* Name: $CONF_NAME" + $ECHO "* Debug level: $DEBUG_LEVEL" + $ECHO "* HS debug level: $HOTSPOT_DEBUG_LEVEL" + $ECHO "* JVM variants: $JVM_VARIANTS" + $ECHO -n "* JVM features: " for variant in $JVM_VARIANTS; do features_var_name=JVM_FEATURES_$variant JVM_FEATURES_FOR_VARIANT=${!features_var_name} - printf "$variant: \'$JVM_FEATURES_FOR_VARIANT\' " + $ECHO -n "$variant: '$JVM_FEATURES_FOR_VARIANT' " done - printf "\n" + $ECHO "" - printf "* OpenJDK target: OS: $OPENJDK_TARGET_OS, CPU architecture: $OPENJDK_TARGET_CPU_ARCH, address length: $OPENJDK_TARGET_CPU_BITS\n" - printf "* Version string: $VERSION_STRING ($VERSION_SHORT)\n" + $ECHO "* OpenJDK target: OS: $OPENJDK_TARGET_OS, CPU architecture: $OPENJDK_TARGET_CPU_ARCH, address length: $OPENJDK_TARGET_CPU_BITS" + $ECHO "* Version string: $VERSION_STRING ($VERSION_SHORT)" if test "x$SOURCE_DATE" != xupdated; then source_date_info="$SOURCE_DATE ($SOURCE_DATE_ISO_8601)" else source_date_info="Determined at build time" fi - printf "* Source date: $source_date_info\n" + $ECHO "* Source date: $source_date_info" - printf "\n" - printf "Tools summary:\n" + $ECHO "" + $ECHO "Tools summary:" if test "x$OPENJDK_BUILD_OS" = "xwindows"; then - printf "* Environment: %s version %s; windows version %s; prefix \"%s\"; root \"%s\"\n" \ - "$WINENV_VENDOR" "$WINENV_VERSION" "$WINDOWS_VERSION" "$WINENV_PREFIX" "$WINENV_ROOT" + $ECHO "* Environment: $WINENV_VENDOR version $WINENV_VERSION; windows version $WINDOWS_VERSION; prefix \"$WINENV_PREFIX\"; root \"$WINENV_ROOT\"" fi - printf "* Boot JDK: $BOOT_JDK_VERSION (at $BOOT_JDK)\n" - printf "* Toolchain: $TOOLCHAIN_TYPE ($TOOLCHAIN_DESCRIPTION)\n" + $ECHO "* Boot JDK: $BOOT_JDK_VERSION (at $BOOT_JDK)" + $ECHO "* Toolchain: $TOOLCHAIN_TYPE ($TOOLCHAIN_DESCRIPTION)" if test "x$DEVKIT_NAME" != x; then - printf "* Devkit: $DEVKIT_NAME ($DEVKIT_ROOT)\n" + $ECHO "* Devkit: $DEVKIT_NAME ($DEVKIT_ROOT)" elif test "x$DEVKIT_ROOT" != x; then - printf "* Devkit: $DEVKIT_ROOT\n" + $ECHO "* Devkit: $DEVKIT_ROOT" elif test "x$SYSROOT" != x; then - printf "* Sysroot: $SYSROOT\n" + $ECHO "* Sysroot: $SYSROOT" fi - printf "* C Compiler: Version $CC_VERSION_NUMBER (at ${CC#"$FIXPATH "})\n" - printf "* C++ Compiler: Version $CXX_VERSION_NUMBER (at ${CXX#"$FIXPATH "})\n" + $ECHO "* C Compiler: Version $CC_VERSION_NUMBER (at ${CC#"$FIXPATH "})" + $ECHO "* C++ Compiler: Version $CXX_VERSION_NUMBER (at ${CXX#"$FIXPATH "})" - printf "\n" - printf "Build performance summary:\n" - printf "* Build jobs: $JOBS\n" - printf "* Memory limit: $MEMORY_SIZE MB\n" + $ECHO "" + $ECHO "Build performance summary:" + $ECHO "* Build jobs: $JOBS" + $ECHO "* Memory limit: $MEMORY_SIZE MB" if test "x$CCACHE_STATUS" != "x"; then - printf "* ccache status: $CCACHE_STATUS\n" + $ECHO "* ccache status: $CCACHE_STATUS" fi - printf "\n" + $ECHO "" if test "x$BUILDING_MULTIPLE_JVM_VARIANTS" = "xtrue"; then - printf "NOTE: You have requested to build more than one version of the JVM, which\n" - printf "will result in longer build times.\n" - printf "\n" + $ECHO "NOTE: You have requested to build more than one version of the JVM, which" + $ECHO "will result in longer build times." + $ECHO "" fi if test "x$OUTPUT_DIR_IS_LOCAL" != "xyes"; then - printf "WARNING: Your build output directory is not on a local disk.\n" - printf "This will severely degrade build performance!\n" - printf "It is recommended that you create an output directory on a local disk,\n" - printf "and run the configure script again from that directory.\n" - printf "\n" + $ECHO "WARNING: Your build output directory is not on a local disk." + $ECHO "This will severely degrade build performance!" + $ECHO "It is recommended that you create an output directory on a local disk," + $ECHO "and run the configure script again from that directory." + $ECHO "" fi if test "x$IS_RECONFIGURE" = "xyes" && test "x$no_create" != "xyes"; then - printf "WARNING: The result of this configuration has overridden an older\n" - printf "configuration. You *should* run 'make clean' to make sure you get a\n" - printf "proper build. Failure to do so might result in strange build problems.\n" - printf "\n" + $ECHO "WARNING: The result of this configuration has overridden an older" + $ECHO "configuration. You *should* run 'make clean' to make sure you get a" + $ECHO "proper build. Failure to do so might result in strange build problems." + $ECHO "" fi if test "x$IS_RECONFIGURE" != "xyes" && test "x$no_create" = "xyes"; then - printf "WARNING: The result of this configuration was not saved.\n" - printf "You should run without '--no-create | -n' to create the configuration.\n" - printf "\n" + $ECHO "WARNING: The result of this configuration was not saved." + $ECHO "You should run without '--no-create | -n' to create the configuration." + $ECHO "" fi if test "x$UNSUPPORTED_TOOLCHAIN_VERSION" = "xyes"; then - printf "WARNING: The toolchain version used is known to have issues. Please\n" - printf "consider using a supported version unless you know what you are doing.\n" - printf "\n" + $ECHO "WARNING: The toolchain version used is known to have issues. Please" + $ECHO "consider using a supported version unless you know what you are doing." + $ECHO "" fi ]) @@ -381,10 +383,10 @@ AC_DEFUN_ONCE([HELP_REPEAT_WARNINGS], if test -e "$CONFIG_LOG_PATH/config.log"; then $GREP '^configure:.*: WARNING:' "$CONFIG_LOG_PATH/config.log" > /dev/null 2>&1 if test $? -eq 0; then - printf "The following warnings were produced. Repeated here for convenience:\n" + $ECHO "The following warnings were produced. Repeated here for convenience:" # We must quote sed expression (using []) to stop m4 from eating the []. $GREP '^configure:.*: WARNING:' "$CONFIG_LOG_PATH/config.log" | $SED -e [ 's/^configure:[0-9]*: //' ] - printf "\n" + $ECHO "" fi fi ]) diff --git a/make/common/FindTests.gmk b/make/common/FindTests.gmk index 1f3a70b30356a..41cf08d9e483e 100644 --- a/make/common/FindTests.gmk +++ b/make/common/FindTests.gmk @@ -58,13 +58,15 @@ ifeq ($(GENERATE_FIND_TESTS_FILE), true) $(TOPDIR)/test/make/TestMake.gmk $(call MakeTargetDir) ( $(foreach root, $(JTREG_TESTROOTS), \ - $(PRINTF) "\n$(root)_JTREG_TEST_GROUPS := " ; \ + $(ECHO) ""; \ + $(ECHO) -n "$(root)_JTREG_TEST_GROUPS := "; \ $(SED) -n -e 's/^\#.*//g' -e 's/\([^ ]*\)\w*=.*/\1/gp' \ $($(root)_JTREG_GROUP_FILES) \ | $(SORT) -u | $(TR) '\n' ' ' ; \ ) \ ) > $@ - $(PRINTF) "\nMAKE_TEST_TARGETS := " >> $@ + $(ECHO) "" >> $@ + $(ECHO) -n "MAKE_TEST_TARGETS := " >> $@ $(MAKE) -s --no-print-directory $(MAKE_ARGS) \ SPEC=$(SPEC) -f $(TOPDIR)/test/make/TestMake.gmk print-targets \ TARGETS_FILE=$@ diff --git a/make/common/JarArchive.gmk b/make/common/JarArchive.gmk index 1f8ed1bc002ef..26a98f289498b 100644 --- a/make/common/JarArchive.gmk +++ b/make/common/JarArchive.gmk @@ -256,7 +256,7 @@ define SetupJarArchiveBody $$(if $$($1_JARMAIN), \ $(ECHO) "Main-Class: $$(strip $$($1_JARMAIN))" >> $$($1_MANIFEST_FILE) $$(NEWLINE)) \ $$(if $$($1_EXTRA_MANIFEST_ATTR), \ - $(PRINTF) "$$($1_EXTRA_MANIFEST_ATTR)\n" >> $$($1_MANIFEST_FILE) $$(NEWLINE)) \ + $(ECHO) "$$($1_EXTRA_MANIFEST_ATTR)" >> $$($1_MANIFEST_FILE) $$(NEWLINE)) \ $(ECHO) Creating $$($1_NAME) $$(NEWLINE) \ $$($1_JAR_CMD) --create $$($1_JAR_OPTIONS) --file $$@ --manifest $$($1_MANIFEST_FILE) $$(NEWLINE) \ $$($1_SCAPTURE_CONTENTS) \ diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk index f4f815c740db6..663e9075cf8f2 100644 --- a/make/common/Modules.gmk +++ b/make/common/Modules.gmk @@ -180,7 +180,7 @@ ifeq ($(GENERATE_MODULE_DEPS_FILE), true) $(call MakeTargetDir) $(RM) $@ $(foreach m, $(MODULE_INFOS), \ - ( $(PRINTF) "DEPS_$(call GetModuleNameFromModuleInfo, $m) := " && \ + ( $(ECHO) -n "DEPS_$(call GetModuleNameFromModuleInfo, $m) := " && \ $(AWK) -v MODULE=$(call GetModuleNameFromModuleInfo, $m) ' \ BEGIN { if (MODULE != "java.base") printf(" java.base"); } \ /^ *requires/ { sub(/;/, ""); \ @@ -194,7 +194,7 @@ ifeq ($(GENERATE_MODULE_DEPS_FILE), true) gsub(/\r/, ""); \ printf(" %s", $$0) } \ END { printf("\n") }' $m && \ - $(PRINTF) "TRANSITIVE_MODULES_$(call GetModuleNameFromModuleInfo, $m) := " && \ + $(ECHO) -n "TRANSITIVE_MODULES_$(call GetModuleNameFromModuleInfo, $m) := " && \ $(AWK) -v MODULE=$(call GetModuleNameFromModuleInfo, $m) ' \ BEGIN { if (MODULE != "java.base") printf(" java.base"); } \ /^ *requires *transitive/ { \ diff --git a/make/common/modules/GensrcCommon.gmk b/make/common/modules/GensrcCommon.gmk index 64d1f71d82e65..2a94c3f9a4200 100644 --- a/make/common/modules/GensrcCommon.gmk +++ b/make/common/modules/GensrcCommon.gmk @@ -41,8 +41,8 @@ include $(TOPDIR)/make/ToolsJdk.gmk define SetupVersionProperties $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/$$(strip $2): $$(call MakeTargetDir) - $(PRINTF) "jdk=$(VERSION_NUMBER)\nfull=$(VERSION_STRING)\nrelease=$(VERSION_SHORT)\n" \ - > $$@ + $(PRINTF) "jdk=%s\nfull=%s\nrelease=%s\n" \ + $(VERSION_NUMBER) $(VERSION_STRING) $(VERSION_SHORT) > $$@ $$(strip $1) += $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/$$(strip $2) endef diff --git a/make/modules/java.base/Copy.gmk b/make/modules/java.base/Copy.gmk index e33676529cdf3..4625c1f7dbca1 100644 --- a/make/modules/java.base/Copy.gmk +++ b/make/modules/java.base/Copy.gmk @@ -99,7 +99,7 @@ JVMCFG := $(LIB_DST_DIR)/jvm.cfg define print-cfg-line $(call LogInfo, Adding -$1 $2 to jvm.cfg) - $(PRINTF) -- "-$1 $2\n" >> $@ $(NEWLINE) + $(ECHO) "-$1 $2" >> $@ $(NEWLINE) endef $(JVMCFG): $(call DependOnVariable, ORDERED_CFG_VARIANTS) diff --git a/make/modules/java.base/gensrc/GensrcBuffer.gmk b/make/modules/java.base/gensrc/GensrcBuffer.gmk index f769a8e61e052..dd91c8c870a13 100644 --- a/make/modules/java.base/gensrc/GensrcBuffer.gmk +++ b/make/modules/java.base/gensrc/GensrcBuffer.gmk @@ -272,7 +272,7 @@ define SetupGenBuffer $$($1_long_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp $$($1_float_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp $$($1_double_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp - $(PRINTF) "}\n" >> $$($1_DST).tmp + $(ECHO) "}" >> $$($1_DST).tmp mv $$($1_DST).tmp $$($1_DST) endif diff --git a/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk b/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk index 00fba64394b7b..ea51e4fd4ee12 100644 --- a/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk +++ b/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk @@ -163,7 +163,7 @@ $(SCOPED_MEMORY_ACCESS_DEST): $(BUILD_TOOLS_JDK) $(SCOPED_MEMORY_ACCESS_TEMPLATE $(foreach t, $(SCOPE_MEMORY_ACCESS_TYPES), \ $(TOOL_SPP) -nel -K$(BIN_$t_type) -Dtype=$(BIN_$t_type) -DType=$(BIN_$t_Type) $(BIN_$t_ARGS) \ -i$(SCOPED_MEMORY_ACCESS_BIN_TEMPLATE) -o$(SCOPED_MEMORY_ACCESS_DEST) ;) - $(PRINTF) "}\n" >> $(SCOPED_MEMORY_ACCESS_DEST) + $(ECHO) "}" >> $(SCOPED_MEMORY_ACCESS_DEST) TARGETS += $(SCOPED_MEMORY_ACCESS_DEST) diff --git a/make/scripts/compare.sh b/make/scripts/compare.sh index cc2f4adf2ed8b..250b5a37b9f5f 100644 --- a/make/scripts/compare.sh +++ b/make/scripts/compare.sh @@ -203,12 +203,12 @@ compare_permissions() { do if [ ! -f ${OTHER_DIR}/$f ]; then continue; fi if [ ! -f ${THIS_DIR}/$f ]; then continue; fi - OP=`ls -l ${OTHER_DIR}/$f | awk '{printf("%.10s\n", $1);}'` - TP=`ls -l ${THIS_DIR}/$f | awk '{printf("%.10s\n", $1);}'` + OP=`ls -l ${OTHER_DIR}/$f | $AWK '{printf("%.10s\n", $1);}'` + TP=`ls -l ${THIS_DIR}/$f | $AWK '{printf("%.10s\n", $1);}'` if [ "$OP" != "$TP" ] then if [ -z "$found" ]; then echo ; found="yes"; fi - $PRINTF "\tother: ${OP} this: ${TP}\t$f\n" + $PRINTF "\tother: %s this: %s\t%s\n" "${OP}" "${TP}" "$f" fi done if [ -z "$found" ]; then @@ -260,7 +260,7 @@ compare_file_types() { continue else if [ -z "$found" ]; then echo ; found="yes"; fi - $PRINTF "\tother: ${OF}\n\tthis : ${TF}\n" + $PRINTF "\tother: %s\n\tthis : %s\n" "${OF}" "${TF}" fi fi done diff --git a/test/make/autoconf/test.m4 b/test/make/autoconf/test.m4 index 07fb91f6ff7c7..0aa002ef9bf4e 100644 --- a/test/make/autoconf/test.m4 +++ b/test/make/autoconf/test.m4 @@ -92,14 +92,16 @@ AC_DEFUN([TEST_ARG_ENABLE], # Use the CUSTOM_EARLY_HOOK to inject our test after basic init is done. AC_DEFUN_ONCE([CUSTOM_EARLY_HOOK], [ - $PRINTF "\nStarting configure tests\n" - $PRINTF "==============================\n" + $ECHO "" + $ECHO "Starting configure tests" + $ECHO "==============================" TEST_STRING_OPS TEST_ARG_ENABLE # If no assertions failed, report success - $PRINTF "==============================\n" - $PRINTF "Configure tests finished successfully\n\n" + $ECHO "==============================" + $ECHO "Configure tests finished successfully" + $ECHO "" exit 0 ]) From a8dfcf55849775a7ac4822a8b7661f20f1b33bb0 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Mon, 7 Apr 2025 20:45:51 +0000 Subject: [PATCH 0438/1101] 8353322: Specification of ChoiceFormat#parse(String, ParsePosition) is inadequate Reviewed-by: naoto --- .../share/classes/java/text/ChoiceFormat.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/text/ChoiceFormat.java b/src/java.base/share/classes/java/text/ChoiceFormat.java index cf951ebf81fda..560f3017824e2 100644 --- a/src/java.base/share/classes/java/text/ChoiceFormat.java +++ b/src/java.base/share/classes/java/text/ChoiceFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -558,7 +558,20 @@ StringBuf format(double number, StringBuf toAppendTo, } /** - * Parses a Number from the input text. + * Parses the input text starting at the index given by the {@code ParsePosition} + * as a {@code Double}. The value returned is the {@code limit} corresponding + * to the {@code format} that is the longest substring of the input text. + * Matching is done in ascending order, when multiple {@code format}s match + * the text equivalently in strength, the first matching {@code limit} is + * returned. If there is no match, {@code Double.NaN} is returned. + *

+ * For example, + * {@snippet lang=java : + * var fmt = new ChoiceFormat("0#foo|1#bar|2#baz"); + * fmt.parse("baz", new ParsePosition(0)); // returns 2.0 + * fmt.parse("quux", new ParsePosition(0)); // returns NaN + * } + * * @param text the source text. * @param status an input-output parameter. On input, the * status.index field indicates the first character of the @@ -567,7 +580,8 @@ StringBuf format(double number, StringBuf toAppendTo, * in the source text. On exit, if an error did occur, * status.index is unchanged and status.errorIndex is set to the * first index of the character that caused the parse to fail. - * @return A Number representing the value of the number parsed. + * @return A Number which represents the {@code limit} corresponding to the + * {@code format} parsed, or {@code Double.NaN} if the parse fails. * @throws NullPointerException if {@code status} is {@code null} * or if {@code text} is {@code null} and the list of * choice strings is not empty. From e266eba40131bb97c392c8c87551d28e74c4764a Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Mon, 7 Apr 2025 20:50:41 +0000 Subject: [PATCH 0439/1101] 8352972: PPC64: Intrinsify Unsafe::setMemory Reviewed-by: lucy --- src/hotspot/cpu/ppc/stubGenerator_ppc.cpp | 100 ++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index fa356ec13ac16..939c3d3094a1a 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -2383,6 +2383,105 @@ class StubGenerator: public StubCodeGenerator { } + // Helper for generate_unsafe_setmemory + // + // Atomically fill an array of memory using 1-, 2-, 4-, or 8-byte chunks and return. + static void do_setmemory_atomic_loop(int elem_size, Register dest, Register size, Register byteVal, + MacroAssembler *_masm) { + + Label L_Loop, L_Tail; // 2x unrolled loop + + // Propagate byte to required width + if (elem_size > 1) __ rldimi(byteVal, byteVal, 8, 64 - 2 * 8); + if (elem_size > 2) __ rldimi(byteVal, byteVal, 16, 64 - 2 * 16); + if (elem_size > 4) __ rldimi(byteVal, byteVal, 32, 64 - 2 * 32); + + __ srwi_(R0, size, exact_log2(2 * elem_size)); // size is a 32 bit value + __ beq(CR0, L_Tail); + __ mtctr(R0); + + __ align(32); // loop alignment + __ bind(L_Loop); + __ store_sized_value(byteVal, 0, dest, elem_size); + __ store_sized_value(byteVal, elem_size, dest, elem_size); + __ addi(dest, dest, 2 * elem_size); + __ bdnz(L_Loop); + + __ bind(L_Tail); + __ andi_(R0, size, elem_size); + __ bclr(Assembler::bcondCRbiIs1, Assembler::bi0(CR0, Assembler::equal), Assembler::bhintbhBCLRisReturn); + __ store_sized_value(byteVal, 0, dest, elem_size); + __ blr(); + } + + // + // Generate 'unsafe' set memory stub + // Though just as safe as the other stubs, it takes an unscaled + // size_t (# bytes) argument instead of an element count. + // + // Input: + // R3_ARG1 - destination array address + // R4_ARG2 - byte count (size_t) + // R5_ARG3 - byte value + // + address generate_unsafe_setmemory(address unsafe_byte_fill) { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, StubGenStubId::unsafe_setmemory_id); + address start = __ function_entry(); + + // bump this on entry, not on exit: + // inc_counter_np(SharedRuntime::_unsafe_set_memory_ctr); + + { + Label L_fill8Bytes, L_fill4Bytes, L_fillBytes; + + const Register dest = R3_ARG1; + const Register size = R4_ARG2; + const Register byteVal = R5_ARG3; + const Register rScratch1 = R6; + + // fill_to_memory_atomic(unsigned char*, unsigned long, unsigned char) + + // Check for pointer & size alignment + __ orr(rScratch1, dest, size); + + __ andi_(R0, rScratch1, 7); + __ beq(CR0, L_fill8Bytes); + + __ andi_(R0, rScratch1, 3); + __ beq(CR0, L_fill4Bytes); + + __ andi_(R0, rScratch1, 1); + __ bne(CR0, L_fillBytes); + + // Mark remaining code as such which performs Unsafe accesses. + UnsafeMemoryAccessMark umam(this, true, false); + + // At this point, we know the lower bit of size is zero and a + // multiple of 2 + do_setmemory_atomic_loop(2, dest, size, byteVal, _masm); + + __ align(32); + __ bind(L_fill8Bytes); + // At this point, we know the lower 3 bits of size are zero and a + // multiple of 8 + do_setmemory_atomic_loop(8, dest, size, byteVal, _masm); + + __ align(32); + __ bind(L_fill4Bytes); + // At this point, we know the lower 2 bits of size are zero and a + // multiple of 4 + do_setmemory_atomic_loop(4, dest, size, byteVal, _masm); + + __ align(32); + __ bind(L_fillBytes); + do_setmemory_atomic_loop(1, dest, size, byteVal, _masm); + } + + return start; + } + + // // Generate generic array copy stubs // @@ -3207,6 +3306,7 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_arrayof_jshort_fill = generate_fill(StubGenStubId::arrayof_jshort_fill_id); StubRoutines::_arrayof_jint_fill = generate_fill(StubGenStubId::arrayof_jint_fill_id); } + StubRoutines::_unsafe_setmemory = generate_unsafe_setmemory(StubRoutines::_jbyte_fill); #endif } From fd2734e97d3ef505473938109746ae59d5fefca6 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Mon, 7 Apr 2025 21:52:57 +0000 Subject: [PATCH 0440/1101] 8353585: Provide ChoiceFormat#parse(String, ParsePosition) tests Reviewed-by: naoto --- .../text/Format/ChoiceFormat/ParseTest.java | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 test/jdk/java/text/Format/ChoiceFormat/ParseTest.java diff --git a/test/jdk/java/text/Format/ChoiceFormat/ParseTest.java b/test/jdk/java/text/Format/ChoiceFormat/ParseTest.java new file mode 100644 index 0000000000000..17ead8f450c99 --- /dev/null +++ b/test/jdk/java/text/Format/ChoiceFormat/ParseTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8353585 + * @summary Basic parse tests. Enforce regular behavior, no match, and multi match. + * @run junit ParseTest + */ + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.text.ChoiceFormat; +import java.text.ParsePosition; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ParseTest { + + // Ensure that the parsed text produces the expected number + // i.e. return limit corresponding to format matched + @ParameterizedTest + @MethodSource + void parseTest(String pattern, String text, Double expected, int index) { + var pp = new ParsePosition(index); + var fmt = new ChoiceFormat(pattern); + assertEquals(expected, fmt.parse(text, pp), "Incorrect limit returned"); + if (expected.equals(Double.NaN)) { // AKA failed parse + assertEquals(index, pp.getErrorIndex(), + "Failed parse produced incorrect error index"); + } else { + assertEquals(-1, pp.getErrorIndex(), + "Error index should remain -1 on match"); + } + } + + private static Stream parseTest() { + return Stream.of( + Arguments.of("1#foo", "foo", Double.NaN, -1), + Arguments.of("1#baz", "foo bar baz", Double.NaN, 20), + Arguments.of("1#baz", "foo bar baz", 1d, 8), + Arguments.of("1#baz", "foo baz quux", Double.NaN, 8), + Arguments.of("1#a", "", Double.NaN, 0), + Arguments.of("1#a", "a", 1d, 0), + Arguments.of("1# ", " ", 1d, 0), + Arguments.of("1#a|2#a", "a", 1d, 0), + Arguments.of("1#a|2#aa", "aa", 2d, 0), + Arguments.of("1#a|2#aa", "aabb", 2d, 0), + Arguments.of("1#a|2#aa", "bbaa", Double.NaN, 0), + Arguments.of("1#aa|2#aaa", "a", Double.NaN, 0) + ); + } +} From 3951a8e01945d262cdd6ebbe4e1548ddf8e3c02a Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 7 Apr 2025 23:36:04 +0000 Subject: [PATCH 0441/1101] 8353365: TOUCH_ASSERT_POISON clears GetLastError() Reviewed-by: kbarrett, stuefe, jwaters --- src/hotspot/os/windows/os_windows.cpp | 1 + test/hotspot/gtest/utilities/test_vmerror.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 06fe8a826cdf4..ec03a45594cdf 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -2600,6 +2600,7 @@ static inline void report_error(Thread* t, DWORD exception_code, //----------------------------------------------------------------------------- JNIEXPORT LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { + PreserveLastError ple; if (InterceptOSException) return EXCEPTION_CONTINUE_SEARCH; PEXCEPTION_RECORD exception_record = exceptionInfo->ExceptionRecord; DWORD exception_code = exception_record->ExceptionCode; diff --git a/test/hotspot/gtest/utilities/test_vmerror.cpp b/test/hotspot/gtest/utilities/test_vmerror.cpp index a779133b711ab..ad2f2c3004f9d 100644 --- a/test/hotspot/gtest/utilities/test_vmerror.cpp +++ b/test/hotspot/gtest/utilities/test_vmerror.cpp @@ -28,6 +28,17 @@ #ifdef ASSERT +#ifdef _WINDOWS + +#include + +TEST_VM_ASSERT_MSG(vmErrorTest, fatalWithError, + "fatal error: GetLastError should be 6 - actually: 6") { + SetLastError(6); + fatal("GetLastError should be 6 - actually: %lu", GetLastError()); +} +#endif // WINDOWS + TEST_VM_ASSERT_MSG(vmErrorTest, resourceMark, "fatal error: memory leak: allocating without ResourceMark") { From edaeb4b2da7c7a49ea3f3baebc7a072b56088e34 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 8 Apr 2025 00:33:36 +0000 Subject: [PATCH 0442/1101] 8352895: UserCookie.java runs wrong test class Reviewed-by: dfuchs --- test/jdk/sun/net/www/protocol/http/UserCookie.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/jdk/sun/net/www/protocol/http/UserCookie.java b/test/jdk/sun/net/www/protocol/http/UserCookie.java index 29261112ece88..7867523719b13 100644 --- a/test/jdk/sun/net/www/protocol/http/UserCookie.java +++ b/test/jdk/sun/net/www/protocol/http/UserCookie.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,9 @@ /* * @test * @bug 6439651 - * @modules jdk.httpserver - * @run main/othervm UserAuth * @summary Sending "Cookie" header with JRE 1.5.0_07 doesn't work anymore + * @modules jdk.httpserver + * @run main/othervm UserCookie */ import java.net.*; From b64cdc28132c889ca8e21dc9534590ba2a778bcd Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 8 Apr 2025 00:35:33 +0000 Subject: [PATCH 0443/1101] 8353787: Increased number of SHA-384-Digest java.util.jar.Attributes$Name instances leading to higher memory footprint Reviewed-by: mullan, lancea --- src/java.base/share/classes/java/util/jar/Attributes.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/util/jar/Attributes.java b/src/java.base/share/classes/java/util/jar/Attributes.java index 149bf38f67cb0..9322bb9acace8 100644 --- a/src/java.base/share/classes/java/util/jar/Attributes.java +++ b/src/java.base/share/classes/java/util/jar/Attributes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -727,6 +727,7 @@ private static void addName(Map names, Name name) { addName(names, new Name("Created-By")); addName(names, new Name("SHA1-Digest")); addName(names, new Name("SHA-256-Digest")); + addName(names, new Name("SHA-384-Digest")); KNOWN_NAMES = Map.copyOf(names); } else { // Even if KNOWN_NAMES was read from archive, we still need From 80ff7b9c9406c7845ecb3bc40910e92ccdd23ff2 Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Tue, 8 Apr 2025 01:37:29 +0000 Subject: [PATCH 0444/1101] 8353695: RISC-V: compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java is failing with Zvkn Reviewed-by: fjiang, mli --- .../cpuflags/TestAESIntrinsicsOnSupportedConfig.java | 2 +- .../cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java | 2 +- .../compiler/lib/ir_framework/test/IREncodingPrinter.java | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java index b710ebcd28358..4956b1495740b 100644 --- a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java +++ b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java @@ -26,7 +26,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.cpu.features ~= ".*aes.*" & !vm.graal.enabled + * @requires (vm.cpu.features ~= ".*aes.*" | vm.cpu.features ~= ".*zvkn.*") & !vm.graal.enabled * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java index 26ad906095ff5..ef947c4e05741 100644 --- a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java +++ b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java @@ -28,7 +28,7 @@ * java.management * * @build jdk.test.whitebox.WhiteBox - * @requires !(vm.cpu.features ~= ".*aes.*") + * @requires !(vm.cpu.features ~= ".*aes.*" | vm.cpu.features ~= ".*zvkn.*") * @requires vm.compiler1.enabled | !vm.graal.enabled * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java index c9904404e9018..7d229cae15201 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java @@ -109,12 +109,13 @@ public class IREncodingPrinter { "asimd", "sve", "sve2", - // Riscv64 + // RISCV64 "rvv", "zbkb", "zfh", "zvbb", - "zvfh" + "zvfh", + "zvkn" )); public IREncodingPrinter() { From fb955bcb153b7008b45e9080c0817fcce7b5463e Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Tue, 8 Apr 2025 06:03:16 +0000 Subject: [PATCH 0445/1101] 8353267: jmod create finds the wrong set of packages when class file are in non-package location Reviewed-by: rriggs --- .../jlink/internal/ResourcePoolManager.java | 17 ++- .../classes/jdk/tools/jmod/JmodTask.java | 61 +++++---- test/jdk/tools/jlink/ClassFileInMetaInfo.java | 120 ++++++++++++++++++ test/jdk/tools/jmod/JmodTest.java | 44 ++++++- 4 files changed, 208 insertions(+), 34 deletions(-) create mode 100644 test/jdk/tools/jlink/ClassFileInMetaInfo.java diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java index 028bca2ecac23..ba04b9db014e8 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import java.util.Set; import java.util.stream.Stream; import jdk.internal.jimage.decompressor.CompressedResourceHeader; -import jdk.internal.module.Resources; +import jdk.internal.module.Checks; import jdk.internal.module.ModuleInfo; import jdk.internal.module.ModuleInfo.Attributes; import jdk.internal.module.ModuleTarget; @@ -67,11 +67,16 @@ static Attributes readModuleAttributes(ResourcePoolModule mod) { } /** - * Returns true if a resource has an effective package. + * Returns true if a resource is located in a named package. */ - public static boolean isNamedPackageResource(String path) { - return (path.endsWith(".class") && !path.endsWith("module-info.class")) || - Resources.canEncapsulate(path); + public static boolean isNamedPackageResource(String name) { + int index = name.lastIndexOf("/"); + if (index == -1) { + return false; + } else { + String pn = name.substring(0, index).replace('/', '.'); + return Checks.isPackageName(pn); + } } static class ResourcePoolModuleImpl implements ResourcePoolModule { diff --git a/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java b/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java index ed1620ec0f022..5345ee4253ca4 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java @@ -87,7 +87,7 @@ import jdk.internal.module.ModulePath; import jdk.internal.module.ModuleResolution; import jdk.internal.module.ModuleTarget; -import jdk.internal.module.Resources; +import jdk.internal.module.Checks; import jdk.tools.jlink.internal.Utils; import static java.util.stream.Collectors.joining; @@ -689,7 +689,6 @@ Set findPackages(Path dir) { (path, attrs) -> attrs.isRegularFile(), FileVisitOption.FOLLOW_LINKS)) { return stream.map(dir::relativize) - .filter(path -> isResource(path.toString())) .map(path -> toPackageName(path)) .filter(pkg -> pkg.length() > 0) .collect(Collectors.toSet()); @@ -703,46 +702,58 @@ Set findPackages(Path dir) { */ Set findPackages(JarFile jf) { return jf.stream() - .filter(e -> !e.isDirectory() && isResource(e.getName())) + .filter(e -> !e.isDirectory()) .map(e -> toPackageName(e)) .filter(pkg -> pkg.length() > 0) .collect(Collectors.toSet()); } /** - * Returns true if it's a .class or a resource with an effective - * package name. + * Maps the given relative file path to a package name. + * @throws UncheckedIOException for a class file in a top-level directory */ - boolean isResource(String name) { - name = name.replace(File.separatorChar, '/'); - return name.endsWith(".class") || Resources.canEncapsulate(name); - } - - - String toPackageName(Path path) { - String name = path.toString(); - int index = name.lastIndexOf(File.separatorChar); - if (index != -1) - return name.substring(0, index).replace(File.separatorChar, '.'); - - if (name.endsWith(".class") && !name.equals(MODULE_INFO)) { - IOException e = new IOException(name + " in the unnamed package"); - throw new UncheckedIOException(e); + private String toPackageName(Path path) { + assert path.getRoot() == null; + + Path parent = path.getParent(); + if (parent != null) { + String sep = path.getFileSystem().getSeparator(); + String pn = parent.toString().replace(sep, "."); + return Checks.isPackageName(pn) ? pn : ""; + } else { + // file in top-level directory + ensureNotClassFile(path.toString()); + return ""; } - return ""; } - String toPackageName(ZipEntry entry) { + /** + * Maps the name of a JAR file entry to a package name. + * @throws UncheckedIOException for a class file in a top-level directory + */ + private String toPackageName(ZipEntry entry) { String name = entry.getName(); + assert !name.endsWith("/"); + int index = name.lastIndexOf("/"); - if (index != -1) - return name.substring(0, index).replace('/', '.'); + if (index != -1) { + String pn = name.substring(0, index).replace('/', '.'); + return Checks.isPackageName(pn) ? pn : ""; + } else { + // entry in top-level directory + ensureNotClassFile(name); + return ""; + } + } + /** + * Throws IOException for a .class file that is not module-info.class. + */ + private void ensureNotClassFile(String name) { if (name.endsWith(".class") && !name.equals(MODULE_INFO)) { IOException e = new IOException(name + " in the unnamed package"); throw new UncheckedIOException(e); } - return ""; } void processClasses(JmodOutputStream out, List classpaths) diff --git a/test/jdk/tools/jlink/ClassFileInMetaInfo.java b/test/jdk/tools/jlink/ClassFileInMetaInfo.java new file mode 100644 index 0000000000000..028da2cbe5042 --- /dev/null +++ b/test/jdk/tools/jlink/ClassFileInMetaInfo.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8353267 + * @summary Test jlink with a module containing a class file in its META-INF directory + * @library /test/lib + * @modules java.base/jdk.internal.module + * jdk.jlink + * jdk.jartool + * @run junit ClassFileInMetaInfo + */ + +import java.lang.module.ModuleDescriptor; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.spi.ToolProvider; + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.ModuleInfoWriter; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeAll; +import static org.junit.jupiter.api.Assertions.*; + +class ClassFileInMetaInfo { + private static PrintStream out; + private static String moduleName; + private static String classesDir; + + @BeforeAll + static void setup() throws Exception { + out = System.err; // inline with Junit + + // Create module foo containing + // module-info.class + // p/C.class + // META-INF/extra/q/C.class + moduleName = "foo"; + ModuleDescriptor descriptor = ModuleDescriptor.newModule(moduleName).build(); + byte[] moduleInfo = ModuleInfoWriter.toBytes(descriptor); + Path dir = Files.createTempDirectory(Path.of("."), moduleName); + Files.write(dir.resolve("module-info.class"), moduleInfo); + Files.createFile(Files.createDirectory(dir.resolve("p")).resolve("C.class")); + Path extraClasses = dir.resolve("META-INF/extra/"); + Files.createFile(Files.createDirectories(extraClasses.resolve("q")).resolve("C.class")); + classesDir = dir.toString(); + } + + @Test + void testExplodedModule() throws Exception { + test(classesDir); + } + + @Test + void testModularJar() throws Exception { + String jarFile = "foo.jar"; + ToolProvider jarTool = ToolProvider.findFirst("jar").orElseThrow(); + int res = jarTool.run(out, out, "cf", jarFile, "-C", classesDir, "."); + assertEquals(0, res); + test(jarFile); + } + + @Test + void testJmod() throws Exception { + String jmodFile = "foo.jmod"; + ToolProvider jmodTool = ToolProvider.findFirst("jmod").orElseThrow(); + int res = jmodTool.run(out, out, "create", "--class-path", classesDir, jmodFile); + assertEquals(0, res); + test(jmodFile); + } + + /** + * jlink --module-path .. --add-modules foo --ouptut image + * image/bin/java --describe-module foo + */ + private void test(String modulePath) throws Exception { + Path dir = Files.createTempDirectory(Path.of("."), "image"); + Files.delete(dir); + String image = dir.toString(); + + ToolProvider jlinkTool = ToolProvider.findFirst("jlink").orElseThrow(); + int res = jlinkTool.run(out, out, + "--module-path", modulePath, + "--add-modules", moduleName, + "--output", image); + assertEquals(0, res); + + var pb = new ProcessBuilder(image + "/bin/java", "--describe-module", moduleName); + ProcessTools.executeProcess(pb) + .outputTo(out) + .errorTo(out) + .shouldHaveExitValue(0) + .shouldContain(moduleName) + .shouldContain("contains p") + .shouldNotContain("META-INF"); + } +} \ No newline at end of file diff --git a/test/jdk/tools/jmod/JmodTest.java b/test/jdk/tools/jmod/JmodTest.java index d75b31cef23c8..9cf81e6dcafae 100644 --- a/test/jdk/tools/jmod/JmodTest.java +++ b/test/jdk/tools/jmod/JmodTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,12 @@ /* * @test - * @bug 8142968 8166568 8166286 8170618 8168149 8240910 8276764 8276766 + * @bug 8142968 8166568 8166286 8170618 8168149 8240910 8276764 8276766 8353267 * @summary Basic test for jmod * @library /test/lib * @modules jdk.compiler * jdk.jlink + * java.base/jdk.internal.module * @build jdk.test.lib.compiler.CompilerUtils * jdk.test.lib.util.FileUtils * jdk.test.lib.Platform @@ -45,6 +46,7 @@ import java.util.stream.Stream; import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.util.FileUtils; +import jdk.test.lib.util.ModuleInfoWriter; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; @@ -682,7 +684,43 @@ public void testPackagesAttribute() throws IOException { Set pkgs = getModuleDescriptor(jmod).packages(); assertEquals(pkgs, expectedPackages); }); - } + } + + /** + * Test class files is the META-INF directory. + */ + @Test + public void testClassInMetaInf() throws IOException { + Path jmod = MODS_DIR.resolve("baz.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + + ModuleDescriptor descriptor = ModuleDescriptor.newModule("baz").build(); + byte[] moduleInfo = ModuleInfoWriter.toBytes(descriptor); + + Path dir = Files.createTempDirectory(Path.of("."), "baz"); + Files.write(dir.resolve("module-info.class"), moduleInfo); + Files.createFile(Files.createDirectory(dir.resolve("p")).resolve("C.class")); + + // META-INF/extra/q/C.class + Path extraClasses = dir.resolve("META-INF/extra/"); + Files.createFile(Files.createDirectories(extraClasses.resolve("q")).resolve("C.class")); + + Set expectedPackages = Set.of("p"); + Set expectedContent = Set.of( + CLASSES_PREFIX + "module-info.class", + CLASSES_PREFIX + "p/C.class", + CLASSES_PREFIX + "META-INF/extra/q/C.class"); + + jmod("create", + "--class-path", dir.toString(), + jmod.toString()) + .assertSuccess() + .resultChecker(r -> { + Set pkgs = getModuleDescriptor(jmod).packages(); + assertEquals(pkgs, expectedPackages); + assertJmodContent(jmod, expectedContent); + }); + } @Test public void testVersion() { From 9844c1c52b9b7b6959d4e5cc626495c83f4aa9d4 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 8 Apr 2025 06:07:44 +0000 Subject: [PATCH 0446/1101] 8066583: DeflaterInput/OutputStream and InflaterInput/OutputStream should explain responsibility for freeing resources Reviewed-by: liach, alanb, lancea --- .../java/util/zip/DeflaterInputStream.java | 39 ++++++- .../java/util/zip/DeflaterOutputStream.java | 57 ++++++++-- .../java/util/zip/InflaterInputStream.java | 41 ++++++- .../java/util/zip/InflaterOutputStream.java | 35 +++++- .../java/util/zip/DeflateIn_InflateOut.java | 84 +++++++++++++- .../java/util/zip/InflateIn_DeflateOut.java | 104 ++++++++++++++++++ 6 files changed, 344 insertions(+), 16 deletions(-) diff --git a/src/java.base/share/classes/java/util/zip/DeflaterInputStream.java b/src/java.base/share/classes/java/util/zip/DeflaterInputStream.java index cb3f534cd5e6d..593649805983c 100644 --- a/src/java.base/share/classes/java/util/zip/DeflaterInputStream.java +++ b/src/java.base/share/classes/java/util/zip/DeflaterInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,20 @@ * Implements an input stream filter for compressing data in the "deflate" * compression format. * + *

Compressor Usage

+ * A {@code DeflaterInputStream} created without + * specifying a {@linkplain Deflater compressor} will create a compressor + * at construction time, and close the compressor when the input stream + * is {@linkplain #close closed}. + *

+ * If a compressor is specified when creating a {@code DeflaterInputStream}, it is the + * responsibility of the caller to {@linkplain Deflater#close close} the + * compressor after closing the input stream. + * + * @apiNote + * The {@link #close} method should be called to release resources used by this + * stream, either directly, or with the {@code try}-with-resources statement. + * * @since 1.6 * @author David R Tribble (david@tribble.com) * @@ -68,8 +82,11 @@ private void ensureOpen() throws IOException { } /** - * Creates a new input stream with a default compressor and buffer - * size. + * Creates a new input stream and compressor with the + * default compression level and a default buffer size. + *

+ * The compressor will be closed when this input stream + * is {@linkplain #close() closed}. * * @param in input stream to read the uncompressed data to * @throws NullPointerException if {@code in} is null @@ -82,6 +99,10 @@ public DeflaterInputStream(InputStream in) { /** * Creates a new input stream with the specified compressor and a * default buffer size. + *

+ * {@linkplain #close() Closing} this input stream + * {@linkplain ##compressor-usage will not close} the given + * {@linkplain Deflater compressor}. * * @param in input stream to read the uncompressed data to * @param defl compressor ("deflater") for this stream @@ -94,6 +115,10 @@ public DeflaterInputStream(InputStream in, Deflater defl) { /** * Creates a new input stream with the specified compressor and buffer * size. + *

+ * {@linkplain #close() Closing} this input stream + * {@linkplain ##compressor-usage will not close} the given + * {@linkplain Deflater compressor}. * * @param in input stream to read the uncompressed data to * @param defl compressor ("deflater") for this stream @@ -123,6 +148,7 @@ public DeflaterInputStream(InputStream in, Deflater defl, int bufLen) { * * @throws IOException if an I/O error occurs */ + @Override public void close() throws IOException { if (in != null) { try { @@ -147,6 +173,7 @@ public void close() throws IOException { * @throws IOException if an I/O error occurs or if this stream is * already closed */ + @Override public int read() throws IOException { // Read a single byte of compressed data int len = read(rbuf, 0, 1); @@ -169,6 +196,7 @@ public int read() throws IOException { * @throws IOException if an I/O error occurs or if this input stream is * already closed */ + @Override public int read(byte[] b, int off, int len) throws IOException { // Sanity checks ensureOpen(); @@ -224,6 +252,7 @@ public int read(byte[] b, int off, int len) throws IOException { * already closed * @throws IllegalArgumentException if {@code n < 0} */ + @Override public long skip(long n) throws IOException { if (n < 0) { throw new IllegalArgumentException("negative skip length"); @@ -259,6 +288,7 @@ public long skip(long n) throws IOException { * @throws IOException if an I/O error occurs or if this stream is * already closed */ + @Override public int available() throws IOException { ensureOpen(); if (reachEOF) { @@ -273,6 +303,7 @@ public int available() throws IOException { * * @return false, always */ + @Override public boolean markSupported() { return false; } @@ -282,6 +313,7 @@ public boolean markSupported() { * * @param limit maximum bytes that can be read before invalidating the position marker */ + @Override public void mark(int limit) { // Operation not supported } @@ -291,6 +323,7 @@ public void mark(int limit) { * * @throws IOException always thrown */ + @Override public void reset() throws IOException { throw new IOException("mark/reset not supported"); } diff --git a/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java b/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java index 66630d5adf0d0..3fca6a1b75981 100644 --- a/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,20 @@ * or method in this class will cause a {@link NullPointerException} to be * thrown. * + *

Compressor Usage

+ * A {@code DeflaterOutputStream} created without + * specifying a {@linkplain Deflater compressor} will create a compressor + * at construction time, and close the compressor when the output stream + * is {@linkplain #close closed}. + *

+ * If a compressor is specified when creating a {@code DeflaterOutputStream}, it is the + * responsibility of the caller to {@linkplain Deflater#close close} the + * compressor after closing the output stream. + * + * @apiNote + * The {@link #close} method should be called to release resources used by this + * stream, either directly, or with the {@code try}-with-resources statement. + * * @see Deflater * @author David Connelly * @since 1.1 @@ -63,6 +77,10 @@ public class DeflaterOutputStream extends FilterOutputStream { /** * Creates a new output stream with the specified compressor, * buffer size and flush mode. + *

+ * {@linkplain #close() Closing} this output stream + * {@linkplain ##compressor-usage will not close} the given + * {@linkplain Deflater compressor}. * * @param out the output stream * @param def the compressor ("deflater") @@ -98,7 +116,11 @@ public DeflaterOutputStream(OutputStream out, * buffer size. * *

The new output stream instance is created as if by invoking - * the 4-argument constructor DeflaterOutputStream(out, def, size, false). + * the 4-argument constructor {@code DeflaterOutputStream(out, def, size, false)}. + *

+ * {@linkplain #close() Closing} this output stream + * {@linkplain ##compressor-usage will not close} the given + * {@linkplain Deflater compressor}. * * @param out the output stream * @param def the compressor ("deflater") @@ -112,6 +134,10 @@ public DeflaterOutputStream(OutputStream out, Deflater def, int size) { /** * Creates a new output stream with the specified compressor, flush * mode and a default buffer size. + *

+ * {@linkplain #close() Closing} this output stream + * {@linkplain ##compressor-usage will not close} the given + * {@linkplain Deflater compressor}. * * @param out the output stream * @param def the compressor ("deflater") @@ -135,7 +161,11 @@ public DeflaterOutputStream(OutputStream out, * a default buffer size. * *

The new output stream instance is created as if by invoking - * the 3-argument constructor DeflaterOutputStream(out, def, false). + * the 3-argument constructor {@code DeflaterOutputStream(out, def, false)}. + *

+ * {@linkplain #close() Closing} this output stream + * {@linkplain ##compressor-usage will not close} the given + * {@linkplain Deflater compressor}. * * @param out the output stream * @param def the compressor ("deflater") @@ -148,8 +178,12 @@ public DeflaterOutputStream(OutputStream out, Deflater def) { /** - * Creates a new output stream with a default compressor, a default - * buffer size and the specified flush mode. + * Creates a new output stream and compressor with the + * default compression level, a default buffer size and + * the specified flush mode. + *

+ * The compressor will be closed when this output stream + * is {@linkplain #close() closed}. * * @param out the output stream * @param syncFlush @@ -166,10 +200,14 @@ public DeflaterOutputStream(OutputStream out, boolean syncFlush) { } /** - * Creates a new output stream with a default compressor and buffer size. + * Creates a new output stream and compressor with the + * default compression level and a default buffer size. * *

The new output stream instance is created as if by invoking - * the 2-argument constructor DeflaterOutputStream(out, false). + * the 2-argument constructor {@code DeflaterOutputStream(out, false)}. + *

+ * The compressor will be closed when this output stream + * is {@linkplain #close() closed}. * * @param out the output stream */ @@ -184,6 +222,7 @@ public DeflaterOutputStream(OutputStream out) { * @param b the byte to be written * @throws IOException if an I/O error has occurred */ + @Override public void write(int b) throws IOException { byte[] buf = new byte[1]; buf[0] = (byte)(b & 0xff); @@ -198,6 +237,7 @@ public void write(int b) throws IOException { * @param len the length of the data * @throws IOException if an I/O error has occurred */ + @Override public void write(byte[] b, int off, int len) throws IOException { if (def.finished()) { throw new IOException("write beyond end of stream"); @@ -239,8 +279,10 @@ public void finish() throws IOException { /** * Writes remaining compressed data to the output stream and closes the * underlying stream. + * * @throws IOException if an I/O error has occurred */ + @Override public void close() throws IOException { if (!closed) { closed = true; @@ -296,6 +338,7 @@ protected void deflate() throws IOException { * * @since 1.7 */ + @Override public void flush() throws IOException { if (syncFlush && !def.finished()) { int len = 0; diff --git a/src/java.base/share/classes/java/util/zip/InflaterInputStream.java b/src/java.base/share/classes/java/util/zip/InflaterInputStream.java index f13b5915a84db..81dcf8246e05e 100644 --- a/src/java.base/share/classes/java/util/zip/InflaterInputStream.java +++ b/src/java.base/share/classes/java/util/zip/InflaterInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,21 @@ *

Unless otherwise noted, passing a {@code null} argument to a constructor * or method in this class will cause a {@link NullPointerException} to be * thrown. + * + *

Decompressor Usage

+ * An {@code InflaterInputStream} created without + * specifying a {@linkplain Inflater decompressor} will create a decompressor + * at construction time, and close the decompressor when the input stream + * is {@linkplain #close closed}. + *

+ * If a decompressor is specified when creating a {@code InflaterInputStream}, it is the + * responsibility of the caller to {@linkplain Inflater#close close} the + * decompressor after closing the input stream. + * + * @apiNote + * The {@link #close} method should be called to release resources used by this + * stream, either directly, or with the {@code try}-with-resources statement. + * * @see Inflater * @author David Connelly * @since 1.1 @@ -75,6 +90,11 @@ private void ensureOpen() throws IOException { /** * Creates a new input stream with the specified decompressor and * buffer size. + *

+ * {@linkplain #close() Closing} this input stream + * {@linkplain ##decompressor-usage will not close} the given + * {@linkplain Inflater decompressor}. + * * @param in the input stream * @param inf the decompressor ("inflater") * @param size the input buffer size @@ -94,6 +114,11 @@ public InflaterInputStream(InputStream in, Inflater inf, int size) { /** * Creates a new input stream with the specified decompressor and a * default buffer size. + *

+ * {@linkplain #close() Closing} this input stream + * {@linkplain ##decompressor-usage will not close} the given + * {@linkplain Inflater decompressor}. + * * @param in the input stream * @param inf the decompressor ("inflater") */ @@ -104,7 +129,12 @@ public InflaterInputStream(InputStream in, Inflater inf) { boolean usesDefaultInflater = false; /** - * Creates a new input stream with a default decompressor and buffer size. + * Creates a new input stream and decompressor with a + * default buffer size. + *

+ * The decompressor will be closed when this input stream + * is {@linkplain #close() closed}. + * * @param in the input stream */ public InflaterInputStream(InputStream in) { @@ -120,6 +150,7 @@ public InflaterInputStream(InputStream in) { * @return the byte read, or -1 if end of compressed input is reached * @throws IOException if an I/O error has occurred */ + @Override public int read() throws IOException { ensureOpen(); return read(singleByteBuf, 0, 1) == -1 ? -1 : Byte.toUnsignedInt(singleByteBuf[0]); @@ -151,6 +182,7 @@ public int read() throws IOException { * @throws ZipException if a ZIP format error has occurred * @throws IOException if an I/O error has occurred */ + @Override public int read(byte[] b, int off, int len) throws IOException { ensureOpen(); if (b == null) { @@ -193,6 +225,7 @@ public int read(byte[] b, int off, int len) throws IOException { * @throws IOException if an I/O error occurs. * */ + @Override public int available() throws IOException { ensureOpen(); if (reachEOF) { @@ -220,6 +253,7 @@ public int available() throws IOException { * already closed * @throws IllegalArgumentException if {@code n < 0} */ + @Override public long skip(long n) throws IOException { if (n < 0) { throw new IllegalArgumentException("negative skip length"); @@ -246,8 +280,10 @@ public long skip(long n) throws IOException { /** * Closes this input stream and releases any system resources associated * with the stream. + * * @throws IOException if an I/O error has occurred */ + @Override public void close() throws IOException { if (!closed) { if (usesDefaultInflater) @@ -287,6 +323,7 @@ protected void fill() throws IOException { * @see java.io.InputStream#mark(int) * @see java.io.InputStream#reset() */ + @Override public boolean markSupported() { return false; } diff --git a/src/java.base/share/classes/java/util/zip/InflaterOutputStream.java b/src/java.base/share/classes/java/util/zip/InflaterOutputStream.java index 7b08d5b45385c..31c51509a767b 100644 --- a/src/java.base/share/classes/java/util/zip/InflaterOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/InflaterOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,20 @@ * Implements an output stream filter for uncompressing data stored in the * "deflate" compression format. * + *

Decompressor Usage

+ * An {@code InflaterOutputStream} created without + * specifying a {@linkplain Inflater decompressor} will create a decompressor + * at construction time, and close the decompressor when the output stream + * is {@linkplain #close closed}. + *

+ * If a decompressor is specified when creating a {@code InflaterOutputStream}, it is the + * responsibility of the caller to {@linkplain Inflater#close close} the + * decompressor after closing the output stream. + * + * @apiNote + * The {@link #close} method should be called to release resources used by this + * stream, either directly, or with the {@code try}-with-resources statement. + * * @since 1.6 * @author David R Tribble (david@tribble.com) * @@ -68,8 +82,11 @@ private void ensureOpen() throws IOException { } /** - * Creates a new output stream with a default decompressor and buffer - * size. + * Creates a new output stream and decompressor with a + * default buffer size. + *

+ * The decompressor will be closed when this output stream + * is {@linkplain #close() closed}. * * @param out output stream to write the uncompressed data to * @throws NullPointerException if {@code out} is null @@ -82,6 +99,10 @@ public InflaterOutputStream(OutputStream out) { /** * Creates a new output stream with the specified decompressor and a * default buffer size. + *

+ * {@linkplain #close() Closing} this output stream + * {@linkplain ##decompressor-usage will not close} the given + * {@linkplain Inflater decompressor}. * * @param out output stream to write the uncompressed data to * @param infl decompressor ("inflater") for this stream @@ -94,6 +115,10 @@ public InflaterOutputStream(OutputStream out, Inflater infl) { /** * Creates a new output stream with the specified decompressor and * buffer size. + *

+ * {@linkplain #close() Closing} this output stream + * {@linkplain ##decompressor-usage will not close} the given + * {@linkplain Inflater decompressor}. * * @param out output stream to write the uncompressed data to * @param infl decompressor ("inflater") for this stream @@ -123,6 +148,7 @@ public InflaterOutputStream(OutputStream out, Inflater infl, int bufLen) { * * @throws IOException if an I/O error occurs */ + @Override public void close() throws IOException { if (!closed) { // Complete the uncompressed output @@ -142,6 +168,7 @@ public void close() throws IOException { * @throws IOException if an I/O error occurs or this stream is already * closed */ + @Override public void flush() throws IOException { ensureOpen(); @@ -199,6 +226,7 @@ public void finish() throws IOException { * closed * @throws ZipException if a compression (ZIP) format error occurs */ + @Override public void write(int b) throws IOException { // Write a single byte of data wbuf[0] = (byte) b; @@ -219,6 +247,7 @@ public void write(int b) throws IOException { * @throws NullPointerException if {@code b} is null * @throws ZipException if a compression (ZIP) format error occurs */ + @Override public void write(byte[] b, int off, int len) throws IOException { // Sanity checks ensureOpen(); diff --git a/test/jdk/java/util/zip/DeflateIn_InflateOut.java b/test/jdk/java/util/zip/DeflateIn_InflateOut.java index 68ad0eaa036d0..d0b23e6b8110b 100644 --- a/test/jdk/java/util/zip/DeflateIn_InflateOut.java +++ b/test/jdk/java/util/zip/DeflateIn_InflateOut.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ */ import java.io.*; +import java.nio.charset.StandardCharsets; import java.util.*; import java.util.zip.*; @@ -270,6 +271,83 @@ private static void NeedsDictionary() throws Throwable { check(Arrays.equals(data, baos.toByteArray())); } + /** + * Verifies that when a DeflaterInputStream is constructed + * by passing a Deflater instance, then closing the DeflaterInputStream + * will not close the passed Deflater instance. + */ + private static void deflaterInputStreamDeflaterNotClosed() throws Throwable { + // some arbitrary content + final byte[] original = "foo".repeat(1024).getBytes(StandardCharsets.US_ASCII); + // run the DeflaterInputStream tests + try (final Deflater def = new Deflater()) { + try (ByteArrayInputStream bis = new ByteArrayInputStream(original); + DeflaterInputStream iis = new DeflaterInputStream(bis, def)) { + iis.readAllBytes(); + } + // verify the deflater wasn't closed - reset() will throw IllegalStateException if + // the deflater is closed + def.reset(); + + // repeat the test with the other constructor + try (ByteArrayInputStream bis = new ByteArrayInputStream(original); + DeflaterInputStream iis = new DeflaterInputStream(bis, def, 1024)) { + iis.readAllBytes(); + } + // verify the deflater wasn't closed - reset() will throw IllegalStateException if + // the deflater is closed + def.reset(); + } + } + + private static byte[] deflate(final byte[] original) { + final ByteArrayOutputStream compressedBaos = new ByteArrayOutputStream(); + try (Deflater compressor = new Deflater()) { + compressor.setInput(original); + compressor.finish(); + while (!compressor.finished()) { + byte[] tmpBuffer = new byte[1024]; + int numCompressed = compressor.deflate(tmpBuffer); + compressedBaos.write(tmpBuffer, 0, numCompressed); + } + } + return compressedBaos.toByteArray(); + } + + /** + * Verifies that when a InflaterOutputStream is constructed + * by passing a Inflater instance, then closing the InflaterOutputStream + * will not close the passed Inflater instance. + */ + private static void inflaterOutputStreamInflaterNotClosed() throws Throwable { + // some arbitrary content + final byte[] original = "bar".repeat(1024).getBytes(StandardCharsets.US_ASCII); + // deflate it + final byte[] deflated = deflate(original); + try (final Inflater infl = new Inflater()) { + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + InflaterOutputStream dos = new InflaterOutputStream(bos, infl)) { + dos.write(deflated); + dos.flush(); + check(Arrays.equals(original, bos.toByteArray())); + } + // verify the inflater wasn't closed - reset() will throw IllegalStateException if + // the inflater is closed + infl.reset(); + + // repeat the test with the other constructor + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + InflaterOutputStream dos = new InflaterOutputStream(bos, infl, 1024)) { + dos.write(deflated); + dos.flush(); + check(Arrays.equals(original, bos.toByteArray())); + } + // verify the inflater wasn't closed - reset() will throw IllegalStateException if + // the inflater is closed + infl.reset(); + } + } + public static void realMain(String[] args) throws Throwable { new Random(new Date().getTime()).nextBytes(data); @@ -284,6 +362,10 @@ public static void realMain(String[] args) throws Throwable { SkipBytes(); NeedsDictionary(); + + deflaterInputStreamDeflaterNotClosed(); + + inflaterOutputStreamInflaterNotClosed(); } //--------------------- Infrastructure --------------------------- diff --git a/test/jdk/java/util/zip/InflateIn_DeflateOut.java b/test/jdk/java/util/zip/InflateIn_DeflateOut.java index e9c9c59e24e09..31cdf73aaaec3 100644 --- a/test/jdk/java/util/zip/InflateIn_DeflateOut.java +++ b/test/jdk/java/util/zip/InflateIn_DeflateOut.java @@ -1,5 +1,6 @@ /* * Copyright 2009 Google, Inc. All Rights Reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +31,7 @@ */ import java.io.*; +import java.nio.charset.StandardCharsets; import java.util.*; import java.util.zip.*; @@ -293,6 +295,106 @@ private static void GZLineOrientedProtocol() throws Throwable { checkLOP(gis, gos); } + private static byte[] deflate(final byte[] original) { + final ByteArrayOutputStream compressedBaos = new ByteArrayOutputStream(); + try (Deflater compressor = new Deflater()) { + compressor.setInput(original); + compressor.finish(); + while (!compressor.finished()) { + byte[] tmpBuffer = new byte[1024]; + int numCompressed = compressor.deflate(tmpBuffer); + compressedBaos.write(tmpBuffer, 0, numCompressed); + } + } + return compressedBaos.toByteArray(); + } + + /** + * Verifies that when a InflaterInputStream is constructed + * by passing a Inflater instance, then closing the InflaterInputStream + * will not close the passed Inflater instance. + */ + private static void inflaterInputStreamInflaterNotClosed() throws Throwable { + // some arbitrary content + final byte[] original = "foo".repeat(1024).getBytes(StandardCharsets.US_ASCII); + // deflate it + final byte[] deflated = deflate(original); + // run the InflaterInputStream tests + try (final Inflater infl = new Inflater()) { + try (ByteArrayInputStream bis = new ByteArrayInputStream(deflated); + InflaterInputStream iis = new InflaterInputStream(bis, infl)) { + final byte[] inflated = iis.readAllBytes(); + check(Arrays.equals(original, inflated)); + } + // verify the inflater wasn't closed - reset() will throw IllegalStateException if + // the inflater is closed + infl.reset(); + + // repeat the test with the other constructor + try (ByteArrayInputStream bis = new ByteArrayInputStream(deflated); + InflaterInputStream iis = new InflaterInputStream(bis, infl, 1024)) { + final byte[] inflated = iis.readAllBytes(); + check(Arrays.equals(original, inflated)); + } + // verify the inflater wasn't closed - reset() will throw IllegalStateException if + // the inflater is closed + infl.reset(); + } + } + + /** + * Verifies that when a DeflaterOutputStream is constructed + * by passing a Deflater instance, then closing the DeflaterOutputStream + * will not close the passed Deflater instance. + */ + private static void deflaterOutputStreamDeflaterNotClosed() throws Throwable { + // some arbitrary content + final byte[] data = "bar".repeat(1024).getBytes(StandardCharsets.US_ASCII); + // run the InflaterInputStream tests + try (final Deflater def = new Deflater()) { + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DeflaterOutputStream dos = new DeflaterOutputStream(bos, def)) { + dos.write(data); + } + // verify the deflater wasn't closed - reset() will throw IllegalStateException if + // the deflater is closed + def.reset(); + + // repeat the test with the other constructor + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DeflaterOutputStream dos = new DeflaterOutputStream(bos, def, 1024)) { + dos.write(data); + } + // verify the deflater wasn't closed - reset() will throw IllegalStateException if + // the deflater is closed + def.reset(); + + // repeat the test with the other constructor + for (boolean syncFlush : new boolean[] {false, true}) { + System.out.println("testing with syncFlush = " + syncFlush); + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DeflaterOutputStream dos = new DeflaterOutputStream(bos, def, syncFlush)) { + dos.write(data); + } + // verify the deflater wasn't closed - reset() will throw IllegalStateException if + // the deflater is closed + def.reset(); + } + + // repeat the test with the other constructor + for (boolean syncFlush : new boolean[] {false, true}) { + System.out.println("testing with syncFlush = " + syncFlush); + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DeflaterOutputStream dos = new DeflaterOutputStream(bos, def, 1024, syncFlush)) { + dos.write(data); + } + // verify the deflater wasn't closed - reset() will throw IllegalStateException if + // the deflater is closed + def.reset(); + } + } + } + public static void realMain(String[] args) throws Throwable { WriteCloseRead(); WriteFlushRead(); @@ -300,6 +402,8 @@ public static void realMain(String[] args) throws Throwable { GZWriteFlushRead(); GZLineOrientedProtocol(); TestFlushableGZIPOutputStream(); + inflaterInputStreamInflaterNotClosed(); + deflaterOutputStreamDeflaterNotClosed(); } //--------------------- Infrastructure --------------------------- From ea07e719ca255d0da1966118c464ee23f4dc44da Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 8 Apr 2025 08:12:59 +0000 Subject: [PATCH 0447/1101] 8352256: ObjectSynchronizer::quick_notify misses JFR event notification path Reviewed-by: dholmes, coleenp, mgronlun --- src/hotspot/share/runtime/objectMonitor.cpp | 12 ++++++++++++ src/hotspot/share/runtime/objectMonitor.hpp | 2 ++ src/hotspot/share/runtime/synchronizer.cpp | 10 +++------- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index e280de6baf1df..03228d0cb1252 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -2058,6 +2058,12 @@ void ObjectMonitor::notify(TRAPS) { return; } + quick_notify(current); +} + +void ObjectMonitor::quick_notify(JavaThread* current) { + assert(has_owner(current), "Precondition"); + EventJavaMonitorNotify event; DTRACE_MONITOR_PROBE(notify, this, object(), current); int tally = notify_internal(current) ? 1 : 0; @@ -2080,6 +2086,12 @@ void ObjectMonitor::notifyAll(TRAPS) { return; } + quick_notifyAll(current); +} + +void ObjectMonitor::quick_notifyAll(JavaThread* current) { + assert(has_owner(current), "Precondition"); + EventJavaMonitorNotify event; DTRACE_MONITOR_PROBE(notifyAll, this, object(), current); int tally = 0; diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index d24201fafe4d1..729316811c29c 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -385,6 +385,8 @@ class ObjectMonitor : public CHeapObj { void wait(jlong millis, bool interruptible, TRAPS); void notify(TRAPS); void notifyAll(TRAPS); + void quick_notify(JavaThread* current); + void quick_notifyAll(JavaThread* current); void print() const; #ifdef ASSERT diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index 73dd9d5330ea1..d608ffbdc02f2 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -368,16 +368,12 @@ bool ObjectSynchronizer::quick_notify(oopDesc* obj, JavaThread* current, bool al if (mon->first_waiter() != nullptr) { // We have one or more waiters. Since this is an inflated monitor - // that we own, we can transfer one or more threads from the waitset - // to the entry_list here and now, avoiding the slow-path. + // that we own, we quickly notify them here and now, avoiding the slow-path. if (all) { - DTRACE_MONITOR_PROBE(notifyAll, mon, obj, current); + mon->quick_notifyAll(current); } else { - DTRACE_MONITOR_PROBE(notify, mon, obj, current); + mon->quick_notify(current); } - do { - mon->notify_internal(current); - } while (mon->first_waiter() != nullptr && all); } return true; } From fda5eecd6717eb6e1db56be3e41b65deae6e683e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Tue, 8 Apr 2025 08:27:00 +0000 Subject: [PATCH 0448/1101] 8353669: IGV: dump OOP maps for MachSafePoint nodes Reviewed-by: chagedorn, thartmann --- src/hotspot/share/opto/idealGraphPrinter.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp index f6ec1a72506ab..47cc66c4cf005 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.cpp +++ b/src/hotspot/share/opto/idealGraphPrinter.cpp @@ -667,6 +667,15 @@ void IdealGraphPrinter::visit_node(Node* n, bool edges) { print_prop("lrg", lrg_id); } + if (node->is_MachSafePoint()) { + const OopMap* oopmap = node->as_MachSafePoint()->oop_map(); + if (oopmap != nullptr) { + stringStream oopmap_stream; + oopmap->print_on(&oopmap_stream); + print_prop("oopmap", oopmap_stream.freeze()); + } + } + Compile::current()->_in_dump_cnt--; tail(PROPERTIES_ELEMENT); From 9088afc4f16b6265e640bf176d8ca8e3ac6ca45c Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Tue, 8 Apr 2025 09:25:23 +0000 Subject: [PATCH 0449/1101] 8353332: Test jdk/jshell/ToolProviderTest.java failed in relation to enable-preview Reviewed-by: jpai, asotona --- .../jshell/tool/JShellToolProvider.java | 18 +++++--- .../jdk/jshell/ToolProviderTest.java | 46 +++++++++++++++---- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellToolProvider.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellToolProvider.java index f858eb6a40637..ebc02ecd93cc4 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellToolProvider.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellToolProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.Set; +import java.util.function.Function; import javax.lang.model.SourceVersion; import javax.tools.Tool; import jdk.jshell.tool.JavaShellToolBuilder; @@ -40,6 +41,10 @@ */ public class JShellToolProvider implements Tool { + //for tests, so that they can tweak the builder (typically set persistence): + private static Function augmentToolBuilder = + builder -> builder; + /** * Returns the name of this Java shell tool provider. * @@ -86,11 +91,12 @@ public int run(InputStream in, OutputStream out, OutputStream err, String... arg ? (PrintStream) err : new PrintStream(err); try { - return JavaShellToolBuilder - .builder() - .in(xin, null) - .out(xout) - .err(xerr) + return augmentToolBuilder.apply( + JavaShellToolBuilder + .builder() + .in(xin, null) + .out(xout) + .err(xerr)) .start(arguments); } catch (Throwable ex) { xerr.println(ex.getMessage()); diff --git a/test/langtools/jdk/jshell/ToolProviderTest.java b/test/langtools/jdk/jshell/ToolProviderTest.java index ada5f34d8c053..67038c878ab63 100644 --- a/test/langtools/jdk/jshell/ToolProviderTest.java +++ b/test/langtools/jdk/jshell/ToolProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,20 +21,25 @@ * questions. */ +import java.lang.reflect.Field; +import java.util.HashMap; import java.util.ServiceLoader; import java.util.function.Consumer; +import java.util.function.Function; import javax.tools.Tool; +import jdk.internal.jshell.tool.JShellToolProvider; +import jdk.jshell.tool.JavaShellToolBuilder; import org.testng.annotations.Test; import static org.testng.Assert.assertTrue; /* * @test - * @bug 8170044 8171343 8179856 8185840 8190383 + * @bug 8170044 8171343 8179856 8185840 8190383 8353332 * @summary Test ServiceLoader launching of jshell tool * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main * jdk.jdeps/com.sun.tools.javap - * jdk.jshell/jdk.internal.jshell.tool + * jdk.jshell/jdk.internal.jshell.tool:+open * @library /tools/lib * @build Compiler toolbox.ToolBox * @run testng ToolProviderTest @@ -68,13 +73,20 @@ protected void startCheckUserOutput(Consumer checkUserOutput, String... @Override protected int runShell(String... args) { - ServiceLoader sl = ServiceLoader.load(Tool.class); - for (Tool provider : sl) { - if (provider.name().equals("jshell")) { - return provider.run(cmdInStream, cmdout, cmderr, args); + //make sure the JShell running during the test is not using persisted preferences from the machine: + Function prevAugmentedToolBuilder = + getAndSetAugmentedToolBuilder(builder -> builder.persistence(new HashMap<>())); + try { + ServiceLoader sl = ServiceLoader.load(Tool.class); + for (Tool provider : sl) { + if (provider.name().equals("jshell")) { + return provider.run(cmdInStream, cmdout, cmderr, args); + } } + throw new AssertionError("Repl tool not found by ServiceLoader: " + sl); + } finally { + getAndSetAugmentedToolBuilder(prevAugmentedToolBuilder); } - throw new AssertionError("Repl tool not found by ServiceLoader: " + sl); } // Test --show-version @@ -87,4 +99,22 @@ public void testShowVersion() { }, "--show-version"); } + + private Function getAndSetAugmentedToolBuilder + (Function augmentToolBuilder) { + try { + Field f = JShellToolProvider.class.getDeclaredField("augmentToolBuilder"); + + f.setAccessible(true); + + Function prev = + (Function) f.get(null); + + f.set(null, augmentToolBuilder); + + return prev; + } catch (ReflectiveOperationException ex) { + throw new IllegalStateException(ex); + } + } } From d8bed1304713b17286d4ed614f95d0ef6e59a95b Mon Sep 17 00:00:00 2001 From: Koushik Thirupattur Date: Tue, 8 Apr 2025 11:50:59 +0000 Subject: [PATCH 0450/1101] 8353945: Test javax/security/auth/x500/X500Principal/NameFormat.java fails after JDK-8349890 Reviewed-by: mullan --- .../auth/x500/X500Principal/NameFormat.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/jdk/javax/security/auth/x500/X500Principal/NameFormat.java b/test/jdk/javax/security/auth/x500/X500Principal/NameFormat.java index 2503b36f30c94..3f0422ff9336e 100644 --- a/test/jdk/javax/security/auth/x500/X500Principal/NameFormat.java +++ b/test/jdk/javax/security/auth/x500/X500Principal/NameFormat.java @@ -118,22 +118,23 @@ public static void main(String[] args) throws Exception { testName("CN=Before\\0dAfter,DC=example,DC=net", "toString", "CN=Before\\0DAfter, DC=example, DC=net", 22); testName("CN=Before\\0dAfter,DC=example,DC=net", "RFC1779", - "CN=Before\\0DAfter, " + + "CN=Before\r" + "After, " + "OID.0.9.2342.19200300.100.1.25=example, " + "OID.0.9.2342.19200300.100.1.25=net", 23); + testName("CN=Before\\0dAfter,DC=example,DC=net", "RFC2253", - "CN=Before\\0DAfter,DC=example,DC=net", 24); + "CN=Before\r" + "After,DC=example,DC=net", 24); testName("CN=Before\\0dAfter,DC=example,DC=net", "CANONICAL", - "cn=before\\0dafter,dc=#16076578616d706c65,dc=#16036e6574", 25); + "cn=before\r" + "after,dc=#16076578616d706c65,dc=#16036e6574", 25); testName("CN=Lu\\C4\\8Di\\C4\\87", "toString", "CN=Lu\\C4\\8Di\\C4\\87", 26); testName("CN=Lu\\C4\\8Di\\C4\\87", "RFC1779", - "CN=Lu\\C4\\8Di\\C4\\87", 27); + "CN=Lu\u010di\u0107", 27); testName("CN=Lu\\C4\\8Di\\C4\\87", "RFC2253", - "CN=Lu\\C4\\8Di\\C4\\87", 28); + "CN=Lu\u010di\u0107", 28); testName("CN=Lu\\C4\\8Di\\C4\\87", "CANONICAL", - "cn=lu\\c4\\8di\\c4\\87", 29); + "cn=luc\u030cic\u0301", 29); try { p = new X500Principal("cn=\\gg"); From 3d24f1a38280fd7f40148399c1ae2f3bd20763e5 Mon Sep 17 00:00:00 2001 From: Harald Eilertsen Date: Tue, 8 Apr 2025 12:40:10 +0000 Subject: [PATCH 0451/1101] 8353580: libjpeg is not found if not installed in system directories Reviewed-by: erikj --- make/autoconf/lib-bundled.m4 | 24 +++++++++++++++++------- make/autoconf/spec.gmk.template | 1 + 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/make/autoconf/lib-bundled.m4 b/make/autoconf/lib-bundled.m4 index 091f01cadb5d7..2b0d4f2f23fc3 100644 --- a/make/autoconf/lib-bundled.m4 +++ b/make/autoconf/lib-bundled.m4 @@ -62,19 +62,29 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBJPEG], if test "x${with_libjpeg}" = "xbundled"; then USE_EXTERNAL_LIBJPEG=false + LIBJPEG_CFLAGS="" + LIBJPEG_LIBS="" elif test "x${with_libjpeg}" = "xsystem"; then - AC_CHECK_HEADER(jpeglib.h, [], - [ AC_MSG_ERROR([--with-libjpeg=system specified, but jpeglib.h not found!])]) - AC_CHECK_LIB(jpeg, jpeg_CreateDecompress, [], - [ AC_MSG_ERROR([--with-libjpeg=system specified, but no libjpeg found])]) - - USE_EXTERNAL_LIBJPEG=true - LIBJPEG_LIBS="-ljpeg" + PKG_CHECK_MODULES(LIBJPEG, libjpeg, [LIBJPEG_FOUND=yes], [LIBJPEG_FOUND=no]) + if test "x${LIBJPEG_FOUND}" = "xyes"; then + # PKG_CHECK_MODULES will set LIBJPEG_CFLAGS and LIBJPEG_LIBS + USE_EXTERNAL_LIBJPEG=true + else + AC_CHECK_HEADER(jpeglib.h, [], + [ AC_MSG_ERROR([--with-libjpeg=system specified, but jpeglib.h not found!])]) + AC_CHECK_LIB(jpeg, jpeg_CreateDecompress, [], + [ AC_MSG_ERROR([--with-libjpeg=system specified, but no libjpeg found])]) + + USE_EXTERNAL_LIBJPEG=true + LIBJPEG_CFLAGS="" + LIBJPEG_LIBS="-ljpeg" + fi else AC_MSG_ERROR([Invalid use of --with-libjpeg: ${with_libjpeg}, use 'system' or 'bundled']) fi AC_SUBST(USE_EXTERNAL_LIBJPEG) + AC_SUBST(LIBJPEG_CFLAGS) AC_SUBST(LIBJPEG_LIBS) ]) diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template index 80c6dfc2ba223..d433ead98a78d 100644 --- a/make/autoconf/spec.gmk.template +++ b/make/autoconf/spec.gmk.template @@ -800,6 +800,7 @@ TAR_SUPPORTS_TRANSFORM := @TAR_SUPPORTS_TRANSFORM@ # Build setup USE_EXTERNAL_LIBJPEG := @USE_EXTERNAL_LIBJPEG@ +LIBJPEG_CFLAGS := @LIBJPEG_CFLAGS@ LIBJPEG_LIBS := @LIBJPEG_LIBS@ USE_EXTERNAL_LIBGIF := @USE_EXTERNAL_LIBGIF@ GIFLIB_LIBS := @GIFLIB_LIBS@ From b3751b90f6f5406fb78f0f9a01f0337a64021dfc Mon Sep 17 00:00:00 2001 From: Harald Eilertsen Date: Tue, 8 Apr 2025 12:40:54 +0000 Subject: [PATCH 0452/1101] 8353573: System giflib not found by configure if it's not in system directories Reviewed-by: erikj --- make/autoconf/lib-bundled.m4 | 42 +++++++++++++++++++++++++++++---- make/autoconf/spec.gmk.template | 1 + 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/make/autoconf/lib-bundled.m4 b/make/autoconf/lib-bundled.m4 index 2b0d4f2f23fc3..3246697663cef 100644 --- a/make/autoconf/lib-bundled.m4 +++ b/make/autoconf/lib-bundled.m4 @@ -95,6 +95,10 @@ AC_DEFUN_ONCE([LIB_SETUP_GIFLIB], [ AC_ARG_WITH(giflib, [AS_HELP_STRING([--with-giflib], [use giflib from build system or OpenJDK source (system, bundled) @<:@bundled@:>@])]) + AC_ARG_WITH(giflib-include, [AS_HELP_STRING([--with-giflib-include], + [specify directory for the system giflib include files])]) + AC_ARG_WITH(giflib-lib, [AS_HELP_STRING([--with-giflib-lib], + [specify directory for the system giflib library])]) AC_MSG_CHECKING([for which giflib to use]) # default is bundled @@ -107,11 +111,40 @@ AC_DEFUN_ONCE([LIB_SETUP_GIFLIB], if test "x${with_giflib}" = "xbundled"; then USE_EXTERNAL_LIBGIF=false + GIFLIB_CFLAGS="" + GIFLIB_LIBS="" elif test "x${with_giflib}" = "xsystem"; then - AC_CHECK_HEADER(gif_lib.h, [], - [ AC_MSG_ERROR([--with-giflib=system specified, but gif_lib.h not found!])]) - AC_CHECK_LIB(gif, DGifGetCode, [], - [ AC_MSG_ERROR([--with-giflib=system specified, but no giflib found!])]) + GIFLIB_H_FOUND=no + if test "x${with_giflib_include}" != x; then + GIFLIB_CFLAGS="-I${with_giflib_include}" + GIFLIB_H_FOUND=yes + fi + if test "x$GIFLIB_H_FOUND" = xno; then + AC_CHECK_HEADER(gif_lib.h, + [ + GIFLIB_CFLAGS="" + GIFLIB_H_FOUND=yes + ]) + fi + if test "x$GIFLIB_H_FOUND" = xno; then + AC_MSG_ERROR([--with-giflib=system specified, but gif_lib.h not found!]) + fi + + GIFLIB_LIB_FOUND=no + if test "x${with_giflib_lib}" != x; then + GIFLIB_LIBS="-L${with_giflib_lib} -lgif" + GIFLIB_LIB_FOUND=yes + fi + if test "x$GIFLIB_LIB_FOUND" = xno; then + AC_CHECK_LIB(gif, DGifGetCode, + [ + GIFLIB_LIBS="-lgif" + GIFLIB_LIB_FOUND=yes + ]) + fi + if test "x$GIFLIB_LIB_FOUND" = xno; then + AC_MSG_ERROR([--with-giflib=system specified, but no giflib found!]) + fi USE_EXTERNAL_LIBGIF=true GIFLIB_LIBS=-lgif @@ -120,6 +153,7 @@ AC_DEFUN_ONCE([LIB_SETUP_GIFLIB], fi AC_SUBST(USE_EXTERNAL_LIBGIF) + AC_SUBST(GIFLIB_CFLAGS) AC_SUBST(GIFLIB_LIBS) ]) diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template index d433ead98a78d..17a913a2d90e1 100644 --- a/make/autoconf/spec.gmk.template +++ b/make/autoconf/spec.gmk.template @@ -803,6 +803,7 @@ USE_EXTERNAL_LIBJPEG := @USE_EXTERNAL_LIBJPEG@ LIBJPEG_CFLAGS := @LIBJPEG_CFLAGS@ LIBJPEG_LIBS := @LIBJPEG_LIBS@ USE_EXTERNAL_LIBGIF := @USE_EXTERNAL_LIBGIF@ +GIFLIB_CFLAGS := @GIFLIB_CFLAGS@ GIFLIB_LIBS := @GIFLIB_LIBS@ USE_EXTERNAL_LIBZ := @USE_EXTERNAL_LIBZ@ LIBZ_CFLAGS := @LIBZ_CFLAGS@ From 21db0fdbfb019b9a7c6613e190ad457278f29582 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 8 Apr 2025 12:59:36 +0000 Subject: [PATCH 0453/1101] 8353665: RISC-V: IR verification fails in TestSubNodeFloatDoubleNegation.java Reviewed-by: thartmann, luhenry --- .../floatingpoint/TestSubNodeFloatDoubleNegation.java | 4 +++- .../jtreg/compiler/lib/ir_framework/TestFramework.java | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/compiler/floatingpoint/TestSubNodeFloatDoubleNegation.java b/test/hotspot/jtreg/compiler/floatingpoint/TestSubNodeFloatDoubleNegation.java index 66292e37b1c64..e6695081841c9 100644 --- a/test/hotspot/jtreg/compiler/floatingpoint/TestSubNodeFloatDoubleNegation.java +++ b/test/hotspot/jtreg/compiler/floatingpoint/TestSubNodeFloatDoubleNegation.java @@ -55,7 +55,9 @@ public static void assertResults() { @Test // Match a generic SubNode, because scalar Float16 operations are often // performed as float operations. - @IR(counts = { IRNode.SUB, "2" }) + @IR(counts = { IRNode.SUB, "2" }, applyIfPlatform = {"riscv64", "false"}) + @IR(counts = { IRNode.SUB, "2" }, applyIfCPUFeature = {"zfh", "false"}) + @IR(counts = { IRNode.SUB_HF, "2" }, applyIfCPUFeature = {"zfh", "true"}) // Checks that the subtractions in 0 - (0 - hf) do not get eliminiated public static Float16 testHalfFloat(Float16 hf) { return Float16.subtract( diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java index 79c99352a3255..8f70ad9b7d0c0 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java @@ -139,11 +139,14 @@ public class TestFramework { "UseAVX", "UseSSE", "UseSVE", - "UseZbb", - "UseRVV", "Xlog", "LogCompilation", - "UseCompactObjectHeaders" + "UseCompactObjectHeaders", + // Riscv + "UseRVV", + "UseZbb", + "UseZfh", + "UseZvbb" ) ); From cc5e9388d8c55178fd32eabce0f24d5ab8e76fdd Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 8 Apr 2025 13:00:07 +0000 Subject: [PATCH 0454/1101] 8353600: RISC-V: compiler/vectorization/TestRotateByteAndShortVector.java is failing with Zvbb Reviewed-by: fyang, luhenry --- src/hotspot/cpu/riscv/riscv_v.ad | 25 ++------- .../TestRotateByteAndShortVector.java | 51 ++++++++++--------- 2 files changed, 30 insertions(+), 46 deletions(-) diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index cd9d2107b7988..1e99b2ece2914 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -80,8 +80,12 @@ source %{ case Op_PopCountVI: case Op_ReverseBytesV: case Op_ReverseV: + return UseZvbb; case Op_RotateLeftV: case Op_RotateRightV: + if (bt != T_INT && bt != T_LONG) { + return false; + } return UseZvbb; case Op_LoadVectorGather: case Op_LoadVectorGatherMasked: @@ -3413,27 +3417,6 @@ instruct vshiftcnt(vReg dst, iRegIorL2I cnt) %{ %} // --------------------------------- Vector Rotation ---------------------------------- -// -// Following rotate instruct's are shared by vectorization (in SLP, superword.cpp) and Vector API. -// -// Rotate behaviour in vectorization is defined by java API, which includes: -// 1. Integer.rorateRight, Integer.rorateLeft. -// `rotation by any multiple of 32 is a no-op, so all but the last five bits of the rotation distance can be ignored`. -// 2. Long.rorateRight, Long.rorateLeft. -// `rotation by any multiple of 64 is a no-op, so all but the last six bits of the rotation distance can be ignored`. -// -// Rotate behaviour in Vector API is defined as below, e.g. -// 1. For Byte ROR, `a ROR b` is: (byte)(((((byte)a) & 0xFF) >>> (b & 7)) | ((((byte)a) & 0xFF) << (8 - (b & 7)))) -// 2. For Short ROR, `a ROR b` is: (short)(((((short)a) & 0xFFFF) >>> (b & 15)) | ((((short)a) & 0xFFFF) << (16 - (b & 15)))) -// 3. For Integer ROR, `a ROR b` is: Integer.rotateRight(a, ((int)b)) -// 4. For Long ROR, `a ROR b` is: Long.rotateRight(a, ((int)b)) -// -// Basically, the behaviour between vectorization and Vector API is the same for Long and Integer, except that Vector API -// also supports Byte and Short rotation. But we can still share the intrinsics between vectorization and Vector API. -// -// NOTE: As vror.vi encodes 6-bits immediate rotate amount, which is different from other vector-immediate instructions, -// implementation of vector rotation for long and other types can be unified. - // Rotate right instruct vrotate_right(vReg dst, vReg src, vReg shift) %{ diff --git a/test/hotspot/jtreg/compiler/vectorization/TestRotateByteAndShortVector.java b/test/hotspot/jtreg/compiler/vectorization/TestRotateByteAndShortVector.java index 08e69485d56e4..e130fc0ba6c16 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestRotateByteAndShortVector.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestRotateByteAndShortVector.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2022, Loongson Technology Co. Ltd. All rights reserved. + * Copyright (c) 2022, 2025 Loongson Technology Co. Ltd. All rights reserved. + * Copyright (c) 2025, Rivos Inc. 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,15 +24,16 @@ /** * @test - * @bug 8286847 + * @bug 8286847 8353600 * @key randomness * @summary Test vectorization of rotate byte and short - * @library /test/lib - * @run main/othervm -XX:-TieredCompilation -XX:CompileCommand=compileonly,TestRotateByteAndShortVector::testRotate* -Xbatch TestRotateByteAndShortVector + * @library /test/lib / + * @run main/othervm TestRotateByteAndShortVector */ import java.util.Random; import jdk.test.lib.Utils; +import compiler.lib.ir_framework.*; public class TestRotateByteAndShortVector { private static final Random random = Utils.getRandomInstance(); @@ -49,27 +51,7 @@ public class TestRotateByteAndShortVector { private static short resShort = 0; public static void main(String[] args) { - System.out.println("warmup"); - warmup(); - - System.out.println("Testing..."); - runRotateLeftByteTest(); - runRotateRightByteTest(); - runRotateLeftShortTest(); - runRotateRightShortTest(); - - System.out.println("PASSED"); - } - - static void warmup() { - random.nextBytes(arrByte); - randomShorts(); - for (int i = 0; i < ITERS; i++) { - testRotateLeftByte(rolByte, arrByte, i); - testRotateRightByte(rorByte, arrByte, i); - testRotateLeftShort(rolShort, arrShort, i); - testRotateRightShort(rorShort, arrShort, i); - } + TestFramework.run(); } static void randomShorts() { @@ -78,6 +60,7 @@ static void randomShorts() { } } + @Run(test = { "testRotateLeftByte" }) static void runRotateLeftByteTest() { for (int shift = 0; shift < 64; shift++) { random.nextBytes(arrByte); @@ -91,6 +74,7 @@ static void runRotateLeftByteTest() { } } + @Run(test = { "testRotateRightByte" }) static void runRotateRightByteTest() { for (int shift = 0; shift < 64; shift++) { random.nextBytes(arrByte); @@ -104,6 +88,7 @@ static void runRotateRightByteTest() { } } + @Run(test = { "testRotateLeftShort" }) static void runRotateLeftShortTest() { for (int shift = 0; shift < 64; shift++) { randomShorts(); @@ -117,6 +102,7 @@ static void runRotateLeftShortTest() { } } + @Run(test = { "testRotateRightShort" }) static void runRotateRightShortTest() { for (int shift = 0; shift < 64; shift++) { randomShorts(); @@ -130,24 +116,39 @@ static void runRotateRightShortTest() { } } + // NOTE: currently, there is no platform supporting RotateLeftV/RotateRightV intrinsic. + // If there is some implementation, it could probably in a wrong way which is different + // from what java language spec expects. + @Test + @IR(failOn = { IRNode.ROTATE_LEFT_V }) + @IR(failOn = { IRNode.ROTATE_RIGHT_V }) static void testRotateLeftByte(byte[] test, byte[] arr, int shift) { for (int i = 0; i < ARRLEN; i++) { test[i] = (byte) ((arr[i] << shift) | (arr[i] >>> -shift)); } } + @Test + @IR(failOn = { IRNode.ROTATE_LEFT_V }) + @IR(failOn = { IRNode.ROTATE_RIGHT_V }) static void testRotateRightByte(byte[] test, byte[] arr, int shift) { for (int i = 0; i < ARRLEN; i++) { test[i] = (byte) ((arr[i] >>> shift) | (arr[i] << -shift)); } } + @Test + @IR(failOn = { IRNode.ROTATE_LEFT_V }) + @IR(failOn = { IRNode.ROTATE_RIGHT_V }) static void testRotateLeftShort(short[] test, short[] arr, int shift) { for (int i = 0; i < ARRLEN; i++) { test[i] = (short) ((arr[i] << shift) | (arr[i] >>> -shift)); } } + @Test + @IR(failOn = { IRNode.ROTATE_LEFT_V }) + @IR(failOn = { IRNode.ROTATE_RIGHT_V }) static void testRotateRightShort(short[] test, short[] arr, int shift) { for (int i = 0; i < ARRLEN; i++) { test[i] = (short) ((arr[i] >>> shift) | (arr[i] << -shift)); From dfa79c373097d17a347b7c17103c57e12f59dc67 Mon Sep 17 00:00:00 2001 From: Artur Barashev Date: Tue, 8 Apr 2025 13:02:50 +0000 Subject: [PATCH 0455/1101] 8340321: Disable SHA-1 in TLS/DTLS 1.2 handshake signatures Reviewed-by: mullan --- .../sun/security/ssl/SignatureScheme.java | 5 +- .../share/conf/security/java.security | 3 +- ...DisableSHA1inHandshakeSignatureDTLS12.java | 54 ++++++++ .../DisableSHA1inHandshakeSignatureTLS12.java | 120 ++++++++++++++++++ .../DisableSHA1inHandshakeSignatureTLS13.java | 70 ++++++++++ 5 files changed, 249 insertions(+), 3 deletions(-) create mode 100644 test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureDTLS12.java create mode 100644 test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureTLS12.java create mode 100644 test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureTLS13.java diff --git a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java index 00b6b0593f507..b817cc3fb9d5b 100644 --- a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java +++ b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java @@ -132,8 +132,9 @@ enum SignatureScheme { "DSA", ProtocolVersion.PROTOCOLS_TO_12), ECDSA_SHA1 (0x0203, "ecdsa_sha1", "SHA1withECDSA", - "EC", - ProtocolVersion.PROTOCOLS_TO_13), + "EC", null, null, -1, + ProtocolVersion.PROTOCOLS_TO_13, + ProtocolVersion.PROTOCOLS_TO_12), RSA_PKCS1_SHA1 (0x0201, "rsa_pkcs1_sha1", "SHA1withRSA", "RSA", null, null, 511, ProtocolVersion.PROTOCOLS_TO_13, diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 82a57dfed6f76..b115d47983848 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -768,7 +768,8 @@ http.auth.digest.disabledAlgorithms = MD5, SHA-1 # rsa_pkcs1_sha1, secp224r1, TLS_RSA_* jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \ MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \ - ECDH, TLS_RSA_* + ECDH, TLS_RSA_*, rsa_pkcs1_sha1 usage HandshakeSignature, \ + ecdsa_sha1 usage HandshakeSignature, dsa_sha1 usage HandshakeSignature # # Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS) diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureDTLS12.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureDTLS12.java new file mode 100644 index 0000000000000..6c597cd257635 --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureDTLS12.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8340321 + * @summary Disable SHA-1 in TLS/DTLS 1.2 signatures. + * This test only covers DTLS 1.2. + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm DisableSHA1inHandshakeSignatureDTLS12 + */ + +public class DisableSHA1inHandshakeSignatureDTLS12 extends + DisableSHA1inHandshakeSignatureTLS12 { + + protected DisableSHA1inHandshakeSignatureDTLS12() throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + new DisableSHA1inHandshakeSignatureDTLS12().run(); + } + + @Override + protected String getProtocol() { + return "DTLSv1.2"; + } + + // No CertificateRequest in DTLS server flight. + @Override + protected void checkCertificateRequest() { + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureTLS12.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureTLS12.java new file mode 100644 index 0000000000000..0389740b7fe3a --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureTLS12.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8340321 + * @summary Disable SHA-1 in TLS/DTLS 1.2 signatures. + * This test only covers TLS 1.2. + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm DisableSHA1inHandshakeSignatureTLS12 + */ + +import static jdk.test.lib.Asserts.assertFalse; +import static jdk.test.lib.Asserts.assertTrue; + +import java.util.List; + +public class DisableSHA1inHandshakeSignatureTLS12 extends + AbstractCheckSignatureSchemes { + + protected DisableSHA1inHandshakeSignatureTLS12() throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + new DisableSHA1inHandshakeSignatureTLS12().run(); + } + + @Override + protected String getProtocol() { + return "TLSv1.2"; + } + + // Run things in TLS handshake order. + protected void run() throws Exception { + + // Produce client_hello + clientEngine.wrap(clientOut, cTOs); + cTOs.flip(); + + checkClientHello(); + + // Consume client_hello. + serverEngine.unwrap(cTOs, serverIn); + runDelegatedTasks(serverEngine); + + // Produce server_hello. + serverEngine.wrap(serverOut, sTOc); + sTOc.flip(); + + checkCertificateRequest(); + } + + // Returns SHA-1 signature schemes supported for TLSv1.2 handshake + protected List getDisabledSignatureSchemes() { + return List.of( + "ecdsa_sha1", + "rsa_pkcs1_sha1", + "dsa_sha1" + ); + } + + protected void checkClientHello() throws Exception { + // Get signature_algorithms extension signature schemes. + List sigAlgsSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_EXT); + + // Should not be present in signature_algorithms extension. + getDisabledSignatureSchemes().forEach(ss -> + assertFalse(sigAlgsSS.contains(ss), + "Signature Scheme " + ss + + " present in ClientHello's signature_algorithms extension")); + + // Get signature_algorithms_cert extension signature schemes. + List sigAlgsCertSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_CERT_EXT); + + // Should be present in signature_algorithms_cert extension. + getDisabledSignatureSchemes().forEach(ss -> + assertTrue(sigAlgsCertSS.contains(ss), + "Signature Scheme " + ss + + " isn't present in ClientHello's" + + " signature_algorithms extension")); + } + + protected void checkCertificateRequest() throws Exception { + // Get CertificateRequest message signature schemes. + List sigAlgsCertSS = getSigSchemesCertReq( + extractHandshakeMsg(sTOc, TLS_HS_CERT_REQ)); + + // Should not be present in CertificateRequest message. + getDisabledSignatureSchemes().forEach(ss -> + assertFalse(sigAlgsCertSS.contains(ss), + "Signature Scheme " + ss + + " present in CertificateRequest")); + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureTLS13.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureTLS13.java new file mode 100644 index 0000000000000..55f619460d4b9 --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableSHA1inHandshakeSignatureTLS13.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8340321 + * @summary Disable SHA-1 in TLS/DTLS 1.2 signatures. + * This test only covers TLS 1.3. + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm DisableSHA1inHandshakeSignatureTLS13 + */ + +import java.security.Security; +import java.util.List; + +public class DisableSHA1inHandshakeSignatureTLS13 extends + DisableSHA1inHandshakeSignatureTLS12 { + + protected DisableSHA1inHandshakeSignatureTLS13() throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + // SHA-1 algorithm MUST NOT be used in any TLSv1.3 handshake signatures. + // This is regardless of jdk.tls.disabledAlgorithms configuration. + Security.setProperty("jdk.tls.disabledAlgorithms", ""); + new DisableSHA1inHandshakeSignatureTLS13().run(); + } + + @Override + protected String getProtocol() { + return "TLSv1.3"; + } + + // Returns SHA-1 signature schemes NOT supported for TLSv1.3 handshake + // signatures, but supported for TLSv1.3 certificate signatures. + @Override + protected List getDisabledSignatureSchemes() { + return List.of("ecdsa_sha1", "rsa_pkcs1_sha1"); + } + + // TLSv1.3 sends CertificateRequest signature schemes in + // signature_algorithms and signature_algorithms_cert extensions. Same as + // ClientHello, but they are encrypted. So we skip CertificateRequest + // signature schemes verification for TLSv1.3. + @Override + protected void checkCertificateRequest() { + } +} From d9f2e6921558b4919889d81871b699971fb4f3ba Mon Sep 17 00:00:00 2001 From: Damon Fenacci Date: Tue, 8 Apr 2025 13:05:15 +0000 Subject: [PATCH 0456/1101] 8352963: [REDO] Missing late inline cleanup causes compiler/vectorapi/VectorLogicalOpIdentityTest.java IR failure Reviewed-by: vlivanov, thartmann --- src/hotspot/share/opto/callGenerator.cpp | 6 +- src/hotspot/share/opto/callnode.cpp | 119 +++++++++++------- src/hotspot/share/opto/callnode.hpp | 1 + src/hotspot/share/opto/compile.cpp | 11 ++ test/hotspot/jtreg/ProblemList.txt | 1 - .../VectorGatherMaskFoldingTest.java | 11 +- .../VectorLogicalOpIdentityTest.java | 5 +- 7 files changed, 98 insertions(+), 56 deletions(-) diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index ec7117e3568ca..e0ad2f00ab579 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -470,7 +470,7 @@ class LateInlineVirtualCallGenerator : public VirtualCallGenerator { virtual void do_late_inline(); virtual void set_callee_method(ciMethod* m) { - assert(_callee == nullptr, "repeated inlining attempt"); + assert(_callee == nullptr || _callee == m, "repeated inline attempt with different callee"); _callee = m; } @@ -987,8 +987,8 @@ CallGenerator* CallGenerator::for_method_handle_call(JVMState* jvms, ciMethod* c Compile* C = Compile::current(); bool should_delay = C->should_delay_inlining(); if (cg != nullptr) { - if (should_delay) { - return CallGenerator::for_late_inline(callee, cg); + if (should_delay && IncrementalInlineMH) { + return CallGenerator::for_mh_late_inline(caller, callee, input_not_const); } else { return cg; } diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index 68efabea15cf7..bb30dcb2976a7 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -1091,6 +1091,15 @@ void CallJavaNode::dump_compact_spec(outputStream* st) const { } #endif +void CallJavaNode::register_for_late_inline() { + if (generator() != nullptr) { + Compile::current()->prepend_late_inline(generator()); + set_generator(nullptr); + } else { + assert(false, "repeated inline attempt"); + } +} + //============================================================================= uint CallStaticJavaNode::size_of() const { return sizeof(*this); } bool CallStaticJavaNode::cmp( const Node &n ) const { @@ -1101,26 +1110,35 @@ bool CallStaticJavaNode::cmp( const Node &n ) const { Node* CallStaticJavaNode::Ideal(PhaseGVN* phase, bool can_reshape) { CallGenerator* cg = generator(); if (can_reshape && cg != nullptr) { - assert(IncrementalInlineMH, "required"); - assert(cg->call_node() == this, "mismatch"); - assert(cg->is_mh_late_inline(), "not virtual"); - - // Check whether this MH handle call becomes a candidate for inlining. - ciMethod* callee = cg->method(); - vmIntrinsics::ID iid = callee->intrinsic_id(); - if (iid == vmIntrinsics::_invokeBasic) { - if (in(TypeFunc::Parms)->Opcode() == Op_ConP) { - phase->C->prepend_late_inline(cg); - set_generator(nullptr); + if (cg->is_mh_late_inline()) { + assert(IncrementalInlineMH, "required"); + assert(cg->call_node() == this, "mismatch"); + assert(cg->method()->is_method_handle_intrinsic(), "required"); + + // Check whether this MH handle call becomes a candidate for inlining. + ciMethod* callee = cg->method(); + vmIntrinsics::ID iid = callee->intrinsic_id(); + if (iid == vmIntrinsics::_invokeBasic) { + if (in(TypeFunc::Parms)->Opcode() == Op_ConP) { + register_for_late_inline(); + } + } else if (iid == vmIntrinsics::_linkToNative) { + // never retry + } else { + assert(callee->has_member_arg(), "wrong type of call?"); + if (in(TypeFunc::Parms + callee->arg_size() - 1)->Opcode() == Op_ConP) { + register_for_late_inline(); + phase->C->inc_number_of_mh_late_inlines(); + } } - } else if (iid == vmIntrinsics::_linkToNative) { - // never retry } else { - assert(callee->has_member_arg(), "wrong type of call?"); - if (in(TypeFunc::Parms + callee->arg_size() - 1)->Opcode() == Op_ConP) { - phase->C->prepend_late_inline(cg); - set_generator(nullptr); + assert(IncrementalInline, "required"); + assert(!cg->method()->is_method_handle_intrinsic(), "required"); + if (phase->C->print_inlining()) { + phase->C->inline_printer()->record(cg->method(), cg->call_node()->jvms(), InliningResult::FAILURE, + "static call node changed: trying again"); } + register_for_late_inline(); } } return CallNode::Ideal(phase, can_reshape); @@ -1189,39 +1207,46 @@ bool CallDynamicJavaNode::cmp( const Node &n ) const { Node* CallDynamicJavaNode::Ideal(PhaseGVN* phase, bool can_reshape) { CallGenerator* cg = generator(); if (can_reshape && cg != nullptr) { - assert(IncrementalInlineVirtual, "required"); - assert(cg->call_node() == this, "mismatch"); - assert(cg->is_virtual_late_inline(), "not virtual"); - - // Recover symbolic info for method resolution. - ciMethod* caller = jvms()->method(); - ciBytecodeStream iter(caller); - iter.force_bci(jvms()->bci()); - - bool not_used1; - ciSignature* not_used2; - ciMethod* orig_callee = iter.get_method(not_used1, ¬_used2); // callee in the bytecode - ciKlass* holder = iter.get_declared_method_holder(); - if (orig_callee->is_method_handle_intrinsic()) { - assert(_override_symbolic_info, "required"); - orig_callee = method(); - holder = method()->holder(); - } + if (cg->is_virtual_late_inline()) { + assert(IncrementalInlineVirtual, "required"); + assert(cg->call_node() == this, "mismatch"); + + // Recover symbolic info for method resolution. + ciMethod* caller = jvms()->method(); + ciBytecodeStream iter(caller); + iter.force_bci(jvms()->bci()); + + bool not_used1; + ciSignature* not_used2; + ciMethod* orig_callee = iter.get_method(not_used1, ¬_used2); // callee in the bytecode + ciKlass* holder = iter.get_declared_method_holder(); + if (orig_callee->is_method_handle_intrinsic()) { + assert(_override_symbolic_info, "required"); + orig_callee = method(); + holder = method()->holder(); + } - ciInstanceKlass* klass = ciEnv::get_instance_klass_for_declared_method_holder(holder); + ciInstanceKlass* klass = ciEnv::get_instance_klass_for_declared_method_holder(holder); - Node* receiver_node = in(TypeFunc::Parms); - const TypeOopPtr* receiver_type = phase->type(receiver_node)->isa_oopptr(); + Node* receiver_node = in(TypeFunc::Parms); + const TypeOopPtr* receiver_type = phase->type(receiver_node)->isa_oopptr(); - int not_used3; - bool call_does_dispatch; - ciMethod* callee = phase->C->optimize_virtual_call(caller, klass, holder, orig_callee, receiver_type, true /*is_virtual*/, - call_does_dispatch, not_used3); // out-parameters - if (!call_does_dispatch) { - // Register for late inlining. - cg->set_callee_method(callee); - phase->C->prepend_late_inline(cg); // MH late inlining prepends to the list, so do the same - set_generator(nullptr); + int not_used3; + bool call_does_dispatch; + ciMethod* callee = phase->C->optimize_virtual_call(caller, klass, holder, orig_callee, receiver_type, true /*is_virtual*/, + call_does_dispatch, not_used3); // out-parameters + if (!call_does_dispatch) { + // Register for late inlining. + cg->set_callee_method(callee); + register_for_late_inline(); // MH late inlining prepends to the list, so do the same + } + } else { + assert(IncrementalInline, "required"); + if (phase->C->print_inlining()) { + phase->C->inline_printer()->record(cg->method(), cg->call_node()->jvms(), InliningResult::FAILURE, + "dynamic call node changed: trying again"); + } + register_for_late_inline(); } } return CallNode::Ideal(phase, can_reshape); diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index fc03ab5163bb1..db857d4c6d1a6 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -790,6 +790,7 @@ class CallJavaNode : public CallNode { void set_arg_escape(bool f) { _arg_escape = f; } bool arg_escape() const { return _arg_escape; } void copy_call_debug_info(PhaseIterGVN* phase, SafePointNode *sfpt); + void register_for_late_inline(); DEBUG_ONLY( bool validate_symbolic_info() const; ) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 56f57793fbb1e..8a059d0852f7f 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -2085,6 +2085,7 @@ bool Compile::inline_incrementally_one() { for (int i = 0; i < _late_inlines.length(); i++) { _late_inlines_pos = i+1; CallGenerator* cg = _late_inlines.at(i); + bool is_scheduled_for_igvn_before = C->igvn_worklist()->member(cg->call_node()); bool does_dispatch = cg->is_virtual_late_inline() || cg->is_mh_late_inline(); if (inlining_incrementally() || does_dispatch) { // a call can be either inlined or strength-reduced to a direct call cg->do_late_inline(); @@ -2095,6 +2096,16 @@ bool Compile::inline_incrementally_one() { _late_inlines_pos = i+1; // restore the position in case new elements were inserted print_method(PHASE_INCREMENTAL_INLINE_STEP, 3, cg->call_node()); break; // process one call site at a time + } else { + bool is_scheduled_for_igvn_after = C->igvn_worklist()->member(cg->call_node()); + if (!is_scheduled_for_igvn_before && is_scheduled_for_igvn_after) { + // Avoid potential infinite loop if node already in the IGVN list + assert(false, "scheduled for IGVN during inlining attempt"); + } else { + // Ensure call node has not disappeared from IGVN worklist during a failed inlining attempt + assert(!is_scheduled_for_igvn_before || is_scheduled_for_igvn_after, "call node removed from IGVN list during inlining pass"); + cg->call_node()->set_generator(cg); + } } } else { // Ignore late inline direct calls when inlining is not allowed. diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 6dd35997caca3..d76f4b2d95b66 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -56,7 +56,6 @@ compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all compiler/vectorapi/reshape/TestVectorReinterpret.java 8320897,8348519 aix-ppc64,linux-ppc64le,linux-s390x -compiler/vectorapi/VectorLogicalOpIdentityTest.java 8302459 linux-x64,windows-x64 compiler/vectorapi/VectorRebracket128Test.java 8330538 generic-all compiler/jvmci/TestUncaughtErrorInCompileMethod.java 8309073 generic-all diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorGatherMaskFoldingTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorGatherMaskFoldingTest.java index 88175baf8e4a6..7e16c5e5e8645 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorGatherMaskFoldingTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorGatherMaskFoldingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ /** * @test - * @bug 8325520 + * @bug 8325520 8302459 * @library /test/lib / * @summary Don't allow folding of Load/Store vectors when using incompatible indices or masks * @modules jdk.incubator.vector @@ -1398,7 +1398,12 @@ public static void testFloatVectorLoadMaskedStoreVector() { public static void main(String[] args) { TestFramework testFramework = new TestFramework(); testFramework.setDefaultWarmup(10000) - .addFlags("--add-modules=jdk.incubator.vector", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+IncrementalInlineForceCleanup") + .addFlags("--add-modules=jdk.incubator.vector") .start(); + testFramework = new TestFramework(); + testFramework.setDefaultWarmup(10000) + .addFlags("--add-modules=jdk.incubator.vector", "-XX:-TieredCompilation") + .start(); + } } diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java index 426dec6701933..1a2402222ed84 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2022, 2023, Arm Limited. All rights reserved. - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ /** * @test - * @bug 8288294 + * @bug 8288294 8302459 * @key randomness * @library /test/lib / * @summary Add identity transformations for vector logic operations @@ -761,5 +761,6 @@ public static void testMaskXorSame() { public static void main(String[] args) { TestFramework.runWithFlags("--add-modules=jdk.incubator.vector"); + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-XX:-TieredCompilation"); } } From 250437e557c56ba66a74ab759cfd1071a510e184 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Tue, 8 Apr 2025 13:12:28 +0000 Subject: [PATCH 0457/1101] 8351654: Agent transformer bytecodes should be verified Reviewed-by: dholmes, lmesnik --- .../share/classfile/classFileParser.cpp | 3 +- .../share/classfile/classFileStream.cpp | 9 +- .../share/classfile/classFileStream.hpp | 11 +- src/hotspot/share/classfile/klassFactory.cpp | 8 +- .../PatchModuleJavaBaseVerify.java | 63 +++++++ .../runtime/verifier/CFLH/TestChecker.java | 41 +++++ .../runtime/verifier/CFLH/TestVerify.java | 174 ++++++++++++++++++ 7 files changed, 300 insertions(+), 9 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleJavaBaseVerify.java create mode 100644 test/hotspot/jtreg/runtime/verifier/CFLH/TestChecker.java create mode 100644 test/hotspot/jtreg/runtime/verifier/CFLH/TestVerify.java diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index ae66ee22511eb..3e6246d4aeedc 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -5333,7 +5333,8 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream, assert(0 == _access_flags.as_unsigned_short(), "invariant"); // Figure out whether we can skip format checking (matching classic VM behavior) - _need_verify = Verifier::should_verify_for(_loader_data->class_loader()); + // Always verify CFLH bytes from the user agents. + _need_verify = stream->from_class_file_load_hook() ? true : Verifier::should_verify_for(_loader_data->class_loader()); // synch back verification state to stream to check for truncation. stream->set_need_verify(_need_verify); diff --git a/src/hotspot/share/classfile/classFileStream.cpp b/src/hotspot/share/classfile/classFileStream.cpp index 0fc3e5b390c03..382bd58af2bb3 100644 --- a/src/hotspot/share/classfile/classFileStream.cpp +++ b/src/hotspot/share/classfile/classFileStream.cpp @@ -34,13 +34,15 @@ void ClassFileStream::truncated_file_error(TRAPS) const { ClassFileStream::ClassFileStream(const u1* buffer, int length, const char* source, - bool from_boot_loader_modules_image) : + bool from_boot_loader_modules_image, + bool from_class_file_load_hook) : _buffer_start(buffer), _buffer_end(buffer + length), _current(buffer), _source(source), _need_verify(true), // may be reset by ClassFileParser when this stream is parsed. - _from_boot_loader_modules_image(from_boot_loader_modules_image) { + _from_boot_loader_modules_image(from_boot_loader_modules_image), + _from_class_file_load_hook(from_class_file_load_hook) { assert(buffer != nullptr, "caller should throw NPE"); } @@ -68,5 +70,6 @@ const ClassFileStream* ClassFileStream::clone() const { return new ClassFileStream(new_buffer_start, length(), clone_source(), - from_boot_loader_modules_image()); + from_boot_loader_modules_image(), + from_class_file_load_hook()); } diff --git a/src/hotspot/share/classfile/classFileStream.hpp b/src/hotspot/share/classfile/classFileStream.hpp index 67d66bb74a1ff..135a34bdeee1a 100644 --- a/src/hotspot/share/classfile/classFileStream.hpp +++ b/src/hotspot/share/classfile/classFileStream.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,9 @@ class ClassFileStream: public ResourceObj { const char* const _source; // Source of stream (directory name, ZIP/JAR archive name) bool _need_verify; // True if we need to verify and check truncation of stream bytes. bool _from_boot_loader_modules_image; // True if this was created by ClassPathImageEntry. - void truncated_file_error(TRAPS) const ; + bool _from_class_file_load_hook; // True if this is from CFLH (needs verification) + + void truncated_file_error(TRAPS) const; protected: const u1* clone_buffer() const; @@ -55,7 +57,8 @@ class ClassFileStream: public ResourceObj { ClassFileStream(const u1* buffer, int length, const char* source, - bool from_boot_loader_modules_image = false); + bool from_boot_loader_modules_image = false, + bool from_class_file_load_hook = false); virtual const ClassFileStream* clone() const; @@ -154,6 +157,8 @@ class ClassFileStream: public ResourceObj { bool at_eos() const { return _current == _buffer_end; } uint64_t compute_fingerprint() const; + + bool from_class_file_load_hook() const { return _from_class_file_load_hook; } }; #endif // SHARE_CLASSFILE_CLASSFILESTREAM_HPP diff --git a/src/hotspot/share/classfile/klassFactory.cpp b/src/hotspot/share/classfile/klassFactory.cpp index 52da747d8b6e9..28bb176ed0a7d 100644 --- a/src/hotspot/share/classfile/klassFactory.cpp +++ b/src/hotspot/share/classfile/klassFactory.cpp @@ -76,7 +76,9 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook( s2 path_index = ik->shared_classpath_index(); ClassFileStream* stream = new ClassFileStream(ptr, pointer_delta_as_int(end_ptr, ptr), - cfs->source()); + cfs->source(), + /* from_boot_loader_modules_image */ false, + /* from_class_file_load_hook */ true); ClassLoadInfo cl_info(protection_domain); ClassFileParser parser(stream, class_name, @@ -155,7 +157,9 @@ static ClassFileStream* check_class_file_load_hook(ClassFileStream* stream, // Set new class file stream using JVMTI agent modified class file data. stream = new ClassFileStream(ptr, pointer_delta_as_int(end_ptr, ptr), - stream->source()); + stream->source(), + /* from_boot_loader_modules_image */ false, + /* from_class_file_load_hook */ true); } } diff --git a/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleJavaBaseVerify.java b/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleJavaBaseVerify.java new file mode 100644 index 0000000000000..5dd7e6bf005ee --- /dev/null +++ b/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleJavaBaseVerify.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8351654 + * @summary Show that --patch-module for java.base does not verify the classfile. + * @requires vm.flagless + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @compile PatchModuleMain.java + * @run driver PatchModuleJavaBaseVerify + */ + +import jdk.test.lib.compiler.InMemoryJavaCompiler; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.helpers.ClassFileInstaller; + +public class PatchModuleJavaBaseVerify { + + public static void main(String[] args) throws Exception { + String source = "package java.lang; " + + "public class NewClass { " + + " static { " + + " System.out.println(\"I pass!\"); " + + " } " + + "}"; + + ClassFileInstaller.writeClassToDisk("java/lang/NewClass", + InMemoryJavaCompiler.compile("java.lang.NewClass", source, "--patch-module=java.base"), + "mods/java.base"); + + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("--patch-module=java.base=mods/java.base", + "-Xlog:verification", "PatchModuleMain", "java.lang.NewClass"); + + new OutputAnalyzer(pb.start()) + .shouldContain("I pass!") + .shouldContain("End class verification for: PatchModuleMain") + .shouldNotContain("End class verification for: java.lang.NewClass") + .shouldHaveExitValue(0); + } +} diff --git a/test/hotspot/jtreg/runtime/verifier/CFLH/TestChecker.java b/test/hotspot/jtreg/runtime/verifier/CFLH/TestChecker.java new file mode 100644 index 0000000000000..0d990549c2f91 --- /dev/null +++ b/test/hotspot/jtreg/runtime/verifier/CFLH/TestChecker.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package checker; + +public interface TestChecker { + void check(Integer i); + + static TestChecker instance() { + return TestCheckerImpl.instance; + } + + class TestCheckerImpl implements TestChecker { + private static final TestCheckerImpl instance = new TestCheckerImpl(); + + @Override + public void check(Integer i) { + System.out.println("Checking: " + i); + } + } +} diff --git a/test/hotspot/jtreg/runtime/verifier/CFLH/TestVerify.java b/test/hotspot/jtreg/runtime/verifier/CFLH/TestVerify.java new file mode 100644 index 0000000000000..214751863ead6 --- /dev/null +++ b/test/hotspot/jtreg/runtime/verifier/CFLH/TestVerify.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Verifier should verify ClassFileLoadHook bytes even if on bootclasspath + * @bug 8351654 + * @requires vm.jvmti + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @modules java.compiler + * java.instrument + * jdk.jartool/sun.tools.jar + * @compile TestChecker.java + * @run driver jdk.test.lib.helpers.ClassFileInstaller checker/TestChecker + * @run main TestVerify buildAgent + * @run main/othervm --patch-module=java.base=. -Dagent.retransform=false -javaagent:redefineagent.jar TestVerify + * @run main/othervm --patch-module=java.base=. -Dagent.retransform=true -javaagent:redefineagent.jar TestVerify + */ + +import java.lang.invoke.MethodHandles; +import java.time.Duration; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.MethodTransform; +import java.lang.classfile.constantpool.InterfaceMethodRefEntry; +import java.lang.classfile.instruction.ReturnInstruction; +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDescs; +import java.lang.constant.MethodTypeDesc; +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.lang.instrument.Instrumentation; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.ProtectionDomain; + +import java.io.PrintWriter; +import jdk.test.lib.helpers.ClassFileInstaller; +import java.io.FileNotFoundException; + +public class TestVerify { + + private static final String CLASS_TO_BREAK = "java.time.Duration"; + private static final String INTERNAL_CLASS_TO_BREAK = CLASS_TO_BREAK.replace('.', '/'); + private static final boolean DEBUG = false; + + private static class BadTransformer implements ClassFileTransformer { + + @Override + public byte[] transform(Module module, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { + + if (className.equals(INTERNAL_CLASS_TO_BREAK)) { + System.out.println("Instrumenting modular class " + INTERNAL_CLASS_TO_BREAK); + + var methodTransform = MethodTransform.transformingCode((builder, element) -> { + if (element instanceof ReturnInstruction) { + System.out.println("Injecting bug"); + // THE BUG! insert broken function call + + var checkerDesc = ClassDesc.of("checker", "TestChecker"); + builder.invokestatic(checkerDesc, "instance", MethodTypeDesc.of(checkerDesc), true); + + // dup the instance ref, this is just to get a bad argument to the next method call + builder.dup(); + + // then call a check method that doesn't take that type, but we have the wrong desc + builder.invokeinterface(checkerDesc, "check", MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_Integer)); + + System.out.println("Done injecting bug"); + } + builder.with(element); + }); + var classTransform = ClassTransform.transformingMethods(mm -> mm.methodName().stringValue().equals("getSeconds"), methodTransform); + + byte[] bytes; + try { + var cf = ClassFile.of(); + var existingClass = cf.parse(classfileBuffer); + bytes = cf.transformClass(existingClass, classTransform); + + if (DEBUG) Files.write(Path.of("bad.class"), bytes); + } catch (Throwable e) { + throw new AssertionError(e); + } + return bytes; + } + return null; + } + } + + static Instrumentation inst = null; + + public static void premain(String args, Instrumentation instrumentation) throws Exception { + System.out.println("Premain"); + inst = instrumentation; + } + + private static void buildAgent() { + try { + ClassFileInstaller.main("TestVerify"); + } catch (Exception e) { + throw new RuntimeException("Could not write agent classfile", e); + } + + try { + PrintWriter pw = new PrintWriter("MANIFEST.MF"); + pw.println("Premain-Class: TestVerify"); + pw.println("Agent-Class: TestVerify"); + pw.println("Can-Retransform-Classes: true"); + pw.println("Can-Redefine-Classes: true"); + pw.close(); + } catch (FileNotFoundException e) { + throw new RuntimeException("Could not write manifest file for the agent", e); + } + + sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar"); + if (!jarTool.run(new String[] { "-cmf", "MANIFEST.MF", "redefineagent.jar", "TestVerify.class" })) { + throw new RuntimeException("Could not write the agent jar file"); + } + } + + public static void main(String argv[]) throws Exception { + if (argv.length == 1 && argv[0].equals("buildAgent")) { + buildAgent(); + return; + } + + // double check our class hasn't been loaded yet + for (Class clazz : inst.getAllLoadedClasses()) { + if (clazz.getName().equals(CLASS_TO_BREAK)) { + throw new AssertionError("Oops! Class " + CLASS_TO_BREAK + " is already loaded, the test can't work"); + } + } + + boolean retransform = Boolean.getBoolean("agent.retransform"); + + try { + if (retransform) { + // Retransform the class for the VerifyError. + var clazz = Class.forName(CLASS_TO_BREAK); + inst.addTransformer(new BadTransformer(), true); + inst.retransformClasses(clazz); + } else { + // Load the class instrumented with CFLH for the VerifyError. + inst.addTransformer(new BadTransformer()); + System.out.println("1 hour is " + Duration.ofHours(1).getSeconds() + " seconds"); + } + throw new RuntimeException("Failed: Did not throw VerifyError"); + } catch (VerifyError e) { + System.out.println("Passed: VerifyError " + e.getMessage()); + } + } +} From 676cfae91c8bd4799adfedff2ad59a9aab953ece Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 8 Apr 2025 13:49:15 +0000 Subject: [PATCH 0458/1101] 8354016: Update ReentrantReadWriteLock documentation to reflect its new max capacity Reviewed-by: alanb --- .../java/util/concurrent/locks/ReentrantReadWriteLock.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java b/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java index a45043e48ee4b..3e0b293380f5f 100644 --- a/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java +++ b/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java @@ -207,8 +207,8 @@ * *

Implementation Notes

* - *

This lock supports a maximum of 65535 recursive write locks - * and 65535 read locks. Attempts to exceed these limits result in + *

This lock supports a maximum of {@link Integer#MAX_VALUE} recursive write locks + * and {@link Integer#MAX_VALUE} read locks. Attempts to exceed these limits result in * {@link Error} throws from locking methods. * * @since 1.5 From 58ff36f3bdefe2e883dc871a4e7fcaa81e8eef5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Tue, 8 Apr 2025 15:19:32 +0000 Subject: [PATCH 0459/1101] 8350705: [JMH] test security.SSLHandshake failed for 2 threads configuration Reviewed-by: hchao, mullan --- .../bench/java/security/SSLHandshake.java | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/test/micro/org/openjdk/bench/java/security/SSLHandshake.java b/test/micro/org/openjdk/bench/java/security/SSLHandshake.java index 5a4529059a56d..d8773781b58cc 100644 --- a/test/micro/org/openjdk/bench/java/security/SSLHandshake.java +++ b/test/micro/org/openjdk/bench/java/security/SSLHandshake.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,6 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; import java.nio.ByteBuffer; @@ -50,13 +49,17 @@ @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.SECONDS) -@State(Scope.Benchmark) +@State(Scope.Thread) @Warmup(iterations = 5, time = 5) @Measurement(iterations = 5, time = 5) @Fork(value = 3) public class SSLHandshake { - private SSLContext sslc; + // one global server context + private static final SSLContext sslServerCtx = getServerContext(); + + // per-thread client contexts + private SSLContext sslClientCtx; private SSLEngine clientEngine; private ByteBuffer clientOut = ByteBuffer.allocate(5); @@ -75,22 +78,33 @@ public class SSLHandshake { @Param({"TLSv1.2", "TLS"}) String tlsVersion; + private static SSLContext getServerContext() { + try { + KeyStore ks = TestCertificates.getKeyStore(); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance( + KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(ks, new char[0]); + + SSLContext sslCtx = SSLContext.getInstance("TLS"); + sslCtx.init(kmf.getKeyManagers(), null, null); + return sslCtx; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Setup(Level.Trial) public void init() throws Exception { - KeyStore ks = TestCertificates.getKeyStore(); KeyStore ts = TestCertificates.getTrustStore(); - KeyManagerFactory kmf = KeyManagerFactory.getInstance( - KeyManagerFactory.getDefaultAlgorithm()); - kmf.init(ks, new char[0]); - TrustManagerFactory tmf = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ts); SSLContext sslCtx = SSLContext.getInstance(tlsVersion); - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - sslc = sslCtx; + sslCtx.init(null, tmf.getTrustManagers(), null); + sslClientCtx = sslCtx; } private HandshakeStatus checkResult(SSLEngine engine, SSLEngineResult result) { @@ -173,13 +187,13 @@ private void createSSLEngines() { * Configure the serverEngine to act as a server in the SSL/TLS * handshake. */ - serverEngine = sslc.createSSLEngine(); + serverEngine = sslServerCtx.createSSLEngine(); serverEngine.setUseClientMode(false); /* * Similar to above, but using client mode instead. */ - clientEngine = sslc.createSSLEngine("client", 80); + clientEngine = sslClientCtx.createSSLEngine("client", 80); clientEngine.setUseClientMode(true); } } From 4645ddbb6be6b4456cc4d9f58188b0561a8e593d Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 8 Apr 2025 15:52:05 +0000 Subject: [PATCH 0460/1101] 8341976: C2: use_mem_state != load->find_exact_control(load->in(0)) assert failure Reviewed-by: chagedorn, dfenacci --- src/hotspot/share/opto/arraycopynode.cpp | 23 ++++--- src/hotspot/share/opto/arraycopynode.hpp | 2 +- src/hotspot/share/opto/macro.hpp | 4 +- src/hotspot/share/opto/macroArrayCopy.cpp | 55 ++++++++++------ src/hotspot/share/opto/memnode.hpp | 6 +- .../arraycopy/TestSunkLoadAntiDependency.java | 66 +++++++++++++++++++ 6 files changed, 117 insertions(+), 39 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/arraycopy/TestSunkLoadAntiDependency.java diff --git a/src/hotspot/share/opto/arraycopynode.cpp b/src/hotspot/share/opto/arraycopynode.cpp index 23a6ee31fffde..85b6bd21aece1 100644 --- a/src/hotspot/share/opto/arraycopynode.cpp +++ b/src/hotspot/share/opto/arraycopynode.cpp @@ -681,18 +681,21 @@ bool ArrayCopyNode::may_modify(const TypeOopPtr* t_oop, PhaseValues* phase) { return CallNode::may_modify_arraycopy_helper(dest_t, t_oop, phase); } -bool ArrayCopyNode::may_modify_helper(const TypeOopPtr* t_oop, Node* n, PhaseValues* phase, CallNode*& call) { +bool ArrayCopyNode::may_modify_helper(const TypeOopPtr* t_oop, Node* n, PhaseValues* phase, ArrayCopyNode*& ac) { if (n != nullptr && - n->is_Call() && - n->as_Call()->may_modify(t_oop, phase) && - (n->as_Call()->is_ArrayCopy() || n->as_Call()->is_call_to_arraycopystub())) { - call = n->as_Call(); + n->is_ArrayCopy() && + n->as_ArrayCopy()->may_modify(t_oop, phase)) { + ac = n->as_ArrayCopy(); return true; } return false; } bool ArrayCopyNode::may_modify(const TypeOopPtr* t_oop, MemBarNode* mb, PhaseValues* phase, ArrayCopyNode*& ac) { + if (mb->trailing_expanded_array_copy()) { + return true; + } + Node* c = mb->in(0); BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); @@ -705,23 +708,19 @@ bool ArrayCopyNode::may_modify(const TypeOopPtr* t_oop, MemBarNode* mb, PhaseVal for (uint i = 1; i < c->req(); i++) { if (c->in(i) != nullptr) { Node* n = c->in(i)->in(0); - if (may_modify_helper(t_oop, n, phase, call)) { - ac = call->isa_ArrayCopy(); + if (may_modify_helper(t_oop, n, phase, ac)) { assert(c == mb->in(0), "only for clone"); return true; } } } - } else if (may_modify_helper(t_oop, c->in(0), phase, call)) { - ac = call->isa_ArrayCopy(); + } else if (may_modify_helper(t_oop, c->in(0), phase, ac)) { #ifdef ASSERT bool use_ReduceInitialCardMarks = BarrierSet::barrier_set()->is_a(BarrierSet::CardTableBarrierSet) && static_cast(bs)->use_ReduceInitialCardMarks(); - assert(c == mb->in(0) || (ac != nullptr && ac->is_clonebasic() && !use_ReduceInitialCardMarks), "only for clone"); + assert(c == mb->in(0) || (ac->is_clonebasic() && !use_ReduceInitialCardMarks), "only for clone"); #endif return true; - } else if (mb->trailing_partial_array_copy()) { - return true; } return false; diff --git a/src/hotspot/share/opto/arraycopynode.hpp b/src/hotspot/share/opto/arraycopynode.hpp index f792722068fe3..13e739fc2c7a5 100644 --- a/src/hotspot/share/opto/arraycopynode.hpp +++ b/src/hotspot/share/opto/arraycopynode.hpp @@ -121,7 +121,7 @@ class ArrayCopyNode : public CallNode { BasicType copy_type, const Type* value_type, int count); bool finish_transform(PhaseGVN *phase, bool can_reshape, Node* ctl, Node *mem); - static bool may_modify_helper(const TypeOopPtr* t_oop, Node* n, PhaseValues* phase, CallNode*& call); + static bool may_modify_helper(const TypeOopPtr* t_oop, Node* n, PhaseValues* phase, ArrayCopyNode*& ac); public: static Node* load(BarrierSetC2* bs, PhaseGVN *phase, Node*& ctl, MergeMemNode* mem, Node* addr, const TypePtr* adr_type, const Type *type, BasicType bt); private: diff --git a/src/hotspot/share/opto/macro.hpp b/src/hotspot/share/opto/macro.hpp index e10326e9d8725..0e2326fd9d472 100644 --- a/src/hotspot/share/opto/macro.hpp +++ b/src/hotspot/share/opto/macro.hpp @@ -111,7 +111,7 @@ class PhaseMacroExpand : public Phase { void expand_unlock_node(UnlockNode *unlock); // More helper methods modeled after GraphKit for array copy - void insert_mem_bar(Node** ctrl, Node** mem, int opcode, Node* precedent = nullptr); + void insert_mem_bar(Node** ctrl, Node** mem, int opcode, int alias_idx, Node* precedent = nullptr); Node* array_element_address(Node* ary, Node* idx, BasicType elembt); Node* ConvI2L(Node* offset); @@ -171,7 +171,7 @@ class PhaseMacroExpand : public Phase { Node* src, Node* src_offset, Node* dest, Node* dest_offset, Node* copy_length, bool dest_uninitialized); - bool generate_unchecked_arraycopy(Node** ctrl, MergeMemNode** mem, + void generate_unchecked_arraycopy(Node** ctrl, MergeMemNode** mem, const TypePtr* adr_type, BasicType basic_elem_type, bool disjoint_bases, diff --git a/src/hotspot/share/opto/macroArrayCopy.cpp b/src/hotspot/share/opto/macroArrayCopy.cpp index e37c961e88d66..e2209fddbdfa0 100644 --- a/src/hotspot/share/opto/macroArrayCopy.cpp +++ b/src/hotspot/share/opto/macroArrayCopy.cpp @@ -36,8 +36,8 @@ #include "utilities/align.hpp" #include "utilities/powerOfTwo.hpp" -void PhaseMacroExpand::insert_mem_bar(Node** ctrl, Node** mem, int opcode, Node* precedent) { - MemBarNode* mb = MemBarNode::make(C, opcode, Compile::AliasIdxBot, precedent); +void PhaseMacroExpand::insert_mem_bar(Node** ctrl, Node** mem, int opcode, int alias_idx, Node* precedent) { + MemBarNode* mb = MemBarNode::make(C, opcode, alias_idx, precedent); mb->init_req(TypeFunc::Control, *ctrl); mb->init_req(TypeFunc::Memory, *mem); transform_later(mb); @@ -45,7 +45,14 @@ void PhaseMacroExpand::insert_mem_bar(Node** ctrl, Node** mem, int opcode, Node* transform_later(*ctrl); Node* mem_proj = new ProjNode(mb,TypeFunc::Memory); transform_later(mem_proj); - *mem = mem_proj; + if (alias_idx == Compile::AliasIdxBot) { + *mem = mem_proj; + } else { + MergeMemNode* mm = (*mem)->clone()->as_MergeMem(); + mm->set_memory_at(alias_idx, mem_proj); + transform_later(mm); + *mem = mm; + } } Node* PhaseMacroExpand::array_element_address(Node* ary, Node* idx, BasicType elembt) { @@ -667,16 +674,15 @@ Node* PhaseMacroExpand::generate_arraycopy(ArrayCopyNode *ac, AllocateArrayNode* } } - bool is_partial_array_copy = false; if (!(*ctrl)->is_top()) { // Generate the fast path, if possible. Node* local_ctrl = *ctrl; MergeMemNode* local_mem = MergeMemNode::make(mem); transform_later(local_mem); - is_partial_array_copy = generate_unchecked_arraycopy(&local_ctrl, &local_mem, - adr_type, copy_type, disjoint_bases, - src, src_offset, dest, dest_offset, - ConvI2X(copy_length), acopy_to_uninitialized); + generate_unchecked_arraycopy(&local_ctrl, &local_mem, + adr_type, copy_type, disjoint_bases, + src, src_offset, dest, dest_offset, + ConvI2X(copy_length), acopy_to_uninitialized); // Present the results of the fast call. result_region->init_req(fast_path, local_ctrl); @@ -818,16 +824,23 @@ Node* PhaseMacroExpand::generate_arraycopy(ArrayCopyNode *ac, AllocateArrayNode* // Do not let stores that initialize this object be reordered with // a subsequent store that would make this object accessible by // other threads. - insert_mem_bar(ctrl, &out_mem, Op_MemBarStoreStore); + assert(ac->_dest_type == TypeOopPtr::BOTTOM, "non escaping destination shouldn't have narrow slice"); + insert_mem_bar(ctrl, &out_mem, Op_MemBarStoreStore, Compile::AliasIdxBot); } else { - insert_mem_bar(ctrl, &out_mem, Op_MemBarCPUOrder); + int mem_bar_alias_idx = Compile::AliasIdxBot; + if (ac->_dest_type != TypeOopPtr::BOTTOM) { + // The graph was transformed under the assumption the ArrayCopy node only had an effect on a narrow slice. We can't + // insert a wide membar now that it's being expanded: a load that uses the input memory state of the ArrayCopy + // could then become anti dependent on the membar when it was not anti dependent on the ArrayCopy leading to a + // broken graph. + mem_bar_alias_idx = C->get_alias_index(ac->_dest_type->add_offset(Type::OffsetBot)->is_ptr()); + } + insert_mem_bar(ctrl, &out_mem, Op_MemBarCPUOrder, mem_bar_alias_idx); } - if (is_partial_array_copy) { - assert((*ctrl)->is_Proj(), "MemBar control projection"); - assert((*ctrl)->in(0)->isa_MemBar(), "MemBar node"); - (*ctrl)->in(0)->isa_MemBar()->set_trailing_partial_array_copy(); - } + assert((*ctrl)->is_Proj(), "MemBar control projection"); + assert((*ctrl)->in(0)->isa_MemBar(), "MemBar node"); + (*ctrl)->in(0)->isa_MemBar()->set_trailing_expanded_array_copy(); _igvn.replace_node(_callprojs.fallthrough_memproj, out_mem); if (_callprojs.fallthrough_ioproj != nullptr) { @@ -837,7 +850,7 @@ Node* PhaseMacroExpand::generate_arraycopy(ArrayCopyNode *ac, AllocateArrayNode* #ifdef ASSERT const TypeOopPtr* dest_t = _igvn.type(dest)->is_oopptr(); - if (dest_t->is_known_instance() && !is_partial_array_copy) { + if (dest_t->is_known_instance()) { ArrayCopyNode* ac = nullptr; assert(ArrayCopyNode::may_modify(dest_t, (*ctrl)->in(0)->as_MemBar(), &_igvn, ac), "dependency on arraycopy lost"); assert(ac == nullptr, "no arraycopy anymore"); @@ -1174,14 +1187,16 @@ Node* PhaseMacroExpand::generate_generic_arraycopy(Node** ctrl, MergeMemNode** m } // Helper function; generates the fast out-of-line call to an arraycopy stub. -bool PhaseMacroExpand::generate_unchecked_arraycopy(Node** ctrl, MergeMemNode** mem, +void PhaseMacroExpand::generate_unchecked_arraycopy(Node** ctrl, MergeMemNode** mem, const TypePtr* adr_type, BasicType basic_elem_type, bool disjoint_bases, Node* src, Node* src_offset, Node* dest, Node* dest_offset, Node* copy_length, bool dest_uninitialized) { - if ((*ctrl)->is_top()) return false; + if ((*ctrl)->is_top()) { + return; + } Node* src_start = src; Node* dest_start = dest; @@ -1226,9 +1241,7 @@ bool PhaseMacroExpand::generate_unchecked_arraycopy(Node** ctrl, MergeMemNode** } transform_later(*mem); *ctrl = exit_block; - return true; } - return false; } #undef XTOP @@ -1311,7 +1324,7 @@ void PhaseMacroExpand::expand_arraycopy_node(ArrayCopyNode *ac) { // Do not let writes into the source float below the arraycopy. { Node* mem = ac->in(TypeFunc::Memory); - insert_mem_bar(&ctrl, &mem, Op_MemBarCPUOrder); + insert_mem_bar(&ctrl, &mem, Op_MemBarCPUOrder, Compile::AliasIdxBot); merge_mem = MergeMemNode::make(mem); transform_later(merge_mem); diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index eca891bebbbce..f17db05e68362 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -1132,7 +1132,7 @@ class MemBarNode: public MultiNode { LeadingStore, TrailingLoadStore, LeadingLoadStore, - TrailingPartialArrayCopy + TrailingExpandedArrayCopy } _kind; #ifdef ASSERT @@ -1169,8 +1169,8 @@ class MemBarNode: public MultiNode { bool trailing() const { return _kind == TrailingLoad || _kind == TrailingStore || _kind == TrailingLoadStore; } bool leading() const { return _kind == LeadingStore || _kind == LeadingLoadStore; } bool standalone() const { return _kind == Standalone; } - void set_trailing_partial_array_copy() { _kind = TrailingPartialArrayCopy; } - bool trailing_partial_array_copy() const { return _kind == TrailingPartialArrayCopy; } + void set_trailing_expanded_array_copy() { _kind = TrailingExpandedArrayCopy; } + bool trailing_expanded_array_copy() const { return _kind == TrailingExpandedArrayCopy; } static void set_store_pair(MemBarNode* leading, MemBarNode* trailing); static void set_load_store_pair(MemBarNode* leading, MemBarNode* trailing); diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestSunkLoadAntiDependency.java b/test/hotspot/jtreg/compiler/arraycopy/TestSunkLoadAntiDependency.java new file mode 100644 index 0000000000000..2cb185f58bf86 --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/TestSunkLoadAntiDependency.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8341976 + * @summary C2: use_mem_state != load->find_exact_control(load->in(0)) assert failure + * @run main/othervm -XX:-BackgroundCompilation TestSunkLoadAntiDependency + * @run main TestSunkLoadAntiDependency + */ + +public class TestSunkLoadAntiDependency { + private static volatile int volatileField; + + public static void main(String[] args) { + int[] array = new int[100]; + for (int i = 0; i < 20_000; i++) { + test1(array, 2); + inlined1(array, 100, 0, 100, array); + } + } + + private static int test1(int[] src, int length) { + length = Integer.max(1, length); + int[] dst = new int[2]; + int stop; + for (stop = 0; stop < 10; stop++) { + for (int i = 0; i < 10; i++) { + } + } + int start; + for (start = 0; start < 9; start++) { + for (int i = 0; i < 10; i++) { + } + } + inlined1(src, length, start, stop, dst); + return dst[0] + dst[1]; + } + + private static void inlined1(int[] src, int length, int start, int stop, int[] dst) { + for (int i = start; i < stop; i++) { + volatileField = 42; + System.arraycopy(src, 0, dst, 0, length); + } + } +} From 3cbe686d6203043e95604b3d6c96d6ed9d5364c3 Mon Sep 17 00:00:00 2001 From: Sean Mullan Date: Tue, 8 Apr 2025 16:13:43 +0000 Subject: [PATCH 0461/1101] 8348967: Deprecate security permission classes for removal Reviewed-by: rriggs, iris --- src/java.base/share/classes/java/security/Permissions.java | 3 +++ .../share/classes/java/security/SecurityPermission.java | 5 +++-- .../share/classes/java/security/UnresolvedPermission.java | 6 +++++- .../java/security/UnresolvedPermissionCollection.java | 3 ++- .../share/classes/javax/net/ssl/SSLPermission.java | 5 +++-- .../share/classes/javax/security/auth/AuthPermission.java | 5 +++-- .../javax/security/auth/PrivateCredentialPermission.java | 5 +++-- .../javax/security/auth/kerberos/DelegationPermission.java | 7 +++++-- .../javax/security/auth/kerberos/ServicePermission.java | 7 +++++-- .../org/apache/xml/internal/security/utils/JavaUtils.java | 1 + .../com/sun/security/jgss/InquireSecContextPermission.java | 5 +++-- 11 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/java.base/share/classes/java/security/Permissions.java b/src/java.base/share/classes/java/security/Permissions.java index ecb18aca8bb2b..269c988ebee8a 100644 --- a/src/java.base/share/classes/java/security/Permissions.java +++ b/src/java.base/share/classes/java/security/Permissions.java @@ -125,6 +125,7 @@ public Permissions() { * @see PermissionCollection#isReadOnly() */ @Override + @SuppressWarnings("removal") public void add(Permission permission) { if (isReadOnly()) throw new SecurityException( @@ -288,6 +289,7 @@ private PermissionCollection createPermissionCollection(Permission p, * or {@code null} if there were no unresolved permissions of type p. * */ + @SuppressWarnings("removal") private PermissionCollection getUnresolvedPermissions(Permission p) { UnresolvedPermissionCollection uc = @@ -392,6 +394,7 @@ private void writeObject(ObjectOutputStream out) throws IOException { * permsMap field. Reads in allPermission. */ @java.io.Serial + @SuppressWarnings("removal") private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { // Don't call defaultReadObject() diff --git a/src/java.base/share/classes/java/security/SecurityPermission.java b/src/java.base/share/classes/java/security/SecurityPermission.java index c378953095cc9..7fee76417a661 100644 --- a/src/java.base/share/classes/java/security/SecurityPermission.java +++ b/src/java.base/share/classes/java/security/SecurityPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ *

* The target name is the name of a security configuration parameter. * - * @apiNote + * @deprecated * This permission cannot be used for controlling access to resources * as the Security Manager is no longer supported. * @@ -47,6 +47,7 @@ * @since 1.2 */ +@Deprecated(since="25", forRemoval=true) public final class SecurityPermission extends BasicPermission { @java.io.Serial diff --git a/src/java.base/share/classes/java/security/UnresolvedPermission.java b/src/java.base/share/classes/java/security/UnresolvedPermission.java index 07c30e2668d76..8a9b51396bd46 100644 --- a/src/java.base/share/classes/java/security/UnresolvedPermission.java +++ b/src/java.base/share/classes/java/security/UnresolvedPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,8 +49,12 @@ * * @author Roland Schemers * @since 1.2 + * + * @deprecated This permission cannot be used for controlling access to + * resources as the Security Manager is no longer supported. */ +@Deprecated(since="25", forRemoval=true) public final class UnresolvedPermission extends Permission implements java.io.Serializable { diff --git a/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java b/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java index c0bdf5fc2a1f8..93e09251a0221 100644 --- a/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java +++ b/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,6 +49,7 @@ * @serial include */ +@SuppressWarnings("removal") final class UnresolvedPermissionCollection extends PermissionCollection implements java.io.Serializable diff --git a/src/java.base/share/classes/javax/net/ssl/SSLPermission.java b/src/java.base/share/classes/javax/net/ssl/SSLPermission.java index 2f8e06d2ee6c0..7246708951089 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLPermission.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ * signify a wildcard match. For example: "foo.*" and "*" signify a wildcard * match, while "*foo" and "a*b" do not. * - * @apiNote + * @deprecated * This permission cannot be used for controlling access to resources * as the Security Manager is no longer supported. * @@ -55,6 +55,7 @@ * @author Roland Schemers */ +@Deprecated(since="25", forRemoval=true) public final class SSLPermission extends BasicPermission { @java.io.Serial diff --git a/src/java.base/share/classes/javax/security/auth/AuthPermission.java b/src/java.base/share/classes/javax/security/auth/AuthPermission.java index 7ad61db21cf2f..d45aea5fbaf63 100644 --- a/src/java.base/share/classes/javax/security/auth/AuthPermission.java +++ b/src/java.base/share/classes/javax/security/auth/AuthPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,12 +30,13 @@ * contains a name (also referred to as a "target name") but no actions * list; you either have the named permission or you don't. * - * @apiNote + * @deprecated * This permission cannot be used for controlling access to resources * as the Security Manager is no longer supported. * * @since 1.4 */ +@Deprecated(since="25", forRemoval=true) public final class AuthPermission extends java.security.BasicPermission { diff --git a/src/java.base/share/classes/javax/security/auth/PrivateCredentialPermission.java b/src/java.base/share/classes/javax/security/auth/PrivateCredentialPermission.java index d25a5a81d9dcd..5d1688f17d6f7 100644 --- a/src/java.base/share/classes/javax/security/auth/PrivateCredentialPermission.java +++ b/src/java.base/share/classes/javax/security/auth/PrivateCredentialPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,12 +47,13 @@ * CredentialClass {PrincipalClass "PrincipalName"}* * * - * @apiNote + * @deprecated * This permission cannot be used for controlling access to resources * as the Security Manager is no longer supported. * * @since 1.4 */ +@Deprecated(since="25", forRemoval=true) public final class PrivateCredentialPermission extends Permission { @java.io.Serial diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/DelegationPermission.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/DelegationPermission.java index b2a14bf616404..310e05bf45f17 100644 --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/DelegationPermission.java +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/DelegationPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,13 +43,14 @@ * latter service principal is specified to restrict the use of a * proxiable ticket. * - * @apiNote + * @deprecated * This permission cannot be used for controlling access to resources * as the Security Manager is no longer supported. * * @since 1.4 */ +@Deprecated(since="25", forRemoval=true) public final class DelegationPermission extends BasicPermission implements java.io.Serializable { @@ -249,6 +250,7 @@ public KrbDelegationPermissionCollection() { * the collection, false if not. */ @Override + @SuppressWarnings("removal") public boolean implies(Permission permission) { if (! (permission instanceof DelegationPermission)) return false; @@ -270,6 +272,7 @@ public boolean implies(Permission permission) { * has been marked readonly */ @Override + @SuppressWarnings("removal") public void add(Permission permission) { if (! (permission instanceof DelegationPermission)) throw new IllegalArgumentException("invalid permission: "+ diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/ServicePermission.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/ServicePermission.java index df45b4c72da8f..616e6be1d514e 100644 --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/ServicePermission.java +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/ServicePermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,13 +54,14 @@ * principal. * * - * @apiNote + * @deprecated * This permission cannot be used for controlling access to resources * as the Security Manager is no longer supported. * * @since 1.4 */ +@Deprecated(since="25", forRemoval=true) public final class ServicePermission extends Permission implements java.io.Serializable { @@ -433,6 +434,7 @@ public KrbServicePermissionCollection() { * the collection, false if not. */ @Override + @SuppressWarnings("removal") public boolean implies(Permission permission) { if (! (permission instanceof ServicePermission np)) return false; @@ -480,6 +482,7 @@ public boolean implies(Permission permission) { * has been marked readonly */ @Override + @SuppressWarnings("removal") public void add(Permission permission) { if (! (permission instanceof ServicePermission sp)) throw new IllegalArgumentException("invalid permission: "+ diff --git a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/utils/JavaUtils.java b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/utils/JavaUtils.java index 647675ae61cbe..53396553bb65d 100644 --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/utils/JavaUtils.java +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/utils/JavaUtils.java @@ -39,6 +39,7 @@ public final class JavaUtils { private static final com.sun.org.slf4j.internal.Logger LOG = com.sun.org.slf4j.internal.LoggerFactory.getLogger(JavaUtils.class); + @SuppressWarnings("removal") private static final SecurityPermission REGISTER_PERMISSION = new SecurityPermission("com.sun.org.apache.xml.internal.security.register"); diff --git a/src/jdk.security.jgss/share/classes/com/sun/security/jgss/InquireSecContextPermission.java b/src/jdk.security.jgss/share/classes/com/sun/security/jgss/InquireSecContextPermission.java index 641edec9c3844..fce26e077fce9 100644 --- a/src/jdk.security.jgss/share/classes/com/sun/security/jgss/InquireSecContextPermission.java +++ b/src/jdk.security.jgss/share/classes/com/sun/security/jgss/InquireSecContextPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,12 +32,13 @@ * *

The target name is the {@link InquireType} allowed. * - * @apiNote + * @deprecated * This permission cannot be used for controlling access to resources * as the Security Manager is no longer supported. * * @since 1.7 */ +@Deprecated(since="25", forRemoval=true) public final class InquireSecContextPermission extends BasicPermission { private static final long serialVersionUID = -7131173349668647297L; From b98d6aebdd897959785ea27ee7855d26c9ed35d7 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Tue, 8 Apr 2025 16:34:20 +0000 Subject: [PATCH 0462/1101] 8339527: Adjust threshold for MemorySegment::fill native invocation Reviewed-by: jvernee --- .../classes/jdk/internal/foreign/SegmentBulkOperations.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java index 068db1bf593c6..5f0794c81d96d 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,9 +53,7 @@ private SegmentBulkOperations() {} // All the threshold values below MUST be a power of two and should preferably be // greater or equal to 2^3. - - // Update the FILL value for Aarch64 once 8338975 is fixed. - private static final int NATIVE_THRESHOLD_FILL = powerOfPropertyOr("fill", Architecture.isAARCH64() ? 10 : 5); + private static final int NATIVE_THRESHOLD_FILL = powerOfPropertyOr("fill", Architecture.isAARCH64() ? 18 : 5); private static final int NATIVE_THRESHOLD_MISMATCH = powerOfPropertyOr("mismatch", 6); private static final int NATIVE_THRESHOLD_COPY = powerOfPropertyOr("copy", 6); From bd73a0641615d743663ef652bc1f27305af1517b Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Tue, 8 Apr 2025 16:55:48 +0000 Subject: [PATCH 0463/1101] 8300339: Run jtreg in the work dir Reviewed-by: erikj --- make/RunTests.gmk | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 7aa0082e0ae81..ebae510fc07d9 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -995,24 +995,27 @@ define SetupRunJtregTestBody $$(RM) -r $$($1_TEST_SUPPORT_DIR) $$(RM) -r $$($1_TEST_RESULTS_DIR) + $1_JTREG_ARGUMENTS := \ + $$($1_JTREG_LAUNCHER_OPTIONS) \ + -Dprogram=jtreg -jar $$(JT_HOME)/lib/jtreg.jar \ + $$($1_JTREG_BASIC_OPTIONS) \ + -testjdk:$$(JDK_UNDER_TEST) \ + -dir:$$(JTREG_TOPDIR) \ + -reportDir:$$($1_TEST_RESULTS_DIR) \ + -workDir:$$($1_TEST_SUPPORT_DIR) \ + -report:$${JTREG_REPORT} \ + $$$${JTREG_STATUS} \ + $$(JTREG_OPTIONS) \ + $$(JTREG_FAILURE_HANDLER_OPTIONS) \ + $$(JTREG_COV_OPTIONS) \ + $$($1_TEST_NAME) \ + # + $1_COMMAND_LINE := \ - $$(JTREG_JAVA) $$($1_JTREG_LAUNCHER_OPTIONS) \ - -Dprogram=jtreg -jar $$(JT_HOME)/lib/jtreg.jar \ - $$($1_JTREG_BASIC_OPTIONS) \ - -testjdk:$$(JDK_UNDER_TEST) \ - -dir:$$(JTREG_TOPDIR) \ - -reportDir:$$($1_TEST_RESULTS_DIR) \ - -workDir:$$($1_TEST_SUPPORT_DIR) \ - -report:$${JTREG_REPORT} \ - $$$${JTREG_STATUS} \ - $$(JTREG_OPTIONS) \ - $$(JTREG_FAILURE_HANDLER_OPTIONS) \ - $$(JTREG_COV_OPTIONS) \ - $$($1_TEST_NAME) \ + cd $$($1_TEST_SUPPORT_DIR) && $$(JTREG_JAVA) $$($1_JTREG_ARGUMENTS) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) - ifneq ($$(JTREG_RETRY_COUNT), 0) $1_COMMAND_LINE := \ for i in {0..$$(JTREG_RETRY_COUNT)}; do \ From e1a4a6beb61c70228c3aa54ddf2d9310fd5020e2 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Tue, 8 Apr 2025 16:57:00 +0000 Subject: [PATCH 0464/1101] 8340185: Use make -k on GHA to catch more build errors Reviewed-by: shade --- .github/actions/do-build/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/do-build/action.yml b/.github/actions/do-build/action.yml index 252105f29fddf..6f2c2ce02180c 100644 --- a/.github/actions/do-build/action.yml +++ b/.github/actions/do-build/action.yml @@ -1,5 +1,5 @@ # -# Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ runs: - name: 'Build' id: build run: > - make LOG=info ${{ inputs.make-target }} + make -k LOG=info ${{ inputs.make-target }} || bash ./.github/scripts/gen-build-failure-report.sh "$GITHUB_STEP_SUMMARY" shell: bash From 5cac579619164b9a664327a4f71c4de7e7575276 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Tue, 8 Apr 2025 17:37:13 +0000 Subject: [PATCH 0465/1101] 8353713: Improve Currency.getInstance exception handling Reviewed-by: naoto --- .../share/classes/java/util/Currency.java | 24 ++++++------ test/jdk/java/util/Currency/CurrencyTest.java | 38 ++++++++++++------- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/java.base/share/classes/java/util/Currency.java b/src/java.base/share/classes/java/util/Currency.java index bc13eff2a602f..3aa966e83e8f4 100644 --- a/src/java.base/share/classes/java/util/Currency.java +++ b/src/java.base/share/classes/java/util/Currency.java @@ -314,8 +314,8 @@ private static Currency getInstance(String currencyCode, int defaultFractionDigi // or in the list of other currencies. boolean found = false; if (currencyCode.length() != 3) { - throw new IllegalArgumentException("The input currency code must " + - "have a length of 3 characters"); + throw new IllegalArgumentException( + "The input currency code: \"%s\" must have a length of 3 characters".formatted(currencyCode)); } char char1 = currencyCode.charAt(0); char char2 = currencyCode.charAt(1); @@ -338,8 +338,8 @@ private static Currency getInstance(String currencyCode, int defaultFractionDigi if (!found) { OtherCurrencyEntry ocEntry = OtherCurrencyEntry.findEntry(currencyCode); if (ocEntry == null) { - throw new IllegalArgumentException("The input currency code" + - " is not a valid ISO 4217 code"); + throw new IllegalArgumentException( + "The input currency code: \"%s\" is not a valid ISO 4217 code".formatted(currencyCode)); } defaultFractionDigits = ocEntry.fraction; numericCode = ocEntry.numericCode; @@ -394,8 +394,8 @@ public static Currency getInstance(Locale locale) { String country = CalendarDataUtility.findRegionOverride(locale).getCountry(); if (country == null || !country.matches("^[a-zA-Z]{2}$")) { - throw new IllegalArgumentException("The country of the input locale" + - " is not a valid ISO 3166 country code"); + throw new IllegalArgumentException( + "The country of the input locale: \"%s\" is not a valid ISO 3166 country code".formatted(locale)); } char char1 = country.charAt(0); @@ -412,8 +412,8 @@ public static Currency getInstance(Locale locale) { } else { // special cases if (tableEntry == INVALID_COUNTRY_ENTRY) { - throw new IllegalArgumentException("The country of the input locale" + - " is not a valid ISO 3166 country code"); + throw new IllegalArgumentException( + "The country of the input locale: \"%s\" is not a valid ISO 3166 country code".formatted(locale)); } if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) { return null; @@ -698,8 +698,8 @@ private Object readResolve() { */ private static int getMainTableEntry(char char1, char char2) { if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') { - throw new IllegalArgumentException("The country code is not a " + - "valid ISO 3166 code"); + throw new IllegalArgumentException( + "The country code: \"%c%c\" is not a valid ISO 3166 code".formatted(char1, char2)); } return mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')]; } @@ -710,8 +710,8 @@ private static int getMainTableEntry(char char1, char char2) { */ private static void setMainTableEntry(char char1, char char2, int entry) { if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') { - throw new IllegalArgumentException("The country code is not a " + - "valid ISO 3166 code"); + throw new IllegalArgumentException( + "The country code: \"%c%c\" is not a valid ISO 3166 code".formatted(char1, char2)); } mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')] = entry; } diff --git a/test/jdk/java/util/Currency/CurrencyTest.java b/test/jdk/java/util/Currency/CurrencyTest.java index c8dfb5013bd52..7e4155eb65c57 100644 --- a/test/jdk/java/util/Currency/CurrencyTest.java +++ b/test/jdk/java/util/Currency/CurrencyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531 * 6488442 7036905 8008577 8039317 8074350 8074351 8150324 8167143 - * 8264792 8334653 + * 8264792 8334653 8353713 * @summary Basic tests for Currency class. * @modules java.base/java.util:open * jdk.localedata @@ -84,14 +84,24 @@ private static Stream validCurrencies() { public void invalidCurrencyTest(String currencyCode) { IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> Currency.getInstance(currencyCode), "getInstance() did not throw IAE"); - assertEquals("The input currency code is not a" + - " valid ISO 4217 code", ex.getMessage()); + assertEquals("The input currency code: \"%s\" is not a valid ISO 4217 code" + .formatted(currencyCode), ex.getMessage()); } private static Stream non4217Currencies() { return Stream.of("AQD", "US$"); } + // Provide 3 length code, but first 2 chars should not be able to index + // the main table, thus resulting as incorrect country code + @Test + void invalidCountryInCodeTest() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + Currency.getInstance("..A"), "getInstance() did not throw IAE"); + assertEquals("The country code: \"%s\" is not a valid ISO 3166 code" + .formatted(".."), ex.getMessage()); + } + // Calling getInstance() with a currency code not 3 characters long should throw // an IAE @ParameterizedTest @@ -99,8 +109,8 @@ private static Stream non4217Currencies() { public void invalidCurrencyLengthTest(String currencyCode) { IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> Currency.getInstance(currencyCode), "getInstance() did not throw IAE"); - assertEquals("The input currency code must have a length of 3" + - " characters", ex.getMessage()); + assertEquals("The input currency code: \"%s\" must have a length of 3 characters" + .formatted(currencyCode), ex.getMessage()); } private static Stream invalidLengthCurrencies() { @@ -163,8 +173,8 @@ public void localeMappingTest() { "AC|CP|DG|EA|EU|FX|IC|SU|TA|UK")) { // exceptional reservation codes IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> Currency.getInstance(locale), "Did not throw IAE"); - assertEquals("The country of the input locale is not a" + - " valid ISO 3166 country code", ex.getMessage()); + assertEquals("The country of the input locale: \"%s\" is not a valid ISO 3166 country code" + .formatted(locale), ex.getMessage()); } else { goodCountries++; Currency currency = Currency.getInstance(locale); @@ -180,13 +190,15 @@ public void localeMappingTest() { } } - // Check an invalid country code + // Check an invalid country code supplied via the region override @Test - public void invalidCountryTest() { + public void invalidCountryRegionOverrideTest() { + // Override US with nonsensical country + var loc = Locale.forLanguageTag("en-US-u-rg-XXzzzz"); IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, - ()-> Currency.getInstance(Locale.of("", "EU")), "Did not throw IAE"); - assertEquals("The country of the input locale is not a valid" + - " ISO 3166 country code", ex.getMessage()); + ()-> Currency.getInstance(loc), "Did not throw IAE"); + assertEquals("The country of the input locale: \"%s\" is not a valid ISO 3166 country code" + .formatted(loc), ex.getMessage()); } // Ensure a selection of countries have the expected currency From 689d73a30d0701693ad86be164e4406effa11f2e Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Tue, 8 Apr 2025 17:39:59 +0000 Subject: [PATCH 0466/1101] 8317012: Explicitly check for 32-bit word size for using libatomic with zero Reviewed-by: erikj, shade --- make/autoconf/libraries.m4 | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4 index b946be97d96ac..bf697928f1bb8 100644 --- a/make/autoconf/libraries.m4 +++ b/make/autoconf/libraries.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -98,13 +98,7 @@ AC_DEFUN([LIB_SETUP_JVM_LIBS], # 32-bit platforms needs fallback library for 8-byte atomic ops on Zero if HOTSPOT_CHECK_JVM_VARIANT(zero); then if test "x$OPENJDK_$1_OS" = xlinux && - (test "x$OPENJDK_$1_CPU" = xarm || - test "x$OPENJDK_$1_CPU" = xm68k || - test "x$OPENJDK_$1_CPU" = xmips || - test "x$OPENJDK_$1_CPU" = xmipsel || - test "x$OPENJDK_$1_CPU" = xppc || - test "x$OPENJDK_$1_CPU" = xsh || - test "x$OPENJDK_$1_CPU" = xriscv32); then + test "x$OPENJDK_TARGET_CPU_BITS" = "x32"; then BASIC_JVM_LIBS_$1="$BASIC_JVM_LIBS_$1 -latomic" fi fi From 257f817c7fca1e8cdb0fec0e18ab9c07b19b1d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Tue, 8 Apr 2025 18:41:10 +0000 Subject: [PATCH 0467/1101] 8353431: JFR: Sets to use hashmap instead of binary search as backend Reviewed-by: egahlin --- .../checkpoint/objectSampleCheckpoint.cpp | 84 +++++++++--- .../checkpoint/objectSampleCheckpoint.hpp | 1 + .../recorder/checkpoint/types/jfrTypeSet.cpp | 3 - .../checkpoint/types/jfrTypeSetUtils.cpp | 11 +- .../jfr/recorder/stacktrace/jfrStackTrace.hpp | 3 +- .../stacktrace/jfrStackTraceRepository.cpp | 38 +----- .../stacktrace/jfrStackTraceRepository.hpp | 8 +- .../jfrStackTraceRepository.inline.hpp | 42 ++++++ .../jfr/support/jfrDeprecationManager.cpp | 1 - .../share/jfr/support/jfrKlassUnloading.cpp | 58 ++++----- .../share/jfr/support/jfrKlassUnloading.hpp | 3 +- src/hotspot/share/jfr/utilities/jfrSet.hpp | 123 ++++++++++++++++++ 12 files changed, 265 insertions(+), 110 deletions(-) create mode 100644 src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.inline.hpp create mode 100644 src/hotspot/share/jfr/utilities/jfrSet.hpp diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp index bd3ab03045f32..5ce2723391adb 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp @@ -34,12 +34,12 @@ #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" -#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" +#include "jfr/recorder/stacktrace/jfrStackTraceRepository.inline.hpp" #include "jfr/recorder/storage/jfrReferenceCountedStorage.hpp" #include "jfr/support/jfrKlassUnloading.hpp" #include "jfr/support/jfrMethodLookup.hpp" #include "jfr/utilities/jfrHashtable.hpp" -#include "jfr/utilities/jfrPredicate.hpp" +#include "jfr/utilities/jfrSet.hpp" #include "jfr/utilities/jfrRelation.hpp" #include "memory/resourceArea.inline.hpp" #include "oops/instanceKlass.inline.hpp" @@ -48,14 +48,13 @@ #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" -const int initial_array_size = 64; +const unsigned int initial_size = 431; -template -static GrowableArray* c_heap_allocate_array(int size = initial_array_size) { - return new (mtTracing) GrowableArray(size, mtTracing); +static JfrCHeapTraceIdSet* c_heap_allocate_set(int size = initial_size) { + return new JfrCHeapTraceIdSet(size); } -static GrowableArray* unloaded_thread_id_set = nullptr; +static JfrCHeapTraceIdSet* unloaded_thread_id_set = nullptr; class ThreadIdExclusiveAccess : public StackObj { private: @@ -73,15 +72,15 @@ static bool has_thread_exited(traceid tid) { return false; } ThreadIdExclusiveAccess lock; - return JfrPredicate::test(unloaded_thread_id_set, tid); + return unloaded_thread_id_set->contains(tid); } static void add_to_unloaded_thread_set(traceid tid) { ThreadIdExclusiveAccess lock; if (unloaded_thread_id_set == nullptr) { - unloaded_thread_id_set = c_heap_allocate_array(); + unloaded_thread_id_set = c_heap_allocate_set(); } - JfrMutablePredicate::test(unloaded_thread_id_set, tid); + unloaded_thread_id_set->add(tid); } void ObjectSampleCheckpoint::on_thread_exit(traceid tid) { @@ -194,10 +193,10 @@ inline void BlobCache::on_unlink(BlobEntry* entry) const { assert(entry != nullptr, "invariant"); } -static GrowableArray* id_set = nullptr; +static JfrResourceAreaTraceIdSet* id_set = nullptr; static void prepare_for_resolution() { - id_set = new GrowableArray(JfrOptionSet::old_object_queue_size()); + id_set = new JfrResourceAreaTraceIdSet(initial_size); } static bool stack_trace_precondition(const ObjectSample* sample) { @@ -267,7 +266,6 @@ static void install_stack_traces(const ObjectSampler* sampler) { assert(last != nullptr, "invariant"); assert(last != sampler->last_resolved(), "invariant"); ResourceMark rm; - JfrKlassUnloading::sort(); StackTraceBlobInstaller installer; iterate_samples(installer); } @@ -317,7 +315,7 @@ static bool is_klass_unloaded(traceid klass_id) { static bool is_processed(traceid method_id) { assert(method_id != 0, "invariant"); assert(id_set != nullptr, "invariant"); - return JfrMutablePredicate::test(id_set, method_id); + return !id_set->add(method_id); } void ObjectSampleCheckpoint::add_to_leakp_set(const InstanceKlass* ik, traceid method_id) { @@ -362,17 +360,57 @@ static void write_thread_blob(const ObjectSample* sample, JfrCheckpointWriter& w } } -static GrowableArray* _stacktrace_ids = nullptr; +static JfrResourceAreaTraceIdSet* _stacktrace_id_set = nullptr; + +static inline bool should_write(const JfrStackTrace* stacktrace) { + assert(stacktrace != nullptr, "invariant"); + assert(_stacktrace_id_set != nullptr, "invariant"); + return stacktrace->should_write() && _stacktrace_id_set->contains(stacktrace->id()); +} + +class LeakProfilerStackTraceWriter { + private: + JfrCheckpointWriter& _writer; + int _count; + public: + LeakProfilerStackTraceWriter(JfrCheckpointWriter& writer) : _writer(writer), _count(0) { + assert(_stacktrace_id_set != nullptr, "invariant"); + } + + int count() const { return _count; } + + void operator()(const JfrStackTrace* stacktrace) { + if (should_write(stacktrace)) { + stacktrace->write(_writer); + ++_count; + } + } +}; + +void ObjectSampleCheckpoint::write_stacktraces(Thread* thread) { + assert(_stacktrace_id_set != nullptr, "invariant"); + assert(_stacktrace_id_set->is_nonempty(), "invariant"); + + JfrCheckpointWriter writer(thread); + writer.write_type(TYPE_STACKTRACE); + const int64_t count_offset = writer.reserve(sizeof(u4)); // Don't know how many yet + + LeakProfilerStackTraceWriter lpstw(writer); + JfrStackTraceRepository::iterate_leakprofiler(lpstw); + assert(lpstw.count() == _stacktrace_id_set->size(), "invariant"); + writer.write_count(lpstw.count(), count_offset); +} static void write_stacktrace_blob(const ObjectSample* sample, JfrCheckpointWriter& writer) { - assert(_stacktrace_ids != nullptr, "invariant"); + assert(sample != nullptr, "invariant"); + assert(_stacktrace_id_set != nullptr, "invariant"); if (sample->has_stacktrace()) { write_blob(sample->stacktrace(), writer); return; } const traceid stacktrace_id = sample->stack_trace_id(); if (stacktrace_id != 0) { - _stacktrace_ids->append(stacktrace_id); + _stacktrace_id_set->add(stacktrace_id); } } @@ -406,17 +444,21 @@ static void write_sample_blobs(const ObjectSampler* sampler, bool emit_all, Thre iterate_samples(cbw, true); } +static inline unsigned int set_size() { + const unsigned int queue_size = static_cast(JfrOptionSet::old_object_queue_size()); + return queue_size > initial_size ? queue_size : initial_size; +} + void ObjectSampleCheckpoint::write(const ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread) { assert(sampler != nullptr, "invariant"); assert(edge_store != nullptr, "invariant"); assert(thread != nullptr, "invariant"); { ResourceMark rm(thread); - _stacktrace_ids = new GrowableArray(JfrOptionSet::old_object_queue_size()); + _stacktrace_id_set = new JfrResourceAreaTraceIdSet(set_size()); write_sample_blobs(sampler, emit_all, thread); - if (_stacktrace_ids->is_nonempty()) { - _stacktrace_ids->sort(sort_traceid); - JfrStackTraceRepository::write_leak_profiler(_stacktrace_ids, thread); + if (_stacktrace_id_set->is_nonempty()) { + write_stacktraces(thread); } } // write reference chains diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp index bf1965b13b508..2ab2e12302ff3 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp @@ -47,6 +47,7 @@ class ObjectSampleCheckpoint : AllStatic { static void add_to_leakp_set(const InstanceKlass* ik, traceid method_id); static int save_mark_words(const ObjectSampler* sampler, ObjectSampleMarker& marker, bool emit_all); static void write_stacktrace(const JfrStackTrace* trace, JfrCheckpointWriter& writer); + static void write_stacktraces(Thread* thread); static void write(const ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread); static void clear(); public: diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index b9dcd7a3694e5..a1b10e8cfb873 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -1225,9 +1225,6 @@ static void setup(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer } else { _artifacts->initialize(class_unload); } - if (!_class_unload) { - JfrKlassUnloading::sort(previous_epoch()); - } assert(_artifacts != nullptr, "invariant"); assert(!_artifacts->has_klass_entries(), "invariant"); } diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp index 5e70fdcb941d6..d213ecd7d75fe 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp @@ -37,7 +37,7 @@ JfrArtifactSet::JfrArtifactSet(bool class_unload) : _symbol_table(nullptr), assert(_klass_list != nullptr, "invariant"); } -static const size_t initial_klass_list_size = 256; +static const size_t initial_klass_list_size = 4096; const int initial_klass_loader_set_size = 64; void JfrArtifactSet::initialize(bool class_unload) { @@ -49,10 +49,10 @@ void JfrArtifactSet::initialize(bool class_unload) { assert(_symbol_table != nullptr, "invariant"); _symbol_table->set_class_unload(class_unload); _total_count = 0; - // resource allocation - _klass_list = new GrowableArray(initial_klass_list_size); - _klass_loader_set = new GrowableArray(initial_klass_loader_set_size); + // Resource allocations. Keep in this allocation order. _klass_loader_leakp_set = new GrowableArray(initial_klass_loader_set_size); + _klass_loader_set = new GrowableArray(initial_klass_loader_set_size); + _klass_list = new GrowableArray(initial_klass_list_size); } void JfrArtifactSet::clear() { @@ -63,7 +63,8 @@ void JfrArtifactSet::clear() { JfrArtifactSet::~JfrArtifactSet() { delete _symbol_table; - // _klass_list and _klass_loader_list will be cleared by a ResourceMark + // _klass_loader_set, _klass_loader_leakp_set and + // _klass_list will be cleared by a ResourceMark } traceid JfrArtifactSet::bootstrap_name(bool leakp) { diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.hpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.hpp index 6a7b750752c39..101dae21681ff 100644 --- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.hpp +++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,6 +64,7 @@ class JfrStackFrame { class JfrStackTrace : public JfrCHeapObj { friend class JfrNativeSamplerCallback; friend class JfrStackTraceRepository; + friend class LeakProfilerStackTraceWriter; friend class ObjectSampleCheckpoint; friend class ObjectSampler; friend class OSThreadSampler; diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp index b75ac95e27fd1..99d26c4689edd 100644 --- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp +++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp @@ -27,10 +27,7 @@ #include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" #include "jfr/support/jfrThreadLocal.hpp" -#include "jfr/utilities/jfrPredicate.hpp" -#include "jfr/utilities/jfrRelation.hpp" #include "runtime/mutexLocker.hpp" -#include "utilities/growableArray.hpp" /* * There are two separate repository instances. @@ -48,7 +45,7 @@ JfrStackTraceRepository& JfrStackTraceRepository::instance() { return *_instance; } -static JfrStackTraceRepository& leak_profiler_instance() { +JfrStackTraceRepository& JfrStackTraceRepository::leak_profiler_instance() { assert(_leak_profiler_instance != nullptr, "invariant"); return *_leak_profiler_instance; } @@ -245,36 +242,3 @@ traceid JfrStackTraceRepository::next_id() { MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag); return ++_next_id; } - -static inline bool should_write(const JfrStackTrace* stacktrace, GrowableArray* leakp_set) { - assert(stacktrace != nullptr, "invariant"); - return stacktrace->should_write() && JfrPredicate::test(leakp_set, stacktrace->id()); -} - -void JfrStackTraceRepository::write_leak_profiler(GrowableArray* leakp_set, Thread* t) { - assert(leakp_set != nullptr, "invariant"); - assert(leakp_set->is_nonempty(), "invariant"); - assert(t != nullptr, "invariant"); - - JfrCheckpointWriter writer(t); - writer.write_type(TYPE_STACKTRACE); - const int64_t count_offset = writer.reserve(sizeof(u4)); // Don't know how many yet - - int count = 0; - const JfrStackTraceRepository& repo = leak_profiler_instance(); - - for (u4 i = 0; i < TABLE_SIZE; ++i) { - const JfrStackTrace* stacktrace = repo._table[i]; - while (stacktrace != nullptr) { - if (should_write(stacktrace, leakp_set)) { - stacktrace->write(writer); - ++count; - } - stacktrace = stacktrace->next(); - } - } - - assert(count > 0, "invariant"); - assert(count <= leakp_set->length(), "invariant"); - writer.write_count(count, count_offset); -} diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp index 427aff0eb9ab7..5aa382944e25f 100644 --- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp +++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp @@ -32,9 +32,6 @@ class JavaThread; class JfrChunkWriter; -template -class GrowableArray; - class JfrStackTraceRepository : public JfrCHeapObj { friend class JfrDeprecatedEdge; friend class JfrRecorder; @@ -54,6 +51,7 @@ class JfrStackTraceRepository : public JfrCHeapObj { JfrStackTraceRepository(); static JfrStackTraceRepository& instance(); + static JfrStackTraceRepository& leak_profiler_instance(); static JfrStackTraceRepository* create(); static void destroy(); bool initialize(); @@ -64,9 +62,11 @@ class JfrStackTraceRepository : public JfrCHeapObj { static const JfrStackTrace* lookup_for_leak_profiler(traceid hash, traceid id); static void record_for_leak_profiler(JavaThread* thread, int skip = 0); - static void write_leak_profiler(GrowableArray* leakp_set, Thread* t); static void clear_leak_profiler(); + template + static void iterate_leakprofiler(Callback& cb); + static traceid next_id(); traceid add_trace(const JfrStackTrace& stacktrace); diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.inline.hpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.inline.hpp new file mode 100644 index 0000000000000..5b30216ecca76 --- /dev/null +++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.inline.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_JFR_RECORDER_STACKTRACE_JFRSTACKTRACEREPOSITORY_INLINE_HPP +#define SHARE_JFR_RECORDER_STACKTRACE_JFRSTACKTRACEREPOSITORY_INLINE_HPP + +#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" + +template +inline void JfrStackTraceRepository::iterate_leakprofiler(Callback& cb) { + JfrStackTraceRepository& repo = leak_profiler_instance(); + for (u4 i = 0; i < TABLE_SIZE; ++i) { + const JfrStackTrace* stacktrace = repo._table[i]; + while (stacktrace != nullptr) { + cb(stacktrace); + stacktrace = stacktrace->next(); + } + } +} + +#endif // SHARE_JFR_RECORDER_STACKTRACE_JFRSTACKTRACEREPOSITORY_INLINE_HPP diff --git a/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp b/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp index ef1f25c84b308..4eb8662c2091b 100644 --- a/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp +++ b/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp @@ -354,7 +354,6 @@ static void reset_type_set_blobs() { void JfrDeprecationManager::prepare_type_set(JavaThread* jt) { reset_type_set_blobs(); if (_pending_list.is_nonempty()) { - JfrKlassUnloading::sort(true); JfrCheckpointWriter writer(true /* prev epoch */, jt, false /* header */); PendingListProcessor plp(writer, jt); _pending_list.iterate(plp); diff --git a/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp b/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp index 31eb83e16674a..ce5de54ed1644 100644 --- a/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp +++ b/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp @@ -26,56 +26,48 @@ #include "jfr/periodic/jfrFinalizerStatisticsEvent.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" #include "jfr/support/jfrKlassUnloading.hpp" -#include "jfr/utilities/jfrPredicate.hpp" -#include "jfr/utilities/jfrRelation.hpp" +#include "jfr/utilities/jfrSet.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/macros.hpp" -static const int initial_array_size = 64; +static const int initial_size = 1009; -template -static GrowableArray* c_heap_allocate_array(int size = initial_array_size) { - return new (mtTracing) GrowableArray(size, mtTracing); +static JfrCHeapTraceIdSet* c_heap_allocate_set(int size = initial_size) { + return new JfrCHeapTraceIdSet(size); } // Track the set of unloaded klasses during a chunk / epoch. -static GrowableArray* _unload_set_epoch_0 = nullptr; -static GrowableArray* _unload_set_epoch_1 = nullptr; +static JfrCHeapTraceIdSet* _unload_set_epoch_0 = nullptr; +static JfrCHeapTraceIdSet* _unload_set_epoch_1 = nullptr; static s8 event_klass_unloaded_count = 0; -static GrowableArray* unload_set_epoch_0() { +static JfrCHeapTraceIdSet* unload_set_epoch_0() { if (_unload_set_epoch_0 == nullptr) { - _unload_set_epoch_0 = c_heap_allocate_array(initial_array_size); + _unload_set_epoch_0 = c_heap_allocate_set(); } return _unload_set_epoch_0; } -static GrowableArray* unload_set_epoch_1() { +static JfrCHeapTraceIdSet* unload_set_epoch_1() { if (_unload_set_epoch_1 == nullptr) { - _unload_set_epoch_1 = c_heap_allocate_array(initial_array_size); + _unload_set_epoch_1 = c_heap_allocate_set(); } return _unload_set_epoch_1; } -static GrowableArray* get_unload_set(u1 epoch) { +static JfrCHeapTraceIdSet* get_unload_set(u1 epoch) { return epoch == 0 ? unload_set_epoch_0() : unload_set_epoch_1(); } -static GrowableArray* get_unload_set() { +static JfrCHeapTraceIdSet* get_unload_set() { return get_unload_set(JfrTraceIdEpoch::current()); } -static GrowableArray* get_unload_set_previous_epoch() { +static JfrCHeapTraceIdSet* get_unload_set_previous_epoch() { return get_unload_set(JfrTraceIdEpoch::previous()); } -static void sort_set(GrowableArray* set) { - assert(set != nullptr, "invariant"); - assert(set->is_nonempty(), "invariant"); - set->sort(sort_traceid); -} - static bool is_nonempty_set(u1 epoch) { if (epoch == 0) { return _unload_set_epoch_0 != nullptr && _unload_set_epoch_0->is_nonempty(); @@ -83,16 +75,6 @@ static bool is_nonempty_set(u1 epoch) { return _unload_set_epoch_1 != nullptr && _unload_set_epoch_1->is_nonempty(); } -void JfrKlassUnloading::sort(bool previous_epoch) { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - if (is_nonempty_set(JfrTraceIdEpoch::current())) { - sort_set(get_unload_set()); - } - if (previous_epoch && is_nonempty_set(JfrTraceIdEpoch::previous())) { - sort_set(get_unload_set_previous_epoch()); - } -} - void JfrKlassUnloading::clear() { assert_locked_or_safepoint(ClassLoaderDataGraph_lock); if (is_nonempty_set(JfrTraceIdEpoch::previous())) { @@ -102,10 +84,9 @@ void JfrKlassUnloading::clear() { static void add_to_unloaded_klass_set(traceid klass_id) { assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - GrowableArray* const unload_set = get_unload_set(); + JfrCHeapTraceIdSet* const unload_set = get_unload_set(); assert(unload_set != nullptr, "invariant"); - assert(unload_set->find(klass_id) == -1, "invariant"); - unload_set->append(klass_id); + unload_set->add(klass_id); } #if INCLUDE_MANAGEMENT @@ -131,14 +112,19 @@ bool JfrKlassUnloading::on_unload(const Klass* k) { return USED_THIS_EPOCH(k); } +static inline bool is_unloaded(const JfrCHeapTraceIdSet* set, const traceid& id) { + assert(set != nullptr, "invariant"); + return set->contains(id); +} + bool JfrKlassUnloading::is_unloaded(traceid klass_id, bool previous_epoch /* false */) { assert_locked_or_safepoint(ClassLoaderDataGraph_lock); if (previous_epoch) { - if (JfrPredicate::test(get_unload_set_previous_epoch(), klass_id)) { + if (::is_unloaded(get_unload_set_previous_epoch(), klass_id)) { return true; } } - return JfrPredicate::test(get_unload_set(), klass_id); + return ::is_unloaded(get_unload_set(), klass_id); } int64_t JfrKlassUnloading::event_class_count() { diff --git a/src/hotspot/share/jfr/support/jfrKlassUnloading.hpp b/src/hotspot/share/jfr/support/jfrKlassUnloading.hpp index 5d380df436cd8..25ff820fc095b 100644 --- a/src/hotspot/share/jfr/support/jfrKlassUnloading.hpp +++ b/src/hotspot/share/jfr/support/jfrKlassUnloading.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,6 @@ class JfrKlassUnloading : AllStatic { static bool on_unload(const Klass* k); static int64_t event_class_count(); static bool is_unloaded(traceid klass_id, bool previous_epoch = false); - static void sort(bool previous_epoch = false); static void clear(); }; diff --git a/src/hotspot/share/jfr/utilities/jfrSet.hpp b/src/hotspot/share/jfr/utilities/jfrSet.hpp new file mode 100644 index 0000000000000..b4dfc4f6240e1 --- /dev/null +++ b/src/hotspot/share/jfr/utilities/jfrSet.hpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_JFR_UTILITIES_JFRSET_HPP +#define SHARE_JFR_UTILITIES_JFRSET_HPP + +#include "jfr/utilities/jfrAllocation.hpp" +#include "jfr/utilities/jfrTypes.hpp" +#include "utilities/resizeableResourceHash.hpp" + +template +class ConfigTraceID : public AllStatic { + public: + typedef AllocPolicy STORAGE; + typedef traceid TYPE; + + constexpr static AnyObj::allocation_type alloc_type() { + return AllocType; + } + + constexpr static MemTag memory_tag() { + return memtag; + } + + // Knuth multiplicative hashing. + static uint32_t hash(const TYPE& id) { + const uint32_t v = static_cast(id); + return v * UINT32_C(2654435761); + } + + static bool cmp(const TYPE& lhs, const TYPE& rhs) { + return lhs == rhs; + } +}; + +constexpr static unsigned int MAX_TABLE_SIZE = 0x3fffffff; + +template +class JfrSet : public CONFIG::STORAGE { + public: + typedef typename CONFIG::TYPE TYPE; + typedef ResizeableResourceHashtable HashMap; + + constexpr static bool is_cheap() { + return CONFIG::alloc_type() == AnyObj::C_HEAP; + } + + JfrSet(unsigned int initial_size, unsigned int max_size = MAX_TABLE_SIZE) : + _map(is_cheap() ? new (CONFIG::memory_tag()) HashMap(initial_size, max_size) : new HashMap(initial_size, max_size)) {} + + ~JfrSet() { + if (is_cheap()) { + delete _map; + } + } + + bool add(const TYPE& k) { + bool inserted; + _map->put_if_absent(k, &inserted); + return inserted; + } + + bool remove(const TYPE& k) { + return _map->remove(k); + } + + bool contains(const TYPE& k) const { + return _map->contains(k); + } + + bool is_empty() const { + return _map->number_of_entries() == 0; + } + + bool is_nonempty() const { + return !is_empty(); + } + + int size() const { + return _map->number_of_entries(); + } + + void clear() { + if (is_nonempty()) { + _map->unlink(this); + } + assert(is_empty(), "invariant"); + } + + // Callback for node deletion, used by clear(). + bool do_entry(const TYPE& k, const TYPE& v) { + return true; + } + + private: + HashMap* _map; +}; + +typedef JfrSet > JfrCHeapTraceIdSet; +typedef JfrSet > JfrResourceAreaTraceIdSet; + +#endif // SHARE_JFR_UTILITIES_JFRSET_HPP From 24ff96afe41b62275fe8635e477ecc04bff93123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Tue, 8 Apr 2025 18:45:53 +0000 Subject: [PATCH 0468/1101] 8352389: Remove incidental whitespace in pre/code content Reviewed-by: liach --- .../tools/javac/parser/DocCommentParser.java | 129 ++++++++++++++ .../formats/html/resources/stylesheet.css | 2 +- .../TestLiteralCodeInPre.java | 11 +- .../doclet/testPreCode/TestPreCode.java | 165 ++++++++++++++++++ .../tools/javac/doctree/CodeTest.java | 4 +- .../tools/javac/doctree/DocCommentTester.java | 4 +- .../tools/javac/doctree/InPreTest.java | 46 ++++- 7 files changed, 349 insertions(+), 12 deletions(-) create mode 100644 test/langtools/jdk/javadoc/doclet/testPreCode/TestPreCode.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java index 017c39b3c54bb..cf545a8f52033 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java @@ -34,8 +34,12 @@ import com.sun.source.doctree.AttributeTree.ValueKind; import com.sun.source.doctree.DocTree; import com.sun.source.doctree.ErroneousTree; +import com.sun.source.doctree.LiteralTree; +import com.sun.source.doctree.StartElementTree; +import com.sun.source.doctree.TextTree; import com.sun.source.doctree.UnknownBlockTagTree; import com.sun.source.doctree.UnknownInlineTagTree; +import com.sun.source.util.SimpleDocTreeVisitor; import com.sun.tools.javac.parser.Tokens.Comment; import com.sun.tools.javac.tree.DCTree; import com.sun.tools.javac.tree.DCTree.DCAttribute; @@ -126,6 +130,9 @@ private enum Phase { private int lastNonWhite = -1; private boolean newline = true; + /** Used for whitespace normalization in pre/code/literal tags. */ + private boolean inPre = false; + private final Map tagParsers; /** @@ -281,6 +288,7 @@ protected List blockContent() { */ protected List content(Phase phase) { ListBuffer trees = new ListBuffer<>(); + ListBuffer mainTrees = null; textStart = -1; int depth = 1; // only used when phase is INLINE @@ -349,6 +357,18 @@ protected List content(Phase phase) { addPendingText(trees, bp - 1); trees.add(html()); + // Create new list for

 content which is merged into main list when element is closed.
+                            if (inPre) {
+                                if (mainTrees == null) {
+                                    mainTrees = trees;
+                                    trees = new ListBuffer<>();
+                                }
+                            } else if (mainTrees != null) {
+                                mainTrees.addAll(normalizePreContent(trees));
+                                trees = mainTrees;
+                                mainTrees = null;
+                            }
+
                             if (phase == Phase.PREAMBLE || phase == Phase.POSTAMBLE) {
                                 break; // Ignore newlines after html tags, in the meta content
                             }
@@ -476,6 +496,13 @@ protected List content(Phase phase) {
         if (lastNonWhite != -1)
             addPendingText(trees, lastNonWhite);
 
+        // Happens with unclosed 
 element. Add content without normalizing.
+        if (mainTrees != null) {
+            mainTrees.addAll(trees);
+            trees = mainTrees;
+            mainTrees = null;
+        }
+
         return (phase == Phase.INLINE)
                 ? List.of(erroneous("dc.unterminated.inline.tag", pos))
                 : trees.toList();
@@ -1054,6 +1081,9 @@ private DCTree html() {
                 }
                 if (ch == '>') {
                     nextChar();
+                    if ("pre".equalsIgnoreCase(name.toString())) {
+                        inPre = true;
+                    }
                     return m.at(p).newStartElementTree(name, attrs, selfClosing).setEndPos(bp);
                 }
             }
@@ -1064,6 +1094,9 @@ private DCTree html() {
                 skipWhitespace();
                 if (ch == '>') {
                     nextChar();
+                    if ("pre".equalsIgnoreCase(name.toString())) {
+                        inPre = false;
+                    }
                     return m.at(p).newEndElementTree(name).setEndPos(bp);
                 }
             }
@@ -1186,6 +1219,102 @@ protected List htmlAttrs() {
         return attrs.toList();
     }
 
+    /*
+     * Removes a newline character following a , {@code or {@literal tag at the
+     * beginning of 
 element content, as well as any space/tabs between the pre
+     * and code tags. The operation is only performed on traditional doc comments.
+     * If conditions are not met the list is returned unchanged.
+     */
+    ListBuffer normalizePreContent(ListBuffer trees) {
+        // Do nothing if comment is not eligible for whitespace normalization.
+        if (textKind == DocTree.Kind.MARKDOWN || isHtmlFile) {
+            return trees;
+        }
+
+        enum State {
+            BEFORE_CODE, // at beginning of 
 content, or after leading horizontal whitespace
+            AFTER_CODE,  // after  start tag (not used for {@code} tag)
+            SUCCEEDED,   // normalization succeeded, add remaining trees
+            FAILED;      // normalization failed, return original trees
+        }
+
+        class Context {
+            State state = State.BEFORE_CODE;
+
+            // Called when an unexpected tree is encountered. Set state to
+            // FAILED unless normalization already terminated successfully.
+            void unexpectedTree() {
+                if (state != State.SUCCEEDED) {
+                    state = State.FAILED;
+                }
+            }
+        }
+
+        var visitor = new SimpleDocTreeVisitor() {
+            @Override
+            public DCTree visitText(TextTree text, Context cx) {
+                if (cx.state == State.BEFORE_CODE && text.getBody().matches("[ \t]+")) {
+                    // 
  ...
+                    return null;
+                } else if (cx.state == State.AFTER_CODE && text.getBody().startsWith("\n")) {
+                    // 
\n...
+                    cx.state = State.SUCCEEDED;
+                    return m.at(((DCText) text).pos + 1).newTextTree(text.getBody().substring(1));
+                }
+                cx.unexpectedTree();
+                return (DCTree) text;
+            }
+
+            @Override
+            public DCTree visitLiteral(LiteralTree literal, Context cx) {
+                if (cx.state == State.BEFORE_CODE && literal.getBody().getBody().startsWith("\n")) {
+                    // 
{@code\n...
+                    cx.state = State.SUCCEEDED;
+                    DCText oldBody = (DCText) literal.getBody();
+                    DCText newBody = m.at(oldBody.pos + 1).newTextTree(oldBody.getBody().substring(1));
+                    m.at(((DCTree) literal).pos);
+                    return literal.getKind() == DocTree.Kind.CODE
+                            ? m.newCodeTree(newBody)
+                            : m.newLiteralTree(newBody);
+                }
+                cx.unexpectedTree();
+                return (DCTree) literal;
+            }
+
+            @Override
+            public DCTree visitStartElement(StartElementTree node, Context cx) {
+                if (cx.state == State.BEFORE_CODE && node.getName().toString().equalsIgnoreCase("code")) {
+                    cx.state = State.AFTER_CODE;
+                } else {
+                    cx.unexpectedTree();
+                }
+                return (DCTree) node;
+            }
+
+            @Override
+            protected DCTree defaultAction(DocTree node, Context cx) {
+                cx.unexpectedTree();
+                return (DCTree) node;
+            }
+        };
+
+        Context cx = new Context();
+        var normalized = new ListBuffer();
+
+        for (var tree : trees) {
+            var visited = visitor.visit(tree, cx);
+            // null return value means the tree should be dropped
+            if (visited != null) {
+                normalized.add(visited);
+            }
+            if (cx.state == State.FAILED) {
+                return trees;
+            }
+        }
+
+        return cx.state == State.SUCCEEDED ? normalized : trees;
+    }
+
     protected void attrValueChar(ListBuffer list) {
         switch (ch) {
             case '&' -> entity(list);
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css
index ac393e8a7620b..54c7c5cbe219c 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css
@@ -133,7 +133,7 @@ pre {
     line-height: var(--code-line-height);
     background-color: var(--pre-background-color);
     color: var(--pre-text-color);
-    padding: 8px;
+    padding: 10px;
     overflow-x:auto;
 }
 h1 {
diff --git a/test/langtools/jdk/javadoc/doclet/testLiteralCodeInPre/TestLiteralCodeInPre.java b/test/langtools/jdk/javadoc/doclet/testLiteralCodeInPre/TestLiteralCodeInPre.java
index ac5259686f165..1a96da79fb326 100644
--- a/test/langtools/jdk/javadoc/doclet/testLiteralCodeInPre/TestLiteralCodeInPre.java
+++ b/test/langtools/jdk/javadoc/doclet/testLiteralCodeInPre/TestLiteralCodeInPre.java
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug      8002387 8014636 8078320 8175200 8186332 8352249
+ * @bug      8002387 8014636 8078320 8175200 8186332 8352249 8352389
  * @summary  Improve rendered HTML formatting for {@code}
  * @library  ../../lib
  * @modules jdk.javadoc/jdk.javadoc.internal.tool
@@ -70,8 +70,7 @@ public void test() {
                 """
                     typical_usage_code()
                     
Lorem ipsum dolor sit amet, consectetur adipiscing elit. - Example:

-                      line 0 @Override
+                    Example:  
  line 0 @Override
                       line 1 <T> void m(T t) {
                       line 2     // do something with T
                       line 3 }
@@ -80,8 +79,7 @@ public void test() {
                 """
                     typical_usage_literal()
Lorem ipsum dolor sit amet, consectetur adipiscing elit. - Example:
-                      line 0 @Override
+                    Example:  
  line 0 @Override
                       line 1 <T> void m(T t) {
                       line 2     // do something with T
                       line 3 }
@@ -90,8 +88,7 @@ public void test() {
                 """
                     recommended_usage_literal()
Lorem ipsum dolor sit amet, consectetur adipiscing elit. - Example:
-                      line 0 @Override
+                    Example:  
  line 0 @Override
                       line 1 <T> void m(T t) {
                       line 2     // do something with T
                       line 3 } 
diff --git a/test/langtools/jdk/javadoc/doclet/testPreCode/TestPreCode.java b/test/langtools/jdk/javadoc/doclet/testPreCode/TestPreCode.java new file mode 100644 index 0000000000000..c3614126aae3b --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testPreCode/TestPreCode.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8352389 + * @summary Remove incidental whitespace in pre/code content + * @library /tools/lib ../../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build javadoc.tester.* toolbox.ToolBox builder.ClassBuilder + * @run main TestPreCode + */ + + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +import builder.AbstractBuilder; +import builder.ClassBuilder; +import toolbox.ToolBox; + +import javadoc.tester.JavadocTester; + +public class TestPreCode extends JavadocTester { + + final ToolBox tb; + + public static void main(String... args) throws Exception { + var tester = new TestPreCode(); + tester.runTests(); + } + + TestPreCode() { + tb = new ToolBox(); + } + + @Test + public void testWhitespace(Path base) throws Exception { + Path srcDir = base.resolve("src"); + Path outDir = base.resolve("out"); + + new ClassBuilder(tb, "pkg.A") + .setComments(""" + Class A. +
 \t
+                      first line
+                      second line
+                    
""") + .setModifiers("public", "class") + .addMembers(ClassBuilder.MethodBuilder.parse("public void m0() {}") + .setComments(""" + Method m0. +
 {@code
+                                  first line
+                                  second line
+                                }
"""), + ClassBuilder.MethodBuilder.parse("public void m1() {}") + .setComments(""" + Method m1. +
  first line
+                                  second line
+                                
"""), + ClassBuilder.MethodBuilder.parse("public void m2() {}") + .setComments(""" + Method m2. +
 {@code\s
+                                  first line
+                                  second line
+                                }
"""), + ClassBuilder.MethodBuilder.parse("public void m3() {}") + .setComments(""" + Method m3. +
  .
+                                  second line
+                                
""")) + .write(srcDir); + + javadoc("-d", outDir.toString(), + "-sourcepath", srcDir.toString(), + "pkg"); + + checkExit(Exit.OK); + + checkOrder("pkg/A.html", + """ + Class A. +
  first line
+                      second line
+                    
""", + """ + Method m0. +
  first line
+                      second line
+                    
""", + """ + Method m1. +
  first line
+                      second line
+                    
""", + """ + Method m2. +
  first line
+                      second line
+                    
""", + """ + Method m3. +
  .
+                      second line
+                    
"""); + } + + @Test + public void testUnclosed(Path base) throws Exception { + Path srcDir = base.resolve("src"); + Path outDir = base.resolve("out"); + + new ClassBuilder(tb, "pkg.A") + .setComments(""" + Class A. +

+                      first line
+                      second line
+                    """)
+                .setModifiers("public", "class")
+                .write(srcDir);
+
+        javadoc("-d", outDir.toString(),
+                "-sourcepath", srcDir.toString(),
+                "pkg");
+
+        checkExit(Exit.ERROR);
+
+        // No whitespace normalization for unclosed 
 element
+        checkOrder("pkg/A.html",
+                """
+                    Class A.
+                    

+                      first line
+                      second line
+                    
"""); + } + +} diff --git a/test/langtools/tools/javac/doctree/CodeTest.java b/test/langtools/tools/javac/doctree/CodeTest.java index b77701227155a..7623c41497d2b 100644 --- a/test/langtools/tools/javac/doctree/CodeTest.java +++ b/test/langtools/tools/javac/doctree/CodeTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 8241780 8273244 8284908 8352249 + * @bug 7021614 8241780 8273244 8284908 8352249 8352389 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file @@ -128,7 +128,7 @@ void pre_at_code() { } name:pre attributes: empty ] - Literal[CODE, pos:5, |____@Override|____void_m()_{_}|] + Literal[CODE, pos:5, ____@Override|____void_m()_{_}|] body: 1 EndElement[END_ELEMENT, pos:44, pre] block tags: empty diff --git a/test/langtools/tools/javac/doctree/DocCommentTester.java b/test/langtools/tools/javac/doctree/DocCommentTester.java index 3591fcbca2dc8..1d723a2b62588 100644 --- a/test/langtools/tools/javac/doctree/DocCommentTester.java +++ b/test/langtools/tools/javac/doctree/DocCommentTester.java @@ -1023,7 +1023,9 @@ String normalize(String s, boolean isLineComment) { .replaceFirst("\\.\\s*\\n *@(?![@*])", ".\n@") // Between block tags .replaceAll("\n[ \t]+@(?!([@*]|(dummy|Override)))", "\n@") .replaceAll("(?i)\\{@([a-z][a-z0-9.:-]*)\\s+}", "{@$1}") - .replaceAll("(\\{@value\\s+[^}]+)\\s+(})", "$1$2"); + .replaceAll("(\\{@value\\s+[^}]+)\\s+(})", "$1$2") + .replaceAll("
 *\\{@code\\n", "
{@code ")
+                    .replaceAll("
 *\\n", "
");
         }
     }
 
diff --git a/test/langtools/tools/javac/doctree/InPreTest.java b/test/langtools/tools/javac/doctree/InPreTest.java
index 9203f56a0f215..8f7a705c75a93 100644
--- a/test/langtools/tools/javac/doctree/InPreTest.java
+++ b/test/langtools/tools/javac/doctree/InPreTest.java
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8078320 8273244 8284908 8352249
+ * @bug 8078320 8273244 8284908 8352249 8352389
  * @summary extend com.sun.source API to support parsing javadoc comments
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.file
@@ -163,6 +163,50 @@ public void in_pre_with_nl() { }
     EndElement[END_ELEMENT, pos:26, pre]
   block tags: empty
 ]
+*/
+    /**
+     * 
 {@code
+     * abc  }
+     * def
+ */ + public void in_pre_with_space_at_code_nl() { } +/* +DocComment[DOC_COMMENT, pos:0 + firstSentence: 3 + StartElement[START_ELEMENT, pos:0 + name:pre + attributes: empty + ] + Literal[CODE, pos:6, abc__] + Text[TEXT, pos:19, |def] + body: 1 + EndElement[END_ELEMENT, pos:23, pre] + block tags: empty +] +*/ + /** + *
 
+     *   abc
+     * 
+ */ + public void in_pre_with_space_code_nl() { } +/* +DocComment[DOC_COMMENT, pos:0 + firstSentence: 4 + StartElement[START_ELEMENT, pos:0 + name:pre + attributes: empty + ] + StartElement[START_ELEMENT, pos:6 + name:code + attributes: empty + ] + Text[TEXT, pos:13, __abc|] + EndElement[END_ELEMENT, pos:19, code] + body: 1 + EndElement[END_ELEMENT, pos:26, pre] + block tags: empty +] */ /** * abc {@code From 5b42c46b48363acd00ee4a183edca9a48cdc16c8 Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Tue, 8 Apr 2025 20:04:44 +0000 Subject: [PATCH 0469/1101] 8353757: Log class should have a proper clear() method Reviewed-by: vromero, mcimadamore --- .../com/sun/tools/javac/api/JavacTaskPool.java | 12 +++++------- .../classes/com/sun/tools/javac/util/Log.java | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java index 1ce4cf50ada8a..87bc64c4e1976 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -267,7 +267,7 @@ void clear() { if (ht.get(Log.logKey) instanceof ReusableLog) { //log already inited - not first round - ((ReusableLog)Log.instance(this)).clear(); + Log.instance(this).clear(); Enter.instance(this).newRound(); ((ReusableJavaCompiler)ReusableJavaCompiler.instance(this)).clear(); Types.instance(this).newRound(); @@ -395,11 +395,9 @@ static class ReusableLog extends Log { this.context = context; } - void clear() { - recorded.clear(); - sourceMap.clear(); - nerrors = 0; - nwarnings = 0; + @Override + public void clear() { + super.clear(); //Set a fake listener that will lazily lookup the context for the 'real' listener. Since //this field is never updated when a new task is created, we cannot simply reset the field //or keep old value. This is a hack to workaround the limitations in the current infrastructure. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java index 56ee413ea0716..2167f47110477 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java @@ -689,6 +689,20 @@ public void report(JCDiagnostic diagnostic) { diagnosticHandler.report(diagnostic); } + /** + * Reset the state of this instance. + */ + public void clear() { + recorded.clear(); + sourceMap.clear(); + nerrors = 0; + nwarnings = 0; + nsuppressederrors = 0; + nsuppressedwarns = 0; + while (diagnosticHandler.prev != null) + popDiagnosticHandler(diagnosticHandler); + } + /** * Common diagnostic handling. * The diagnostic is counted, and depending on the options and how many diagnostics have been From 63fa255c06a273b00f99d4e8649dab618cbf5773 Mon Sep 17 00:00:00 2001 From: Koushik Thirupattur Date: Tue, 8 Apr 2025 21:58:21 +0000 Subject: [PATCH 0470/1101] 8354061: Update copyright in NameFormat.java fix after JDK-8349890 Reviewed-by: mullan --- test/jdk/javax/security/auth/x500/X500Principal/NameFormat.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/javax/security/auth/x500/X500Principal/NameFormat.java b/test/jdk/javax/security/auth/x500/X500Principal/NameFormat.java index 3f0422ff9336e..6962465e9fc3d 100644 --- a/test/jdk/javax/security/auth/x500/X500Principal/NameFormat.java +++ b/test/jdk/javax/security/auth/x500/X500Principal/NameFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it From b4ab964b72c631632511e6f01cdd5a47fb2e31fa Mon Sep 17 00:00:00 2001 From: William Kemper Date: Tue, 8 Apr 2025 22:00:58 +0000 Subject: [PATCH 0471/1101] 8353218: Shenandoah: Out of date comment references Brooks pointers Reviewed-by: ysr, kdnilsen --- src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 2bbb590f3552d..db7d62c9ba429 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -122,9 +122,9 @@ typedef ShenandoahLock ShenandoahHeapLock; typedef ShenandoahLocker ShenandoahHeapLocker; typedef Stack ShenandoahScanObjectStack; -// Shenandoah GC is low-pause concurrent GC that uses Brooks forwarding pointers -// to encode forwarding data. See BrooksPointer for details on forwarding data encoding. -// See ShenandoahControlThread for GC cycle structure. +// Shenandoah GC is low-pause concurrent GC that uses a load reference barrier +// for concurent evacuation and a snapshot-at-the-beginning write barrier for +// concurrent marking. See ShenandoahControlThread for GC cycle structure. // class ShenandoahHeap : public CollectedHeap { friend class ShenandoahAsserts; From aec1fe0a17fa6801e26a517d4d21656353409f7c Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Wed, 9 Apr 2025 01:00:02 +0000 Subject: [PATCH 0472/1101] 8351091: Shenandoah: global marking context completeness is not accurately maintained Reviewed-by: ysr, wkemper --- .../shenandoahGenerationalHeuristics.cpp | 2 +- .../heuristics/shenandoahHeuristics.cpp | 4 +--- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 2 +- .../share/gc/shenandoah/shenandoahFullGC.cpp | 16 +++++++-------- .../gc/shenandoah/shenandoahGeneration.cpp | 4 ---- .../gc/shenandoah/shenandoahGeneration.hpp | 2 +- .../shenandoahGenerationalEvacuationTask.cpp | 3 ++- .../shenandoahGenerationalFullGC.cpp | 4 ++-- .../share/gc/shenandoah/shenandoahHeap.cpp | 2 -- .../share/gc/shenandoah/shenandoahHeap.hpp | 2 +- .../gc/shenandoah/shenandoahHeap.inline.hpp | 5 ----- .../gc/shenandoah/shenandoahHeapRegion.cpp | 4 +--- .../shenandoah/shenandoahMarkingContext.cpp | 14 ++----------- .../shenandoah/shenandoahMarkingContext.hpp | 6 ------ .../shenandoahReferenceProcessor.cpp | 9 +++++---- .../share/gc/shenandoah/shenandoahUnload.cpp | 2 +- .../gc/shenandoah/shenandoahVerifier.cpp | 20 ++++++++++--------- 17 files changed, 37 insertions(+), 64 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp index 0568d9b4fff95..afc9abc496eb3 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp @@ -131,7 +131,7 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio // Reclaim humongous regions here, and count them as the immediate garbage #ifdef ASSERT bool reg_live = region->has_live(); - bool bm_live = heap->complete_marking_context()->is_marked(cast_to_oop(region->bottom())); + bool bm_live = heap->active_generation()->complete_marking_context()->is_marked(cast_to_oop(region->bottom())); assert(reg_live == bm_live, "Humongous liveness and marks should agree. Region live: %s; Bitmap live: %s; Region Live Words: %zu", BOOL_TO_STR(reg_live), BOOL_TO_STR(bm_live), region->get_live_data_words()); diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp index 0f570078150ae..4c7ed07b2a053 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp @@ -96,8 +96,6 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec size_t free = 0; size_t free_regions = 0; - ShenandoahMarkingContext* const ctx = heap->complete_marking_context(); - for (size_t i = 0; i < num_regions; i++) { ShenandoahHeapRegion* region = heap->get_region(i); @@ -122,7 +120,7 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec // Reclaim humongous regions here, and count them as the immediate garbage #ifdef ASSERT bool reg_live = region->has_live(); - bool bm_live = ctx->is_marked(cast_to_oop(region->bottom())); + bool bm_live = heap->gc_generation()->complete_marking_context()->is_marked(cast_to_oop(region->bottom())); assert(reg_live == bm_live, "Humongous liveness and marks should agree. Region live: %s; Bitmap live: %s; Region Live Words: %zu", BOOL_TO_STR(reg_live), BOOL_TO_STR(bm_live), region->get_live_data_words()); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 9fa4978dfe7ef..e87c771dec49c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -1030,7 +1030,7 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah _heap->generation_for(r->affiliation())->increment_affiliated_region_count(); #ifdef ASSERT - ShenandoahMarkingContext* const ctx = _heap->complete_marking_context(); + ShenandoahMarkingContext* const ctx = _heap->marking_context(); assert(ctx->top_at_mark_start(r) == r->bottom(), "Newly established allocation region starts with TAMS equal to bottom"); assert(ctx->is_bitmap_range_within_region_clear(ctx->top_bitmap(r), r->end()), "Bitmap above top_bitmap() must be clear"); #endif diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index 621a7233606f5..9436f09cbe050 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -348,8 +348,8 @@ class ShenandoahPrepareForCompactionObjectClosure : public ObjectClosure { void do_object(oop p) { assert(_from_region != nullptr, "must set before work"); - assert(_heap->complete_marking_context()->is_marked(p), "must be marked"); - assert(!_heap->complete_marking_context()->allocated_after_mark_start(p), "must be truly marked"); + assert(_heap->gc_generation()->complete_marking_context()->is_marked(p), "must be marked"); + assert(!_heap->gc_generation()->complete_marking_context()->allocated_after_mark_start(p), "must be truly marked"); size_t obj_size = p->size(); if (_compact_point + obj_size > _to_region->end()) { @@ -551,7 +551,7 @@ class ShenandoahTrashImmediateGarbageClosure: public ShenandoahHeapRegionClosure public: ShenandoahTrashImmediateGarbageClosure() : _heap(ShenandoahHeap::heap()), - _ctx(ShenandoahHeap::heap()->complete_marking_context()) {} + _ctx(ShenandoahHeap::heap()->global_generation()->complete_marking_context()) {} void heap_region_do(ShenandoahHeapRegion* r) override { if (r->is_humongous_start()) { @@ -775,7 +775,7 @@ class ShenandoahAdjustPointersClosure : public MetadataVisitingOopIterateClosure public: ShenandoahAdjustPointersClosure() : _heap(ShenandoahHeap::heap()), - _ctx(ShenandoahHeap::heap()->complete_marking_context()) {} + _ctx(ShenandoahHeap::heap()->gc_generation()->complete_marking_context()) {} void do_oop(oop* p) { do_oop_work(p); } void do_oop(narrowOop* p) { do_oop_work(p); } @@ -793,7 +793,7 @@ class ShenandoahAdjustPointersObjectClosure : public ObjectClosure { _heap(ShenandoahHeap::heap()) { } void do_object(oop p) { - assert(_heap->complete_marking_context()->is_marked(p), "must be marked"); + assert(_heap->gc_generation()->complete_marking_context()->is_marked(p), "must be marked"); p->oop_iterate(&_cl); } }; @@ -877,7 +877,7 @@ class ShenandoahCompactObjectsClosure : public ObjectClosure { _heap(ShenandoahHeap::heap()), _worker_id(worker_id) {} void do_object(oop p) { - assert(_heap->complete_marking_context()->is_marked(p), "must be marked"); + assert(_heap->gc_generation()->complete_marking_context()->is_marked(p), "must be marked"); size_t size = p->size(); if (FullGCForwarding::is_forwarded(p)) { HeapWord* compact_from = cast_from_oop(p); @@ -950,7 +950,7 @@ class ShenandoahPostCompactClosure : public ShenandoahHeapRegionClosure { // NOTE: See blurb at ShenandoahMCResetCompleteBitmapTask on why we need to skip // pinned regions. if (!r->is_pinned()) { - _heap->complete_marking_context()->reset_top_at_mark_start(r); + _heap->gc_generation()->complete_marking_context()->reset_top_at_mark_start(r); } size_t live = r->used(); @@ -1091,7 +1091,7 @@ class ShenandoahMCResetCompleteBitmapTask : public WorkerTask { ShenandoahParallelWorkerSession worker_session(worker_id); ShenandoahHeapRegion* region = _regions.next(); ShenandoahHeap* heap = ShenandoahHeap::heap(); - ShenandoahMarkingContext* const ctx = heap->complete_marking_context(); + ShenandoahMarkingContext* const ctx = heap->gc_generation()->complete_marking_context(); while (region != nullptr) { if (heap->is_bitmap_slice_committed(region) && !region->is_pinned() && region->has_live()) { ctx->clear_bitmap(region); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index 48e30ed585fe0..ad91119ddad98 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -775,10 +775,6 @@ bool ShenandoahGeneration::is_bitmap_clear() { return true; } -bool ShenandoahGeneration::is_mark_complete() { - return _is_marking_complete.is_set(); -} - void ShenandoahGeneration::set_mark_complete() { _is_marking_complete.set(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp index fddc71d153e6f..31c86985c6f58 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp @@ -201,7 +201,7 @@ class ShenandoahGeneration : public CHeapObj, public ShenandoahSpaceInfo { bool is_bitmap_clear(); // We need to track the status of marking for different generations. - bool is_mark_complete(); + bool is_mark_complete() { return _is_marking_complete.is_set(); } virtual void set_mark_complete(); virtual void set_mark_incomplete(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp index 5672463799af4..6a845afa4fdff 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp @@ -169,7 +169,8 @@ void ShenandoahGenerationalEvacuationTask::maybe_promote_region(ShenandoahHeapRe // 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) { - ShenandoahMarkingContext* const marking_context = _heap->complete_marking_context(); + assert(!_heap->gc_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); { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp index 98028b67c7b10..3387ed9d7a846 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp @@ -275,8 +275,8 @@ void ShenandoahPrepareForGenerationalCompactionObjectClosure::do_object(oop p) { assert(_from_region != nullptr, "must set before work"); assert((_from_region->bottom() <= cast_from_oop(p)) && (cast_from_oop(p) < _from_region->top()), "Object must reside in _from_region"); - assert(_heap->complete_marking_context()->is_marked(p), "must be marked"); - assert(!_heap->complete_marking_context()->allocated_after_mark_start(p), "must be truly marked"); + assert(_heap->global_generation()->complete_marking_context()->is_marked(p), "must be marked"); + assert(!_heap->global_generation()->complete_marking_context()->allocated_after_mark_start(p), "must be truly marked"); size_t obj_size = p->size(); uint from_region_age = _from_region->age(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index c055a3f9b5a9d..045f485090d2c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -424,8 +424,6 @@ jint ShenandoahHeap::initialize() { _affiliations[i] = ShenandoahAffiliation::FREE; } - // Initialize to complete - _marking_context->mark_complete(); size_t young_cset_regions, old_cset_regions; // We are initializing free set. We ignore cset region tallies. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index db7d62c9ba429..46f8a1340512a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -742,7 +742,7 @@ class ShenandoahHeap : public CollectedHeap { ShenandoahLiveData** _liveness_cache; public: - inline ShenandoahMarkingContext* complete_marking_context() const; + // Return the marking context regardless of the completeness status. inline ShenandoahMarkingContext* marking_context() const; template diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index 13c203d423c55..f4ef186743cdf 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -643,11 +643,6 @@ inline ShenandoahHeapRegion* ShenandoahHeap::get_region(size_t region_idx) const } } -inline ShenandoahMarkingContext* ShenandoahHeap::complete_marking_context() const { - assert (_marking_context->is_complete()," sanity"); - return _marking_context; -} - inline ShenandoahMarkingContext* ShenandoahHeap::marking_context() const { return _marking_context; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index 2c70cecf70523..a25e2dfd88f67 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -855,8 +855,8 @@ void ShenandoahHeapRegion::set_affiliation(ShenandoahAffiliation new_affiliation ShenandoahHeap* heap = ShenandoahHeap::heap(); ShenandoahAffiliation region_affiliation = heap->region_affiliation(this); + ShenandoahMarkingContext* const ctx = heap->marking_context(); { - ShenandoahMarkingContext* const ctx = heap->complete_marking_context(); log_debug(gc)("Setting affiliation of Region %zu from %s to %s, top: " PTR_FORMAT ", TAMS: " PTR_FORMAT ", watermark: " PTR_FORMAT ", top_bitmap: " PTR_FORMAT, index(), shenandoah_affiliation_name(region_affiliation), shenandoah_affiliation_name(new_affiliation), @@ -865,8 +865,6 @@ void ShenandoahHeapRegion::set_affiliation(ShenandoahAffiliation new_affiliation #ifdef ASSERT { - // During full gc, heap->complete_marking_context() is not valid, may equal nullptr. - ShenandoahMarkingContext* const ctx = heap->complete_marking_context(); size_t idx = this->index(); HeapWord* top_bitmap = ctx->top_bitmap(this); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp index 4fa006e60fb61..399db525cf95c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp @@ -28,6 +28,8 @@ #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahMarkingContext.hpp" +#include "shenandoahGlobalGeneration.hpp" + ShenandoahMarkingContext::ShenandoahMarkingContext(MemRegion heap_region, MemRegion bitmap_region, size_t num_regions) : _mark_bit_map(heap_region, bitmap_region), _top_bitmaps(NEW_C_HEAP_ARRAY(HeapWord*, num_regions, mtGC)), @@ -96,15 +98,3 @@ void ShenandoahMarkingContext::clear_bitmap(ShenandoahHeapRegion* r) { assert(is_bitmap_range_within_region_clear(bottom, r->end()), "Region %zu should have no marks in bitmap", r->index()); } - -bool ShenandoahMarkingContext::is_complete() { - return _is_complete.is_set(); -} - -void ShenandoahMarkingContext::mark_complete() { - _is_complete.set(); -} - -void ShenandoahMarkingContext::mark_incomplete() { - _is_complete.unset(); -} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.hpp index 854f42f26041d..8a52042e513ef 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.hpp @@ -47,8 +47,6 @@ class ShenandoahMarkingContext : public CHeapObj { HeapWord** const _top_at_mark_starts_base; HeapWord** const _top_at_mark_starts; - ShenandoahSharedFlag _is_complete; - public: ShenandoahMarkingContext(MemRegion heap_region, MemRegion bitmap_region, size_t num_regions); @@ -86,10 +84,6 @@ class ShenandoahMarkingContext : public CHeapObj { bool is_bitmap_clear() const; bool is_bitmap_range_within_region_clear(const HeapWord* start, const HeapWord* end) const; - - bool is_complete(); - void mark_complete(); - void mark_incomplete(); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHMARKINGCONTEXT_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp index 04d38d97f61af..0e10e8c819f2e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp @@ -328,12 +328,13 @@ bool ShenandoahReferenceProcessor::should_drop(oop reference, ReferenceType type return true; } + ShenandoahHeap* heap = ShenandoahHeap::heap(); // Check if the referent is still alive, in which case we should // drop the reference. if (type == REF_PHANTOM) { - return ShenandoahHeap::heap()->complete_marking_context()->is_marked(raw_referent); + return heap->active_generation()->complete_marking_context()->is_marked(raw_referent); } else { - return ShenandoahHeap::heap()->complete_marking_context()->is_marked_strong(raw_referent); + return heap->active_generation()->complete_marking_context()->is_marked_strong(raw_referent); } } @@ -345,7 +346,7 @@ void ShenandoahReferenceProcessor::make_inactive(oop reference, ReferenceType ty // next field. An application can't call FinalReference.enqueue(), so there is // no race to worry about when setting the next field. assert(reference_next(reference) == nullptr, "Already inactive"); - assert(ShenandoahHeap::heap()->marking_context()->is_marked(reference_referent_raw(reference)), "only make inactive final refs with alive referents"); + assert(ShenandoahHeap::heap()->active_generation()->complete_marking_context()->is_marked(reference_referent_raw(reference)), "only make inactive final refs with alive referents"); reference_set_next(reference, reference); } else { // Clear referent @@ -435,7 +436,7 @@ oop ShenandoahReferenceProcessor::drop(oop reference, ReferenceType type) { HeapWord* raw_referent = reference_referent_raw(reference); #ifdef ASSERT - assert(raw_referent == nullptr || ShenandoahHeap::heap()->marking_context()->is_marked(raw_referent), + assert(raw_referent == nullptr || ShenandoahHeap::heap()->active_generation()->complete_marking_context()->is_marked(raw_referent), "only drop references with alive referents"); #endif diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp index 24fb56b80377c..6bd50154b4fde 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp @@ -50,7 +50,7 @@ class ShenandoahIsUnloadingOopClosure : public OopClosure { public: ShenandoahIsUnloadingOopClosure() : - _marking_context(ShenandoahHeap::heap()->complete_marking_context()), + _marking_context(ShenandoahHeap::heap()->global_generation()->complete_marking_context()), _is_unloading(false) { } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index 1d9895b700bc1..37951c311ed99 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -268,12 +268,12 @@ class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { "Must be marked in incomplete bitmap"); break; case ShenandoahVerifier::_verify_marked_complete: - check(ShenandoahAsserts::_safe_all, obj, _heap->complete_marking_context()->is_marked(obj), + check(ShenandoahAsserts::_safe_all, obj, _heap->gc_generation()->complete_marking_context()->is_marked(obj), "Must be marked in complete bitmap"); break; case ShenandoahVerifier::_verify_marked_complete_except_references: case ShenandoahVerifier::_verify_marked_complete_satb_empty: - check(ShenandoahAsserts::_safe_all, obj, _heap->complete_marking_context()->is_marked(obj), + check(ShenandoahAsserts::_safe_all, obj, _heap->gc_generation()->complete_marking_context()->is_marked(obj), "Must be marked in complete bitmap, except j.l.r.Reference referents"); break; default: @@ -701,7 +701,7 @@ class ShenandoahVerifierMarkedRegionTask : public WorkerTask { virtual void work_humongous(ShenandoahHeapRegion *r, ShenandoahVerifierStack& stack, ShenandoahVerifyOopClosure& cl) { size_t processed = 0; HeapWord* obj = r->bottom(); - if (_heap->complete_marking_context()->is_marked(cast_to_oop(obj))) { + if (_heap->gc_generation()->complete_marking_context()->is_marked(cast_to_oop(obj))) { verify_and_follow(obj, stack, cl, &processed); } Atomic::add(&_processed, processed, memory_order_relaxed); @@ -709,7 +709,7 @@ class ShenandoahVerifierMarkedRegionTask : public WorkerTask { virtual void work_regular(ShenandoahHeapRegion *r, ShenandoahVerifierStack &stack, ShenandoahVerifyOopClosure &cl) { size_t processed = 0; - ShenandoahMarkingContext* ctx = _heap->complete_marking_context(); + ShenandoahMarkingContext* ctx = _heap->gc_generation()->complete_marking_context(); HeapWord* tams = ctx->top_at_mark_start(r); // Bitmaps, before TAMS @@ -788,9 +788,11 @@ class VerifyThreadGCState : public ThreadClosure { void ShenandoahVerifier::verify_at_safepoint(const char* label, VerifyRememberedSet remembered, - VerifyForwarded forwarded, VerifyMarked marked, + VerifyForwarded forwarded, + VerifyMarked marked, VerifyCollectionSet cset, - VerifyLiveness liveness, VerifyRegions regions, + VerifyLiveness liveness, + VerifyRegions regions, VerifySize sizeness, VerifyGCState gcstate) { guarantee(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "only when nothing else happens"); @@ -989,7 +991,7 @@ void ShenandoahVerifier::verify_at_safepoint(const char* label, (marked == _verify_marked_complete || marked == _verify_marked_complete_except_references || marked == _verify_marked_complete_satb_empty)) { - guarantee(_heap->marking_context()->is_complete(), "Marking context should be complete"); + guarantee(_heap->gc_generation()->is_mark_complete(), "Marking context should be complete"); ShenandoahVerifierMarkedRegionTask task(_verification_bit_map, ld, label, options); _heap->workers()->run_task(&task); count_marked = task.processed(); @@ -1186,7 +1188,7 @@ void ShenandoahVerifier::verify_after_fullgc() { "After Full GC", _verify_remembered_after_full_gc, // verify read-write remembered set _verify_forwarded_none, // all objects are non-forwarded - _verify_marked_complete, // all objects are marked in complete bitmap + _verify_marked_incomplete, // all objects are marked in incomplete bitmap _verify_cset_none, // no cset references _verify_liveness_disable, // no reliable liveness data anymore _verify_regions_notrash_nocset, // no trash, no cset @@ -1294,7 +1296,7 @@ void ShenandoahVerifier::help_verify_region_rem_set(Scanner* scanner, Shenandoah ShenandoahOldGeneration* old_gen = _heap->old_generation(); assert(old_gen->is_mark_complete() || old_gen->is_parsable(), "Sanity"); - ShenandoahMarkingContext* ctx = old_gen->is_mark_complete() ?old_gen->complete_marking_context() : nullptr; + ShenandoahMarkingContext* ctx = old_gen->is_mark_complete() ? old_gen->complete_marking_context() : nullptr; ShenandoahVerifyRemSetClosure check_interesting_pointers(scanner, message); HeapWord* from = r->bottom(); HeapWord* obj_addr = from; From c26c5758679b803489f401fbb23e8153ca10e19f Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 9 Apr 2025 01:15:40 +0000 Subject: [PATCH 0473/1101] 8353014: Exclude AOT tooling classes from AOT cache Reviewed-by: vlivanov, kvn --- src/hotspot/share/cds/aotArtifactFinder.cpp | 9 +- src/hotspot/share/cds/aotClassFilter.cpp | 55 ++++++++++++ src/hotspot/share/cds/aotClassFilter.hpp | 60 +++++++++++++ src/hotspot/share/cds/cdsConfig.cpp | 18 ++++ src/hotspot/share/cds/cdsConfig.hpp | 1 + src/hotspot/share/cds/dumpTimeClassInfo.hpp | 17 +++- src/hotspot/share/cds/dynamicArchive.cpp | 39 +++++---- src/hotspot/share/cds/dynamicArchive.hpp | 3 +- src/hotspot/share/cds/lambdaFormInvokers.cpp | 53 ++++++++---- .../share/cds/lambdaProxyClassDictionary.cpp | 5 ++ src/hotspot/share/cds/metaspaceShared.cpp | 86 +++++++++++-------- src/hotspot/share/cds/metaspaceShared.hpp | 3 +- .../classfile/systemDictionaryShared.cpp | 12 +-- .../classfile/systemDictionaryShared.hpp | 2 +- 14 files changed, 279 insertions(+), 84 deletions(-) create mode 100644 src/hotspot/share/cds/aotClassFilter.cpp create mode 100644 src/hotspot/share/cds/aotClassFilter.hpp diff --git a/src/hotspot/share/cds/aotArtifactFinder.cpp b/src/hotspot/share/cds/aotArtifactFinder.cpp index e644a5e6f5fd1..6a7faee51330c 100644 --- a/src/hotspot/share/cds/aotArtifactFinder.cpp +++ b/src/hotspot/share/cds/aotArtifactFinder.cpp @@ -109,7 +109,10 @@ void AOTArtifactFinder::find_artifacts() { // Add all the InstanceKlasses (and their array classes) that are always included. SystemDictionaryShared::dumptime_table()->iterate_all_live_classes([&] (InstanceKlass* ik, DumpTimeClassInfo& info) { - if (!info.is_excluded()) { + // Skip "AOT tooling classes" in this block. They will be included in the AOT cache only if + // - One of their subtypes is included + // - One of their instances is found by HeapShared. + if (!info.is_excluded() && !info.is_aot_tooling_class()) { bool add = false; if (!ik->is_hidden()) { // All non-hidden classes are always included into the AOT cache @@ -149,10 +152,10 @@ void AOTArtifactFinder::find_artifacts() { SystemDictionaryShared::dumptime_table()->iterate_all_live_classes([&] (InstanceKlass* k, DumpTimeClassInfo& info) { if (!info.is_excluded() && _seen_classes->get(k) == nullptr) { info.set_excluded(); - assert(k->is_hidden(), "must be"); if (log_is_enabled(Info, cds)) { ResourceMark rm; - log_info(cds)("Skipping %s: Hidden class", k->name()->as_C_string()); + log_info(cds)("Skipping %s: %s class", k->name()->as_C_string(), + k->is_hidden() ? "Hidden" : "AOT tooling"); } } }); diff --git a/src/hotspot/share/cds/aotClassFilter.cpp b/src/hotspot/share/cds/aotClassFilter.cpp new file mode 100644 index 0000000000000..959bea6a62303 --- /dev/null +++ b/src/hotspot/share/cds/aotClassFilter.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "cds/aotClassFilter.hpp" +#include "runtime/javaThread.hpp" +#include "runtime/mutexLocker.hpp" + +AOTClassFilter::FilterMark* AOTClassFilter::_current_mark = nullptr; +Thread* AOTClassFilter::_filtering_thread = nullptr; + +AOTClassFilter::FilterMark::FilterMark() { + MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); + assert(_current_mark == nullptr &&_filtering_thread == nullptr, + "impl note: we support only a single AOTClassFilter used by a single thread"); + _current_mark = this; + _filtering_thread = Thread::current(); +} + +AOTClassFilter::FilterMark::~FilterMark() { + MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); + assert(_current_mark == this && _filtering_thread == Thread::current(), "sanity"); + _current_mark = nullptr; + _filtering_thread = nullptr; +} + +// Is called only from SystemDictionaryShared::init_dumptime_info(), which holds DumpTimeTable_lock +bool AOTClassFilter::is_aot_tooling_class(InstanceKlass* ik) { + assert_lock_strong(DumpTimeTable_lock); + if (_current_mark == nullptr || _filtering_thread != Thread::current()) { + return false; + } else { + return _current_mark->is_aot_tooling_class(ik); + } +} diff --git a/src/hotspot/share/cds/aotClassFilter.hpp b/src/hotspot/share/cds/aotClassFilter.hpp new file mode 100644 index 0000000000000..b85b83c3a3240 --- /dev/null +++ b/src/hotspot/share/cds/aotClassFilter.hpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_CDS_AOTCLASSFILTER_HPP +#define SHARE_CDS_AOTCLASSFILTER_HPP + +#include "memory/allStatic.hpp" +#include "utilities/debug.hpp" + +class InstanceKlass; +class Thread; + +// Used by SystemDictionaryShared/AOTArtifactFinder to filter out classes that +// shouldn't be included into the AOT cache -- for example, classes that are used only +// in the training/assembly phases for building contents in the AOT cache. +// +// The only use case today is in lambdaFormInvokers.cpp. +class AOTClassFilter : AllStatic { +public: + + // Filters should be defined using RAII pattern + class FilterMark { + public: + FilterMark(); + ~FilterMark(); + virtual bool is_aot_tooling_class(InstanceKlass* ik) = 0; + }; + + // Called when ik is being loaded. Return true iff this class is loaded + // only because it's used by the AOT tooling code. + static bool is_aot_tooling_class(InstanceKlass* ik); + +private: + // For the time being, we allow at most one filter. + static FilterMark* _current_mark; + static Thread* _filtering_thread; +}; + +#endif // SHARE_CDS_AOTCLASSFILTER_HPP diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index 055b84ed284d2..47613e090086c 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -573,6 +573,24 @@ bool CDSConfig::is_logging_lambda_form_invokers() { return ClassListWriter::is_enabled() || is_dumping_dynamic_archive(); } +bool CDSConfig::is_dumping_regenerated_lambdaform_invokers() { + if (is_dumping_final_static_archive()) { + // No need to regenerate -- the lambda form invokers should have been regenerated + // in the preimage archive (if allowed) + return false; + } else if (is_dumping_dynamic_archive() && is_using_aot_linked_classes()) { + // The base archive has aot-linked classes that may have AOT-resolved CP references + // that point to the lambda form invokers in the base archive. Such pointers will + // be invalid if lambda form invokers are regenerated in the dynamic archive. + return false; + } else if (CDSConfig::is_dumping_method_handles()) { + // Work around JDK-8310831, as some methods in lambda form holder classes may not get generated. + return false; + } else { + return is_dumping_archive(); + } +} + void CDSConfig::stop_using_optimized_module_handling() { _is_using_optimized_module_handling = false; _is_dumping_full_module_graph = false; // This requires is_using_optimized_module_handling() diff --git a/src/hotspot/share/cds/cdsConfig.hpp b/src/hotspot/share/cds/cdsConfig.hpp index 8a3a060e3c396..f02258eb6feaa 100644 --- a/src/hotspot/share/cds/cdsConfig.hpp +++ b/src/hotspot/share/cds/cdsConfig.hpp @@ -139,6 +139,7 @@ class CDSConfig : public AllStatic { static void stop_using_optimized_module_handling() NOT_CDS_RETURN; static bool is_logging_lambda_form_invokers() NOT_CDS_RETURN_(false); + static bool is_dumping_regenerated_lambdaform_invokers() NOT_CDS_RETURN_(false); static bool is_dumping_aot_linked_classes() NOT_CDS_JAVA_HEAP_RETURN_(false); static bool is_using_aot_linked_classes() NOT_CDS_JAVA_HEAP_RETURN_(false); diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.hpp b/src/hotspot/share/cds/dumpTimeClassInfo.hpp index 79ede224bb6e7..0bb60dfbb29bc 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.hpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.hpp @@ -39,9 +39,11 @@ class Method; class Symbol; class DumpTimeClassInfo: public CHeapObj { - bool _excluded; - bool _is_early_klass; - bool _has_checked_exclusion; + bool _excluded; + bool _is_aot_tooling_class; + bool _is_early_klass; + bool _has_checked_exclusion; + class DTLoaderConstraint { Symbol* _name; char _loader_type1; @@ -140,6 +142,7 @@ class DumpTimeClassInfo: public CHeapObj { _clsfile_size = -1; _clsfile_crc32 = -1; _excluded = false; + _is_aot_tooling_class = false; _is_early_klass = JvmtiExport::is_early_phase(); _verifier_constraints = nullptr; _verifier_constraint_flags = nullptr; @@ -199,6 +202,14 @@ class DumpTimeClassInfo: public CHeapObj { return _excluded || _failed_verification; } + bool is_aot_tooling_class() { + return _is_aot_tooling_class; + } + + void set_is_aot_tooling_class() { + _is_aot_tooling_class = true; + } + // Was this class loaded while JvmtiExport::is_early_phase()==true bool is_early_klass() { return _is_early_klass; diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index 3cf1019d9ea5c..c3a6db9e9b973 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -32,6 +32,8 @@ #include "cds/cdsConfig.hpp" #include "cds/dynamicArchive.hpp" #include "cds/lambdaProxyClassDictionary.hpp" +#include "cds/lambdaFormInvokers.hpp" +#include "cds/metaspaceShared.hpp" #include "cds/regeneratedClasses.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.inline.hpp" @@ -495,6 +497,16 @@ void DynamicArchive::check_for_dynamic_dump() { } } +void DynamicArchive::dump_impl(bool jcmd_request, const char* archive_name, TRAPS) { + MetaspaceShared::link_shared_classes(CHECK); + if (!jcmd_request && CDSConfig::is_dumping_regenerated_lambdaform_invokers()) { + LambdaFormInvokers::regenerate_holder_classes(CHECK); + } + + VM_PopulateDynamicDumpSharedSpace op(archive_name); + VMThread::execute(&op); +} + void DynamicArchive::dump_at_exit(JavaThread* current, const char* archive_name) { ExceptionMark em(current); ResourceMark rm(current); @@ -507,20 +519,16 @@ void DynamicArchive::dump_at_exit(JavaThread* current, const char* archive_name) log_info(cds, dynamic)("Preparing for dynamic dump at exit in thread %s", current->name()); JavaThread* THREAD = current; // For TRAPS processing related to link_shared_classes - MetaspaceShared::link_shared_classes(false/*not from jcmd*/, THREAD); - if (!HAS_PENDING_EXCEPTION) { - VM_PopulateDynamicDumpSharedSpace op(archive_name); - VMThread::execute(&op); - return; + dump_impl(/*jcmd_request=*/false, archive_name, THREAD); + if (HAS_PENDING_EXCEPTION) { + // One of the prepatory steps failed + oop ex = current->pending_exception(); + log_error(cds)("Dynamic dump has failed"); + log_error(cds)("%s: %s", ex->klass()->external_name(), + java_lang_String::as_utf8_string(java_lang_Throwable::message(ex))); + CLEAR_PENDING_EXCEPTION; + CDSConfig::disable_dumping_dynamic_archive(); // Just for good measure } - - // One of the prepatory steps failed - oop ex = current->pending_exception(); - log_error(cds)("Dynamic dump has failed"); - log_error(cds)("%s: %s", ex->klass()->external_name(), - java_lang_String::as_utf8_string(java_lang_Throwable::message(ex))); - CLEAR_PENDING_EXCEPTION; - CDSConfig::disable_dumping_dynamic_archive(); // Just for good measure } // This is called by "jcmd VM.cds dynamic_dump" @@ -529,10 +537,7 @@ void DynamicArchive::dump_for_jcmd(const char* archive_name, TRAPS) { assert(CDSConfig::is_using_archive() && RecordDynamicDumpInfo, "already checked in arguments.cpp"); assert(ArchiveClassesAtExit == nullptr, "already checked in arguments.cpp"); assert(CDSConfig::is_dumping_dynamic_archive(), "already checked by check_for_dynamic_dump() during VM startup"); - MetaspaceShared::link_shared_classes(true/*from jcmd*/, CHECK); - // copy shared path table to saved. - VM_PopulateDynamicDumpSharedSpace op(archive_name); - VMThread::execute(&op); + dump_impl(/*jcmd_request=*/true, archive_name, CHECK); } bool DynamicArchive::validate(FileMapInfo* dynamic_info) { diff --git a/src/hotspot/share/cds/dynamicArchive.hpp b/src/hotspot/share/cds/dynamicArchive.hpp index eb5fd5f9aba8d..905c511c4e0ac 100644 --- a/src/hotspot/share/cds/dynamicArchive.hpp +++ b/src/hotspot/share/cds/dynamicArchive.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,6 +66,7 @@ class DynamicArchive : AllStatic { static void check_for_dynamic_dump(); static void dump_for_jcmd(const char* archive_name, TRAPS); static void dump_at_exit(JavaThread* current, const char* archive_name); + static void dump_impl(bool jcmd_request, const char* archive_name, TRAPS); static bool is_mapped() { return FileMapInfo::dynamic_info() != nullptr; } static bool validate(FileMapInfo* dynamic_info); static void dump_array_klasses(); diff --git a/src/hotspot/share/cds/lambdaFormInvokers.cpp b/src/hotspot/share/cds/lambdaFormInvokers.cpp index ab22b4775b7c0..7832de8c6cc53 100644 --- a/src/hotspot/share/cds/lambdaFormInvokers.cpp +++ b/src/hotspot/share/cds/lambdaFormInvokers.cpp @@ -22,8 +22,10 @@ * */ +#include "cds/aotClassFilter.hpp" #include "cds/archiveBuilder.hpp" -#include "cds/lambdaFormInvokers.hpp" +#include "cds/cdsConfig.hpp" +#include "cds/lambdaFormInvokers.inline.hpp" #include "cds/metaspaceShared.hpp" #include "cds/regeneratedClasses.hpp" #include "classfile/classFileStream.hpp" @@ -88,30 +90,39 @@ class PrintLambdaFormMessage { } }; -void LambdaFormInvokers::regenerate_holder_classes(TRAPS) { - PrintLambdaFormMessage plm; - if (_lambdaform_lines == nullptr || _lambdaform_lines->length() == 0) { - log_info(cds)("Nothing to regenerate for holder classes"); - return; +class LambdaFormInvokersClassFilterMark : public AOTClassFilter::FilterMark { +public: + bool is_aot_tooling_class(InstanceKlass* ik) { + if (ik->name()->index_of_at(0, "$Species_", 9) > 0) { + // Classes like java.lang.invoke.BoundMethodHandle$Species_L should be included in AOT cache + return false; + } + if (LambdaFormInvokers::may_be_regenerated_class(ik->name())) { + // Regenerated holder classes should be included in AOT cache. + return false; + } + // Treat all other classes loaded during LambdaFormInvokers::regenerate_holder_classes() as + // "AOT tooling classes". + return true; } +}; - if (CDSConfig::is_dumping_static_archive() && CDSConfig::is_dumping_method_handles()) { - // Work around JDK-8310831, as some methods in lambda form holder classes may not get generated. - log_info(cds)("Archived MethodHandles may refer to lambda form holder classes. Cannot regenerate."); +void LambdaFormInvokers::regenerate_holder_classes(TRAPS) { + if (!CDSConfig::is_dumping_regenerated_lambdaform_invokers()) { return; } - if (CDSConfig::is_dumping_dynamic_archive() && CDSConfig::is_dumping_aot_linked_classes() && - CDSConfig::is_using_aot_linked_classes()) { - // The base archive may have some pre-resolved CP entries that point to the lambda form holder - // classes in the base archive. If we generate new versions of these classes, those CP entries - // will be pointing to invalid classes. - log_info(cds)("Base archive already has aot-linked lambda form holder classes. Cannot regenerate."); + PrintLambdaFormMessage plm; + if (_lambdaform_lines == nullptr || _lambdaform_lines->length() == 0) { + log_info(cds)("Nothing to regenerate for holder classes"); return; } ResourceMark rm(THREAD); + // Filter out AOT tooling classes like java.lang.invoke.GenerateJLIClassesHelper, etc. + LambdaFormInvokersClassFilterMark filter_mark; + Symbol* cds_name = vmSymbols::jdk_internal_misc_CDS(); Klass* cds_klass = SystemDictionary::resolve_or_null(cds_name, THREAD); guarantee(cds_klass != nullptr, "jdk/internal/misc/CDS must exist!"); @@ -245,7 +256,7 @@ void LambdaFormInvokers::dump_static_archive_invokers() { } assert(index == count, "Should match"); } - log_debug(cds)("Total LF lines stored into static archive: %d", count); + log_debug(cds)("Total LF lines stored into %s: %d", CDSConfig::type_of_archive_being_written(), count); } } @@ -257,14 +268,20 @@ void LambdaFormInvokers::read_static_archive_invokers() { char* str = line->adr_at(0); append(str); } - log_debug(cds)("Total LF lines read from static archive: %d", _static_archive_invokers->length()); + log_debug(cds)("Total LF lines read from %s: %d", CDSConfig::type_of_archive_being_loaded(), _static_archive_invokers->length()); } } void LambdaFormInvokers::serialize(SerializeClosure* soc) { soc->do_ptr(&_static_archive_invokers); if (soc->reading() && CDSConfig::is_dumping_final_static_archive()) { - LambdaFormInvokers::read_static_archive_invokers(); + if (!CDSConfig::is_dumping_aot_linked_classes()) { + // See CDSConfig::is_dumping_regenerated_lambdaform_invokers() -- a dynamic archive can + // regenerate lambda form invokers only if the base archive does not contain aot-linked classes. + // If so, we copy the contents of _static_archive_invokers (from the preimage) into + //_lambdaform_lines, which will be written as _static_archive_invokers into final static archive. + LambdaFormInvokers::read_static_archive_invokers(); + } _static_archive_invokers = nullptr; } } diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp index c0e31eea399ee..6b2e432d55961 100644 --- a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp +++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotClassFilter.hpp" #include "cds/archiveBuilder.hpp" #include "cds/cdsConfig.hpp" #include "cds/cdsProtectionDomain.hpp" @@ -390,6 +391,10 @@ void LambdaProxyClassDictionary::add_to_dumptime_table(LambdaProxyClassKey& key, InstanceKlass* proxy_klass) { assert_lock_strong(DumpTimeTable_lock); + if (AOTClassFilter::is_aot_tooling_class(proxy_klass)) { + return; + } + bool created; DumpTimeLambdaProxyClassInfo* info = _dumptime_table->put_if_absent(key, &created); info->add_proxy_klass(proxy_klass); diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 277c6ce90e73d..85916ced3cfac 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -97,6 +97,8 @@ #include "utilities/ostream.hpp" #include "utilities/resourceHash.hpp" +#include + ReservedSpace MetaspaceShared::_symbol_rs; VirtualSpace MetaspaceShared::_symbol_vs; bool MetaspaceShared::_archive_loading_failed = false; @@ -696,6 +698,16 @@ class CollectClassesForLinking : public KlassClosure { GrowableArray _mirrors; public: + CollectClassesForLinking() : _mirrors() { + // ClassLoaderDataGraph::loaded_classes_do_keepalive() requires ClassLoaderDataGraph_lock. + // We cannot link the classes while holding this lock (or else we may run into deadlock). + // Therefore, we need to first collect all the classes, keeping them alive by + // holding onto their java_mirrors in global OopHandles. We then link the classes after + // releasing the lock. + MutexLocker lock(ClassLoaderDataGraph_lock); + ClassLoaderDataGraph::loaded_classes_do_keepalive(this); + } + ~CollectClassesForLinking() { for (int i = 0; i < _mirrors.length(); i++) { _mirrors.at(i).release(Universe::vm_global()); @@ -736,43 +748,20 @@ bool MetaspaceShared::may_be_eagerly_linked(InstanceKlass* ik) { return true; } -bool MetaspaceShared::link_class_for_cds(InstanceKlass* ik, TRAPS) { - // Link the class to cause the bytecodes to be rewritten and the - // cpcache to be created. Class verification is done according - // to -Xverify setting. - bool res = MetaspaceShared::try_link_class(THREAD, ik); - AOTConstantPoolResolver::dumptime_resolve_constants(ik, CHECK_(false)); - return res; -} - -void MetaspaceShared::link_shared_classes(bool jcmd_request, TRAPS) { +void MetaspaceShared::link_shared_classes(TRAPS) { AOTClassLinker::initialize(); AOTClassInitializer::init_test_class(CHECK); - if (!jcmd_request && !CDSConfig::is_dumping_final_static_archive()) { - LambdaFormInvokers::regenerate_holder_classes(CHECK); - } - - while (true) { + ResourceMark rm(THREAD); CollectClassesForLinking collect_classes; - { - // ClassLoaderDataGraph::loaded_classes_do_keepalive() requires ClassLoaderDataGraph_lock. - // We cannot link the classes while holding this lock (or else we may run into deadlock). - // Therefore, we need to first collect all the classes, keeping them alive by - // holding onto their java_mirrors in global OopHandles. We then link the classes after - // releasing the lock. - MutexLocker lock(ClassLoaderDataGraph_lock); - ClassLoaderDataGraph::loaded_classes_do_keepalive(&collect_classes); - } - bool has_linked = false; const GrowableArray* mirrors = collect_classes.mirrors(); for (int i = 0; i < mirrors->length(); i++) { OopHandle mirror = mirrors->at(i); InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(mirror.resolve())); if (may_be_eagerly_linked(ik)) { - has_linked |= link_class_for_cds(ik, CHECK); + has_linked |= try_link_class(THREAD, ik); } } @@ -783,6 +772,18 @@ void MetaspaceShared::link_shared_classes(bool jcmd_request, TRAPS) { // Keep scanning until we have linked no more classes. } + // Resolve constant pool entries -- we don't load any new classes during this stage + { + ResourceMark rm(THREAD); + CollectClassesForLinking collect_classes; + const GrowableArray* mirrors = collect_classes.mirrors(); + for (int i = 0; i < mirrors->length(); i++) { + OopHandle mirror = mirrors->at(i); + InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(mirror.resolve())); + AOTConstantPoolResolver::dumptime_resolve_constants(ik, CHECK); + } + } + if (CDSConfig::is_dumping_final_static_archive()) { FinalImageRecipes::apply_recipes(CHECK); } @@ -823,8 +824,14 @@ void MetaspaceShared::preload_and_dump(TRAPS) { // When the new -XX:AOTMode=create flag is used, we can't return // to the JLI launcher, as the launcher will fail when trying to // run the main class, which is not what we want. - tty->print_cr("AOTCache creation is complete: %s", AOTCache); - vm_exit(0); + struct stat st; + if (os::stat(AOTCache, &st) != 0) { + tty->print_cr("AOTCache creation failed: %s", AOTCache); + vm_exit(0); + } else { + tty->print_cr("AOTCache creation is complete: %s " INT64_FORMAT " bytes", AOTCache, (int64_t)(st.st_size)); + vm_exit(0); + } } } } @@ -926,6 +933,18 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS } } +#if INCLUDE_CDS_JAVA_HEAP + if (CDSConfig::is_dumping_heap()) { + assert(CDSConfig::allow_only_single_java_thread(), "Required"); + if (!HeapShared::is_archived_boot_layer_available(THREAD)) { + log_info(cds)("archivedBootLayer not available, disabling full module graph"); + CDSConfig::stop_dumping_full_module_graph(); + } + // Do this before link_shared_classes(), as the following line may load new classes. + HeapShared::init_for_dumping(CHECK); + } +#endif + if (CDSConfig::is_dumping_final_static_archive()) { if (ExtraSharedClassListFile) { log_info(cds)("Loading extra classes from %s ...", ExtraSharedClassListFile); @@ -941,16 +960,15 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS // were not explicitly specified in the classlist. E.g., if an interface implemented by class K // fails verification, all other interfaces that were not specified in the classlist but // are implemented by K are not verified. - link_shared_classes(false/*not from jcmd*/, CHECK); + link_shared_classes(CHECK); log_info(cds)("Rewriting and linking classes: done"); + if (CDSConfig::is_dumping_regenerated_lambdaform_invokers()) { + LambdaFormInvokers::regenerate_holder_classes(CHECK); + } + #if INCLUDE_CDS_JAVA_HEAP if (CDSConfig::is_dumping_heap()) { - if (!HeapShared::is_archived_boot_layer_available(THREAD)) { - log_info(cds)("archivedBootLayer not available, disabling full module graph"); - CDSConfig::stop_dumping_full_module_graph(); - } - HeapShared::init_for_dumping(CHECK); ArchiveHeapWriter::init(); if (CDSConfig::is_dumping_full_module_graph()) { ClassLoaderDataShared::ensure_module_entry_tables_exist(); diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp index 27df816833cee..8881dc6d6fd0a 100644 --- a/src/hotspot/share/cds/metaspaceShared.hpp +++ b/src/hotspot/share/cds/metaspaceShared.hpp @@ -131,8 +131,7 @@ class MetaspaceShared : AllStatic { } static bool try_link_class(JavaThread* current, InstanceKlass* ik); - static void link_shared_classes(bool jcmd_request, TRAPS) NOT_CDS_RETURN; - static bool link_class_for_cds(InstanceKlass* ik, TRAPS) NOT_CDS_RETURN_(false); + static void link_shared_classes(TRAPS) NOT_CDS_RETURN; static bool may_be_eagerly_linked(InstanceKlass* ik) NOT_CDS_RETURN_(false); #if INCLUDE_CDS diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index c4e061b8fa993..2fbee502b9372 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotClassFilter.hpp" #include "cds/aotClassLocation.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" @@ -34,6 +35,7 @@ #include "cds/filemap.hpp" #include "cds/heapShared.hpp" #include "cds/lambdaProxyClassDictionary.hpp" +#include "cds/lambdaFormInvokers.inline.hpp" #include "cds/metaspaceShared.hpp" #include "cds/runTimeClassInfo.hpp" #include "cds/unregisteredClasses.hpp" @@ -484,7 +486,10 @@ void SystemDictionaryShared::initialize() { void SystemDictionaryShared::init_dumptime_info(InstanceKlass* k) { MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); assert(SystemDictionaryShared::class_loading_may_happen(), "sanity"); - _dumptime_table->allocate_info(k); + DumpTimeClassInfo* info = _dumptime_table->allocate_info(k); + if (AOTClassFilter::is_aot_tooling_class(k)) { + info->set_is_aot_tooling_class(); + } } void SystemDictionaryShared::remove_dumptime_info(InstanceKlass* k) { @@ -1056,10 +1061,7 @@ SystemDictionaryShared::find_record(RunTimeSharedDictionary* static_dict, RunTim if (DynamicArchive::is_mapped()) { // Use the regenerated holder classes in the dynamic archive as they // have more methods than those in the base archive. - if (name == vmSymbols::java_lang_invoke_Invokers_Holder() || - name == vmSymbols::java_lang_invoke_DirectMethodHandle_Holder() || - name == vmSymbols::java_lang_invoke_LambdaForm_Holder() || - name == vmSymbols::java_lang_invoke_DelegatingMethodHandle_Holder()) { + if (LambdaFormInvokers::may_be_regenerated_class(name)) { record = dynamic_dict->lookup(name, hash, 0); if (record != nullptr) { return record; diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index 671eb69b8c65a..e910bfb5d472e 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -244,7 +244,7 @@ class SystemDictionaryShared: public SystemDictionary { static bool check_linking_constraints(Thread* current, InstanceKlass* klass) NOT_CDS_RETURN_(false); static void record_linking_constraint(Symbol* name, InstanceKlass* klass, Handle loader1, Handle loader2) NOT_CDS_RETURN; - static bool is_builtin(InstanceKlass* k) { + static bool is_builtin(const InstanceKlass* k) { return (k->shared_classpath_index() != UNREGISTERED_INDEX); } static bool add_unregistered_class(Thread* current, InstanceKlass* k); From 73bb647218ac4c9742cb974d23c5f223bbd56c0a Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Wed, 9 Apr 2025 01:44:46 +0000 Subject: [PATCH 0474/1101] 8353829: RISC-V: Auto-enable several more extensions for debug builds Reviewed-by: rehn, fjiang --- src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp index 8572d54716bc3..06d6aaf109f86 100644 --- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp @@ -223,6 +223,16 @@ void RiscvHwprobe::add_features_from_query_result() { if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZFA)) { VM_Version::ext_Zfa.enable_feature(); } +#endif +#ifndef PRODUCT + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZTSO)) { + VM_Version::ext_Ztso.enable_feature(); + } +#endif +#ifndef PRODUCT + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZACAS)) { + VM_Version::ext_Zacas.enable_feature(); + } #endif if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZICOND)) { VM_Version::ext_Zicond.enable_feature(); From 2a0cf8353ae0528a8417407d5719df0dadceadcf Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 9 Apr 2025 03:03:14 +0000 Subject: [PATCH 0475/1101] 8354088: [BACKOUT] Run jtreg in the work dir Reviewed-by: darcy, iris --- make/RunTests.gmk | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index ebae510fc07d9..7aa0082e0ae81 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -995,27 +995,24 @@ define SetupRunJtregTestBody $$(RM) -r $$($1_TEST_SUPPORT_DIR) $$(RM) -r $$($1_TEST_RESULTS_DIR) - $1_JTREG_ARGUMENTS := \ - $$($1_JTREG_LAUNCHER_OPTIONS) \ - -Dprogram=jtreg -jar $$(JT_HOME)/lib/jtreg.jar \ - $$($1_JTREG_BASIC_OPTIONS) \ - -testjdk:$$(JDK_UNDER_TEST) \ - -dir:$$(JTREG_TOPDIR) \ - -reportDir:$$($1_TEST_RESULTS_DIR) \ - -workDir:$$($1_TEST_SUPPORT_DIR) \ - -report:$${JTREG_REPORT} \ - $$$${JTREG_STATUS} \ - $$(JTREG_OPTIONS) \ - $$(JTREG_FAILURE_HANDLER_OPTIONS) \ - $$(JTREG_COV_OPTIONS) \ - $$($1_TEST_NAME) \ - # - $1_COMMAND_LINE := \ - cd $$($1_TEST_SUPPORT_DIR) && $$(JTREG_JAVA) $$($1_JTREG_ARGUMENTS) \ + $$(JTREG_JAVA) $$($1_JTREG_LAUNCHER_OPTIONS) \ + -Dprogram=jtreg -jar $$(JT_HOME)/lib/jtreg.jar \ + $$($1_JTREG_BASIC_OPTIONS) \ + -testjdk:$$(JDK_UNDER_TEST) \ + -dir:$$(JTREG_TOPDIR) \ + -reportDir:$$($1_TEST_RESULTS_DIR) \ + -workDir:$$($1_TEST_SUPPORT_DIR) \ + -report:$${JTREG_REPORT} \ + $$$${JTREG_STATUS} \ + $$(JTREG_OPTIONS) \ + $$(JTREG_FAILURE_HANDLER_OPTIONS) \ + $$(JTREG_COV_OPTIONS) \ + $$($1_TEST_NAME) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) + ifneq ($$(JTREG_RETRY_COUNT), 0) $1_COMMAND_LINE := \ for i in {0..$$(JTREG_RETRY_COUNT)}; do \ From 743d1c64c29118b15897b3c676919353ced467f5 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Wed, 9 Apr 2025 05:08:51 +0000 Subject: [PATCH 0476/1101] 8353273: Reduce number of oop map entries in instances Reviewed-by: lmesnik, fparain, jsjolen --- .../share/classfile/fieldLayoutBuilder.cpp | 46 +++- .../share/classfile/fieldLayoutBuilder.hpp | 7 +- src/hotspot/share/oops/instanceKlass.cpp | 2 +- .../FieldLayout/TestOopMapSizeMinimal.java | 257 ++++++++++++++++++ 4 files changed, 297 insertions(+), 15 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/FieldLayout/TestOopMapSizeMinimal.java diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp index 1af9bb8336194..b6007923907c8 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp @@ -126,17 +126,19 @@ void FieldLayout::initialize_static_layout() { } } -void FieldLayout::initialize_instance_layout(const InstanceKlass* super_klass) { +void FieldLayout::initialize_instance_layout(const InstanceKlass* super_klass, bool& super_ends_with_oop) { if (super_klass == nullptr) { + super_ends_with_oop = false; _blocks = new LayoutRawBlock(LayoutRawBlock::EMPTY, INT_MAX); _blocks->set_offset(0); _last = _blocks; _start = _blocks; insert(first_empty_block(), new LayoutRawBlock(LayoutRawBlock::RESERVED, instanceOopDesc::base_offset_in_bytes())); } else { - bool has_fields = reconstruct_layout(super_klass); + bool super_has_instance_fields = false; + reconstruct_layout(super_klass, super_has_instance_fields, super_ends_with_oop); fill_holes(super_klass); - if (!super_klass->has_contended_annotations() || !has_fields) { + if (!super_klass->has_contended_annotations() || !super_has_instance_fields) { _start = _blocks; // start allocating fields from the first empty block } else { _start = _last; // append fields at the end of the reconstructed layout @@ -293,15 +295,21 @@ LayoutRawBlock* FieldLayout::insert_field_block(LayoutRawBlock* slot, LayoutRawB return block; } -bool FieldLayout::reconstruct_layout(const InstanceKlass* ik) { - bool has_instance_fields = false; +void FieldLayout::reconstruct_layout(const InstanceKlass* ik, bool& has_instance_fields, bool& ends_with_oop) { + has_instance_fields = ends_with_oop = false; GrowableArray* all_fields = new GrowableArray(32); + BasicType last_type; + int last_offset = -1; while (ik != nullptr) { for (AllFieldStream fs(ik->fieldinfo_stream(), ik->constants()); !fs.done(); fs.next()) { BasicType type = Signature::basic_type(fs.signature()); // distinction between static and non-static fields is missing if (fs.access_flags().is_static()) continue; has_instance_fields = true; + if (fs.offset() > last_offset) { + last_offset = fs.offset(); + last_type = type; + } int size = type2aelembytes(type); // INHERITED blocks are marked as non-reference because oop_maps are handled by their holder class LayoutRawBlock* block = new LayoutRawBlock(fs.index(), LayoutRawBlock::INHERITED, size, size, false); @@ -310,6 +318,11 @@ bool FieldLayout::reconstruct_layout(const InstanceKlass* ik) { } ik = ik->super() == nullptr ? nullptr : InstanceKlass::cast(ik->super()); } + assert(last_offset == -1 || last_offset > 0, "Sanity"); + if (last_offset > 0 && + (last_type == BasicType::T_ARRAY || last_type == BasicType::T_OBJECT)) { + ends_with_oop = true; + } all_fields->sort(LayoutRawBlock::compare_offset); _blocks = new LayoutRawBlock(LayoutRawBlock::RESERVED, instanceOopDesc::base_offset_in_bytes()); @@ -323,7 +336,6 @@ bool FieldLayout::reconstruct_layout(const InstanceKlass* ik) { _last = b; } _start = _blocks; - return has_instance_fields; } // Called during the reconstruction of a layout, after fields from super @@ -516,7 +528,7 @@ FieldGroup* FieldLayoutBuilder::get_or_create_contended_group(int g) { void FieldLayoutBuilder::prologue() { _layout = new FieldLayout(_field_info, _constant_pool); const InstanceKlass* super_klass = _super_klass; - _layout->initialize_instance_layout(super_klass); + _layout->initialize_instance_layout(super_klass, _super_ends_with_oop); if (super_klass != nullptr) { _has_nonstatic_fields = super_klass->has_nonstatic_fields(); } @@ -594,8 +606,14 @@ void FieldLayoutBuilder::insert_contended_padding(LayoutRawBlock* slot) { // Computation of regular classes layout is an evolution of the previous default layout // (FieldAllocationStyle 1): // - primitive fields are allocated first (from the biggest to the smallest) -// - then oop fields are allocated, either in existing gaps or at the end of -// the layout +// - oop fields are allocated, either in existing gaps or at the end of +// the layout. We allocate oops in a single block to have a single oop map entry. +// - if the super class ended with an oop, we lead with oops. That will cause the +// trailing oop map entry of the super class and the oop map entry of this class +// to be folded into a single entry later. Correspondingly, if the super class +// ends with a primitive field, we gain nothing by leading with oops; therefore +// we let oop fields trail, thus giving future derived classes the chance to apply +// the same trick. void FieldLayoutBuilder::compute_regular_layout() { bool need_tail_padding = false; prologue(); @@ -608,8 +626,14 @@ void FieldLayoutBuilder::compute_regular_layout() { insert_contended_padding(_layout->start()); need_tail_padding = true; } - _layout->add(_root_group->primitive_fields()); - _layout->add(_root_group->oop_fields()); + + if (_super_ends_with_oop) { + _layout->add(_root_group->oop_fields()); + _layout->add(_root_group->primitive_fields()); + } else { + _layout->add(_root_group->primitive_fields()); + _layout->add(_root_group->oop_fields()); + } if (!_contended_groups.is_empty()) { for (int i = 0; i < _contended_groups.length(); i++) { diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp index 9b0d80b2a5583..82bbaefc62315 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -169,7 +169,7 @@ class FieldLayout : public ResourceObj { public: FieldLayout(GrowableArray* field_info, ConstantPool* cp); void initialize_static_layout(); - void initialize_instance_layout(const InstanceKlass* ik); + void initialize_instance_layout(const InstanceKlass* ik, bool& super_ends_with_oop); LayoutRawBlock* first_empty_block() { LayoutRawBlock* block = _start; @@ -188,7 +188,7 @@ class FieldLayout : public ResourceObj { void add_field_at_offset(LayoutRawBlock* blocks, int offset, LayoutRawBlock* start = nullptr); void add_contiguously(GrowableArray* list, LayoutRawBlock* start = nullptr); LayoutRawBlock* insert_field_block(LayoutRawBlock* slot, LayoutRawBlock* block); - bool reconstruct_layout(const InstanceKlass* ik); + void reconstruct_layout(const InstanceKlass* ik, bool& has_instance_fields, bool& ends_with_oop); void fill_holes(const InstanceKlass* ik); LayoutRawBlock* insert(LayoutRawBlock* slot, LayoutRawBlock* block); void remove(LayoutRawBlock* block); @@ -237,6 +237,7 @@ class FieldLayoutBuilder : public ResourceObj { int _alignment; bool _has_nonstatic_fields; bool _is_contended; // is a contended class? + bool _super_ends_with_oop; public: FieldLayoutBuilder(const Symbol* classname, const InstanceKlass* super_klass, ConstantPool* constant_pool, diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index a5afcb68299ab..31a74dd64236f 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -3763,7 +3763,7 @@ void InstanceKlass::print_on(outputStream* st) const { InstanceKlass* ik = const_cast(this); ik->print_nonstatic_fields(&print_nonstatic_field); - st->print(BULLET"non-static oop maps: "); + st->print(BULLET"non-static oop maps (%d entries): ", nonstatic_oop_map_count()); OopMapBlock* map = start_of_nonstatic_oop_maps(); OopMapBlock* end_map = map + nonstatic_oop_map_count(); while (map < end_map) { diff --git a/test/hotspot/jtreg/runtime/FieldLayout/TestOopMapSizeMinimal.java b/test/hotspot/jtreg/runtime/FieldLayout/TestOopMapSizeMinimal.java new file mode 100644 index 0000000000000..861f1aa3d1b17 --- /dev/null +++ b/test/hotspot/jtreg/runtime/FieldLayout/TestOopMapSizeMinimal.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Red Hat, Inc. 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. + */ + +import jdk.internal.misc.Unsafe; +import jdk.test.whitebox.WhiteBox; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +/* + * @test id=no_coops_no_ccptr_no_coh + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:-UseCompactObjectHeaders TestOopMapSizeMinimal + */ + +/* + * @test id=coops_no_ccptr_no_coh + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+UseCompressedOops -XX:-UseCompressedClassPointers -XX:-UseCompactObjectHeaders TestOopMapSizeMinimal + */ + +/* + * @test id=no_coops_ccptr_no_coh + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:-UseCompressedOops -XX:+UseCompressedClassPointers -XX:-UseCompactObjectHeaders TestOopMapSizeMinimal + */ + +/* + * @test id=coops_ccptr_no_coh + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:-UseCompactObjectHeaders TestOopMapSizeMinimal + */ + +/* + * @test id=no_coops_ccptr_coh + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:-UseCompressedOops -XX:+UseCompactObjectHeaders TestOopMapSizeMinimal + */ + +public class TestOopMapSizeMinimal { + + public static int OOP_SIZE_IN_BYTES = -1; + public static int HEADER_SIZE_IN_BYTES = -1; + + static { + WhiteBox WB = WhiteBox.getWhiteBox(); + boolean is_64_bit = System.getProperty("sun.arch.data.model").equals("64"); + if (is_64_bit) { + if (System.getProperty("java.vm.compressedOopsMode") == null) { + OOP_SIZE_IN_BYTES = 8; + } else { + OOP_SIZE_IN_BYTES = 4; + } + } else { + OOP_SIZE_IN_BYTES = 4; + } + if (is_64_bit) { + if (WB.getBooleanVMFlag("UseCompactObjectHeaders")) { + HEADER_SIZE_IN_BYTES = 8; + } else if (WB.getBooleanVMFlag("UseCompressedClassPointers")) { + HEADER_SIZE_IN_BYTES = 12; + } else { + HEADER_SIZE_IN_BYTES = 16; + } + } else { + HEADER_SIZE_IN_BYTES = 8; + } + } + + public static long alignUp(long value, long alignment) { + return (value + alignment - 1) & ~(alignment - 1); + } + + public static long alignForOop(long position) { + return alignUp(position, OOP_SIZE_IN_BYTES); + } + + private static final Unsafe U = Unsafe.getUnsafe(); + + public static class BASE { + int i1; + Object o1; + } + + public static class DERIVED1 extends BASE { + int i2; + Object o2; + } + + public static class DERIVED2 extends DERIVED1 { + int i3; + Object o3; + } + + public static class DERIVED3 extends DERIVED2 { + int i4; + Object o4; + } + + static boolean mismatch = false; + + private static void checkOffset(Field f, long expectedOffset) { + long realOffset = U.objectFieldOffset(f); + System.out.println("Offset for field " + f.getName() + + ": expected " + expectedOffset + ", got " + realOffset + "."); + if (U.objectFieldOffset(f) != expectedOffset) { + mismatch = true; + System.out.println(" ... mimatch"); + } + } + + private static List allFieldsOf(Class c) { + ArrayList l = new ArrayList<>(); + while (c != null) { + for (Field f : c.getDeclaredFields()) { + l.add(f); + } + c = c.getSuperclass(); + } + return l; + } + + public static void main(String[] args) throws Exception { + + System.out.println("HEADER_SIZE_IN_BYTES " + HEADER_SIZE_IN_BYTES + ", OOP_SIZE_IN_BYTES " + OOP_SIZE_IN_BYTES); + + long i1_loc_expected; + long o1_loc_expected; + long o2_loc_expected; + long i2_loc_expected; + long i3_loc_expected; + long o3_loc_expected; + long o4_loc_expected; + long i4_loc_expected; + + // We expect the layouter to reverse order of oop- and non-oop fields + // when it is useful to minimize the number of oop map entries. + // + // If we have no gaps, this should be the layout: + // BASE i1 + // o1 oopmap entry 1 + // DERIVED1 o2 oopmap entry 1 (reversed order) + // i2 + // DERIVED3 i3 + // o3 oopmap entry 2 + // DERIVED4 o4 oopmap entry 2 (reversed order) + // i4 + + // There are two combinations that have gaps: + // -UseCompressedOops + +COH, and -UseCompressedOops + -UseCompressedClassPointers. + // In both cases there is a gap following i1, and i2 will therefore nestle into that gap. + // Otherwise the same logic applies. + + if (OOP_SIZE_IN_BYTES == 4 || // oop size == int size + (OOP_SIZE_IN_BYTES == 8 && HEADER_SIZE_IN_BYTES == 12) + ) { + // No gaps + + // Expected layout for BASE: int, object + i1_loc_expected = HEADER_SIZE_IN_BYTES; + o1_loc_expected = i1_loc_expected + 4; + + // Expected layout for DERIVED1: object, int (to make o2 border o1) + o2_loc_expected = o1_loc_expected + OOP_SIZE_IN_BYTES; + i2_loc_expected = o2_loc_expected + OOP_SIZE_IN_BYTES; + + // Expected layout for DERIVED2: int, object (to trail with oops, for derived classes to nestle against) + i3_loc_expected = i2_loc_expected + 4; + o3_loc_expected = i3_loc_expected + 4; + + // Expected layout for DERIVED3: object, int (to make o4 border o3) + o4_loc_expected = o3_loc_expected + OOP_SIZE_IN_BYTES; + i4_loc_expected = o4_loc_expected + OOP_SIZE_IN_BYTES; + + } else if (OOP_SIZE_IN_BYTES == 8) { + + // gap after i1 + + i1_loc_expected = HEADER_SIZE_IN_BYTES; + o1_loc_expected = i1_loc_expected + 4 + 4; // + alignment gap + + o2_loc_expected = o1_loc_expected + OOP_SIZE_IN_BYTES; + i2_loc_expected = i1_loc_expected + 4; // into gap following i1 + + o3_loc_expected = o2_loc_expected + OOP_SIZE_IN_BYTES; + i3_loc_expected = o3_loc_expected + OOP_SIZE_IN_BYTES; + + i4_loc_expected = i3_loc_expected + 4; + o4_loc_expected = i4_loc_expected + 4; + } else { + throw new RuntimeException("Unexpected"); + } + + List l = allFieldsOf(DERIVED3.class); + for (Field f : l) { + switch (f.getName()) { + case "i1" : checkOffset(f, i1_loc_expected); break; + case "o1" : checkOffset(f, o1_loc_expected); break; + case "i2" : checkOffset(f, i2_loc_expected); break; + case "o2" : checkOffset(f, o2_loc_expected); break; + case "i3" : checkOffset(f, i3_loc_expected); break; + case "o3" : checkOffset(f, o3_loc_expected); break; + case "i4" : checkOffset(f, i4_loc_expected); break; + case "o4" : checkOffset(f, o4_loc_expected); break; + default: throw new RuntimeException("Unexpected"); + } + } + if (mismatch) { + throw new RuntimeException("Mismatch!"); + } + System.out.println("All good."); + } + +} + From 473251dbb308016ccda6c88fd36bd10c81e65865 Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Wed, 9 Apr 2025 05:09:30 +0000 Subject: [PATCH 0477/1101] 8353593: MethodData "mileage_*" methods and fields aren't used and can be removed Reviewed-by: phh, thartmann --- src/hotspot/share/oops/methodData.cpp | 6 ------ src/hotspot/share/oops/methodData.hpp | 11 ++--------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index 2d366168f08c6..280a69df58359 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -1257,7 +1257,6 @@ void MethodData::initialize() { ResourceMark rm(thread); init(); - set_creation_mileage(mileage_of(method())); // Go through the bytecodes and allocate and initialize the // corresponding data cells. @@ -1364,11 +1363,6 @@ void MethodData::init() { clear_escape_info(); } -// Get a measure of how much mileage the method has on it. -int MethodData::mileage_of(Method* method) { - return MAX2(method->invocation_count(), method->backedge_count()); -} - bool MethodData::is_mature() const { return CompilationPolicy::is_mature(_method); } diff --git a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp index 8375552a911b2..7870d6e459f1f 100644 --- a/src/hotspot/share/oops/methodData.hpp +++ b/src/hotspot/share/oops/methodData.hpp @@ -56,8 +56,7 @@ class BytecodeStream; // counter overflow, multiprocessor races during data collection, space // limitations, missing MDO blocks, etc. Bad or missing data will degrade // optimization quality but will not affect correctness. Also, each MDO -// is marked with its birth-date ("creation_mileage") which can be used -// to assess the quality ("maturity") of its data. +// can be checked for its "maturity" by calling is_mature(). // // Short (<32-bit) counters are designed to overflow to a known "saturated" // state. Also, certain recorded per-BCI events are given one-bit counters @@ -2061,8 +2060,6 @@ class MethodData : public Metadata { intx _arg_stack; // bit set of stack-allocatable arguments intx _arg_returned; // bit set of returned arguments - int _creation_mileage; // method mileage at MDO creation - // How many invocations has this MDO seen? // These counters are used to determine the exact age of MDO. // We need those because in tiered a method can be concurrently @@ -2225,9 +2222,6 @@ class MethodData : public Metadata { int size_in_bytes() const { return _size; } int size() const { return align_metadata_size(align_up(_size, BytesPerWord)/BytesPerWord); } - int creation_mileage() const { return _creation_mileage; } - void set_creation_mileage(int x) { _creation_mileage = x; } - int invocation_count() { if (invocation_counter()->carry()) { return InvocationCounter::count_limit; @@ -2280,8 +2274,7 @@ class MethodData : public Metadata { int num_blocks() const { return _num_blocks; } void set_num_blocks(short n) { _num_blocks = n; } - bool is_mature() const; // consult mileage and ProfileMaturityPercentage - static int mileage_of(Method* m); + bool is_mature() const; // Support for interprocedural escape analysis, from Thomas Kotzmann. enum EscapeFlag { From b045e3fbd7920465b5b67d43e35db98b935241d5 Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Wed, 9 Apr 2025 05:34:01 +0000 Subject: [PATCH 0478/1101] 8352681: C2 compilation hits asserts "must set the initial type just once" Reviewed-by: chagedorn, dfenacci --- src/hotspot/share/opto/memnode.cpp | 15 +++-- .../TestReduceAllocationAndSetTypeTwice.java | 62 +++++++++++++++++++ 2 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/escapeAnalysis/TestReduceAllocationAndSetTypeTwice.java diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index a19dbd664eb09..e596db8e0c7ce 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -289,10 +289,17 @@ static Node *step_through_mergemem(PhaseGVN *phase, MergeMemNode *mmem, const T toop->isa_instptr() && toop->is_instptr()->instance_klass()->is_java_lang_Object() && toop->offset() == Type::OffsetBot)) { - // compress paths and change unreachable cycles to TOP - // If not, we can update the input infinitely along a MergeMem cycle - // Equivalent code in PhiNode::Ideal - Node* m = phase->transform(mmem); + // IGVN _delay_transform may be set to true and if that is the case and mmem + // is already a registered node then the validation inside transform will + // complain. + Node* m = mmem; + PhaseIterGVN* igvn = phase->is_IterGVN(); + if (igvn == nullptr || !igvn->delay_transform()) { + // compress paths and change unreachable cycles to TOP + // If not, we can update the input infinitely along a MergeMem cycle + // Equivalent code in PhiNode::Ideal + m = phase->transform(mmem); + } // If transformed to a MergeMem, get the desired slice // Otherwise the returned node represents memory for every slice mem = (m->is_MergeMem())? m->as_MergeMem()->memory_at(alias_idx) : m; diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestReduceAllocationAndSetTypeTwice.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestReduceAllocationAndSetTypeTwice.java new file mode 100644 index 0000000000000..b44e70f536223 --- /dev/null +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestReduceAllocationAndSetTypeTwice.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8352681 + * @summary Check that RAM does not crash when split load through phi + * tries to register an old node twice with IGVN. + * @run main/othervm -XX:CompileCommand=compileonly,*TestReduceAllocationAndSetTypeTwice*::* + * -XX:CompileCommand=dontinline,*TestReduceAllocationAndSetTypeTwice*::* + * -Xcomp compiler.escapeAnalysis.TestReduceAllocationAndSetTypeTwice + * @run main compiler.escapeAnalysis.TestReduceAllocationAndSetTypeTwice + */ + +package compiler.escapeAnalysis; + +public class TestReduceAllocationAndSetTypeTwice { + public static double dummy() { + return 3.1415; + } + + public static double test(double param) { + Double double_1 = -26.335025324149626D; + Double double_2 = 87.9546734116494D; + + for (int i = 0, j = 0; i < 256; i++) { + if (param != param) { + j--; + } else if (dummy() > 0) { + return (j < 1234 ? double_1 : double_2); + } + } + + return 10.0; + } + + public static void main(String[] args) { + for (int i = 0; i < 512; i++) { + test(-3.1415); + } + } +} From 3340e13fd0a8d25212003e8371a135471b2f44b3 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Wed, 9 Apr 2025 06:19:08 +0000 Subject: [PATCH 0479/1101] 8352994: ZGC: Fix regression introduced in JDK-8350572 Reviewed-by: aboldtch, tschatzl --- src/hotspot/share/gc/z/zVerify.cpp | 2 +- test/jdk/ProblemList-zgc.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index 439a3710185a9..117d27997eed4 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -61,7 +61,7 @@ // with callers to this function. Typically used to verify that object oops // and headers are safe to access. void z_verify_safepoints_are_blocked() { - if (VMError::is_error_reported_in_current_thread()) { + if (VMError::is_error_reported() && VMError::is_error_reported_in_current_thread()) { // The current thread has crashed and is creating an error report. // This may occur from any thread state, skip the safepoint_are_blocked // verification. diff --git a/test/jdk/ProblemList-zgc.txt b/test/jdk/ProblemList-zgc.txt index 2bd7691be100e..ab44c5e47a970 100644 --- a/test/jdk/ProblemList-zgc.txt +++ b/test/jdk/ProblemList-zgc.txt @@ -38,4 +38,3 @@ sun/tools/jhsdb/heapconfig/JMapHeapConfigTest.java 8307393 generic-all sun/tools/jhsdb/HeapDumpTestWithActiveProcess.java 8307393 generic-all com/sun/jdi/ThreadMemoryLeakTest.java 8307402 generic-all -com/sun/jdi/JdbStopInNotificationThreadTest.java 8351607 linux-all From 0f70aae1cc4fd48ef2de3b0fe4741a32660ed4f9 Mon Sep 17 00:00:00 2001 From: Evgeny Nikitin Date: Wed, 9 Apr 2025 07:03:24 +0000 Subject: [PATCH 0480/1101] 8353841: [jittester] Fix JITTester build after asm removal Reviewed-by: thartmann, chagedorn --- test/hotspot/jtreg/testlibrary/jittester/Makefile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/testlibrary/jittester/Makefile b/test/hotspot/jtreg/testlibrary/jittester/Makefile index be06329a535a1..ec88f62e9ed82 100644 --- a/test/hotspot/jtreg/testlibrary/jittester/Makefile +++ b/test/hotspot/jtreg/testlibrary/jittester/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -83,6 +83,8 @@ TESTLIBRARY_SRC_FILES = $(TESTLIBRARY_SRC_DIR)/Asserts.java \ $(TESTLIBRARY_SRC_DIR)/util/FileUtils.java \ $(TESTLIBRARY_SRC_DIR)/util/Pair.java +ASM_SRC_DIR = ../asm/org/objectweb/asm/ + .PHONY: cleantmp all: $(DIST_JAR) @@ -95,11 +97,15 @@ manifest: @echo 'X-COMMENT: Main-Class will be added automatically by build' >> $(MANIFEST) @echo 'Main-Class: jdk.test.lib.jittester.Automatic' >> $(MANIFEST) +compile_asm: INIT + $(shell find $(ASM_SRC_DIR) -name '*.java' > $(CLASSES_DIR)/filelist_asm) + ${JAVAC} -d $(CLASSES_DIR) @$(CLASSES_DIR)/filelist_asm + compile_testlib: INIT - $(JAVAC) -XDignore.symbol.file --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED --add-exports=java.base/org.objectweb.asm=ALL-UNNAMED -Xlint $(TESTLIBRARY_SRC_FILES) -d $(CLASSES_DIR) + $(JAVAC) -XDignore.symbol.file --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED -Xlint $(TESTLIBRARY_SRC_FILES) -d $(CLASSES_DIR) -COMPILE: INIT filelist compile_testlib - $(JAVAC) -cp $(CLASSES_DIR) -XDignore.symbol.file --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED --add-exports=java.base/org.objectweb.asm=ALL-UNNAMED -Xlint -sourcepath $(SRC_DIR) -d $(CLASSES_DIR) @filelist +COMPILE: INIT filelist compile_asm compile_testlib + $(JAVAC) -cp $(CLASSES_DIR) -XDignore.symbol.file --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED -Xlint -sourcepath $(SRC_DIR) -d $(CLASSES_DIR) @filelist filelist: $(SRC_FILES) @rm -f $@ From 6df34c361e0d1b6fe90ca97c1aaa56e57a86d12c Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 9 Apr 2025 07:28:47 +0000 Subject: [PATCH 0481/1101] 8353174: Clean up thread register handling after 32-bit x86 removal Reviewed-by: cslucas, kvn, vlivanov --- src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp | 4 +- src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp | 5 +- src/hotspot/cpu/x86/c1_Runtime1_x86.cpp | 21 +- src/hotspot/cpu/x86/downcallLinker_x86_64.cpp | 4 +- src/hotspot/cpu/x86/interp_masm_x86.cpp | 20 +- src/hotspot/cpu/x86/interp_masm_x86.hpp | 5 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 185 ++++++------------ src/hotspot/cpu/x86/macroAssembler_x86.hpp | 46 ++--- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 15 +- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 10 +- .../x86/stubGenerator_x86_64_arraycopy.cpp | 2 +- .../x86/templateInterpreterGenerator_x86.cpp | 13 +- .../templateInterpreterGenerator_x86_64.cpp | 4 +- src/hotspot/cpu/x86/templateTable_x86.cpp | 14 +- src/hotspot/cpu/x86/x86_64.ad | 4 +- 15 files changed, 135 insertions(+), 217 deletions(-) diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index fa1bfaa71dbac..04e32e2b8be8c 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -326,7 +326,7 @@ void LIR_Assembler::clinit_barrier(ciMethod* method) { Register klass = rscratch1; __ mov_metadata(klass, method->holder()->constant_encoding()); - __ clinit_barrier(klass, r15_thread, &L_skip_barrier /*L_fast_path*/); + __ clinit_barrier(klass, &L_skip_barrier /*L_fast_path*/); __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); @@ -482,7 +482,7 @@ void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) { code_stub->set_safepoint_offset(__ offset()); __ relocate(relocInfo::poll_return_type); - __ safepoint_poll(*code_stub->entry(), r15_thread, true /* at_return */, true /* in_nmethod */); + __ safepoint_poll(*code_stub->entry(), true /* at_return */, true /* in_nmethod */); __ ret(0); } diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index 7ffa6d9bdd4fd..dd8c075cb872c 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -62,8 +62,7 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr } if (LockingMode == LM_LIGHTWEIGHT) { - const Register thread = r15_thread; - lightweight_lock(disp_hdr, obj, hdr, thread, tmp, slow_case); + lightweight_lock(disp_hdr, obj, hdr, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { Label done; // Load object header @@ -128,7 +127,7 @@ void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_ verify_oop(obj); if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_unlock(obj, disp_hdr, r15_thread, hdr, slow_case); + lightweight_unlock(obj, disp_hdr, hdr, slow_case); } else if (LockingMode == LM_LEGACY) { // test if object header is pointing to the displaced header, and if so, restore // the displaced header in the object - if the object header is not pointing to diff --git a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp index bb5111fa65236..f42032bb27535 100644 --- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp +++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp @@ -51,7 +51,7 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, int args_size) { // setup registers - const Register thread = r15_thread; // is callee-saved register (Visual C++ calling conventions) + const Register thread = r15_thread; assert(!(oop_result1->is_valid() || metadata_result->is_valid()) || oop_result1 != metadata_result, "registers must be different"); assert(oop_result1 != thread && metadata_result != thread, "registers must be different"); assert(args_size >= 0, "illegal args_size"); @@ -66,11 +66,11 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre int call_offset = -1; if (!align_stack) { - set_last_Java_frame(thread, noreg, rbp, nullptr, rscratch1); + set_last_Java_frame(noreg, rbp, nullptr, rscratch1); } else { address the_pc = pc(); call_offset = offset(); - set_last_Java_frame(thread, noreg, rbp, the_pc, rscratch1); + set_last_Java_frame(noreg, rbp, the_pc, rscratch1); andptr(rsp, -(StackAlignmentInBytes)); // Align stack } @@ -84,7 +84,7 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre guarantee(thread != rax, "change this code"); push(rax); { Label L; - get_thread(rax); + get_thread_slow(rax); cmpptr(thread, rax); jcc(Assembler::equal, L); int3(); @@ -93,7 +93,7 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre } pop(rax); #endif - reset_last_Java_frame(thread, true); + reset_last_Java_frame(true); // check for pending exceptions { Label L; @@ -120,10 +120,10 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre } // get oop results if there are any and reset the values in the thread if (oop_result1->is_valid()) { - get_vm_result(oop_result1, thread); + get_vm_result(oop_result1); } if (metadata_result->is_valid()) { - get_vm_result_2(metadata_result, thread); + get_vm_result_2(metadata_result); } assert(call_offset >= 0, "Should be set"); @@ -715,8 +715,7 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) { const Register thread = r15_thread; // No need to worry about dummy __ mov(c_rarg0, thread); - - __ set_last_Java_frame(thread, noreg, rbp, nullptr, rscratch1); + __ set_last_Java_frame(noreg, rbp, nullptr, rscratch1); // do the call __ call(RuntimeAddress(target)); OopMapSet* oop_maps = new OopMapSet(); @@ -726,7 +725,7 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) { guarantee(thread != rax, "change this code"); __ push(rax); { Label L; - __ get_thread(rax); + __ get_thread_slow(rax); __ cmpptr(thread, rax); __ jcc(Assembler::equal, L); __ stop("StubAssembler::call_RT: rdi/r15 not callee saved?"); @@ -734,7 +733,7 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) { } __ pop(rax); #endif - __ reset_last_Java_frame(thread, true); + __ reset_last_Java_frame(true); // check for pending exceptions { Label L; diff --git a/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp b/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp index 15c311ffd39b7..c48940198ea89 100644 --- a/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp +++ b/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp @@ -291,7 +291,7 @@ void DowncallLinker::StubGenerator::generate() { Assembler::StoreLoad | Assembler::StoreStore)); } - __ safepoint_poll(L_safepoint_poll_slow_path, r15_thread, true /* at_return */, false /* in_nmethod */); + __ safepoint_poll(L_safepoint_poll_slow_path, true /* at_return */, false /* in_nmethod */); __ cmpl(Address(r15_thread, JavaThread::suspend_flags_offset()), 0); __ jcc(Assembler::notEqual, L_safepoint_poll_slow_path); @@ -305,7 +305,7 @@ void DowncallLinker::StubGenerator::generate() { __ jcc(Assembler::equal, L_reguard); __ bind(L_after_reguard); - __ reset_last_Java_frame(r15_thread, true); + __ reset_last_Java_frame(true); __ block_comment("} thread native2java"); } diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index 84a99060a3efa..93117ff8b7d47 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -296,7 +296,6 @@ void InterpreterMacroAssembler::call_VM_leaf_base(address entry_point, } void InterpreterMacroAssembler::call_VM_base(Register oop_result, - Register java_thread, Register last_java_sp, address entry_point, int number_of_arguments, @@ -319,7 +318,7 @@ void InterpreterMacroAssembler::call_VM_base(Register oop_result, } #endif /* ASSERT */ // super call - MacroAssembler::call_VM_base(oop_result, noreg, last_java_sp, + MacroAssembler::call_VM_base(oop_result, last_java_sp, entry_point, number_of_arguments, check_exceptions); // interpreter specific @@ -379,7 +378,7 @@ void InterpreterMacroAssembler::restore_after_resume(bool is_native) { } } -void InterpreterMacroAssembler::check_and_handle_popframe(Register java_thread) { +void InterpreterMacroAssembler::check_and_handle_popframe() { if (JvmtiExport::can_pop_frame()) { Label L; // Initiate popframe handling only if it is not already being @@ -389,7 +388,7 @@ void InterpreterMacroAssembler::check_and_handle_popframe(Register java_thread) // This method is only called just after the call into the vm in // call_VM_base, so the arg registers are available. Register pop_cond = c_rarg0; - movl(pop_cond, Address(java_thread, JavaThread::popframe_condition_offset())); + movl(pop_cond, Address(r15_thread, JavaThread::popframe_condition_offset())); testl(pop_cond, JavaThread::popframe_pending_bit); jcc(Assembler::zero, L); testl(pop_cond, JavaThread::popframe_processing_bit); @@ -430,7 +429,7 @@ void InterpreterMacroAssembler::load_earlyret_value(TosState state) { } -void InterpreterMacroAssembler::check_and_handle_earlyret(Register java_thread) { +void InterpreterMacroAssembler::check_and_handle_earlyret() { if (JvmtiExport::can_force_early_return()) { Label L; Register tmp = c_rarg0; @@ -810,13 +809,13 @@ void InterpreterMacroAssembler::remove_activation( // the stack, will call InterpreterRuntime::at_unwind. Label slow_path; Label fast_path; - safepoint_poll(slow_path, rthread, true /* at_return */, false /* in_nmethod */); + safepoint_poll(slow_path, true /* at_return */, false /* in_nmethod */); jmp(fast_path); bind(slow_path); push(state); - set_last_Java_frame(rthread, noreg, rbp, (address)pc(), rscratch1); + set_last_Java_frame(noreg, rbp, (address)pc(), rscratch1); super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind), rthread); - reset_last_Java_frame(rthread, true); + reset_last_Java_frame(true); pop(state); bind(fast_path); @@ -1031,8 +1030,7 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) { } if (LockingMode == LM_LIGHTWEIGHT) { - const Register thread = r15_thread; - lightweight_lock(lock_reg, obj_reg, swap_reg, thread, tmp_reg, slow_case); + lightweight_lock(lock_reg, obj_reg, swap_reg, tmp_reg, slow_case); } else if (LockingMode == LM_LEGACY) { // Load immediate 1 into swap_reg %rax movl(swap_reg, 1); @@ -1141,7 +1139,7 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) { movptr(Address(lock_reg, BasicObjectLock::obj_offset()), NULL_WORD); if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_unlock(obj_reg, swap_reg, r15_thread, header_reg, slow_case); + lightweight_unlock(obj_reg, swap_reg, header_reg, slow_case); } else if (LockingMode == LM_LEGACY) { // Load the old header from BasicLock structure movptr(header_reg, Address(swap_reg, diff --git a/src/hotspot/cpu/x86/interp_masm_x86.hpp b/src/hotspot/cpu/x86/interp_masm_x86.hpp index e537e9efc9678..308d700ff4fbf 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.hpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.hpp @@ -42,7 +42,6 @@ class InterpreterMacroAssembler: public MacroAssembler { protected: virtual void call_VM_base(Register oop_result, - Register java_thread, Register last_java_sp, address entry_point, int number_of_arguments, @@ -58,8 +57,8 @@ class InterpreterMacroAssembler: public MacroAssembler { void jump_to_entry(address entry); - virtual void check_and_handle_popframe(Register java_thread); - virtual void check_and_handle_earlyret(Register java_thread); + virtual void check_and_handle_popframe(); + virtual void check_and_handle_earlyret(); void load_earlyret_value(TosState state); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index c92ce2f283cea..a2173be609b62 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -724,17 +724,6 @@ void MacroAssembler::pushptr(AddressLiteral src, Register rscratch) { } } -void MacroAssembler::reset_last_Java_frame(bool clear_fp) { - reset_last_Java_frame(r15_thread, clear_fp); -} - -void MacroAssembler::set_last_Java_frame(Register last_java_sp, - Register last_java_fp, - address last_java_pc, - Register rscratch) { - set_last_Java_frame(r15_thread, last_java_sp, last_java_fp, last_java_pc, rscratch); -} - static void pass_arg0(MacroAssembler* masm, Register arg) { if (c_rarg0 != arg ) { masm->mov(c_rarg0, arg); @@ -1487,8 +1476,7 @@ void MacroAssembler::call_VM(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) { - Register thread = LP64_ONLY(r15_thread) NOT_LP64(noreg); - call_VM_base(oop_result, thread, last_java_sp, entry_point, number_of_arguments, check_exceptions); + call_VM_base(oop_result, last_java_sp, entry_point, number_of_arguments, check_exceptions); } void MacroAssembler::call_VM(Register oop_result, @@ -1533,8 +1521,7 @@ void MacroAssembler::super_call_VM(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) { - Register thread = LP64_ONLY(r15_thread) NOT_LP64(noreg); - MacroAssembler::call_VM_base(oop_result, thread, last_java_sp, entry_point, number_of_arguments, check_exceptions); + MacroAssembler::call_VM_base(oop_result, last_java_sp, entry_point, number_of_arguments, check_exceptions); } void MacroAssembler::super_call_VM(Register oop_result, @@ -1575,31 +1562,22 @@ void MacroAssembler::super_call_VM(Register oop_result, } void MacroAssembler::call_VM_base(Register oop_result, - Register java_thread, Register last_java_sp, address entry_point, int number_of_arguments, bool check_exceptions) { - // determine java_thread register - if (!java_thread->is_valid()) { -#ifdef _LP64 - java_thread = r15_thread; -#else - java_thread = rdi; - get_thread(java_thread); -#endif // LP64 - } + Register java_thread = r15_thread; + // determine last_java_sp register if (!last_java_sp->is_valid()) { last_java_sp = rsp; } // debugging support assert(number_of_arguments >= 0 , "cannot have negative number of arguments"); - LP64_ONLY(assert(java_thread == r15_thread, "unexpected register")); #ifdef ASSERT // TraceBytecodes does not use r12 but saves it over the call, so don't verify // r12 is the heapbase. - LP64_ONLY(if (UseCompressedOops && !TraceBytecodes) verify_heapbase("call_VM_base: heap base corrupted?");) + if (UseCompressedOops && !TraceBytecodes) verify_heapbase("call_VM_base: heap base corrupted?"); #endif // ASSERT assert(java_thread != oop_result , "cannot use the same register for java_thread & oop_result"); @@ -1607,53 +1585,42 @@ void MacroAssembler::call_VM_base(Register oop_result, // push java thread (becomes first argument of C function) - NOT_LP64(push(java_thread); number_of_arguments++); - LP64_ONLY(mov(c_rarg0, r15_thread)); + mov(c_rarg0, r15_thread); // set last Java frame before call assert(last_java_sp != rbp, "can't use ebp/rbp"); // Only interpreter should have to set fp - set_last_Java_frame(java_thread, last_java_sp, rbp, nullptr, rscratch1); + set_last_Java_frame(last_java_sp, rbp, nullptr, rscratch1); // do the call, remove parameters MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments); - // restore the thread (cannot use the pushed argument since arguments - // may be overwritten by C code generated by an optimizing compiler); - // however can use the register value directly if it is callee saved. - if (LP64_ONLY(true ||) java_thread == rdi || java_thread == rsi) { - // rdi & rsi (also r15) are callee saved -> nothing to do #ifdef ASSERT - guarantee(java_thread != rax, "change this code"); - push(rax); - { Label L; - get_thread(rax); - cmpptr(java_thread, rax); - jcc(Assembler::equal, L); - STOP("MacroAssembler::call_VM_base: rdi not callee saved?"); - bind(L); - } - pop(rax); -#endif - } else { - get_thread(java_thread); + // Check that thread register is not clobbered. + guarantee(java_thread != rax, "change this code"); + push(rax); + { Label L; + get_thread_slow(rax); + cmpptr(java_thread, rax); + jcc(Assembler::equal, L); + STOP("MacroAssembler::call_VM_base: java_thread not callee saved?"); + bind(L); } + pop(rax); +#endif + // reset last Java frame // Only interpreter should have to clear fp - reset_last_Java_frame(java_thread, true); + reset_last_Java_frame(true); // C++ interp handles this in the interpreter - check_and_handle_popframe(java_thread); - check_and_handle_earlyret(java_thread); + check_and_handle_popframe(); + check_and_handle_earlyret(); if (check_exceptions) { // check for pending exceptions (java_thread is set upon return) - cmpptr(Address(java_thread, Thread::pending_exception_offset()), NULL_WORD); -#ifndef _LP64 - jump_cc(Assembler::notEqual, - RuntimeAddress(StubRoutines::forward_exception_entry())); -#else + cmpptr(Address(r15_thread, Thread::pending_exception_offset()), NULL_WORD); // This used to conditionally jump to forward_exception however it is // possible if we relocate that the branch will not reach. So we must jump // around so we can always reach @@ -1662,36 +1629,24 @@ void MacroAssembler::call_VM_base(Register oop_result, jcc(Assembler::equal, ok); jump(RuntimeAddress(StubRoutines::forward_exception_entry())); bind(ok); -#endif // LP64 } // get oop result if there is one and reset the value in the thread if (oop_result->is_valid()) { - get_vm_result(oop_result, java_thread); + get_vm_result(oop_result); } } void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) { + // Calculate the value for last_Java_sp somewhat subtle. + // call_VM does an intermediate call which places a return address on + // the stack just under the stack pointer as the user finished with it. + // This allows use to retrieve last_Java_pc from last_Java_sp[-1]. - // Calculate the value for last_Java_sp - // somewhat subtle. call_VM does an intermediate call - // which places a return address on the stack just under the - // stack pointer as the user finished with it. This allows - // use to retrieve last_Java_pc from last_Java_sp[-1]. - // On 32bit we then have to push additional args on the stack to accomplish - // the actual requested call. On 64bit call_VM only can use register args - // so the only extra space is the return address that call_VM created. - // This hopefully explains the calculations here. - -#ifdef _LP64 // We've pushed one address, correct last_Java_sp lea(rax, Address(rsp, wordSize)); -#else - lea(rax, Address(rsp, (1 + number_of_arguments) * wordSize)); -#endif // LP64 - - call_VM_base(oop_result, noreg, rax, entry_point, number_of_arguments, check_exceptions); + call_VM_base(oop_result, rax, entry_point, number_of_arguments, check_exceptions); } // Use this method when MacroAssembler version of call_VM_leaf_base() should be called from Interpreter. @@ -1768,21 +1723,21 @@ void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Reg MacroAssembler::call_VM_leaf_base(entry_point, 4); } -void MacroAssembler::get_vm_result(Register oop_result, Register java_thread) { - movptr(oop_result, Address(java_thread, JavaThread::vm_result_offset())); - movptr(Address(java_thread, JavaThread::vm_result_offset()), NULL_WORD); +void MacroAssembler::get_vm_result(Register oop_result) { + movptr(oop_result, Address(r15_thread, JavaThread::vm_result_offset())); + movptr(Address(r15_thread, JavaThread::vm_result_offset()), NULL_WORD); verify_oop_msg(oop_result, "broken oop in call_VM_base"); } -void MacroAssembler::get_vm_result_2(Register metadata_result, Register java_thread) { - movptr(metadata_result, Address(java_thread, JavaThread::vm_result_2_offset())); - movptr(Address(java_thread, JavaThread::vm_result_2_offset()), NULL_WORD); +void MacroAssembler::get_vm_result_2(Register metadata_result) { + movptr(metadata_result, Address(r15_thread, JavaThread::vm_result_2_offset())); + movptr(Address(r15_thread, JavaThread::vm_result_2_offset()), NULL_WORD); } -void MacroAssembler::check_and_handle_earlyret(Register java_thread) { +void MacroAssembler::check_and_handle_earlyret() { } -void MacroAssembler::check_and_handle_popframe(Register java_thread) { +void MacroAssembler::check_and_handle_popframe() { } void MacroAssembler::cmp32(AddressLiteral src1, int32_t imm, Register rscratch) { @@ -3170,20 +3125,16 @@ void MacroAssembler::stop_if_in_cont(Register cont, const char* name) { } #endif -void MacroAssembler::reset_last_Java_frame(Register java_thread, bool clear_fp) { // determine java_thread register - if (!java_thread->is_valid()) { - java_thread = rdi; - get_thread(java_thread); - } +void MacroAssembler::reset_last_Java_frame(bool clear_fp) { // determine java_thread register // we must set sp to zero to clear frame - movptr(Address(java_thread, JavaThread::last_Java_sp_offset()), NULL_WORD); + movptr(Address(r15_thread, JavaThread::last_Java_sp_offset()), NULL_WORD); // must clear fp, so that compiled frames are not confused; it is // possible that we need it only for debugging if (clear_fp) { - movptr(Address(java_thread, JavaThread::last_Java_fp_offset()), NULL_WORD); + movptr(Address(r15_thread, JavaThread::last_Java_fp_offset()), NULL_WORD); } // Always clear the pc because it could have been set by make_walkable() - movptr(Address(java_thread, JavaThread::last_Java_pc_offset()), NULL_WORD); + movptr(Address(r15_thread, JavaThread::last_Java_pc_offset()), NULL_WORD); vzeroupper(); } @@ -3202,15 +3153,15 @@ void MacroAssembler::save_rax(Register tmp) { else if (tmp != rax) mov(tmp, rax); } -void MacroAssembler::safepoint_poll(Label& slow_path, Register thread_reg, bool at_return, bool in_nmethod) { +void MacroAssembler::safepoint_poll(Label& slow_path, bool at_return, bool in_nmethod) { if (at_return) { // Note that when in_nmethod is set, the stack pointer is incremented before the poll. Therefore, // we may safely use rsp instead to perform the stack watermark check. - cmpptr(in_nmethod ? rsp : rbp, Address(thread_reg, JavaThread::polling_word_offset())); + cmpptr(in_nmethod ? rsp : rbp, Address(r15_thread, JavaThread::polling_word_offset())); jcc(Assembler::above, slow_path); return; } - testb(Address(thread_reg, JavaThread::polling_word_offset()), SafepointMechanism::poll_bit()); + testb(Address(r15_thread, JavaThread::polling_word_offset()), SafepointMechanism::poll_bit()); jcc(Assembler::notZero, slow_path); // handshake bit set implies poll } @@ -3219,44 +3170,36 @@ void MacroAssembler::safepoint_poll(Label& slow_path, Register thread_reg, bool // When entering C land, the rbp, & rsp of the last Java frame have to be recorded // in the (thread-local) JavaThread object. When leaving C land, the last Java fp // has to be reset to 0. This is required to allow proper stack traversal. -void MacroAssembler::set_last_Java_frame(Register java_thread, - Register last_java_sp, +void MacroAssembler::set_last_Java_frame(Register last_java_sp, Register last_java_fp, address last_java_pc, Register rscratch) { vzeroupper(); - // determine java_thread register - if (!java_thread->is_valid()) { - java_thread = rdi; - get_thread(java_thread); - } // determine last_java_sp register if (!last_java_sp->is_valid()) { last_java_sp = rsp; } // last_java_fp is optional if (last_java_fp->is_valid()) { - movptr(Address(java_thread, JavaThread::last_Java_fp_offset()), last_java_fp); + movptr(Address(r15_thread, JavaThread::last_Java_fp_offset()), last_java_fp); } // last_java_pc is optional if (last_java_pc != nullptr) { - Address java_pc(java_thread, + Address java_pc(r15_thread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::last_Java_pc_offset()); lea(java_pc, InternalAddress(last_java_pc), rscratch); } - movptr(Address(java_thread, JavaThread::last_Java_sp_offset()), last_java_sp); + movptr(Address(r15_thread, JavaThread::last_Java_sp_offset()), last_java_sp); } -#ifdef _LP64 void MacroAssembler::set_last_Java_frame(Register last_java_sp, Register last_java_fp, Label &L, Register scratch) { lea(scratch, L); movptr(Address(r15_thread, JavaThread::last_Java_pc_offset()), scratch); - set_last_Java_frame(r15_thread, last_java_sp, last_java_fp, nullptr, scratch); + set_last_Java_frame(last_java_sp, last_java_fp, nullptr, scratch); } -#endif void MacroAssembler::shlptr(Register dst, int imm8) { LP64_ONLY(shlq(dst, imm8)) NOT_LP64(shll(dst, imm8)); @@ -4111,8 +4054,8 @@ void MacroAssembler::clear_jobject_tag(Register possibly_non_local) { } void MacroAssembler::resolve_jobject(Register value, - Register thread, Register tmp) { + Register thread = r15_thread; assert_different_registers(value, thread, tmp); Label done, tagged, weak_tagged; testptr(value, value); @@ -4144,8 +4087,8 @@ void MacroAssembler::resolve_jobject(Register value, } void MacroAssembler::resolve_global_jobject(Register value, - Register thread, Register tmp) { + Register thread = r15_thread; assert_different_registers(value, thread, tmp); Label done; @@ -5476,7 +5419,7 @@ void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass, #endif // LP64 -void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fast_path, Label* L_slow_path) { +void MacroAssembler::clinit_barrier(Register klass, Label* L_fast_path, Label* L_slow_path) { assert(L_fast_path != nullptr || L_slow_path != nullptr, "at least one is required"); Label L_fallthrough; @@ -5492,7 +5435,7 @@ void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fa jcc(Assembler::equal, *L_fast_path); // Fast path check: current thread is initializer thread - cmpptr(thread, Address(klass, InstanceKlass::init_thread_offset())); + cmpptr(r15_thread, Address(klass, InstanceKlass::init_thread_offset())); if (L_slow_path == &L_fallthrough) { jcc(Assembler::equal, *L_fast_path); bind(*L_slow_path); @@ -10746,33 +10689,29 @@ Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) } // This is simply a call to Thread::current() -void MacroAssembler::get_thread(Register thread) { +void MacroAssembler::get_thread_slow(Register thread) { if (thread != rax) { push(rax); } - LP64_ONLY(push(rdi);) - LP64_ONLY(push(rsi);) + push(rdi); + push(rsi); push(rdx); push(rcx); -#ifdef _LP64 push(r8); push(r9); push(r10); push(r11); -#endif MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, Thread::current), 0); -#ifdef _LP64 pop(r11); pop(r10); pop(r9); pop(r8); -#endif pop(rcx); pop(rdx); - LP64_ONLY(pop(rsi);) - LP64_ONLY(pop(rdi);) + pop(rsi); + pop(rdi); if (thread != rax) { mov(thread, rax); pop(rax); @@ -10801,7 +10740,9 @@ void MacroAssembler::check_stack_alignment(Register sp, const char* msg, unsigne // reg_rax: rax // thread: the thread which attempts to lock obj // tmp: a temporary register -void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Register reg_rax, Register thread, Register tmp, Label& slow) { +void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Register reg_rax, Register tmp, Label& slow) { + Register thread = r15_thread; + assert(reg_rax == rax, ""); assert_different_registers(basic_lock, obj, reg_rax, thread, tmp); @@ -10855,7 +10796,9 @@ void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Registe // reg_rax: rax // thread: the thread // tmp: a temporary register -void MacroAssembler::lightweight_unlock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow) { +void MacroAssembler::lightweight_unlock(Register obj, Register reg_rax, Register tmp, Label& slow) { + Register thread = r15_thread; + assert(reg_rax == rax, ""); assert_different_registers(obj, reg_rax, thread, tmp); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 36ef3a69d49d4..79f99afded24d 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -59,13 +59,10 @@ class MacroAssembler: public Assembler { // may customize this version by overriding it for its purposes (e.g., to save/restore // additional registers when doing a VM call). // - // If no java_thread register is specified (noreg) than rdi will be used instead. call_VM_base - // returns the register which contains the thread upon return. If a thread register has been - // specified, the return value will correspond to that register. If no last_java_sp is specified - // (noreg) than rsp will be used instead. + // call_VM_base returns the register which contains the thread upon return. + // If no last_java_sp is specified (noreg) than rsp will be used instead. virtual void call_VM_base( // returns the register containing the thread upon return Register oop_result, // where an oop-result ends up if any; use noreg otherwise - Register java_thread, // the thread if computed before ; use noreg otherwise Register last_java_sp, // to set up last_Java_frame in stubs; use noreg otherwise address entry_point, // the entry point int number_of_arguments, // the number of arguments (w/o thread) to pop after the call @@ -85,8 +82,8 @@ class MacroAssembler: public Assembler { // These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code. // The implementation is only non-empty for the InterpreterMacroAssembler, // as only the interpreter handles PopFrame and ForceEarlyReturn requests. - virtual void check_and_handle_popframe(Register java_thread); - virtual void check_and_handle_earlyret(Register java_thread); + virtual void check_and_handle_popframe(); + virtual void check_and_handle_earlyret(); Address as_Address(AddressLiteral adr); Address as_Address(ArrayAddress adr, Register rscratch); @@ -224,9 +221,10 @@ class MacroAssembler: public Assembler { void enter(); void leave(); - // Support for getting the JavaThread pointer (i.e.; a reference to thread-local information) - // The pointer will be loaded into the thread register. - void get_thread(Register thread); + // Support for getting the JavaThread pointer (i.e.; a reference to thread-local information). + // The pointer will be loaded into the thread register. This is a slow version that does native call. + // Normally, JavaThread pointer is available in r15_thread, use that where possible. + void get_thread_slow(Register thread); #ifdef _LP64 // Support for argument shuffling @@ -291,8 +289,8 @@ class MacroAssembler: public Assembler { Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true); - void get_vm_result (Register oop_result, Register thread); - void get_vm_result_2(Register metadata_result, Register thread); + void get_vm_result (Register oop_result); + void get_vm_result_2(Register metadata_result); // These always tightly bind to MacroAssembler::call_VM_base // bypassing the virtual implementation @@ -323,35 +321,22 @@ class MacroAssembler: public Assembler { void super_call_VM_leaf(address entry_point, Register arg_1, Register arg_2, Register arg_3); void super_call_VM_leaf(address entry_point, Register arg_1, Register arg_2, Register arg_3, Register arg_4); - // last Java Frame (fills frame anchor) - void set_last_Java_frame(Register thread, - Register last_java_sp, - Register last_java_fp, - address last_java_pc, - Register rscratch); - - // thread in the default location (r15_thread on 64bit) void set_last_Java_frame(Register last_java_sp, Register last_java_fp, address last_java_pc, Register rscratch); -#ifdef _LP64 void set_last_Java_frame(Register last_java_sp, Register last_java_fp, Label &last_java_pc, Register scratch); -#endif - - void reset_last_Java_frame(Register thread, bool clear_fp); - // thread in the default location (r15_thread on 64bit) void reset_last_Java_frame(bool clear_fp); // jobjects void clear_jobject_tag(Register possibly_non_local); - void resolve_jobject(Register value, Register thread, Register tmp); - void resolve_global_jobject(Register value, Register thread, Register tmp); + void resolve_jobject(Register value, Register tmp); + void resolve_global_jobject(Register value, Register tmp); // C 'boolean' to Java boolean: x == 0 ? 0 : 1 void c2bool(Register x); @@ -762,7 +747,6 @@ class MacroAssembler: public Assembler { Label& L_success); void clinit_barrier(Register klass, - Register thread, Label* L_fast_path = nullptr, Label* L_slow_path = nullptr); @@ -837,7 +821,7 @@ class MacroAssembler: public Assembler { // Check for reserved stack access in method being exited (for JIT) void reserved_stack_check(); - void safepoint_poll(Label& slow_path, Register thread_reg, bool at_return, bool in_nmethod); + void safepoint_poll(Label& slow_path, bool at_return, bool in_nmethod); void verify_tlab(); @@ -2247,8 +2231,8 @@ class MacroAssembler: public Assembler { void check_stack_alignment(Register sp, const char* msg, unsigned bias = 0, Register tmp = noreg); - void lightweight_lock(Register basic_lock, Register obj, Register reg_rax, Register thread, Register tmp, Label& slow); - void lightweight_unlock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow); + void lightweight_lock(Register basic_lock, Register obj, Register reg_rax, Register tmp, Label& slow); + void lightweight_unlock(Register obj, Register reg_rax, Register tmp, Label& slow); #ifdef _LP64 void save_legacy_gprs(); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index d3e7e23678ae7..09c102aa5d16a 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -1104,7 +1104,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm Register klass = rscratch1; __ load_method_holder(klass, method); - __ clinit_barrier(klass, r15_thread, &L_skip_barrier /*L_fast_path*/); + __ clinit_barrier(klass, &L_skip_barrier /*L_fast_path*/); __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path @@ -2003,7 +2003,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label L_skip_barrier; Register klass = r10; __ mov_metadata(klass, method->method_holder()); // InstanceKlass* - __ clinit_barrier(klass, r15_thread, &L_skip_barrier /*L_fast_path*/); + __ clinit_barrier(klass, &L_skip_barrier /*L_fast_path*/); __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path @@ -2280,7 +2280,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ inc_held_monitor_count(); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ lightweight_lock(lock_reg, obj_reg, swap_reg, r15_thread, rscratch1, slow_path_lock); + __ lightweight_lock(lock_reg, obj_reg, swap_reg, rscratch1, slow_path_lock); } // Slow path will re-enter here @@ -2340,7 +2340,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label Continue; Label slow_path; - __ safepoint_poll(slow_path, r15_thread, true /* at_return */, false /* in_nmethod */); + __ safepoint_poll(slow_path, true /* at_return */, false /* in_nmethod */); __ cmpl(Address(r15_thread, JavaThread::suspend_flags_offset()), 0); __ jcc(Assembler::equal, Continue); @@ -2431,7 +2431,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ dec_held_monitor_count(); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ lightweight_unlock(obj_reg, swap_reg, r15_thread, lock_reg, slow_path_unlock); + __ lightweight_unlock(obj_reg, swap_reg, lock_reg, slow_path_unlock); } // slow path re-enters here @@ -2456,7 +2456,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Unbox oop result, e.g. JNIHandles::resolve value. if (is_reference_type(ret_type)) { __ resolve_jobject(rax /* value */, - r15_thread /* thread */, rcx /* tmp */); } @@ -3234,7 +3233,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti __ jcc(Assembler::notEqual, pending); // get the returned Method* - __ get_vm_result_2(rbx, r15_thread); + __ get_vm_result_2(rbx); __ movptr(Address(rsp, RegisterSaver::rbx_offset_in_bytes()), rbx); __ movptr(Address(rsp, RegisterSaver::rax_offset_in_bytes()), rax); @@ -3661,7 +3660,7 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { __ reset_last_Java_frame(true); // rax is jobject handle result, unpack and process it through a barrier. - __ resolve_global_jobject(rax, r15_thread, c_rarg0); + __ resolve_global_jobject(rax, c_rarg0); __ leave(); __ ret(0); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 7e63e6fb49b62..9fcb044b09a42 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -339,7 +339,7 @@ address StubGenerator::generate_call_stub(address& return_address) { __ jcc(Assembler::equal, L1); __ stop("StubRoutines::call_stub: r15_thread is corrupted"); __ bind(L1); - __ get_thread(rbx); + __ get_thread_slow(rbx); __ cmpptr(r15_thread, thread); __ jcc(Assembler::equal, L2); __ stop("StubRoutines::call_stub: r15_thread is modified by call"); @@ -426,7 +426,7 @@ address StubGenerator::generate_catch_exception() { __ jcc(Assembler::equal, L1); __ stop("StubRoutines::catch_exception: r15_thread is corrupted"); __ bind(L1); - __ get_thread(rbx); + __ get_thread_slow(rbx); __ cmpptr(r15_thread, thread); __ jcc(Assembler::equal, L2); __ stop("StubRoutines::catch_exception: r15_thread is modified by call"); @@ -1313,7 +1313,7 @@ void StubGenerator::setup_arg_regs_using_thread(int nargs) { __ mov(rax, r9); // r9 is also saved_r15 } __ mov(saved_r15, r15); // r15 is callee saved and needs to be restored - __ get_thread(r15_thread); + __ get_thread_slow(r15_thread); assert(c_rarg0 == rcx && c_rarg1 == rdx && c_rarg2 == r8 && c_rarg3 == r9, "unexpected argument registers"); __ movptr(Address(r15_thread, in_bytes(JavaThread::windows_saved_rdi_offset())), rdi); @@ -1337,7 +1337,7 @@ void StubGenerator::restore_arg_regs_using_thread() { assert(_regs_in_thread, "wrong call to restore_arg_regs"); const Register saved_r15 = r9; #ifdef _WIN64 - __ get_thread(r15_thread); + __ get_thread_slow(r15_thread); __ movptr(rsi, Address(r15_thread, in_bytes(JavaThread::windows_saved_rsi_offset()))); __ movptr(rdi, Address(r15_thread, in_bytes(JavaThread::windows_saved_rdi_offset()))); __ mov(r15, saved_r15); // r15 is callee saved and needs to be restored @@ -3974,7 +3974,7 @@ address StubGenerator::generate_upcall_stub_load_target() { StubCodeMark mark(this, stub_id); address start = __ pc(); - __ resolve_global_jobject(j_rarg0, r15_thread, rscratch1); + __ resolve_global_jobject(j_rarg0, rscratch1); // Load target method from receiver __ load_heap_oop(rbx, Address(j_rarg0, java_lang_invoke_MethodHandle::form_offset()), rscratch1); __ load_heap_oop(rbx, Address(rbx, java_lang_invoke_LambdaForm::vmentry_offset()), rscratch1); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp index ccc8e456d5717..1e056f15213ee 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp @@ -2476,7 +2476,7 @@ address StubGenerator::generate_checkcast_copy(StubGenStubId stub_id, address *e #ifdef ASSERT Label L2; - __ get_thread(r14); + __ get_thread_slow(r14); __ cmpptr(r15_thread, r14); __ jcc(Assembler::equal, L2); __ stop("StubRoutines::call_stub: r15_thread is modified by call"); diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index efbdac8244dfc..fecc804a04424 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -204,10 +204,10 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, } if (JvmtiExport::can_pop_frame()) { - __ check_and_handle_popframe(r15_thread); + __ check_and_handle_popframe(); } if (JvmtiExport::can_force_early_return()) { - __ check_and_handle_earlyret(r15_thread); + __ check_and_handle_earlyret(); } __ dispatch_next(state, step); @@ -991,7 +991,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { Label Continue; Label slow_path; - __ safepoint_poll(slow_path, thread, true /* at_return */, false /* in_nmethod */); + __ safepoint_poll(slow_path, true /* at_return */, false /* in_nmethod */); __ cmpl(Address(thread, JavaThread::suspend_flags_offset()), 0); __ jcc(Assembler::equal, Continue); @@ -1034,7 +1034,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { } // reset_last_Java_frame - __ reset_last_Java_frame(thread, true); + __ reset_last_Java_frame(true); if (CheckJNICalls) { // clear_pending_jni_exception_check @@ -1057,7 +1057,6 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ pop(ltos); // Unbox oop result, e.g. JNIHandles::resolve value. __ resolve_jobject(rax /* value */, - thread /* thread */, t /* tmp */); __ movptr(Address(rbp, frame::interpreter_frame_oop_temp_offset*wordSize), rax); // keep stack depth as expected by pushing oop which will eventually be discarded @@ -1495,7 +1494,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() { // PC must point into interpreter here __ set_last_Java_frame(noreg, rbp, __ pc(), rscratch1); __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::popframe_move_outgoing_args), r15_thread, c_rarg1, c_rarg2); - __ reset_last_Java_frame(thread, true); + __ reset_last_Java_frame(true); // Restore the last_sp and null it out __ movptr(rcx, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize)); @@ -1548,7 +1547,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() { // remove the activation (without doing throws on illegalMonitorExceptions) __ remove_activation(vtos, rdx, false, true, false); // restore exception - __ get_vm_result(rax, thread); + __ get_vm_result(rax); // In between activations - previous activation type unknown yet // compute continuation point - the continuation point expects the diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp index f4ed1081c3b6a..6be702f2699a6 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp @@ -190,7 +190,7 @@ address TemplateInterpreterGenerator::generate_CRC32_update_entry() { // c_rarg1: scratch (rsi on non-Win64, rdx on Win64) Label slow_path; - __ safepoint_poll(slow_path, r15_thread, true /* at_return */, false /* in_nmethod */); + __ safepoint_poll(slow_path, true /* at_return */, false /* in_nmethod */); // We don't generate local frame and don't align stack because // we call stub code and there is no safepoint on this path. @@ -234,7 +234,7 @@ address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractI // r13: senderSP must preserved for slow path, set SP to it on fast path Label slow_path; - __ safepoint_poll(slow_path, r15_thread, false /* at_return */, false /* in_nmethod */); + __ safepoint_poll(slow_path, false /* at_return */, false /* in_nmethod */); // We don't generate local frame and don't align stack because // we call stub code and there is no safepoint on this path. diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index b378bc431fad5..1641abac9235b 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -478,7 +478,7 @@ void TemplateTable::condy_helper(Label& Done) { const Register rarg = c_rarg1; __ movl(rarg, (int)bytecode()); call_VM(obj, CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc), rarg); - __ get_vm_result_2(flags, r15_thread); + __ get_vm_result_2(flags); // VMr = obj = base address to find primitive value to push // VMr2 = flags = (tos, off) using format of CPCE::_flags __ movl(off, flags); @@ -2263,12 +2263,10 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no, if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) { const Register method = temp; const Register klass = temp; - const Register thread = r15_thread; - assert(thread != noreg, "x86_32 not supported"); __ movptr(method, Address(cache, in_bytes(ResolvedMethodEntry::method_offset()))); __ load_method_holder(klass, method); - __ clinit_barrier(klass, thread, nullptr /*L_fast_path*/, &L_clinit_barrier_slow); + __ clinit_barrier(klass, nullptr /*L_fast_path*/, &L_clinit_barrier_slow); } } @@ -3572,7 +3570,7 @@ void TemplateTable::_new() { // make sure klass is initialized // init_state needs acquire, but x86 is TSO, and so we are already good. assert(VM_Version::supports_fast_class_init_checks(), "must support fast class initialization checks"); - __ clinit_barrier(rcx, r15_thread, nullptr /*L_fast_path*/, &slow_case); + __ clinit_barrier(rcx, nullptr /*L_fast_path*/, &slow_case); // get instance_size in InstanceKlass (scaled to a count of bytes) __ movl(rdx, Address(rcx, Klass::layout_helper_offset())); @@ -3712,7 +3710,7 @@ void TemplateTable::checkcast() { call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); // vm_result_2 has metadata result - __ get_vm_result_2(rax, r15_thread); + __ get_vm_result_2(rax); __ pop_ptr(rdx); // restore receiver __ jmpb(resolved); @@ -3767,9 +3765,9 @@ void TemplateTable::instanceof() { __ push(atos); // save receiver for result, and for GC call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); - // vm_result_2 has metadata result - __ get_vm_result_2(rax, r15_thread); + // vm_result_2 has metadata result + __ get_vm_result_2(rax); __ pop_ptr(rdx); // restore receiver __ verify_oop(rdx); diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index b94ff7dbd9e5a..5781ffce4bdc4 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -845,7 +845,7 @@ void MachPrologNode::emit(C2_MacroAssembler *masm, PhaseRegAlloc *ra_) const { Register klass = rscratch1; __ mov_metadata(klass, C->method()->holder()->constant_encoding()); - __ clinit_barrier(klass, r15_thread, &L_skip_barrier /*L_fast_path*/); + __ clinit_barrier(klass, &L_skip_barrier /*L_fast_path*/); __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path @@ -943,7 +943,7 @@ void MachEpilogNode::emit(C2_MacroAssembler* masm, PhaseRegAlloc* ra_) const code_stub = &stub->entry(); } __ relocate(relocInfo::poll_return_type); - __ safepoint_poll(*code_stub, r15_thread, true /* at_return */, true /* in_nmethod */); + __ safepoint_poll(*code_stub, true /* at_return */, true /* in_nmethod */); } } From 9ee5590328e7d5f5070efdbd7ffc44cb660005cc Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Wed, 9 Apr 2025 08:01:13 +0000 Subject: [PATCH 0482/1101] 8334046: Set different values for CompLevel_any and CompLevel_all Reviewed-by: shade, kvn --- src/hotspot/share/compiler/compilerDefinitions.hpp | 2 +- .../jtreg/compiler/whitebox/CompilerWhiteBoxTest.java | 8 +++++--- test/lib/jdk/test/whitebox/WhiteBox.java | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/compiler/compilerDefinitions.hpp b/src/hotspot/share/compiler/compilerDefinitions.hpp index bdaa6dffb8f5f..2c1ae85af8ab3 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.hpp +++ b/src/hotspot/share/compiler/compilerDefinitions.hpp @@ -53,7 +53,7 @@ enum MethodCompilation { // Enumeration to distinguish tiers of compilation enum CompLevel : s1 { - CompLevel_any = -1, // Used for querying the state + CompLevel_any = -2, // Used for querying the state CompLevel_all = -1, // Used for changing the state CompLevel_none = 0, // Interpreter CompLevel_simple = 1, // C1 diff --git a/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java b/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java index f87292be019c0..dde2b3cdfd01f 100644 --- a/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java +++ b/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java @@ -41,8 +41,10 @@ public abstract class CompilerWhiteBoxTest { /** {@code CompLevel::CompLevel_none} -- Interpreter */ public static final int COMP_LEVEL_NONE = 0; - /** {@code CompLevel::CompLevel_any}, {@code CompLevel::CompLevel_all} */ - public static final int COMP_LEVEL_ANY = -1; + /** {@code CompLevel::CompLevel_any} */ + public static final int COMP_LEVEL_ANY = -2; + /** {@code CompLevel::CompLevel_all} */ + public static final int COMP_LEVEL_ALL = -1; /** {@code CompLevel::CompLevel_simple} -- C1 */ public static final int COMP_LEVEL_SIMPLE = 1; /** {@code CompLevel::CompLevel_limited_profile} -- C1, invocation & backedge counters */ @@ -284,7 +286,7 @@ protected final boolean isCompilable(int compLevel) { } protected final void makeNotCompilable() { - WHITE_BOX.makeMethodNotCompilable(method, COMP_LEVEL_ANY, + WHITE_BOX.makeMethodNotCompilable(method, COMP_LEVEL_ALL, testCase.isOsr()); } diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index f0e164d94b518..2744978b8a935 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -345,7 +345,7 @@ public boolean isMethodCompiled(Executable method, boolean isOsr){ return isMethodCompiled0(method, isOsr); } public boolean isMethodCompilable(Executable method) { - return isMethodCompilable(method, -1 /*any*/); + return isMethodCompilable(method, -2 /*any*/); } public boolean isMethodCompilable(Executable method, int compLevel) { return isMethodCompilable(method, compLevel, false /*not osr*/); @@ -393,7 +393,7 @@ public int deoptimizeMethod(Executable method, boolean isOsr) { return deoptimizeMethod0(method, isOsr); } public void makeMethodNotCompilable(Executable method) { - makeMethodNotCompilable(method, -1 /*any*/); + makeMethodNotCompilable(method, -1 /*all*/); } public void makeMethodNotCompilable(Executable method, int compLevel) { makeMethodNotCompilable(method, compLevel, false /*not osr*/); From 250eb743c112fbcc45bf2b3ded1c644b19893577 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 9 Apr 2025 08:22:48 +0000 Subject: [PATCH 0483/1101] 8353192: C2: Clean up x86 backend after 32-bit x86 removal Reviewed-by: kvn, epeter --- src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp | 14 - src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 119 +----- src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp | 21 +- src/hotspot/cpu/x86/matcher_x86.hpp | 31 -- src/hotspot/cpu/x86/x86.ad | 377 +++--------------- src/hotspot/share/adlc/archDesc.cpp | 3 +- 6 files changed, 73 insertions(+), 492 deletions(-) diff --git a/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp index 83ecdee52199b..b4f8e9d95147d 100644 --- a/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp +++ b/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp @@ -43,22 +43,8 @@ void C2SafepointPollStub::emit(C2_MacroAssembler& masm) { __ bind(entry()); InternalAddress safepoint_pc(masm.pc() - masm.offset() + _safepoint_offset); -#ifdef _LP64 __ lea(rscratch1, safepoint_pc); __ movptr(Address(r15_thread, JavaThread::saved_exception_pc_offset()), rscratch1); -#else - const Register tmp1 = rcx; - const Register tmp2 = rdx; - __ push(tmp1); - __ push(tmp2); - - __ lea(tmp1, safepoint_pc); - __ get_thread(tmp2); - __ movptr(Address(tmp2, JavaThread::saved_exception_pc_offset()), tmp1); - - __ pop(tmp2); - __ pop(tmp1); -#endif __ jump(callback_addr); } diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index b6d513f50f288..9ca463336681e 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -107,16 +107,6 @@ void C2_MacroAssembler::verified_entry(int framesize, int stack_bang_size, bool movptr(Address(rsp, framesize), (int32_t)0xbadb100d); } -#ifndef _LP64 - // If method sets FPU control word do it now - if (fp_mode_24b) { - fldcw(ExternalAddress(StubRoutines::x86::addr_fpu_cntrl_wrd_24())); - } - if (UseSSE >= 2 && VerifyFPU) { - verify_FPU(0, "FPU stack must be clean on entry"); - } -#endif - #ifdef ASSERT if (VerifyStackAtCalls) { Label L; @@ -133,7 +123,6 @@ void C2_MacroAssembler::verified_entry(int framesize, int stack_bang_size, bool if (!is_stub) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); - #ifdef _LP64 // We put the non-hot code of the nmethod entry barrier out-of-line in a stub. Label dummy_slow_path; Label dummy_continuation; @@ -147,10 +136,6 @@ void C2_MacroAssembler::verified_entry(int framesize, int stack_bang_size, bool continuation = &stub->continuation(); } bs->nmethod_entry_barrier(this, slow_path, continuation); -#else - // Don't bother with out-of-line nmethod entry barrier stub for x86_32. - bs->nmethod_entry_barrier(this, nullptr /* slow_path */, nullptr /* continuation */); -#endif } } @@ -299,7 +284,7 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp // Locked by current thread if difference with current SP is less than one page. subptr(tmpReg, rsp); // Next instruction set ZFlag == 1 (Success) if difference is less then one page. - andptr(tmpReg, (int32_t) (NOT_LP64(0xFFFFF003) LP64_ONLY(7 - (int)os::vm_page_size())) ); + andptr(tmpReg, (int32_t) (7 - (int)os::vm_page_size()) ); movptr(Address(boxReg, 0), tmpReg); } jmp(DONE_LABEL); @@ -307,10 +292,6 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp bind(IsInflated); // The object is inflated. tmpReg contains pointer to ObjectMonitor* + markWord::monitor_value -#ifndef _LP64 - // Just take slow path to avoid dealing with 64 bit atomic instructions here. - orl(boxReg, 1); // set ICC.ZF=0 to indicate failure -#else // Unconditionally set box->_displaced_header = markWord::unused_mark(). // Without cast to int32_t this style of movptr will destroy r10 which is typically obj. movptr(Address(boxReg, 0), checked_cast(markWord::unused_mark().value())); @@ -329,7 +310,6 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp jccb(Assembler::notEqual, NO_COUNT); // If not recursive, ZF = 0 at this point (fail) incq(Address(scrReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); xorq(rax, rax); // Set ZF = 1 (success) for recursive lock, denoting locking success -#endif // _LP64 bind(DONE_LABEL); // ZFlag == 1 count in fast path @@ -338,10 +318,8 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp bind(COUNT); if (LockingMode == LM_LEGACY) { -#ifdef _LP64 // Count monitors in fast path increment(Address(thread, JavaThread::held_monitor_count_offset())); -#endif } xorl(tmpReg, tmpReg); // Set ZF == 1 @@ -404,11 +382,6 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t // It's inflated. -#ifndef _LP64 - // Just take slow path to avoid dealing with 64 bit atomic instructions here. - orl(boxReg, 1); // set ICC.ZF=0 to indicate failure - jmpb(DONE_LABEL); -#else // Despite our balanced locking property we still check that m->_owner == Self // as java routines or native JNI code called by this thread might // have released the lock. @@ -462,7 +435,6 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t bind (LSuccess); testl (boxReg, 0); // set ICC.ZF=1 to indicate success jmpb (DONE_LABEL); -#endif // _LP64 if (LockingMode == LM_LEGACY) { bind (Stacked); @@ -482,9 +454,7 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t if (LockingMode == LM_LEGACY) { // Count monitors in fast path -#ifdef _LP64 decrementq(Address(r15_thread, JavaThread::held_monitor_count_offset())); -#endif } xorl(tmpReg, tmpReg); // Set ZF == 1 @@ -563,11 +533,6 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist { // Handle inflated monitor. bind(inflated); -#ifndef _LP64 - // Just take slow path to avoid dealing with 64 bit atomic instructions here. - orl(box, 1); // set ICC.ZF=0 to indicate failure - jmpb(slow_path); -#else const Register monitor = t; if (!UseObjectMonitorTable) { @@ -633,7 +598,6 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist increment(recursions_address); bind(monitor_locked); -#endif // _LP64 } bind(locked); @@ -746,11 +710,6 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, bind(inflated); -#ifndef _LP64 - // Just take slow path to avoid dealing with 64 bit atomic instructions here. - orl(t, 1); // set ICC.ZF=0 to indicate failure - jmpb(slow_path); -#else if (!UseObjectMonitorTable) { assert(mark == monitor, "should be the same here"); } else { @@ -800,7 +759,6 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, // Recursive unlock. bind(recursive); decrement(recursions_address); -#endif // _LP64 } bind(unlocked); @@ -1522,7 +1480,6 @@ void C2_MacroAssembler::vinsert(BasicType typ, XMMRegister dst, XMMRegister src, } } -#ifdef _LP64 void C2_MacroAssembler::vgather8b_masked_offset(BasicType elem_bt, XMMRegister dst, Register base, Register idx_base, @@ -1561,7 +1518,6 @@ void C2_MacroAssembler::vgather8b_masked_offset(BasicType elem_bt, } } } -#endif // _LP64 void C2_MacroAssembler::vgather8b_offset(BasicType elem_bt, XMMRegister dst, Register base, Register idx_base, @@ -1633,7 +1589,7 @@ void C2_MacroAssembler::vgather_subword(BasicType elem_ty, XMMRegister dst, if (mask == noreg) { vgather8b_offset(elem_ty, temp_dst, base, idx_base, offset, rtmp, vlen_enc); } else { - LP64_ONLY(vgather8b_masked_offset(elem_ty, temp_dst, base, idx_base, offset, mask, mask_idx, rtmp, vlen_enc)); + vgather8b_masked_offset(elem_ty, temp_dst, base, idx_base, offset, mask, mask_idx, rtmp, vlen_enc); } // TEMP_PERM_VEC(temp_dst) = PERMUTE TMP_VEC_64(temp_dst) PERM_INDEX(xtmp1) vpermd(temp_dst, xtmp1, temp_dst, vlen_enc == Assembler::AVX_512bit ? vlen_enc : Assembler::AVX_256bit); @@ -2037,7 +1993,6 @@ void C2_MacroAssembler::reduceI(int opcode, int vlen, } } -#ifdef _LP64 void C2_MacroAssembler::reduceL(int opcode, int vlen, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2) { @@ -2049,7 +2004,6 @@ void C2_MacroAssembler::reduceL(int opcode, int vlen, default: assert(false, "wrong vector length"); } } -#endif // _LP64 void C2_MacroAssembler::reduceF(int opcode, int vlen, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2) { switch (vlen) { @@ -2299,7 +2253,6 @@ void C2_MacroAssembler::reduce32S(int opcode, Register dst, Register src1, XMMRe reduce16S(opcode, dst, src1, vtmp1, vtmp1, vtmp2); } -#ifdef _LP64 void C2_MacroAssembler::reduce2L(int opcode, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2) { pshufd(vtmp2, src2, 0xE); reduce_operation_128(T_LONG, opcode, vtmp2, src2); @@ -2325,7 +2278,6 @@ void C2_MacroAssembler::genmask(KRegister dst, Register len, Register temp) { bzhiq(temp, temp, len); kmovql(dst, temp); } -#endif // _LP64 void C2_MacroAssembler::reduce2F(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp) { reduce_operation_128(T_FLOAT, opcode, dst, src); @@ -2741,7 +2693,6 @@ void C2_MacroAssembler::vpadd(BasicType elem_bt, XMMRegister dst, XMMRegister sr } } -#ifdef _LP64 void C2_MacroAssembler::vpbroadcast(BasicType elem_bt, XMMRegister dst, Register src, int vlen_enc) { assert(UseAVX >= 2, "required"); bool is_bw = ((elem_bt == T_BYTE) || (elem_bt == T_SHORT)); @@ -2770,7 +2721,6 @@ void C2_MacroAssembler::vpbroadcast(BasicType elem_bt, XMMRegister dst, Register } } } -#endif void C2_MacroAssembler::vconvert_b2x(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vlen_enc) { switch (to_elem_bt) { @@ -3698,7 +3648,7 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, XMMRegister vec1, int ae, KRegister mask) { ShortBranchVerifier sbv(this); Label LENGTH_DIFF_LABEL, POP_LABEL, DONE_LABEL, WHILE_HEAD_LABEL; - Label COMPARE_WIDE_VECTORS_LOOP_FAILED; // used only _LP64 && AVX3 + Label COMPARE_WIDE_VECTORS_LOOP_FAILED; // used only AVX3 int stride, stride2, adr_stride, adr_stride1, adr_stride2; int stride2x2 = 0x40; Address::ScaleFactor scale = Address::no_scale; @@ -3768,7 +3718,7 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, Label COMPARE_WIDE_VECTORS_LOOP, COMPARE_16_CHARS, COMPARE_INDEX_CHAR; Label COMPARE_WIDE_VECTORS_LOOP_AVX2; Label COMPARE_TAIL_LONG; - Label COMPARE_WIDE_VECTORS_LOOP_AVX3; // used only _LP64 && AVX3 + Label COMPARE_WIDE_VECTORS_LOOP_AVX3; // used only AVX3 int pcmpmask = 0x19; if (ae == StrIntrinsicNode::LL) { @@ -3838,7 +3788,6 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, // In a loop, compare 16-chars (32-bytes) at once using (vpxor+vptest) bind(COMPARE_WIDE_VECTORS_LOOP); -#ifdef _LP64 if ((AVX3Threshold == 0) && VM_Version::supports_avx512vlbw()) { // trying 64 bytes fast loop cmpl(cnt2, stride2x2); jccb(Assembler::below, COMPARE_WIDE_VECTORS_LOOP_AVX2); @@ -3862,8 +3811,6 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, vpxor(vec1, vec1); jmpb(COMPARE_WIDE_TAIL); }//if (VM_Version::supports_avx512vlbw()) -#endif // _LP64 - bind(COMPARE_WIDE_VECTORS_LOOP_AVX2); if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { @@ -4032,7 +3979,6 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, } jmpb(DONE_LABEL); -#ifdef _LP64 if (VM_Version::supports_avx512vlbw()) { bind(COMPARE_WIDE_VECTORS_LOOP_FAILED); @@ -4058,7 +4004,6 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, subl(result, cnt1); jmpb(POP_LABEL); }//if (VM_Version::supports_avx512vlbw()) -#endif // _LP64 // Discard the stored length difference bind(POP_LABEL); @@ -4133,7 +4078,6 @@ void C2_MacroAssembler::count_positives(Register ary1, Register len, // check the tail for absense of negatives // ~(~0 << len) applied up to two times (for 32-bit scenario) -#ifdef _LP64 { Register tmp3_aliased = len; mov64(tmp3_aliased, 0xFFFFFFFFFFFFFFFF); @@ -4141,33 +4085,7 @@ void C2_MacroAssembler::count_positives(Register ary1, Register len, notq(tmp3_aliased); kmovql(mask2, tmp3_aliased); } -#else - Label k_init; - jmp(k_init); - - // We could not read 64-bits from a general purpose register thus we move - // data required to compose 64 1's to the instruction stream - // We emit 64 byte wide series of elements from 0..63 which later on would - // be used as a compare targets with tail count contained in tmp1 register. - // Result would be a k register having tmp1 consecutive number or 1 - // counting from least significant bit. - address tmp = pc(); - emit_int64(0x0706050403020100); - emit_int64(0x0F0E0D0C0B0A0908); - emit_int64(0x1716151413121110); - emit_int64(0x1F1E1D1C1B1A1918); - emit_int64(0x2726252423222120); - emit_int64(0x2F2E2D2C2B2A2928); - emit_int64(0x3736353433323130); - emit_int64(0x3F3E3D3C3B3A3938); - - bind(k_init); - lea(len, InternalAddress(tmp)); - // create mask to test for negative byte inside a vector - evpbroadcastb(vec1, tmp1, Assembler::AVX_512bit); - evpcmpgtb(mask2, vec1, Address(len, 0), Assembler::AVX_512bit); -#endif evpcmpgtb(mask1, mask2, vec2, Address(ary1, 0), Assembler::AVX_512bit); ktestq(mask1, mask2); jcc(Assembler::zero, DONE); @@ -4414,7 +4332,6 @@ void C2_MacroAssembler::arrays_equals(bool is_array_equ, Register ary1, Register lea(ary2, Address(ary2, limit, Address::times_1)); negptr(limit); -#ifdef _LP64 if ((AVX3Threshold == 0) && VM_Version::supports_avx512vlbw()) { // trying 64 bytes fast loop Label COMPARE_WIDE_VECTORS_LOOP_AVX2, COMPARE_WIDE_VECTORS_LOOP_AVX3; @@ -4451,7 +4368,7 @@ void C2_MacroAssembler::arrays_equals(bool is_array_equ, Register ary1, Register bind(COMPARE_WIDE_VECTORS_LOOP_AVX2); }//if (VM_Version::supports_avx512vlbw()) -#endif //_LP64 + bind(COMPARE_WIDE_VECTORS); vmovdqu(vec1, Address(ary1, limit, scaleFactor)); if (expand_ary2) { @@ -4618,8 +4535,6 @@ void C2_MacroAssembler::arrays_equals(bool is_array_equ, Register ary1, Register } } -#ifdef _LP64 - static void convertF2I_slowpath(C2_MacroAssembler& masm, C2GeneralStub& stub) { #define __ masm. Register dst = stub.data<0>(); @@ -4666,8 +4581,6 @@ void C2_MacroAssembler::convertF2I(BasicType dst_bt, BasicType src_bt, Register bind(stub->continuation()); } -#endif // _LP64 - void C2_MacroAssembler::evmasked_op(int ideal_opc, BasicType eType, KRegister mask, XMMRegister dst, XMMRegister src1, int imm8, bool merge, int vlen_enc) { switch(ideal_opc) { @@ -5327,7 +5240,6 @@ void C2_MacroAssembler::vector_castD2X_evex(BasicType to_elem_bt, XMMRegister ds } } -#ifdef _LP64 void C2_MacroAssembler::vector_round_double_evex(XMMRegister dst, XMMRegister src, AddressLiteral double_sign_flip, AddressLiteral new_mxcsr, int vec_enc, Register tmp, XMMRegister xtmp1, XMMRegister xtmp2, KRegister ktmp1, KRegister ktmp2) { @@ -5379,7 +5291,6 @@ void C2_MacroAssembler::vector_round_float_avx(XMMRegister dst, XMMRegister src, ldmxcsr(ExternalAddress(StubRoutines::x86::addr_mxcsr_std()), tmp /*rscratch*/); } -#endif // _LP64 void C2_MacroAssembler::vector_unsigned_cast(XMMRegister dst, XMMRegister src, int vlen_enc, BasicType from_elem_bt, BasicType to_elem_bt) { @@ -5510,7 +5421,6 @@ void C2_MacroAssembler::evpternlog(XMMRegister dst, int func, KRegister mask, XM } } -#ifdef _LP64 void C2_MacroAssembler::vector_long_to_maskvec(XMMRegister dst, Register src, Register rtmp1, Register rtmp2, XMMRegister xtmp, int mask_len, int vec_enc) { @@ -5768,7 +5678,6 @@ void C2_MacroAssembler::vector_compress_expand(int opcode, XMMRegister dst, XMMR } } } -#endif void C2_MacroAssembler::vector_signum_evex(int opcode, XMMRegister dst, XMMRegister src, XMMRegister zero, XMMRegister one, KRegister ktmp1, int vec_enc) { @@ -5833,10 +5742,8 @@ void C2_MacroAssembler::vector_maskall_operation(KRegister dst, Register src, in void C2_MacroAssembler::vbroadcast(BasicType bt, XMMRegister dst, int imm32, Register rtmp, int vec_enc) { int lane_size = type2aelembytes(bt); - bool is_LP64 = LP64_ONLY(true) NOT_LP64(false); - if ((is_LP64 || lane_size < 8) && - ((is_non_subword_integral_type(bt) && VM_Version::supports_avx512vl()) || - (is_subword_type(bt) && VM_Version::supports_avx512vlbw()))) { + if ((is_non_subword_integral_type(bt) && VM_Version::supports_avx512vl()) || + (is_subword_type(bt) && VM_Version::supports_avx512vlbw())) { movptr(rtmp, imm32); switch(lane_size) { case 1 : evpbroadcastb(dst, rtmp, vec_enc); break; @@ -5848,7 +5755,7 @@ void C2_MacroAssembler::vbroadcast(BasicType bt, XMMRegister dst, int imm32, Reg } } else { movptr(rtmp, imm32); - LP64_ONLY(movq(dst, rtmp)) NOT_LP64(movdl(dst, rtmp)); + movq(dst, rtmp); switch(lane_size) { case 1 : vpbroadcastb(dst, dst, vec_enc); break; case 2 : vpbroadcastw(dst, dst, vec_enc); break; @@ -5983,14 +5890,6 @@ void C2_MacroAssembler::vector_popcount_integral_evex(BasicType bt, XMMRegister } } -#ifndef _LP64 -void C2_MacroAssembler::vector_maskall_operation32(KRegister dst, Register src, KRegister tmp, int mask_len) { - assert(VM_Version::supports_avx512bw(), ""); - kmovdl(tmp, src); - kunpckdql(dst, tmp, tmp); -} -#endif - // Bit reversal algorithm first reverses the bits of each byte followed by // a byte level reversal for multi-byte primitive types (short/int/long). // Algorithm performs a lookup table access to get reverse bit sequence @@ -6450,7 +6349,6 @@ void C2_MacroAssembler::udivmodI(Register rax, Register divisor, Register rdx, R bind(done); } -#ifdef _LP64 void C2_MacroAssembler::reverseI(Register dst, Register src, XMMRegister xtmp1, XMMRegister xtmp2, Register rtmp) { if(VM_Version::supports_gfni()) { @@ -6614,7 +6512,6 @@ void C2_MacroAssembler::udivmodL(Register rax, Register divisor, Register rdx, R subq(rdx, tmp); // remainder bind(done); } -#endif void C2_MacroAssembler::rearrange_bytes(XMMRegister dst, XMMRegister shuffle, XMMRegister src, XMMRegister xtmp1, XMMRegister xtmp2, XMMRegister xtmp3, Register rtmp, KRegister ktmp, diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index 29380609b9a1e..2c5fb4b516afc 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -130,9 +130,7 @@ // Covert B2X void vconvert_b2x(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vlen_enc); -#ifdef _LP64 void vpbroadcast(BasicType elem_bt, XMMRegister dst, Register src, int vlen_enc); -#endif // blend void evpcmp(BasicType typ, KRegister kdmask, KRegister ksmask, XMMRegister src1, XMMRegister src2, int comparison, int vector_len); @@ -152,10 +150,8 @@ // dst = src1 reduce(op, src2) using vtmp as temps void reduceI(int opcode, int vlen, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2); -#ifdef _LP64 void reduceL(int opcode, int vlen, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2); void genmask(KRegister dst, Register len, Register temp); -#endif // _LP64 // dst = reduce(op, src2) using vtmp as temps void reduce_fp(int opcode, int vlen, @@ -202,11 +198,9 @@ void reduce32S(int opcode, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2); // Long Reduction -#ifdef _LP64 void reduce2L(int opcode, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2); void reduce4L(int opcode, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2); void reduce8L(int opcode, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2); -#endif // _LP64 // Float Reduction void reduce2F (int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp); @@ -237,7 +231,6 @@ void unordered_reduce_operation_256(BasicType typ, int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2); public: -#ifdef _LP64 void vector_mask_operation_helper(int opc, Register dst, Register tmp, int masklen); void vector_mask_operation(int opc, Register dst, KRegister mask, Register tmp, int masklen, int masksize, int vec_enc); @@ -246,14 +239,9 @@ Register tmp, int masklen, BasicType bt, int vec_enc); void vector_long_to_maskvec(XMMRegister dst, Register src, Register rtmp1, Register rtmp2, XMMRegister xtmp, int mask_len, int vec_enc); -#endif void vector_maskall_operation(KRegister dst, Register src, int mask_len); -#ifndef _LP64 - void vector_maskall_operation32(KRegister dst, Register src, KRegister ktmp, int mask_len); -#endif - void string_indexof_char(Register str1, Register cnt1, Register ch, Register result, XMMRegister vec1, XMMRegister vec2, XMMRegister vec3, Register tmp); @@ -313,9 +301,7 @@ void arrays_hashcode_elvload(XMMRegister dst, AddressLiteral src, BasicType eltype); void arrays_hashcode_elvcast(XMMRegister dst, BasicType eltype); -#ifdef _LP64 void convertF2I(BasicType dst_bt, BasicType src_bt, Register dst, XMMRegister src); -#endif void evmasked_op(int ideal_opc, BasicType eType, KRegister mask, XMMRegister dst, XMMRegister src1, XMMRegister src2, @@ -390,7 +376,6 @@ void vector_mask_cast(XMMRegister dst, XMMRegister src, BasicType dst_bt, BasicType src_bt, int vlen); -#ifdef _LP64 void vector_round_double_evex(XMMRegister dst, XMMRegister src, AddressLiteral double_sign_flip, AddressLiteral new_mxcsr, int vec_enc, Register tmp, XMMRegister xtmp1, XMMRegister xtmp2, KRegister ktmp1, KRegister ktmp2); @@ -403,13 +388,11 @@ void vector_compress_expand_avx2(int opcode, XMMRegister dst, XMMRegister src, XMMRegister mask, Register rtmp, Register rscratch, XMMRegister permv, XMMRegister xtmp, BasicType bt, int vec_enc); -#endif // _LP64 void udivI(Register rax, Register divisor, Register rdx); void umodI(Register rax, Register divisor, Register rdx); void udivmodI(Register rax, Register divisor, Register rdx, Register tmp); -#ifdef _LP64 void reverseI(Register dst, Register src, XMMRegister xtmp1, XMMRegister xtmp2, Register rtmp); void reverseL(Register dst, Register src, XMMRegister xtmp1, @@ -417,7 +400,6 @@ void udivL(Register rax, Register divisor, Register rdx); void umodL(Register rax, Register divisor, Register rdx); void udivmodL(Register rax, Register divisor, Register rdx, Register tmp); -#endif void evpternlog(XMMRegister dst, int func, KRegister mask, XMMRegister src2, XMMRegister src3, bool merge, BasicType bt, int vlen_enc); @@ -511,10 +493,9 @@ Register mask, XMMRegister xtmp1, XMMRegister xtmp2, XMMRegister xtmp3, Register rtmp, Register midx, Register length, int vector_len, int vlen_enc); -#ifdef _LP64 void vgather8b_masked_offset(BasicType elem_bt, XMMRegister dst, Register base, Register idx_base, Register offset, Register mask, Register midx, Register rtmp, int vlen_enc); -#endif + void vgather8b_offset(BasicType elem_bt, XMMRegister dst, Register base, Register idx_base, Register offset, Register rtmp, int vlen_enc); diff --git a/src/hotspot/cpu/x86/matcher_x86.hpp b/src/hotspot/cpu/x86/matcher_x86.hpp index 78591989b5b76..41486c244b247 100644 --- a/src/hotspot/cpu/x86/matcher_x86.hpp +++ b/src/hotspot/cpu/x86/matcher_x86.hpp @@ -59,53 +59,34 @@ static constexpr bool isSimpleConstant64(jlong value) { // Will one (StoreL ConL) be cheaper than two (StoreI ConI)?. //return value == (int) value; // Cf. storeImmL and immL32. - // Probably always true, even if a temp register is required. -#ifdef _LP64 return true; -#else - return false; -#endif } -#ifdef _LP64 // No additional cost for CMOVL. static constexpr int long_cmove_cost() { return 0; } -#else - // Needs 2 CMOV's for longs. - static constexpr int long_cmove_cost() { return 1; } -#endif -#ifdef _LP64 // No CMOVF/CMOVD with SSE2 static int float_cmove_cost() { return ConditionalMoveLimit; } -#else - // No CMOVF/CMOVD with SSE/SSE2 - static int float_cmove_cost() { return (UseSSE>=1) ? ConditionalMoveLimit : 0; } -#endif static bool narrow_oop_use_complex_address() { - NOT_LP64(ShouldNotCallThis();) assert(UseCompressedOops, "only for compressed oops code"); return (LogMinObjAlignmentInBytes <= 3); } static bool narrow_klass_use_complex_address() { - NOT_LP64(ShouldNotCallThis();) assert(UseCompressedClassPointers, "only for compressed klass code"); return (CompressedKlassPointers::shift() <= 3); } // Prefer ConN+DecodeN over ConP. static bool const_oop_prefer_decode() { - NOT_LP64(ShouldNotCallThis();) // Prefer ConN+DecodeN over ConP. return true; } // Prefer ConP over ConNKlass+DecodeNKlass. static bool const_klass_prefer_decode() { - NOT_LP64(ShouldNotCallThis();) return false; } @@ -123,24 +104,12 @@ // Are floats converted to double when stored to stack during deoptimization? // On x64 it is stored without conversion so we can use normal access. - // On x32 it is stored with conversion only when FPU is used for floats. -#ifdef _LP64 static constexpr bool float_in_double() { return false; } -#else - static bool float_in_double() { - return (UseSSE == 0); - } -#endif // Do ints take an entire long register or just half? -#ifdef _LP64 static const bool int_in_long = true; -#else - static const bool int_in_long = false; -#endif - // Does the CPU supports vector variable shift instructions? static bool supports_vector_variable_shifts(void) { diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index afa1a92287d99..2d7548c37a87e 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -210,8 +210,6 @@ reg_def XMM7n( SOC, SOC, Op_RegF, 7, xmm7->as_VMReg()->next(13)); reg_def XMM7o( SOC, SOC, Op_RegF, 7, xmm7->as_VMReg()->next(14)); reg_def XMM7p( SOC, SOC, Op_RegF, 7, xmm7->as_VMReg()->next(15)); -#ifdef _LP64 - reg_def XMM8 ( SOC, SOC, Op_RegF, 8, xmm8->as_VMReg()); reg_def XMM8b( SOC, SOC, Op_RegF, 8, xmm8->as_VMReg()->next(1)); reg_def XMM8c( SOC, SOC, Op_RegF, 8, xmm8->as_VMReg()->next(2)); @@ -620,13 +618,7 @@ reg_def XMM31n( SOC, SOC, Op_RegF, 31, xmm31->as_VMReg()->next(13)); reg_def XMM31o( SOC, SOC, Op_RegF, 31, xmm31->as_VMReg()->next(14)); reg_def XMM31p( SOC, SOC, Op_RegF, 31, xmm31->as_VMReg()->next(15)); -#endif // _LP64 - -#ifdef _LP64 reg_def RFLAGS(SOC, SOC, 0, 16, VMRegImpl::Bad()); -#else -reg_def RFLAGS(SOC, SOC, 0, 8, VMRegImpl::Bad()); -#endif // _LP64 // AVX3 Mask Registers. reg_def K1 (SOC, SOC, Op_RegI, 1, k1->as_VMReg()); @@ -658,17 +650,16 @@ alloc_class chunk1(XMM0, XMM0b, XMM0c, XMM0d, XMM0e, XMM0f, XMM0g, XMM0h, XMM4, XMM4b, XMM4c, XMM4d, XMM4e, XMM4f, XMM4g, XMM4h, XMM4i, XMM4j, XMM4k, XMM4l, XMM4m, XMM4n, XMM4o, XMM4p, XMM5, XMM5b, XMM5c, XMM5d, XMM5e, XMM5f, XMM5g, XMM5h, XMM5i, XMM5j, XMM5k, XMM5l, XMM5m, XMM5n, XMM5o, XMM5p, XMM6, XMM6b, XMM6c, XMM6d, XMM6e, XMM6f, XMM6g, XMM6h, XMM6i, XMM6j, XMM6k, XMM6l, XMM6m, XMM6n, XMM6o, XMM6p, - XMM7, XMM7b, XMM7c, XMM7d, XMM7e, XMM7f, XMM7g, XMM7h, XMM7i, XMM7j, XMM7k, XMM7l, XMM7m, XMM7n, XMM7o, XMM7p -#ifdef _LP64 - ,XMM8, XMM8b, XMM8c, XMM8d, XMM8e, XMM8f, XMM8g, XMM8h, XMM8i, XMM8j, XMM8k, XMM8l, XMM8m, XMM8n, XMM8o, XMM8p, + XMM7, XMM7b, XMM7c, XMM7d, XMM7e, XMM7f, XMM7g, XMM7h, XMM7i, XMM7j, XMM7k, XMM7l, XMM7m, XMM7n, XMM7o, XMM7p, + XMM8, XMM8b, XMM8c, XMM8d, XMM8e, XMM8f, XMM8g, XMM8h, XMM8i, XMM8j, XMM8k, XMM8l, XMM8m, XMM8n, XMM8o, XMM8p, XMM9, XMM9b, XMM9c, XMM9d, XMM9e, XMM9f, XMM9g, XMM9h, XMM9i, XMM9j, XMM9k, XMM9l, XMM9m, XMM9n, XMM9o, XMM9p, XMM10, XMM10b, XMM10c, XMM10d, XMM10e, XMM10f, XMM10g, XMM10h, XMM10i, XMM10j, XMM10k, XMM10l, XMM10m, XMM10n, XMM10o, XMM10p, XMM11, XMM11b, XMM11c, XMM11d, XMM11e, XMM11f, XMM11g, XMM11h, XMM11i, XMM11j, XMM11k, XMM11l, XMM11m, XMM11n, XMM11o, XMM11p, XMM12, XMM12b, XMM12c, XMM12d, XMM12e, XMM12f, XMM12g, XMM12h, XMM12i, XMM12j, XMM12k, XMM12l, XMM12m, XMM12n, XMM12o, XMM12p, XMM13, XMM13b, XMM13c, XMM13d, XMM13e, XMM13f, XMM13g, XMM13h, XMM13i, XMM13j, XMM13k, XMM13l, XMM13m, XMM13n, XMM13o, XMM13p, XMM14, XMM14b, XMM14c, XMM14d, XMM14e, XMM14f, XMM14g, XMM14h, XMM14i, XMM14j, XMM14k, XMM14l, XMM14m, XMM14n, XMM14o, XMM14p, - XMM15, XMM15b, XMM15c, XMM15d, XMM15e, XMM15f, XMM15g, XMM15h, XMM15i, XMM15j, XMM15k, XMM15l, XMM15m, XMM15n, XMM15o, XMM15p - ,XMM16, XMM16b, XMM16c, XMM16d, XMM16e, XMM16f, XMM16g, XMM16h, XMM16i, XMM16j, XMM16k, XMM16l, XMM16m, XMM16n, XMM16o, XMM16p, + XMM15, XMM15b, XMM15c, XMM15d, XMM15e, XMM15f, XMM15g, XMM15h, XMM15i, XMM15j, XMM15k, XMM15l, XMM15m, XMM15n, XMM15o, XMM15p, + XMM16, XMM16b, XMM16c, XMM16d, XMM16e, XMM16f, XMM16g, XMM16h, XMM16i, XMM16j, XMM16k, XMM16l, XMM16m, XMM16n, XMM16o, XMM16p, XMM17, XMM17b, XMM17c, XMM17d, XMM17e, XMM17f, XMM17g, XMM17h, XMM17i, XMM17j, XMM17k, XMM17l, XMM17m, XMM17n, XMM17o, XMM17p, XMM18, XMM18b, XMM18c, XMM18d, XMM18e, XMM18f, XMM18g, XMM18h, XMM18i, XMM18j, XMM18k, XMM18l, XMM18m, XMM18n, XMM18o, XMM18p, XMM19, XMM19b, XMM19c, XMM19d, XMM19e, XMM19f, XMM19g, XMM19h, XMM19i, XMM19j, XMM19k, XMM19l, XMM19m, XMM19n, XMM19o, XMM19p, @@ -683,9 +674,7 @@ alloc_class chunk1(XMM0, XMM0b, XMM0c, XMM0d, XMM0e, XMM0f, XMM0g, XMM0h, XMM28, XMM28b, XMM28c, XMM28d, XMM28e, XMM28f, XMM28g, XMM28h, XMM28i, XMM28j, XMM28k, XMM28l, XMM28m, XMM28n, XMM28o, XMM28p, XMM29, XMM29b, XMM29c, XMM29d, XMM29e, XMM29f, XMM29g, XMM29h, XMM29i, XMM29j, XMM29k, XMM29l, XMM29m, XMM29n, XMM29o, XMM29p, XMM30, XMM30b, XMM30c, XMM30d, XMM30e, XMM30f, XMM30g, XMM30h, XMM30i, XMM30j, XMM30k, XMM30l, XMM30m, XMM30n, XMM30o, XMM30p, - XMM31, XMM31b, XMM31c, XMM31d, XMM31e, XMM31f, XMM31g, XMM31h, XMM31i, XMM31j, XMM31k, XMM31l, XMM31m, XMM31n, XMM31o, XMM31p -#endif - ); + XMM31, XMM31b, XMM31c, XMM31d, XMM31e, XMM31f, XMM31g, XMM31h, XMM31i, XMM31j, XMM31k, XMM31l, XMM31m, XMM31n, XMM31o, XMM31p); alloc_class chunk2(K7, K7_H, K6, K6_H, @@ -726,18 +715,15 @@ reg_class float_reg_legacy(XMM0, XMM4, XMM5, XMM6, - XMM7 -#ifdef _LP64 - ,XMM8, + XMM7, + XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, - XMM15 -#endif - ); + XMM15); // Class for evex float registers reg_class float_reg_evex(XMM0, @@ -747,9 +733,8 @@ reg_class float_reg_evex(XMM0, XMM4, XMM5, XMM6, - XMM7 -#ifdef _LP64 - ,XMM8, + XMM7, + XMM8, XMM9, XMM10, XMM11, @@ -772,9 +757,7 @@ reg_class float_reg_evex(XMM0, XMM28, XMM29, XMM30, - XMM31 -#endif - ); + XMM31); reg_class_dynamic float_reg(float_reg_evex, float_reg_legacy, %{ VM_Version::supports_evex() %} ); reg_class_dynamic float_reg_vl(float_reg_evex, float_reg_legacy, %{ VM_Version::supports_evex() && VM_Version::supports_avx512vl() %} ); @@ -787,18 +770,15 @@ reg_class double_reg_legacy(XMM0, XMM0b, XMM4, XMM4b, XMM5, XMM5b, XMM6, XMM6b, - XMM7, XMM7b -#ifdef _LP64 - ,XMM8, XMM8b, + XMM7, XMM7b, + XMM8, XMM8b, XMM9, XMM9b, XMM10, XMM10b, XMM11, XMM11b, XMM12, XMM12b, XMM13, XMM13b, XMM14, XMM14b, - XMM15, XMM15b -#endif - ); + XMM15, XMM15b); // Class for evex double registers reg_class double_reg_evex(XMM0, XMM0b, @@ -808,9 +788,8 @@ reg_class double_reg_evex(XMM0, XMM0b, XMM4, XMM4b, XMM5, XMM5b, XMM6, XMM6b, - XMM7, XMM7b -#ifdef _LP64 - ,XMM8, XMM8b, + XMM7, XMM7b, + XMM8, XMM8b, XMM9, XMM9b, XMM10, XMM10b, XMM11, XMM11b, @@ -833,9 +812,7 @@ reg_class double_reg_evex(XMM0, XMM0b, XMM28, XMM28b, XMM29, XMM29b, XMM30, XMM30b, - XMM31, XMM31b -#endif - ); + XMM31, XMM31b); reg_class_dynamic double_reg(double_reg_evex, double_reg_legacy, %{ VM_Version::supports_evex() %} ); reg_class_dynamic double_reg_vl(double_reg_evex, double_reg_legacy, %{ VM_Version::supports_evex() && VM_Version::supports_avx512vl() %} ); @@ -848,18 +825,15 @@ reg_class vectors_reg_legacy(XMM0, XMM4, XMM5, XMM6, - XMM7 -#ifdef _LP64 - ,XMM8, + XMM7, + XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, - XMM15 -#endif - ); + XMM15); // Class for evex 32bit vector registers reg_class vectors_reg_evex(XMM0, @@ -869,9 +843,8 @@ reg_class vectors_reg_evex(XMM0, XMM4, XMM5, XMM6, - XMM7 -#ifdef _LP64 - ,XMM8, + XMM7, + XMM8, XMM9, XMM10, XMM11, @@ -894,9 +867,7 @@ reg_class vectors_reg_evex(XMM0, XMM28, XMM29, XMM30, - XMM31 -#endif - ); + XMM31); reg_class_dynamic vectors_reg(vectors_reg_evex, vectors_reg_legacy, %{ VM_Version::supports_evex() %} ); reg_class_dynamic vectors_reg_vlbwdq(vectors_reg_evex, vectors_reg_legacy, %{ VM_Version::supports_avx512vlbwdq() %} ); @@ -909,18 +880,15 @@ reg_class vectord_reg_legacy(XMM0, XMM0b, XMM4, XMM4b, XMM5, XMM5b, XMM6, XMM6b, - XMM7, XMM7b -#ifdef _LP64 - ,XMM8, XMM8b, + XMM7, XMM7b, + XMM8, XMM8b, XMM9, XMM9b, XMM10, XMM10b, XMM11, XMM11b, XMM12, XMM12b, XMM13, XMM13b, XMM14, XMM14b, - XMM15, XMM15b -#endif - ); + XMM15, XMM15b); // Class for all 64bit vector registers reg_class vectord_reg_evex(XMM0, XMM0b, @@ -930,9 +898,8 @@ reg_class vectord_reg_evex(XMM0, XMM0b, XMM4, XMM4b, XMM5, XMM5b, XMM6, XMM6b, - XMM7, XMM7b -#ifdef _LP64 - ,XMM8, XMM8b, + XMM7, XMM7b, + XMM8, XMM8b, XMM9, XMM9b, XMM10, XMM10b, XMM11, XMM11b, @@ -955,9 +922,7 @@ reg_class vectord_reg_evex(XMM0, XMM0b, XMM28, XMM28b, XMM29, XMM29b, XMM30, XMM30b, - XMM31, XMM31b -#endif - ); + XMM31, XMM31b); reg_class_dynamic vectord_reg(vectord_reg_evex, vectord_reg_legacy, %{ VM_Version::supports_evex() %} ); reg_class_dynamic vectord_reg_vlbwdq(vectord_reg_evex, vectord_reg_legacy, %{ VM_Version::supports_avx512vlbwdq() %} ); @@ -970,18 +935,15 @@ reg_class vectorx_reg_legacy(XMM0, XMM0b, XMM0c, XMM0d, XMM4, XMM4b, XMM4c, XMM4d, XMM5, XMM5b, XMM5c, XMM5d, XMM6, XMM6b, XMM6c, XMM6d, - XMM7, XMM7b, XMM7c, XMM7d -#ifdef _LP64 - ,XMM8, XMM8b, XMM8c, XMM8d, + XMM7, XMM7b, XMM7c, XMM7d, + XMM8, XMM8b, XMM8c, XMM8d, XMM9, XMM9b, XMM9c, XMM9d, XMM10, XMM10b, XMM10c, XMM10d, XMM11, XMM11b, XMM11c, XMM11d, XMM12, XMM12b, XMM12c, XMM12d, XMM13, XMM13b, XMM13c, XMM13d, XMM14, XMM14b, XMM14c, XMM14d, - XMM15, XMM15b, XMM15c, XMM15d -#endif - ); + XMM15, XMM15b, XMM15c, XMM15d); // Class for all 128bit vector registers reg_class vectorx_reg_evex(XMM0, XMM0b, XMM0c, XMM0d, @@ -991,9 +953,8 @@ reg_class vectorx_reg_evex(XMM0, XMM0b, XMM0c, XMM0d, XMM4, XMM4b, XMM4c, XMM4d, XMM5, XMM5b, XMM5c, XMM5d, XMM6, XMM6b, XMM6c, XMM6d, - XMM7, XMM7b, XMM7c, XMM7d -#ifdef _LP64 - ,XMM8, XMM8b, XMM8c, XMM8d, + XMM7, XMM7b, XMM7c, XMM7d, + XMM8, XMM8b, XMM8c, XMM8d, XMM9, XMM9b, XMM9c, XMM9d, XMM10, XMM10b, XMM10c, XMM10d, XMM11, XMM11b, XMM11c, XMM11d, @@ -1016,9 +977,7 @@ reg_class vectorx_reg_evex(XMM0, XMM0b, XMM0c, XMM0d, XMM28, XMM28b, XMM28c, XMM28d, XMM29, XMM29b, XMM29c, XMM29d, XMM30, XMM30b, XMM30c, XMM30d, - XMM31, XMM31b, XMM31c, XMM31d -#endif - ); + XMM31, XMM31b, XMM31c, XMM31d); reg_class_dynamic vectorx_reg(vectorx_reg_evex, vectorx_reg_legacy, %{ VM_Version::supports_evex() %} ); reg_class_dynamic vectorx_reg_vlbwdq(vectorx_reg_evex, vectorx_reg_legacy, %{ VM_Version::supports_avx512vlbwdq() %} ); @@ -1031,18 +990,15 @@ reg_class vectory_reg_legacy(XMM0, XMM0b, XMM0c, XMM0d, XMM0e, XMM0f, XMM0 XMM4, XMM4b, XMM4c, XMM4d, XMM4e, XMM4f, XMM4g, XMM4h, XMM5, XMM5b, XMM5c, XMM5d, XMM5e, XMM5f, XMM5g, XMM5h, XMM6, XMM6b, XMM6c, XMM6d, XMM6e, XMM6f, XMM6g, XMM6h, - XMM7, XMM7b, XMM7c, XMM7d, XMM7e, XMM7f, XMM7g, XMM7h -#ifdef _LP64 - ,XMM8, XMM8b, XMM8c, XMM8d, XMM8e, XMM8f, XMM8g, XMM8h, + XMM7, XMM7b, XMM7c, XMM7d, XMM7e, XMM7f, XMM7g, XMM7h, + XMM8, XMM8b, XMM8c, XMM8d, XMM8e, XMM8f, XMM8g, XMM8h, XMM9, XMM9b, XMM9c, XMM9d, XMM9e, XMM9f, XMM9g, XMM9h, XMM10, XMM10b, XMM10c, XMM10d, XMM10e, XMM10f, XMM10g, XMM10h, XMM11, XMM11b, XMM11c, XMM11d, XMM11e, XMM11f, XMM11g, XMM11h, XMM12, XMM12b, XMM12c, XMM12d, XMM12e, XMM12f, XMM12g, XMM12h, XMM13, XMM13b, XMM13c, XMM13d, XMM13e, XMM13f, XMM13g, XMM13h, XMM14, XMM14b, XMM14c, XMM14d, XMM14e, XMM14f, XMM14g, XMM14h, - XMM15, XMM15b, XMM15c, XMM15d, XMM15e, XMM15f, XMM15g, XMM15h -#endif - ); + XMM15, XMM15b, XMM15c, XMM15d, XMM15e, XMM15f, XMM15g, XMM15h); // Class for all 256bit vector registers reg_class vectory_reg_evex(XMM0, XMM0b, XMM0c, XMM0d, XMM0e, XMM0f, XMM0g, XMM0h, @@ -1052,9 +1008,8 @@ reg_class vectory_reg_evex(XMM0, XMM0b, XMM0c, XMM0d, XMM0e, XMM0f, XMM0g, XMM4, XMM4b, XMM4c, XMM4d, XMM4e, XMM4f, XMM4g, XMM4h, XMM5, XMM5b, XMM5c, XMM5d, XMM5e, XMM5f, XMM5g, XMM5h, XMM6, XMM6b, XMM6c, XMM6d, XMM6e, XMM6f, XMM6g, XMM6h, - XMM7, XMM7b, XMM7c, XMM7d, XMM7e, XMM7f, XMM7g, XMM7h -#ifdef _LP64 - ,XMM8, XMM8b, XMM8c, XMM8d, XMM8e, XMM8f, XMM8g, XMM8h, + XMM7, XMM7b, XMM7c, XMM7d, XMM7e, XMM7f, XMM7g, XMM7h, + XMM8, XMM8b, XMM8c, XMM8d, XMM8e, XMM8f, XMM8g, XMM8h, XMM9, XMM9b, XMM9c, XMM9d, XMM9e, XMM9f, XMM9g, XMM9h, XMM10, XMM10b, XMM10c, XMM10d, XMM10e, XMM10f, XMM10g, XMM10h, XMM11, XMM11b, XMM11c, XMM11d, XMM11e, XMM11f, XMM11g, XMM11h, @@ -1077,9 +1032,7 @@ reg_class vectory_reg_evex(XMM0, XMM0b, XMM0c, XMM0d, XMM0e, XMM0f, XMM0g, XMM28, XMM28b, XMM28c, XMM28d, XMM28e, XMM28f, XMM28g, XMM28h, XMM29, XMM29b, XMM29c, XMM29d, XMM29e, XMM29f, XMM29g, XMM29h, XMM30, XMM30b, XMM30c, XMM30d, XMM30e, XMM30f, XMM30g, XMM30h, - XMM31, XMM31b, XMM31c, XMM31d, XMM31e, XMM31f, XMM31g, XMM31h -#endif - ); + XMM31, XMM31b, XMM31c, XMM31d, XMM31e, XMM31f, XMM31g, XMM31h); reg_class_dynamic vectory_reg(vectory_reg_evex, vectory_reg_legacy, %{ VM_Version::supports_evex() %} ); reg_class_dynamic vectory_reg_vlbwdq(vectory_reg_evex, vectory_reg_legacy, %{ VM_Version::supports_avx512vlbwdq() %} ); @@ -1092,17 +1045,16 @@ reg_class vectorz_reg_evex(XMM0, XMM0b, XMM0c, XMM0d, XMM0e, XMM0f, XMM0g, XMM4, XMM4b, XMM4c, XMM4d, XMM4e, XMM4f, XMM4g, XMM4h, XMM4i, XMM4j, XMM4k, XMM4l, XMM4m, XMM4n, XMM4o, XMM4p, XMM5, XMM5b, XMM5c, XMM5d, XMM5e, XMM5f, XMM5g, XMM5h, XMM5i, XMM5j, XMM5k, XMM5l, XMM5m, XMM5n, XMM5o, XMM5p, XMM6, XMM6b, XMM6c, XMM6d, XMM6e, XMM6f, XMM6g, XMM6h, XMM6i, XMM6j, XMM6k, XMM6l, XMM6m, XMM6n, XMM6o, XMM6p, - XMM7, XMM7b, XMM7c, XMM7d, XMM7e, XMM7f, XMM7g, XMM7h, XMM7i, XMM7j, XMM7k, XMM7l, XMM7m, XMM7n, XMM7o, XMM7p -#ifdef _LP64 - ,XMM8, XMM8b, XMM8c, XMM8d, XMM8e, XMM8f, XMM8g, XMM8h, XMM8i, XMM8j, XMM8k, XMM8l, XMM8m, XMM8n, XMM8o, XMM8p, + XMM7, XMM7b, XMM7c, XMM7d, XMM7e, XMM7f, XMM7g, XMM7h, XMM7i, XMM7j, XMM7k, XMM7l, XMM7m, XMM7n, XMM7o, XMM7p, + XMM8, XMM8b, XMM8c, XMM8d, XMM8e, XMM8f, XMM8g, XMM8h, XMM8i, XMM8j, XMM8k, XMM8l, XMM8m, XMM8n, XMM8o, XMM8p, XMM9, XMM9b, XMM9c, XMM9d, XMM9e, XMM9f, XMM9g, XMM9h, XMM9i, XMM9j, XMM9k, XMM9l, XMM9m, XMM9n, XMM9o, XMM9p, XMM10, XMM10b, XMM10c, XMM10d, XMM10e, XMM10f, XMM10g, XMM10h, XMM10i, XMM10j, XMM10k, XMM10l, XMM10m, XMM10n, XMM10o, XMM10p, XMM11, XMM11b, XMM11c, XMM11d, XMM11e, XMM11f, XMM11g, XMM11h, XMM11i, XMM11j, XMM11k, XMM11l, XMM11m, XMM11n, XMM11o, XMM11p, XMM12, XMM12b, XMM12c, XMM12d, XMM12e, XMM12f, XMM12g, XMM12h, XMM12i, XMM12j, XMM12k, XMM12l, XMM12m, XMM12n, XMM12o, XMM12p, XMM13, XMM13b, XMM13c, XMM13d, XMM13e, XMM13f, XMM13g, XMM13h, XMM13i, XMM13j, XMM13k, XMM13l, XMM13m, XMM13n, XMM13o, XMM13p, XMM14, XMM14b, XMM14c, XMM14d, XMM14e, XMM14f, XMM14g, XMM14h, XMM14i, XMM14j, XMM14k, XMM14l, XMM14m, XMM14n, XMM14o, XMM14p, - XMM15, XMM15b, XMM15c, XMM15d, XMM15e, XMM15f, XMM15g, XMM15h, XMM15i, XMM15j, XMM15k, XMM15l, XMM15m, XMM15n, XMM15o, XMM15p - ,XMM16, XMM16b, XMM16c, XMM16d, XMM16e, XMM16f, XMM16g, XMM16h, XMM16i, XMM16j, XMM16k, XMM16l, XMM16m, XMM16n, XMM16o, XMM16p, + XMM15, XMM15b, XMM15c, XMM15d, XMM15e, XMM15f, XMM15g, XMM15h, XMM15i, XMM15j, XMM15k, XMM15l, XMM15m, XMM15n, XMM15o, XMM15p, + XMM16, XMM16b, XMM16c, XMM16d, XMM16e, XMM16f, XMM16g, XMM16h, XMM16i, XMM16j, XMM16k, XMM16l, XMM16m, XMM16n, XMM16o, XMM16p, XMM17, XMM17b, XMM17c, XMM17d, XMM17e, XMM17f, XMM17g, XMM17h, XMM17i, XMM17j, XMM17k, XMM17l, XMM17m, XMM17n, XMM17o, XMM17p, XMM18, XMM18b, XMM18c, XMM18d, XMM18e, XMM18f, XMM18g, XMM18h, XMM18i, XMM18j, XMM18k, XMM18l, XMM18m, XMM18n, XMM18o, XMM18p, XMM19, XMM19b, XMM19c, XMM19d, XMM19e, XMM19f, XMM19g, XMM19h, XMM19i, XMM19j, XMM19k, XMM19l, XMM19m, XMM19n, XMM19o, XMM19p, @@ -1117,9 +1069,7 @@ reg_class vectorz_reg_evex(XMM0, XMM0b, XMM0c, XMM0d, XMM0e, XMM0f, XMM0g, XMM28, XMM28b, XMM28c, XMM28d, XMM28e, XMM28f, XMM28g, XMM28h, XMM28i, XMM28j, XMM28k, XMM28l, XMM28m, XMM28n, XMM28o, XMM28p, XMM29, XMM29b, XMM29c, XMM29d, XMM29e, XMM29f, XMM29g, XMM29h, XMM29i, XMM29j, XMM29k, XMM29l, XMM29m, XMM29n, XMM29o, XMM29p, XMM30, XMM30b, XMM30c, XMM30d, XMM30e, XMM30f, XMM30g, XMM30h, XMM30i, XMM30j, XMM30k, XMM30l, XMM30m, XMM30n, XMM30o, XMM30p, - XMM31, XMM31b, XMM31c, XMM31d, XMM31e, XMM31f, XMM31g, XMM31h, XMM31i, XMM31j, XMM31k, XMM31l, XMM31m, XMM31n, XMM31o, XMM31p -#endif - ); + XMM31, XMM31b, XMM31c, XMM31d, XMM31e, XMM31f, XMM31g, XMM31h, XMM31i, XMM31j, XMM31k, XMM31l, XMM31m, XMM31n, XMM31o, XMM31p); // Class for restricted 512bit vector registers reg_class vectorz_reg_legacy(XMM0, XMM0b, XMM0c, XMM0d, XMM0e, XMM0f, XMM0g, XMM0h, XMM0i, XMM0j, XMM0k, XMM0l, XMM0m, XMM0n, XMM0o, XMM0p, @@ -1129,18 +1079,15 @@ reg_class vectorz_reg_legacy(XMM0, XMM0b, XMM0c, XMM0d, XMM0e, XMM0f, XMM0 XMM4, XMM4b, XMM4c, XMM4d, XMM4e, XMM4f, XMM4g, XMM4h, XMM4i, XMM4j, XMM4k, XMM4l, XMM4m, XMM4n, XMM4o, XMM4p, XMM5, XMM5b, XMM5c, XMM5d, XMM5e, XMM5f, XMM5g, XMM5h, XMM5i, XMM5j, XMM5k, XMM5l, XMM5m, XMM5n, XMM5o, XMM5p, XMM6, XMM6b, XMM6c, XMM6d, XMM6e, XMM6f, XMM6g, XMM6h, XMM6i, XMM6j, XMM6k, XMM6l, XMM6m, XMM6n, XMM6o, XMM6p, - XMM7, XMM7b, XMM7c, XMM7d, XMM7e, XMM7f, XMM7g, XMM7h, XMM7i, XMM7j, XMM7k, XMM7l, XMM7m, XMM7n, XMM7o, XMM7p -#ifdef _LP64 - ,XMM8, XMM8b, XMM8c, XMM8d, XMM8e, XMM8f, XMM8g, XMM8h, XMM8i, XMM8j, XMM8k, XMM8l, XMM8m, XMM8n, XMM8o, XMM8p, + XMM7, XMM7b, XMM7c, XMM7d, XMM7e, XMM7f, XMM7g, XMM7h, XMM7i, XMM7j, XMM7k, XMM7l, XMM7m, XMM7n, XMM7o, XMM7p, + XMM8, XMM8b, XMM8c, XMM8d, XMM8e, XMM8f, XMM8g, XMM8h, XMM8i, XMM8j, XMM8k, XMM8l, XMM8m, XMM8n, XMM8o, XMM8p, XMM9, XMM9b, XMM9c, XMM9d, XMM9e, XMM9f, XMM9g, XMM9h, XMM9i, XMM9j, XMM9k, XMM9l, XMM9m, XMM9n, XMM9o, XMM9p, XMM10, XMM10b, XMM10c, XMM10d, XMM10e, XMM10f, XMM10g, XMM10h, XMM10i, XMM10j, XMM10k, XMM10l, XMM10m, XMM10n, XMM10o, XMM10p, XMM11, XMM11b, XMM11c, XMM11d, XMM11e, XMM11f, XMM11g, XMM11h, XMM11i, XMM11j, XMM11k, XMM11l, XMM11m, XMM11n, XMM11o, XMM11p, XMM12, XMM12b, XMM12c, XMM12d, XMM12e, XMM12f, XMM12g, XMM12h, XMM12i, XMM12j, XMM12k, XMM12l, XMM12m, XMM12n, XMM12o, XMM12p, XMM13, XMM13b, XMM13c, XMM13d, XMM13e, XMM13f, XMM13g, XMM13h, XMM13i, XMM13j, XMM13k, XMM13l, XMM13m, XMM13n, XMM13o, XMM13p, XMM14, XMM14b, XMM14c, XMM14d, XMM14e, XMM14f, XMM14g, XMM14h, XMM14i, XMM14j, XMM14k, XMM14l, XMM14m, XMM14n, XMM14o, XMM14p, - XMM15, XMM15b, XMM15c, XMM15d, XMM15e, XMM15f, XMM15g, XMM15h, XMM15i, XMM15j, XMM15k, XMM15l, XMM15m, XMM15n, XMM15o, XMM15p -#endif - ); + XMM15, XMM15b, XMM15c, XMM15d, XMM15e, XMM15f, XMM15g, XMM15h, XMM15i, XMM15j, XMM15k, XMM15l, XMM15m, XMM15n, XMM15o, XMM15p); reg_class_dynamic vectorz_reg (vectorz_reg_evex, vectorz_reg_legacy, %{ VM_Version::supports_evex() %} ); reg_class_dynamic vectorz_reg_vl(vectorz_reg_evex, vectorz_reg_legacy, %{ VM_Version::supports_evex() && VM_Version::supports_avx512vl() %} ); @@ -1199,21 +1146,10 @@ class HandlerImpl { return NativeJump::instruction_size; } -#ifdef _LP64 static uint size_deopt_handler() { // three 5 byte instructions plus one move for unreachable address. return 15+3; } -#else - static uint size_deopt_handler() { - // NativeCall instruction size is the same as NativeJump. - // exception handler starts out as jump and can be patched to - // a call be deoptimization. (4932387) - // Note that this value is also credited (in output.cpp) to - // the size of the code section. - return 5 + NativeJump::instruction_size; // pushl(); jmp; - } -#endif }; inline Assembler::AvxVectorLen vector_length_encoding(int bytes) { @@ -1334,7 +1270,6 @@ int HandlerImpl::emit_deopt_handler(C2_MacroAssembler* masm) { } int offset = __ offset(); -#ifdef _LP64 address the_pc = (address) __ pc(); Label next; // push a "the_pc" on the stack without destroying any registers @@ -1345,10 +1280,6 @@ int HandlerImpl::emit_deopt_handler(C2_MacroAssembler* masm) { __ bind(next); // adjust it so it matches "the_pc" __ subptr(Address(rsp, 0), __ offset() - offset); -#else - InternalAddress here(__ pc()); - __ pushptr(here.addr(), noreg); -#endif __ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack())); assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow %d", (__ offset() - offset)); @@ -1372,17 +1303,10 @@ static Assembler::Width widthForType(BasicType bt) { //============================================================================= // Float masks come from different places depending on platform. -#ifdef _LP64 static address float_signmask() { return StubRoutines::x86::float_sign_mask(); } static address float_signflip() { return StubRoutines::x86::float_sign_flip(); } static address double_signmask() { return StubRoutines::x86::double_sign_mask(); } static address double_signflip() { return StubRoutines::x86::double_sign_flip(); } -#else - static address float_signmask() { return (address)float_signmask_pool; } - static address float_signflip() { return (address)float_signflip_pool; } - static address double_signmask() { return (address)double_signmask_pool; } - static address double_signflip() { return (address)double_signflip_pool; } -#endif static address vector_short_to_byte_mask() { return StubRoutines::x86::vector_short_to_byte_mask(); } static address vector_int_to_byte_mask() { return StubRoutines::x86::vector_int_to_byte_mask(); } static address vector_byte_perm_mask() { return StubRoutines::x86::vector_byte_perm_mask(); } @@ -1404,7 +1328,6 @@ bool Matcher::match_rule_supported(int opcode) { if (!has_match_rule(opcode)) { return false; // no match rule present } - const bool is_LP64 = LP64_ONLY(true) NOT_LP64(false); switch (opcode) { case Op_AbsVL: case Op_StoreVectorScatter: @@ -1509,7 +1432,7 @@ bool Matcher::match_rule_supported(int opcode) { } break; case Op_PopulateIndex: - if (!is_LP64 || (UseAVX < 2)) { + if (UseAVX < 2) { return false; } break; @@ -1524,9 +1447,7 @@ bool Matcher::match_rule_supported(int opcode) { } break; case Op_CompareAndSwapL: -#ifdef _LP64 case Op_CompareAndSwapP: -#endif break; case Op_StrIndexOf: if (!UseSSE42Intrinsics) { @@ -1555,7 +1476,6 @@ bool Matcher::match_rule_supported(int opcode) { return false; } break; -#ifdef _LP64 case Op_MaxD: case Op_MaxF: case Op_MinD: @@ -1564,7 +1484,6 @@ bool Matcher::match_rule_supported(int opcode) { return false; } break; -#endif case Op_CacheWB: case Op_CacheWBPreSync: case Op_CacheWBPostSync: @@ -1607,7 +1526,7 @@ bool Matcher::match_rule_supported(int opcode) { case Op_VectorCmpMasked: case Op_VectorMaskGen: - if (!is_LP64 || UseAVX < 3 || !VM_Version::supports_bmi2()) { + if (UseAVX < 3 || !VM_Version::supports_bmi2()) { return false; } break; @@ -1615,50 +1534,25 @@ bool Matcher::match_rule_supported(int opcode) { case Op_VectorMaskLastTrue: case Op_VectorMaskTrueCount: case Op_VectorMaskToLong: - if (!is_LP64 || UseAVX < 1) { + if (UseAVX < 1) { return false; } break; case Op_RoundF: case Op_RoundD: - if (!is_LP64) { - return false; - } break; case Op_CopySignD: case Op_CopySignF: - if (UseAVX < 3 || !is_LP64) { + if (UseAVX < 3) { return false; } if (!VM_Version::supports_avx512vl()) { return false; } break; -#ifndef _LP64 - case Op_AddReductionVF: - case Op_AddReductionVD: - case Op_MulReductionVF: - case Op_MulReductionVD: - if (UseSSE < 1) { // requires at least SSE - return false; - } - break; - case Op_MulAddVS2VI: - case Op_RShiftVL: - case Op_AbsVD: - case Op_NegVD: - if (UseSSE < 2) { - return false; - } - break; -#endif // !LP64 case Op_CompressBits: - if (!VM_Version::supports_bmi2() || (!is_LP64 && UseSSE < 2)) { - return false; - } - break; case Op_ExpandBits: - if (!VM_Version::supports_bmi2() || (!is_LP64 && (UseSSE < 2 || !VM_Version::supports_bmi1()))) { + if (!VM_Version::supports_bmi2()) { return false; } break; @@ -1683,14 +1577,9 @@ bool Matcher::match_rule_supported(int opcode) { } break; case Op_SqrtD: -#ifdef _LP64 if (UseSSE < 2) { return false; } -#else - // x86_32.ad has a special match rule for SqrtD. - // Together with common x86 rules, this handles all UseSSE cases. -#endif break; case Op_ConvF2HF: case Op_ConvHF2F: @@ -1722,7 +1611,6 @@ bool Matcher::match_rule_supported_auto_vectorization(int opcode, int vlen, Basi // Identify extra cases that we might want to provide match rules for vector nodes and // other intrinsics guarded with vector length (vlen) and element type (bt). bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { - const bool is_LP64 = LP64_ONLY(true) NOT_LP64(false); if (!match_rule_supported(opcode)) { return false; } @@ -1769,7 +1657,7 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { case Op_ClearArray: case Op_VectorMaskGen: case Op_VectorCmpMasked: - if (!is_LP64 || !VM_Version::supports_avx512bw()) { + if (!VM_Version::supports_avx512bw()) { return false; } if ((size_in_bits != 512) && !VM_Version::supports_avx512vl()) { @@ -1819,19 +1707,7 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { if (is_subword_type(bt) && (UseSSE < 4)) { return false; } -#ifndef _LP64 - if (bt == T_BYTE || bt == T_LONG) { - return false; - } -#endif break; -#ifndef _LP64 - case Op_VectorInsert: - if (bt == T_LONG || bt == T_DOUBLE) { - return false; - } - break; -#endif case Op_MinReductionV: case Op_MaxReductionV: if ((bt == T_INT || is_subword_type(bt)) && UseSSE < 4) { @@ -1846,11 +1722,6 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { if (UseAVX > 2 && (!VM_Version::supports_avx512dq() && size_in_bits == 512)) { return false; } -#ifndef _LP64 - if (bt == T_BYTE || bt == T_LONG) { - return false; - } -#endif break; case Op_VectorTest: if (UseSSE < 4) { @@ -1935,10 +1806,9 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { return false; } if (is_subword_type(bt) && - (!is_LP64 || - (size_in_bits > 256 && !VM_Version::supports_avx512bw()) || - (size_in_bits < 64) || - (bt == T_SHORT && !VM_Version::supports_bmi2()))) { + ((size_in_bits > 256 && !VM_Version::supports_avx512bw()) || + (size_in_bits < 64) || + (bt == T_SHORT && !VM_Version::supports_bmi2()))) { return false; } break; @@ -2007,14 +1877,11 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { if (is_subword_type(bt) && !VM_Version::supports_avx512_vbmi2()) { return false; } - if (!is_LP64 && !VM_Version::supports_avx512vl() && size_in_bits < 512) { - return false; - } if (size_in_bits < 128 ) { return false; } case Op_VectorLongToMask: - if (UseAVX < 1 || !is_LP64) { + if (UseAVX < 1) { return false; } if (UseAVX < 3 && !VM_Version::supports_bmi2()) { @@ -2062,7 +1929,6 @@ bool Matcher::match_rule_supported_vector_masked(int opcode, int vlen, BasicType return false; } - const bool is_LP64 = LP64_ONLY(true) NOT_LP64(false); int size_in_bits = vlen * type2aelembytes(bt) * BitsPerByte; if (size_in_bits != 512 && !VM_Version::supports_avx512vl()) { return false; @@ -2398,7 +2264,6 @@ static bool clone_shift(Node* shift, Matcher* matcher, Matcher::MStack& mstack, address_visited.set(shift->_idx); // Flag as address_visited mstack.push(shift->in(2), Matcher::Visit); Node *conv = shift->in(1); -#ifdef _LP64 // Allow Matcher to match the rule which bypass // ConvI2L operation for an array index on LP64 // if the index value is positive. @@ -2408,9 +2273,9 @@ static bool clone_shift(Node* shift, Matcher* matcher, Matcher::MStack& mstack, !matcher->is_visited(conv)) { address_visited.set(conv->_idx); // Flag as address_visited mstack.push(conv->in(1), Matcher::Pre_Visit); - } else -#endif + } else { mstack.push(conv, Matcher::Pre_Visit); + } return true; } return false; @@ -2548,7 +2413,7 @@ bool Matcher::pd_clone_address_expressions(AddPNode* m, Matcher::MStack& mstack, if (adr->is_AddP() && !adr->in(AddPNode::Base)->is_top() && !adr->in(AddPNode::Offset)->is_Con() && - LP64_ONLY( off->get_long() == (int) (off->get_long()) && ) // immL32 + off->get_long() == (int) (off->get_long()) && // immL32 // Are there other uses besides address expressions? !is_visited(adr)) { address_visited.set(adr->_idx); // Flag as address_visited @@ -2622,26 +2487,18 @@ static void vec_mov_helper(C2_MacroAssembler *masm, int src_lo, int dst_lo, case Op_VecS: // copy whole register case Op_VecD: case Op_VecX: -#ifndef _LP64 - __ movdqu(as_XMMRegister(Matcher::_regEncode[dst_lo]), as_XMMRegister(Matcher::_regEncode[src_lo])); -#else if ((UseAVX < 3) || VM_Version::supports_avx512vl()) { __ movdqu(as_XMMRegister(Matcher::_regEncode[dst_lo]), as_XMMRegister(Matcher::_regEncode[src_lo])); } else { __ vextractf32x4(as_XMMRegister(Matcher::_regEncode[dst_lo]), as_XMMRegister(Matcher::_regEncode[src_lo]), 0x0); } -#endif break; case Op_VecY: -#ifndef _LP64 - __ vmovdqu(as_XMMRegister(Matcher::_regEncode[dst_lo]), as_XMMRegister(Matcher::_regEncode[src_lo])); -#else if ((UseAVX < 3) || VM_Version::supports_avx512vl()) { __ vmovdqu(as_XMMRegister(Matcher::_regEncode[dst_lo]), as_XMMRegister(Matcher::_regEncode[src_lo])); } else { __ vextractf64x4(as_XMMRegister(Matcher::_regEncode[dst_lo]), as_XMMRegister(Matcher::_regEncode[src_lo]), 0x0); } -#endif break; case Op_VecZ: __ evmovdquq(as_XMMRegister(Matcher::_regEncode[dst_lo]), as_XMMRegister(Matcher::_regEncode[src_lo]), 2); @@ -2680,28 +2537,20 @@ void vec_spill_helper(C2_MacroAssembler *masm, bool is_load, __ movq(as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset)); break; case Op_VecX: -#ifndef _LP64 - __ movdqu(as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset)); -#else if ((UseAVX < 3) || VM_Version::supports_avx512vl()) { __ movdqu(as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset)); } else { __ vpxor(as_XMMRegister(Matcher::_regEncode[reg]), as_XMMRegister(Matcher::_regEncode[reg]), as_XMMRegister(Matcher::_regEncode[reg]), 2); __ vinsertf32x4(as_XMMRegister(Matcher::_regEncode[reg]), as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset),0x0); } -#endif break; case Op_VecY: -#ifndef _LP64 - __ vmovdqu(as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset)); -#else if ((UseAVX < 3) || VM_Version::supports_avx512vl()) { __ vmovdqu(as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset)); } else { __ vpxor(as_XMMRegister(Matcher::_regEncode[reg]), as_XMMRegister(Matcher::_regEncode[reg]), as_XMMRegister(Matcher::_regEncode[reg]), 2); __ vinsertf64x4(as_XMMRegister(Matcher::_regEncode[reg]), as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset),0x0); } -#endif break; case Op_VecZ: __ evmovdquq(as_XMMRegister(Matcher::_regEncode[reg]), Address(rsp, stack_offset), 2); @@ -2718,28 +2567,20 @@ void vec_spill_helper(C2_MacroAssembler *masm, bool is_load, __ movq(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg])); break; case Op_VecX: -#ifndef _LP64 - __ movdqu(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg])); -#else if ((UseAVX < 3) || VM_Version::supports_avx512vl()) { __ movdqu(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg])); } else { __ vextractf32x4(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg]), 0x0); } -#endif break; case Op_VecY: -#ifndef _LP64 - __ vmovdqu(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg])); -#else if ((UseAVX < 3) || VM_Version::supports_avx512vl()) { __ vmovdqu(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg])); } else { __ vextractf64x4(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg]), 0x0); } -#endif break; case Op_VecZ: __ evmovdquq(Address(rsp, stack_offset), as_XMMRegister(Matcher::_regEncode[reg]), 2); @@ -3970,7 +3811,6 @@ instruct reinterpret_shrink(vec dst, legVec src) %{ // ---------------------------------------------------------------------------------------------------- -#ifdef _LP64 instruct roundD_reg(legRegD dst, legRegD src, immU8 rmode) %{ match(Set dst (RoundDoubleMode src rmode)); format %{ "roundsd $dst,$src" %} @@ -4041,7 +3881,6 @@ instruct vround8D_mem(vec dst, memory mem, immU8 rmode) %{ %} ins_pipe( pipe_slow ); %} -#endif // _LP64 instruct onspinwait() %{ match(OnSpinWait); @@ -4259,7 +4098,6 @@ instruct vgather_subwordGT8B_off(vec dst, memory mem, rRegP idx_base, rRegI offs %} -#ifdef _LP64 instruct vgather_masked_subwordLE8B_avx3(vec dst, memory mem, rRegP idx_base, immI_0 offset, kReg mask, rRegL mask_idx, rRegP tmp, rRegI rtmp, rRegL rtmp2, rFlagsReg cr) %{ predicate(VM_Version::supports_avx512bw() && is_subword_type(Matcher::vector_element_basic_type(n)) && Matcher::vector_length_in_bytes(n) <= 8); match(Set dst (LoadVectorGatherMasked mem (Binary idx_base (Binary mask offset)))); @@ -4422,7 +4260,6 @@ instruct vgather_masked_subwordGT8B_off_avx2(vec dst, memory mem, rRegP idx_base %} ins_pipe( pipe_slow ); %} -#endif // ====================Scatter======================================= @@ -4538,7 +4375,6 @@ instruct vReplS_reg(vec dst, rRegI src) %{ ins_pipe( pipe_slow ); %} -#ifdef _LP64 instruct ReplHF_imm(vec dst, immH con, rRegI rtmp) %{ match(Set dst (Replicate con)); effect(TEMP rtmp); @@ -4565,7 +4401,6 @@ instruct ReplHF_reg(vec dst, regF src, rRegI rtmp) %{ %} ins_pipe( pipe_slow ); %} -#endif instruct ReplS_mem(vec dst, memory mem) %{ predicate(UseAVX >= 2 && Matcher::vector_element_basic_type(n) == T_SHORT); @@ -4662,7 +4497,6 @@ instruct ReplI_M1(vec dst, immI_M1 con) %{ // ====================ReplicateL======================================= -#ifdef _LP64 // Replicate long (8 byte) scalar to be vector instruct ReplL_reg(vec dst, rRegL src) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); @@ -4683,61 +4517,6 @@ instruct ReplL_reg(vec dst, rRegL src) %{ %} ins_pipe( pipe_slow ); %} -#else // _LP64 -// Replicate long (8 byte) scalar to be vector -instruct ReplL_reg(vec dst, eRegL src, vec tmp) %{ - predicate(Matcher::vector_length(n) <= 4 && Matcher::vector_element_basic_type(n) == T_LONG); - match(Set dst (Replicate src)); - effect(TEMP dst, USE src, TEMP tmp); - format %{ "replicateL $dst,$src" %} - ins_encode %{ - uint vlen = Matcher::vector_length(this); - if (vlen == 2) { - __ movdl($dst$$XMMRegister, $src$$Register); - __ movdl($tmp$$XMMRegister, HIGH_FROM_LOW($src$$Register)); - __ punpckldq($dst$$XMMRegister, $tmp$$XMMRegister); - __ punpcklqdq($dst$$XMMRegister, $dst$$XMMRegister); - } else if (VM_Version::supports_avx512vl()) { // AVX512VL for <512bit operands - int vlen_enc = Assembler::AVX_256bit; - __ movdl($dst$$XMMRegister, $src$$Register); - __ movdl($tmp$$XMMRegister, HIGH_FROM_LOW($src$$Register)); - __ punpckldq($dst$$XMMRegister, $tmp$$XMMRegister); - __ vpbroadcastq($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); - } else { - __ movdl($dst$$XMMRegister, $src$$Register); - __ movdl($tmp$$XMMRegister, HIGH_FROM_LOW($src$$Register)); - __ punpckldq($dst$$XMMRegister, $tmp$$XMMRegister); - __ punpcklqdq($dst$$XMMRegister, $dst$$XMMRegister); - __ vinserti128_high($dst$$XMMRegister, $dst$$XMMRegister); - } - %} - ins_pipe( pipe_slow ); -%} - -instruct ReplL_reg_leg(legVec dst, eRegL src, legVec tmp) %{ - predicate(Matcher::vector_length(n) == 8 && Matcher::vector_element_basic_type(n) == T_LONG); - match(Set dst (Replicate src)); - effect(TEMP dst, USE src, TEMP tmp); - format %{ "replicateL $dst,$src" %} - ins_encode %{ - if (VM_Version::supports_avx512vl()) { - __ movdl($dst$$XMMRegister, $src$$Register); - __ movdl($tmp$$XMMRegister, HIGH_FROM_LOW($src$$Register)); - __ punpckldq($dst$$XMMRegister, $tmp$$XMMRegister); - __ punpcklqdq($dst$$XMMRegister, $dst$$XMMRegister); - __ vinserti128_high($dst$$XMMRegister, $dst$$XMMRegister); - __ vinserti64x4($dst$$XMMRegister, $dst$$XMMRegister, $dst$$XMMRegister, 0x1); - } else { - int vlen_enc = Assembler::AVX_512bit; - __ movdl($dst$$XMMRegister, $src$$Register); - __ movdl($tmp$$XMMRegister, HIGH_FROM_LOW($src$$Register)); - __ punpckldq($dst$$XMMRegister, $tmp$$XMMRegister); - __ vpbroadcastq($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); - } - %} - ins_pipe( pipe_slow ); -%} -#endif // _LP64 instruct ReplL_mem(vec dst, memory mem) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); @@ -5011,7 +4790,6 @@ instruct insert64(vec dst, vec src, rRegI val, immU8 idx, legVec vtmp) %{ ins_pipe( pipe_slow ); %} -#ifdef _LP64 instruct insert2L(vec dst, rRegL val, immU8 idx) %{ predicate(Matcher::vector_length(n) == 2); match(Set dst (VectorInsert (Binary dst val) idx)); @@ -5062,7 +4840,6 @@ instruct insert8L(vec dst, vec src, rRegL val, immU8 idx, legVec vtmp) %{ %} ins_pipe( pipe_slow ); %} -#endif instruct insertF(vec dst, regF val, immU8 idx) %{ predicate(Matcher::vector_length(n) < 8); @@ -5108,7 +4885,6 @@ instruct vinsertF(vec dst, vec src, regF val, immU8 idx, vec vtmp) %{ ins_pipe( pipe_slow ); %} -#ifdef _LP64 instruct insert2D(vec dst, regD val, immU8 idx, rRegL tmp) %{ predicate(Matcher::vector_length(n) == 2); match(Set dst (VectorInsert (Binary dst val) idx)); @@ -5163,7 +4939,6 @@ instruct insert8D(vec dst, vec src, regD val, immI idx, rRegL tmp, legVec vtmp) %} ins_pipe( pipe_slow ); %} -#endif // ====================REDUCTION ARITHMETIC======================================= @@ -5190,7 +4965,6 @@ instruct reductionI(rRegI dst, rRegI src1, legVec src2, legVec vtmp1, legVec vtm // =======================Long Reduction========================================== -#ifdef _LP64 instruct reductionL(rRegL dst, rRegL src1, legVec src2, legVec vtmp1, legVec vtmp2) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_LONG && !VM_Version::supports_avx512dq()); match(Set dst (AddReductionVL src1 src2)); @@ -5228,7 +5002,6 @@ instruct reductionL_avx512dq(rRegL dst, rRegL src1, vec src2, vec vtmp1, vec vtm %} ins_pipe( pipe_slow ); %} -#endif // _LP64 // =======================Float Reduction========================================== @@ -5440,7 +5213,6 @@ instruct unordered_reduction8D(regD dst, regD src1, legVec src2, legVec vtmp1, l // =======================Byte Reduction========================================== -#ifdef _LP64 instruct reductionB(rRegI dst, rRegI src1, legVec src2, legVec vtmp1, legVec vtmp2) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE && !VM_Version::supports_avx512bw()); match(Set dst (AddReductionVI src1 src2)); @@ -5476,7 +5248,6 @@ instruct reductionB_avx512bw(rRegI dst, rRegI src1, vec src2, vec vtmp1, vec vtm %} ins_pipe( pipe_slow ); %} -#endif // =======================Short Reduction========================================== @@ -6777,7 +6548,6 @@ instruct signumV_reg_evex(vec dst, vec src, vec zero, vec one, kReg ktmp1) %{ // Result going from high bit to low bit is 0x11100100 = 0xe4 // --------------------------------------- -#ifdef _LP64 instruct copySignF_reg(regF dst, regF src, regF tmp1, rRegI tmp2) %{ match(Set dst (CopySignF dst src)); effect(TEMP tmp1, TEMP tmp2); @@ -6803,8 +6573,6 @@ instruct copySignD_imm(regD dst, regD src, regD tmp1, rRegL tmp2, immD zero) %{ ins_pipe( pipe_slow ); %} -#endif // _LP64 - //----------------------------- CompressBits/ExpandBits ------------------------ instruct compressBitsI_reg(rRegI dst, rRegI src, rRegI mask) %{ @@ -7977,7 +7745,6 @@ instruct vucast(vec dst, vec src) %{ ins_pipe( pipe_slow ); %} -#ifdef _LP64 instruct vround_float_avx(vec dst, vec src, rRegP tmp, vec xtmp1, vec xtmp2, vec xtmp3, vec xtmp4, rFlagsReg cr) %{ predicate(!VM_Version::supports_avx512vl() && Matcher::vector_length_in_bytes(n) < 64 && @@ -8027,8 +7794,6 @@ instruct vround_reg_evex(vec dst, vec src, rRegP tmp, vec xtmp1, vec xtmp2, kReg ins_pipe( pipe_slow ); %} -#endif // _LP64 - // --------------------------------- VectorMaskCmp -------------------------------------- instruct vcmpFD(legVec dst, legVec src1, legVec src2, immI8 cond) %{ @@ -8238,9 +8003,7 @@ instruct extractI(rRegI dst, legVec src, immU8 idx) %{ predicate(Matcher::vector_length_in_bytes(n->in(1)) <= 16); // src match(Set dst (ExtractI src idx)); match(Set dst (ExtractS src idx)); -#ifdef _LP64 match(Set dst (ExtractB src idx)); -#endif format %{ "extractI $dst,$src,$idx\t!" %} ins_encode %{ assert($idx$$constant < (int)Matcher::vector_length(this, $src), "out of bounds"); @@ -8256,9 +8019,7 @@ instruct vextractI(rRegI dst, legVec src, immI idx, legVec vtmp) %{ Matcher::vector_length_in_bytes(n->in(1)) == 64); // src match(Set dst (ExtractI src idx)); match(Set dst (ExtractS src idx)); -#ifdef _LP64 match(Set dst (ExtractB src idx)); -#endif effect(TEMP vtmp); format %{ "vextractI $dst,$src,$idx\t! using $vtmp as TEMP" %} ins_encode %{ @@ -8271,7 +8032,6 @@ instruct vextractI(rRegI dst, legVec src, immI idx, legVec vtmp) %{ ins_pipe( pipe_slow ); %} -#ifdef _LP64 instruct extractL(rRegL dst, legVec src, immU8 idx) %{ predicate(Matcher::vector_length(n->in(1)) <= 2); // src match(Set dst (ExtractL src idx)); @@ -8299,7 +8059,6 @@ instruct vextractL(rRegL dst, legVec src, immU8 idx, legVec vtmp) %{ %} ins_pipe( pipe_slow ); %} -#endif instruct extractF(legRegF dst, legVec src, immU8 idx, legVec vtmp) %{ predicate(Matcher::vector_length(n->in(1)) <= 4); @@ -8564,7 +8323,6 @@ instruct vabsnegD(vec dst, vec src) %{ //------------------------------------- VectorTest -------------------------------------------- -#ifdef _LP64 instruct vptest_lt16(rFlagsRegU cr, legVec src1, legVec src2, legVec vtmp) %{ predicate(Matcher::vector_length_in_bytes(n->in(1)) < 16); match(Set cr (VectorTest src1 src2)); @@ -8632,7 +8390,6 @@ instruct ktest_ge8(rFlagsRegU cr, kReg src1, kReg src2) %{ %} ins_pipe( pipe_slow ); %} -#endif //------------------------------------- LoadMask -------------------------------------------- @@ -8883,7 +8640,6 @@ instruct loadIotaIndices(vec dst, immI_0 src) %{ ins_pipe( pipe_slow ); %} -#ifdef _LP64 instruct VectorPopulateIndex(vec dst, rRegI src1, immI_1 src2, vec vtmp) %{ match(Set dst (PopulateIndex src1 src2)); effect(TEMP dst, TEMP vtmp); @@ -8915,7 +8671,7 @@ instruct VectorPopulateLIndex(vec dst, rRegL src1, immI_1 src2, vec vtmp) %{ %} ins_pipe( pipe_slow ); %} -#endif + //-------------------------------- Rearrange ---------------------------------- // LoadShuffle/Rearrange for Byte @@ -9496,7 +9252,6 @@ instruct vmasked_store_evex(memory mem, vec src, kReg mask) %{ ins_pipe( pipe_slow ); %} -#ifdef _LP64 instruct verify_vector_alignment(rRegP addr, immL32 mask, rFlagsReg cr) %{ match(Set addr (VerifyVectorAlignment addr mask)); effect(KILL cr); @@ -9710,7 +9465,6 @@ instruct vmask_first_or_last_true_avx(rRegI dst, vec mask, immI size, rRegL tmp, %} // --------------------------------- Compress/Expand Operations --------------------------- -#ifdef _LP64 instruct vcompress_reg_avx(vec dst, vec src, vec mask, rRegI rtmp, rRegL rscratch, vec perm, vec xtmp, rFlagsReg cr) %{ predicate(!VM_Version::supports_avx512vl() && Matcher::vector_length_in_bytes(n) <= 32); match(Set dst (CompressV src mask)); @@ -9726,7 +9480,6 @@ instruct vcompress_reg_avx(vec dst, vec src, vec mask, rRegI rtmp, rRegL rscratc %} ins_pipe( pipe_slow ); %} -#endif instruct vcompress_expand_reg_evex(vec dst, vec src, kReg mask) %{ predicate(VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n) == 64); @@ -9754,8 +9507,6 @@ instruct vcompress_mask_reg_evex(kReg dst, kReg mask, rRegL rtmp1, rRegL rtmp2, ins_pipe( pipe_slow ); %} -#endif // _LP64 - // -------------------------------- Bit and Byte Reversal Vector Operations ------------------------ instruct vreverse_reg(vec dst, vec src, vec xtmp1, vec xtmp2, rRegI rtmp) %{ @@ -10476,7 +10227,6 @@ instruct mask_all_evexI_LE32(kReg dst, rRegI src) %{ ins_pipe( pipe_slow ); %} -#ifdef _LP64 instruct mask_not_immLT8(kReg dst, kReg src, rRegI rtmp, kReg ktmp, immI_M1 cnt) %{ predicate(Matcher::vector_length(n) < 8 && VM_Version::supports_avx512dq()); match(Set dst (XorVMask src (MaskAll cnt))); @@ -10541,7 +10291,6 @@ instruct long_to_mask_evex(kReg dst, rRegL src) %{ %} ins_pipe( pipe_slow ); %} -#endif instruct mask_opers_evex(kReg dst, kReg src1, kReg src2, kReg kscratch) %{ match(Set dst (AndVMask src1 src2)); diff --git a/src/hotspot/share/adlc/archDesc.cpp b/src/hotspot/share/adlc/archDesc.cpp index 8a7d0ee40c40f..263752c521d6f 100644 --- a/src/hotspot/share/adlc/archDesc.cpp +++ b/src/hotspot/share/adlc/archDesc.cpp @@ -751,12 +751,11 @@ bool ArchDesc::check_usage() { callback.do_form_by_name("sRegL"); // special generic vector operands only used in Matcher::pd_specialize_generic_vector_operand - // x86_32 combine x86.ad and x86_32.ad, the vec*/legVec* can not be cleaned from IA32 #if defined(AARCH64) callback.do_form_by_name("vecA"); callback.do_form_by_name("vecD"); callback.do_form_by_name("vecX"); -#elif defined(IA32) || defined(AMD64) +#elif defined(AMD64) callback.do_form_by_name("vecS"); callback.do_form_by_name("vecD"); callback.do_form_by_name("vecX"); From f7fa05f577a28870202ccaa3544c34b58bd4adfe Mon Sep 17 00:00:00 2001 From: Daishi Tabata Date: Wed, 9 Apr 2025 09:11:24 +0000 Subject: [PATCH 0484/1101] 8353698: Output of Simple Web Server is garbled if the console's encoding is not UTF-8 Reviewed-by: djelinski, dfuchs --- .../httpserver/simpleserver/JWebServer.java | 6 ++--- .../sun/net/httpserver/simpleserver/Main.java | 5 ++-- .../simpleserver/CommandLineNegativeTest.java | 21 +++++++++-------- .../CommandLinePortNotSpecifiedTest.java | 5 ++-- .../simpleserver/CommandLinePositiveTest.java | 23 ++++++++++--------- .../jwebserver/CommandLineNegativeTest.java | 21 +++++++++-------- .../CommandLinePortNotSpecifiedTest.java | 5 ++-- .../jwebserver/CommandLinePositiveTest.java | 23 ++++++++++--------- .../jwebserver/IPv6BoundHost.java | 4 +++- .../jwebserver/MaxRequestTimeTest.java | 5 ++-- 10 files changed, 62 insertions(+), 56 deletions(-) diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/JWebServer.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/JWebServer.java index a7daa46bdffe9..c97162ef9bdd5 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/JWebServer.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/JWebServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,8 +27,6 @@ import java.io.PrintWriter; -import static java.nio.charset.StandardCharsets.UTF_8; - /** * Programmatic entry point to start the jwebserver tool. */ @@ -65,7 +63,7 @@ public static void main(String... args) { setMaxReqTime(); setMaxConnectionsIfNotSet(); - int ec = SimpleFileServerImpl.start(new PrintWriter(System.out, true, UTF_8), "jwebserver", args); + int ec = SimpleFileServerImpl.start(new PrintWriter(System.out, true), "jwebserver", args); if (ec != 0) { System.exit(ec); } // otherwise, the server has either been started successfully and diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/Main.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/Main.java index 9ccbbd3edac4b..81ff4e91cac78 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/Main.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ package sun.net.httpserver.simpleserver; import java.io.PrintWriter; -import static java.nio.charset.StandardCharsets.UTF_8; /** * Programmatic entry point to start "java -m jdk.httpserver". @@ -61,7 +60,7 @@ public static void main(String... args) { setMaxReqTime(); JWebServer.setMaxConnectionsIfNotSet(); - int ec = SimpleFileServerImpl.start(new PrintWriter(System.out, true, UTF_8), "java", args); + int ec = SimpleFileServerImpl.start(new PrintWriter(System.out, true), "java", args); if (ec != 0) { System.exit(ec); } // otherwise, the server has either been started successfully and diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java index 3a22d54f36d04..717b92158b8b7 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ public class CommandLineNegativeTest { static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); + static final String LOCALE_OPT = "-Duser.language=en -Duser.country=US"; static final String JAVA = getJava(JAVA_HOME); static final Path CWD = Path.of(".").toAbsolutePath().normalize(); static final Path TEST_DIR = CWD.resolve("CommandLineNegativeTest"); @@ -74,7 +75,7 @@ public Object[][] unknownOption() { @Test(dataProvider = "unknownOption") public void testBadOption(String opt) throws Throwable { out.println("\n--- testUnknownOption, opt=\"%s\" ".formatted(opt)); - simpleserver(JAVA, "-m", "jdk.httpserver", opt) + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", opt) .shouldNotHaveExitValue(0) .shouldContain("Error: unknown option: " + opt); } @@ -97,7 +98,7 @@ public Object[][] tooManyOptionArgs() { @Test(dataProvider = "tooManyOptionArgs") public void testTooManyOptionArgs(String opt, String arg) throws Throwable { out.println("\n--- testTooManyOptionArgs, opt=\"%s\" ".formatted(opt)); - simpleserver(JAVA, "-m", "jdk.httpserver", opt, arg, arg) + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", opt, arg, arg) .shouldNotHaveExitValue(0) .shouldContain("Error: unknown option: " + arg); } @@ -124,7 +125,7 @@ public Object[][] noArg() { @Test(dataProvider = "noArg") public void testNoArg(String opt, String msg) throws Throwable { out.println("\n--- testNoArg, opt=\"%s\" ".formatted(opt)); - simpleserver(JAVA, "-m", "jdk.httpserver", opt) + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", opt) .shouldNotHaveExitValue(0) .shouldContain("Error: no value given for " + opt) .shouldContain(msg); @@ -148,7 +149,7 @@ public Object[][] invalidValue() { @Test(dataProvider = "invalidValue") public void testInvalidValue(String opt, String val) throws Throwable { out.println("\n--- testInvalidValue, opt=\"%s\" ".formatted(opt)); - simpleserver(JAVA, "-m", "jdk.httpserver", opt, val) + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", opt, val) .shouldNotHaveExitValue(0) .shouldContain("Error: invalid value given for " + opt + ": " + val); } @@ -159,7 +160,7 @@ public void testInvalidValue(String opt, String val) throws Throwable { @Test(dataProvider = "portOptions") public void testPortOutOfRange(String opt) throws Throwable { out.println("\n--- testPortOutOfRange, opt=\"%s\" ".formatted(opt)); - simpleserver(JAVA, "-m", "jdk.httpserver", opt, "65536") // range 0 to 65535 + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", opt, "65536") // range 0 to 65535 .shouldNotHaveExitValue(0) .shouldContain("Error: server config failed: " + "port out of range:65536"); } @@ -172,7 +173,7 @@ public void testRootNotAbsolute(String opt) throws Throwable { out.println("\n--- testRootNotAbsolute, opt=\"%s\" ".formatted(opt)); var root = Path.of("."); assertFalse(root.isAbsolute()); - simpleserver(JAVA, "-m", "jdk.httpserver", opt, root.toString()) + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", opt, root.toString()) .shouldNotHaveExitValue(0) .shouldContain("Error: server config failed: " + "Path is not absolute:"); } @@ -182,7 +183,7 @@ public void testRootNotADirectory(String opt) throws Throwable { out.println("\n--- testRootNotADirectory, opt=\"%s\" ".formatted(opt)); var file = TEST_FILE.toString(); assertFalse(Files.isDirectory(TEST_FILE)); - simpleserver(JAVA, "-m", "jdk.httpserver", opt, file) + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", opt, file) .shouldNotHaveExitValue(0) .shouldContain("Error: server config failed: " + "Path is not a directory: " + file); } @@ -192,7 +193,7 @@ public void testRootDoesNotExist(String opt) throws Throwable { out.println("\n--- testRootDoesNotExist, opt=\"%s\" ".formatted(opt)); Path root = TEST_DIR.resolve("not/existent/dir"); assertFalse(Files.exists(root)); - simpleserver(JAVA, "-m", "jdk.httpserver", opt, root.toString()) + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", opt, root.toString()) .shouldNotHaveExitValue(0) .shouldContain("Error: server config failed: " + "Path does not exist: " + root.toString()); } @@ -209,7 +210,7 @@ public void testRootNotReadable(String opt) throws Throwable { try { root.toFile().setReadable(false, false); assertFalse(Files.isReadable(root)); - simpleserver(JAVA, "-m", "jdk.httpserver", opt, root.toString()) + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", opt, root.toString()) .shouldNotHaveExitValue(0) .shouldContain("Error: server config failed: " + "Path is not readable: " + root.toString()); } finally { diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePortNotSpecifiedTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePortNotSpecifiedTest.java index ba414a9d0c1ac..61a872a86554a 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePortNotSpecifiedTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePortNotSpecifiedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,7 @@ public class CommandLinePortNotSpecifiedTest { static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); + static final String LOCALE_OPT = "-Duser.language=en -Duser.country=US"; static final String JAVA = getJava(JAVA_HOME); static final Path CWD = Path.of(".").toAbsolutePath().normalize(); static final Path TEST_DIR = CWD.resolve("CommandLinePortNotSpecifiedTest"); @@ -84,7 +85,7 @@ static int normalExitCode() { @Test public void testPortNotSpecified() throws Throwable { out.println("\n--- testPortNotSpecified"); - simpleserver(JAVA, "-m", "jdk.httpserver") + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver") .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java index 8cf1f8daf943d..de5d6b54334b8 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,6 +50,7 @@ public class CommandLinePositiveTest { static final String JAVA_VERSION = System.getProperty("java.version"); static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); + static final String LOCALE_OPT = "-Duser.language=en -Duser.country=US"; static final String JAVA = getJava(JAVA_HOME); static final Path CWD = Path.of(".").toAbsolutePath().normalize(); static final Path TEST_DIR = CWD.resolve("CommandLinePositiveTest"); @@ -84,7 +85,7 @@ static int normalExitCode() { @Test(dataProvider = "directoryOptions") public void testDirectory(String opt) throws Throwable { out.println("\n--- testDirectory, opt=\"%s\" ".formatted(opt)); - simpleserver(JAVA, "-m", "jdk.httpserver", "-p", "0", opt, TEST_DIR_STR) + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", "-p", "0", opt, TEST_DIR_STR) .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") @@ -97,7 +98,7 @@ public void testDirectory(String opt) throws Throwable { @Test(dataProvider = "portOptions") public void testPort(String opt) throws Throwable { out.println("\n--- testPort, opt=\"%s\" ".formatted(opt)); - simpleserver(JAVA, "-m", "jdk.httpserver", opt, "0") + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", opt, "0") .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") @@ -128,7 +129,7 @@ public void testHelp(String opt) throws Throwable { out.println("\n--- testHelp, opt=\"%s\" ".formatted(opt)); simpleserver(WaitForLine.HELP_STARTUP_LINE, false, // do not explicitly destroy the process - JAVA, "-m", "jdk.httpserver", opt) + JAVA, LOCALE_OPT, "-m", "jdk.httpserver", opt) .shouldHaveExitValue(0) .shouldContain(USAGE_TEXT) .shouldContain(OPTIONS_TEXT); @@ -142,7 +143,7 @@ public void testVersion(String opt) throws Throwable { out.println("\n--- testVersion, opt=\"%s\" ".formatted(opt)); simpleserver(WaitForLine.VERSION_STARTUP_LINE, false, // do not explicitly destroy the process - JAVA, "-m", "jdk.httpserver", opt) + JAVA, LOCALE_OPT, "-m", "jdk.httpserver", opt) .shouldHaveExitValue(0); } @@ -152,12 +153,12 @@ public void testVersion(String opt) throws Throwable { @Test(dataProvider = "bindOptions") public void testBindAllInterfaces(String opt) throws Throwable { out.println("\n--- testBindAllInterfaces, opt=\"%s\" ".formatted(opt)); - simpleserver(JAVA, "-m", "jdk.httpserver", "-p", "0", opt, "0.0.0.0") + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", "-p", "0", opt, "0.0.0.0") .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on 0.0.0.0 (all interfaces) port") .shouldContain("URL http://" + InetAddress.getLocalHost().getHostAddress()); if (IPSupport.hasIPv6()) { - simpleserver(JAVA, "-m", "jdk.httpserver", opt, "::0") + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", opt, "::0") .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on 0.0.0.0 (all interfaces) port") .shouldContain("URL http://" + InetAddress.getLocalHost().getHostAddress()); @@ -167,7 +168,7 @@ public void testBindAllInterfaces(String opt) throws Throwable { @Test(dataProvider = "bindOptions") public void testLastOneWinsBindAddress(String opt) throws Throwable { out.println("\n--- testLastOneWinsBindAddress, opt=\"%s\" ".formatted(opt)); - simpleserver(JAVA, "-m", "jdk.httpserver", "-p", "0", opt, "123.4.5.6", opt, LOOPBACK_ADDR) + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", "-p", "0", opt, "123.4.5.6", opt, LOOPBACK_ADDR) .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") .shouldContain("URL http://" + LOOPBACK_ADDR); @@ -177,7 +178,7 @@ public void testLastOneWinsBindAddress(String opt) throws Throwable { @Test(dataProvider = "directoryOptions") public void testLastOneWinsDirectory(String opt) throws Throwable { out.println("\n--- testLastOneWinsDirectory, opt=\"%s\" ".formatted(opt)); - simpleserver(JAVA, "-m", "jdk.httpserver", "-p", "0", opt, TEST_DIR_STR, opt, TEST_DIR_STR) + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", "-p", "0", opt, TEST_DIR_STR, opt, TEST_DIR_STR) .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") @@ -190,7 +191,7 @@ public void testLastOneWinsDirectory(String opt) throws Throwable { @Test(dataProvider = "outputOptions") public void testLastOneWinsOutput(String opt) throws Throwable { out.println("\n--- testLastOneWinsOutput, opt=\"%s\" ".formatted(opt)); - simpleserver(JAVA, "-m", "jdk.httpserver", "-p", "0", opt, "none", opt, "verbose") + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", "-p", "0", opt, "none", opt, "verbose") .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") @@ -200,7 +201,7 @@ public void testLastOneWinsOutput(String opt) throws Throwable { @Test(dataProvider = "portOptions") public void testLastOneWinsPort(String opt) throws Throwable { out.println("\n--- testLastOneWinsPort, opt=\"%s\" ".formatted(opt)); - simpleserver(JAVA, "-m", "jdk.httpserver", opt, "-999", opt, "0") + simpleserver(JAVA, LOCALE_OPT, "-m", "jdk.httpserver", opt, "-999", opt, "0") .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLineNegativeTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLineNegativeTest.java index 77671d1e82df6..9c7a89696e2ed 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLineNegativeTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLineNegativeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,6 +49,7 @@ public class CommandLineNegativeTest { static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); static final String JWEBSERVER = getJwebserver(JAVA_HOME); + static final String LOCALE_OPT = "-J-Duser.language=en -J-Duser.country=US"; static final Path CWD = Path.of(".").toAbsolutePath().normalize(); static final Path TEST_DIR = CWD.resolve("CommandLineNegativeTest"); static final Path TEST_FILE = TEST_DIR.resolve("file.txt"); @@ -74,7 +75,7 @@ public Object[][] unknownOption() { @Test(dataProvider = "unknownOption") public void testBadOption(String opt) throws Throwable { out.println("\n--- testUnknownOption, opt=\"%s\" ".formatted(opt)); - simpleserver(JWEBSERVER, opt) + simpleserver(JWEBSERVER, LOCALE_OPT, opt) .shouldNotHaveExitValue(0) .shouldContain("Error: unknown option: " + opt); } @@ -97,7 +98,7 @@ public Object[][] tooManyOptionArgs() { @Test(dataProvider = "tooManyOptionArgs") public void testTooManyOptionArgs(String opt, String arg) throws Throwable { out.println("\n--- testTooManyOptionArgs, opt=\"%s\" ".formatted(opt)); - simpleserver(JWEBSERVER, opt, arg, arg) + simpleserver(JWEBSERVER, LOCALE_OPT, opt, arg, arg) .shouldNotHaveExitValue(0) .shouldContain("Error: unknown option: " + arg); } @@ -124,7 +125,7 @@ public Object[][] noArg() { @Test(dataProvider = "noArg") public void testNoArg(String opt, String msg) throws Throwable { out.println("\n--- testNoArg, opt=\"%s\" ".formatted(opt)); - simpleserver(JWEBSERVER, opt) + simpleserver(JWEBSERVER, LOCALE_OPT, opt) .shouldNotHaveExitValue(0) .shouldContain("Error: no value given for " + opt) .shouldContain(msg); @@ -148,7 +149,7 @@ public Object[][] invalidValue() { @Test(dataProvider = "invalidValue") public void testInvalidValue(String opt, String val) throws Throwable { out.println("\n--- testInvalidValue, opt=\"%s\" ".formatted(opt)); - simpleserver(JWEBSERVER, opt, val) + simpleserver(JWEBSERVER, LOCALE_OPT, opt, val) .shouldNotHaveExitValue(0) .shouldContain("Error: invalid value given for " + opt + ": " + val); } @@ -159,7 +160,7 @@ public void testInvalidValue(String opt, String val) throws Throwable { @Test(dataProvider = "portOptions") public void testPortOutOfRange(String opt) throws Throwable { out.println("\n--- testPortOutOfRange, opt=\"%s\" ".formatted(opt)); - simpleserver(JWEBSERVER, opt, "65536") // range 0 to 65535 + simpleserver(JWEBSERVER, LOCALE_OPT, opt, "65536") // range 0 to 65535 .shouldNotHaveExitValue(0) .shouldContain("Error: server config failed: " + "port out of range:65536"); } @@ -172,7 +173,7 @@ public void testRootNotAbsolute(String opt) throws Throwable { out.println("\n--- testRootNotAbsolute, opt=\"%s\" ".formatted(opt)); var root = Path.of("."); assertFalse(root.isAbsolute()); - simpleserver(JWEBSERVER, opt, root.toString()) + simpleserver(JWEBSERVER, LOCALE_OPT, opt, root.toString()) .shouldNotHaveExitValue(0) .shouldContain("Error: server config failed: " + "Path is not absolute:"); } @@ -182,7 +183,7 @@ public void testRootNotADirectory(String opt) throws Throwable { out.println("\n--- testRootNotADirectory, opt=\"%s\" ".formatted(opt)); var file = TEST_FILE.toString(); assertFalse(Files.isDirectory(TEST_FILE)); - simpleserver(JWEBSERVER, opt, file) + simpleserver(JWEBSERVER, LOCALE_OPT, opt, file) .shouldNotHaveExitValue(0) .shouldContain("Error: server config failed: " + "Path is not a directory: " + file); } @@ -192,7 +193,7 @@ public void testRootDoesNotExist(String opt) throws Throwable { out.println("\n--- testRootDoesNotExist, opt=\"%s\" ".formatted(opt)); Path root = TEST_DIR.resolve("not/existent/dir"); assertFalse(Files.exists(root)); - simpleserver(JWEBSERVER, opt, root.toString()) + simpleserver(JWEBSERVER, LOCALE_OPT, opt, root.toString()) .shouldNotHaveExitValue(0) .shouldContain("Error: server config failed: " + "Path does not exist: " + root.toString()); } @@ -209,7 +210,7 @@ public void testRootNotReadable(String opt) throws Throwable { try { root.toFile().setReadable(false, false); assertFalse(Files.isReadable(root)); - simpleserver(JWEBSERVER, opt, root.toString()) + simpleserver(JWEBSERVER, LOCALE_OPT, opt, root.toString()) .shouldNotHaveExitValue(0) .shouldContain("Error: server config failed: " + "Path is not readable: " + root.toString()); } finally { diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePortNotSpecifiedTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePortNotSpecifiedTest.java index 4d850442b25e4..cd2ccbeded425 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePortNotSpecifiedTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePortNotSpecifiedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,7 @@ public class CommandLinePortNotSpecifiedTest { static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); + static final String LOCALE_OPT = "-J-Duser.language=en -J-Duser.country=US"; static final String JWEBSERVER = getJwebserver(JAVA_HOME); static final Path CWD = Path.of(".").toAbsolutePath().normalize(); static final Path TEST_DIR = CWD.resolve("CommandLinePortNotSpecifiedTest"); @@ -84,7 +85,7 @@ static int normalExitCode() { @Test public void testPortNotSpecified() throws Throwable { out.println("\n--- testPortNotSpecified"); - simpleserver(JWEBSERVER) + simpleserver(JWEBSERVER, LOCALE_OPT) .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePositiveTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePositiveTest.java index 88a843bc4ac4c..fc05c44377c3e 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePositiveTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePositiveTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,6 +50,7 @@ public class CommandLinePositiveTest { static final String JAVA_VERSION = System.getProperty("java.version"); static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); + static final String LOCALE_OPT = "-J-Duser.language=en -J-Duser.country=US"; static final String JWEBSERVER = getJwebserver(JAVA_HOME); static final Path CWD = Path.of(".").toAbsolutePath().normalize(); static final Path TEST_DIR = CWD.resolve("CommandLinePositiveTest"); @@ -84,7 +85,7 @@ static int normalExitCode() { @Test(dataProvider = "directoryOptions") public void testDirectory(String opt) throws Throwable { out.println("\n--- testDirectory, opt=\"%s\" ".formatted(opt)); - simpleserver(JWEBSERVER, "-p", "0", opt, TEST_DIR_STR) + simpleserver(JWEBSERVER, LOCALE_OPT, "-p", "0", opt, TEST_DIR_STR) .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") @@ -97,7 +98,7 @@ public void testDirectory(String opt) throws Throwable { @Test(dataProvider = "portOptions") public void testPort(String opt) throws Throwable { out.println("\n--- testPort, opt=\"%s\" ".formatted(opt)); - simpleserver(JWEBSERVER, opt, "0") + simpleserver(JWEBSERVER, LOCALE_OPT, opt, "0") .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") @@ -128,7 +129,7 @@ public void testHelp(String opt) throws Throwable { out.println("\n--- testHelp, opt=\"%s\" ".formatted(opt)); simpleserver(WaitForLine.HELP_STARTUP_LINE, false, // do not explicitly destroy the process - JWEBSERVER, opt) + JWEBSERVER, LOCALE_OPT, opt) .shouldHaveExitValue(0) .shouldContain(USAGE_TEXT) .shouldContain(OPTIONS_TEXT); @@ -142,7 +143,7 @@ public void testVersion(String opt) throws Throwable { out.println("\n--- testVersion, opt=\"%s\" ".formatted(opt)); simpleserver(WaitForLine.VERSION_STARTUP_LINE, false, // do not explicitly destroy the process - JWEBSERVER, opt) + JWEBSERVER, LOCALE_OPT, opt) .shouldHaveExitValue(0); } @@ -152,12 +153,12 @@ public void testVersion(String opt) throws Throwable { @Test(dataProvider = "bindOptions") public void testBindAllInterfaces(String opt) throws Throwable { out.println("\n--- testBindAllInterfaces, opt=\"%s\" ".formatted(opt)); - simpleserver(JWEBSERVER, "-p", "0", opt, "0.0.0.0") + simpleserver(JWEBSERVER, LOCALE_OPT, "-p", "0", opt, "0.0.0.0") .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on 0.0.0.0 (all interfaces) port") .shouldContain("URL http://" + InetAddress.getLocalHost().getHostAddress()); if (IPSupport.hasIPv6()) { - simpleserver(JWEBSERVER, opt, "::0") + simpleserver(JWEBSERVER, LOCALE_OPT, opt, "::0") .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on 0.0.0.0 (all interfaces) port") .shouldContain("URL http://" + InetAddress.getLocalHost().getHostAddress()); @@ -167,7 +168,7 @@ public void testBindAllInterfaces(String opt) throws Throwable { @Test(dataProvider = "bindOptions") public void testLastOneWinsBindAddress(String opt) throws Throwable { out.println("\n--- testLastOneWinsBindAddress, opt=\"%s\" ".formatted(opt)); - simpleserver(JWEBSERVER, "-p", "0", opt, "123.4.5.6", opt, LOOPBACK_ADDR) + simpleserver(JWEBSERVER, LOCALE_OPT, "-p", "0", opt, "123.4.5.6", opt, LOOPBACK_ADDR) .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") .shouldContain("URL http://" + LOOPBACK_ADDR); @@ -177,7 +178,7 @@ public void testLastOneWinsBindAddress(String opt) throws Throwable { @Test(dataProvider = "directoryOptions") public void testLastOneWinsDirectory(String opt) throws Throwable { out.println("\n--- testLastOneWinsDirectory, opt=\"%s\" ".formatted(opt)); - simpleserver(JWEBSERVER, "-p", "0", opt, TEST_DIR_STR, opt, TEST_DIR_STR) + simpleserver(JWEBSERVER, LOCALE_OPT, "-p", "0", opt, TEST_DIR_STR, opt, TEST_DIR_STR) .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") @@ -190,7 +191,7 @@ public void testLastOneWinsDirectory(String opt) throws Throwable { @Test(dataProvider = "outputOptions") public void testLastOneWinsOutput(String opt) throws Throwable { out.println("\n--- testLastOneWinsOutput, opt=\"%s\" ".formatted(opt)); - simpleserver(JWEBSERVER, "-p", "0", opt, "none", opt, "verbose") + simpleserver(JWEBSERVER, LOCALE_OPT, "-p", "0", opt, "none", opt, "verbose") .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") @@ -200,7 +201,7 @@ public void testLastOneWinsOutput(String opt) throws Throwable { @Test(dataProvider = "portOptions") public void testLastOneWinsPort(String opt) throws Throwable { out.println("\n--- testLastOneWinsPort, opt=\"%s\" ".formatted(opt)); - simpleserver(JWEBSERVER, opt, "-999", opt, "0") + simpleserver(JWEBSERVER, LOCALE_OPT, opt, "-999", opt, "0") .shouldHaveExitValue(NORMAL_EXIT_CODE) .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/IPv6BoundHost.java b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/IPv6BoundHost.java index 04c9c3c6fc63c..1aa32505ae4d3 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/IPv6BoundHost.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/IPv6BoundHost.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,7 @@ public class IPv6BoundHost { private static final Path JDK_BIN_DIR = Path.of(System.getProperty("java.home")).resolve("bin"); private static final Path JWEBSERVER_BINARY = OperatingSystem.isWindows() ? JDK_BIN_DIR.resolve("jwebserver.exe") : JDK_BIN_DIR.resolve("jwebserver"); + private static final String LOCALE_OPT = "-J-Duser.language=en -J-Duser.country=US"; public static void main(final String[] args) throws Exception { IPSupport.printPlatformSupport(System.err); // for debug purposes @@ -68,6 +69,7 @@ private static String launchJwebserverAndExit(final List args) throws Ex final StringBuilder sb = new StringBuilder(); // stdout & stderr final List cmd = new ArrayList<>(); cmd.add(JWEBSERVER_BINARY.toString()); + cmd.add(LOCALE_OPT); cmd.addAll(args); // start the process and await the waitForLine before returning final Process p = ProcessTools.startProcess("8332020-test", new ProcessBuilder(cmd), diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/MaxRequestTimeTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/MaxRequestTimeTest.java index e530c9805657c..c972f87dc1809 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/MaxRequestTimeTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/MaxRequestTimeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,6 +71,7 @@ */ public class MaxRequestTimeTest { static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); + static final String LOCALE_OPT = "-J-Duser.language=en -J-Duser.country=US"; static final String JWEBSERVER = getJwebserver(JAVA_HOME); static final Path CWD = Path.of(".").toAbsolutePath().normalize(); static final Path TEST_DIR = CWD.resolve("MaxRequestTimeTest"); @@ -174,7 +175,7 @@ static void parseAndSetPort(String line) { static Process startProcess(String name, StringBuffer sb) throws Throwable { // starts the process, parses the port and awaits startup line before sending requests return ProcessTools.startProcess(name, - new ProcessBuilder(JWEBSERVER, "-p", "0").directory(TEST_DIR.toFile()), + new ProcessBuilder(JWEBSERVER, LOCALE_OPT, "-p", "0").directory(TEST_DIR.toFile()), line -> { if (line.startsWith(REGULAR_STARTUP_LINE_STRING_2)) { parseAndSetPort(line); } sb.append(line + "\n"); From a1d566ce4b0315591ece489347c5d1c253f06be9 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Wed, 9 Apr 2025 09:28:36 +0000 Subject: [PATCH 0485/1101] 8348853: Fold layout helper check for objects implementing non-array interfaces Reviewed-by: thartmann, roland --- src/hotspot/share/ci/ciMetadata.hpp | 2 +- src/hotspot/share/opto/library_call.cpp | 7 +------ src/hotspot/share/opto/memnode.cpp | 6 ++---- src/hotspot/share/opto/type.cpp | 19 +++++++++++++++++++ src/hotspot/share/opto/type.hpp | 4 ++++ 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/ci/ciMetadata.hpp b/src/hotspot/share/ci/ciMetadata.hpp index 62b67d65483b5..2e232c591887d 100644 --- a/src/hotspot/share/ci/ciMetadata.hpp +++ b/src/hotspot/share/ci/ciMetadata.hpp @@ -103,7 +103,7 @@ class ciMetadata: public ciBaseObject { Metadata* constant_encoding() { return _metadata; } - bool equals(ciMetadata* obj) const { return (this == obj); } + bool equals(const ciMetadata* obj) const { return (this == obj); } uint hash() { return ident() * 31; } // ??? diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 708225ba3aa9f..783631bf08d89 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4305,12 +4305,7 @@ Node* LibraryCallKit::generate_array_guard_common(Node* kls, RegionNode* region, if (obj != nullptr && is_array_ctrl != nullptr && is_array_ctrl != top()) { // Keep track of the fact that 'obj' is an array to prevent // array specific accesses from floating above the guard. - Node* cast = _gvn.transform(new CastPPNode(is_array_ctrl, *obj, TypeAryPtr::BOTTOM)); - // Check for top because in rare cases, the type system can determine that - // the object can't be an array but the layout helper check is not folded. - if (!cast->is_top()) { - *obj = cast; - } + *obj = _gvn.transform(new CastPPNode(is_array_ctrl, *obj, TypeAryPtr::BOTTOM)); } return ctrl; } diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index e596db8e0c7ce..9cd3dcfee41df 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -2218,10 +2218,8 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { // This will help short-circuit some reflective code. if (tkls->offset() == in_bytes(Klass::layout_helper_offset()) && tkls->isa_instklassptr() && // not directly typed as an array - !tkls->is_instklassptr()->instance_klass()->is_java_lang_Object() // not the supertype of all T[] and specifically not Serializable & Cloneable - ) { - // Note: When interfaces are reliable, we can narrow the interface - // test to (klass != Serializable && klass != Cloneable). + !tkls->is_instklassptr()->might_be_an_array() // not the supertype of all T[] (java.lang.Object) or has an interface that is not Serializable or Cloneable + ) { assert(Opcode() == Op_LoadI, "must load an int from _layout_helper"); jint min_size = Klass::instance_layout_helper(oopDesc::header_size(), false); // The key property of this type is that it folds up tests diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 474145f2d0620..4556555aceade 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -3685,6 +3685,12 @@ bool TypeInterfaces::singleton(void) const { return Type::singleton(); } +bool TypeInterfaces::has_non_array_interface() const { + assert(TypeAryPtr::_array_interfaces != nullptr, "How come Type::Initialize_shared wasn't called yet?"); + + return !TypeAryPtr::_array_interfaces->contains(this); +} + //------------------------------TypeOopPtr------------------------------------- TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, bool xk, ciObject* o, int offset, int instance_id, const TypePtr* speculative, int inline_depth) @@ -6197,6 +6203,19 @@ template bool TypePtr::is_java_subtype_of_helper_for_instan return this_one->klass()->is_subtype_of(other->klass()) && this_one->_interfaces->contains(other->_interfaces); } +bool TypeInstKlassPtr::might_be_an_array() const { + if (!instance_klass()->is_java_lang_Object()) { + // TypeInstKlassPtr can be an array only if it is java.lang.Object: the only supertype of array types. + return false; + } + if (interfaces()->has_non_array_interface()) { + // Arrays only implement Cloneable and Serializable. If we see any other interface, [this] cannot be an array. + return false; + } + // Cannot prove it's not an array. + return true; +} + bool TypeInstKlassPtr::is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const { return TypePtr::is_java_subtype_of_helper_for_instance(this, other, this_exact, other_exact); } diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index fe460cfb1d43d..9c40e1ab3cdd7 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -943,6 +943,7 @@ class TypeInterfaces : public Type { const Type* xmeet(const Type* t) const; bool singleton(void) const; + bool has_non_array_interface() const; }; //------------------------------TypePtr---------------------------------------- @@ -1420,6 +1421,7 @@ class TypeInstPtr : public TypeOopPtr { class TypeAryPtr : public TypeOopPtr { friend class Type; friend class TypePtr; + friend class TypeInterfaces; TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, bool is_autobox_cache, @@ -1692,6 +1694,8 @@ class TypeInstKlassPtr : public TypeKlassPtr { return klass()->as_instance_klass(); } + bool might_be_an_array() const; + bool is_same_java_type_as_helper(const TypeKlassPtr* other) const; bool is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const; bool maybe_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const; From cd9fa3f7aa0324c575943deebb41f4f7ff4f73d3 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Wed, 9 Apr 2025 09:47:03 +0000 Subject: [PATCH 0486/1101] 8353439: Shell grouping of -XX:OnError= commands is surprising Reviewed-by: dholmes, stuefe --- src/hotspot/share/utilities/vmError.cpp | 10 ++++--- .../runtime/ErrorHandling/TestOnError.java | 29 ++++++++++++++++++- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index ef04d69ee995c..8131df80c0e0a 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -136,7 +136,9 @@ static const char* env_list[] = { nullptr // End marker. }; -// A simple parser for -XX:OnError, usage: +// A simple parser for lists of commands such as -XX:OnError and -XX:OnOutOfMemoryError +// Command list (ptr) is expected to be a sequence of commands delineated by semicolons and/or newlines. +// Usage: // ptr = OnError; // while ((cmd = next_OnError_command(buffer, sizeof(buffer), &ptr) != nullptr) // ... ... @@ -145,13 +147,13 @@ static char* next_OnError_command(char* buf, int buflen, const char** ptr) { const char* cmd = *ptr; - // skip leading blanks or ';' - while (*cmd == ' ' || *cmd == ';') cmd++; + // skip leading blanks, ';' or newlines + while (*cmd == ' ' || *cmd == ';' || *cmd == '\n') cmd++; if (*cmd == '\0') return nullptr; const char * cmdend = cmd; - while (*cmdend != '\0' && *cmdend != ';') cmdend++; + while (*cmdend != '\0' && *cmdend != ';' && *cmdend != '\n') cmdend++; Arguments::copy_expand_pid(cmd, cmdend - cmd, buf, buflen); diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/TestOnError.java b/test/hotspot/jtreg/runtime/ErrorHandling/TestOnError.java index 53410c5379c43..41f2c5eeb42f0 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/TestOnError.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/TestOnError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,10 @@ public class TestOnError { public static void main(String[] args) throws Exception { String msg = "Test Succeeded"; + String msg1 = "OnError Test Message1"; + String msg2 = "OnError Test Message2"; + // Basic OnError test: ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:-CreateCoredumpOnCrash", "-XX:ErrorHandlerTest=14", // trigger potential SEGV @@ -59,6 +62,30 @@ public static void main(String[] args) throws Exception { both get written to stdout. */ output.stdoutShouldMatch("^" + msg); // match start of line only + + // Test multiple OnError arguments: + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:-CreateCoredumpOnCrash", + "-XX:ErrorHandlerTest=14", + "-XX:OnError=echo " + msg1, + "-XX:OnError=echo " + msg2, + TestOnError.class.getName()); + + output = new OutputAnalyzer(pb.start()); + output.stdoutShouldMatch("^" + msg1); + output.stdoutShouldMatch("^" + msg2); + + // Test one argument with multiple commands using ; separator: + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:-CreateCoredumpOnCrash", + "-XX:ErrorHandlerTest=14", + "-XX:OnError=echo " + msg1 + ";echo " + msg2, + TestOnError.class.getName()); + + output = new OutputAnalyzer(pb.start()); + output.stdoutShouldMatch("^" + msg1); + output.stdoutShouldMatch("^" + msg2); + System.out.println("PASSED"); } } From 7aeaa3c21c1420191fe8ff59e4cf99eae830754d Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Wed, 9 Apr 2025 10:40:03 +0000 Subject: [PATCH 0487/1101] 8187520: Add --disable-java-warnings-as-errors configure option Reviewed-by: shade, erikj --- make/Docs.gmk | 8 +++----- make/autoconf/configure.ac | 1 + make/autoconf/jdk-options.m4 | 12 ++++++++++++ make/autoconf/spec.gmk.template | 1 + make/common/JavaCompilation.gmk | 9 +++++---- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/make/Docs.gmk b/make/Docs.gmk index 0948f8ff76cf1..5f10d623211ac 100644 --- a/make/Docs.gmk +++ b/make/Docs.gmk @@ -92,10 +92,6 @@ REFERENCE_TAGS := $(JAVADOC_TAGS) JAVADOC_DISABLED_DOCLINT_WARNINGS := missing JAVADOC_DISABLED_DOCLINT_PACKAGES := org.w3c.* javax.smartcardio -# Allow overriding on the command line -# (intentionally sharing name with the javac option) -JAVA_WARNINGS_ARE_ERRORS ?= -Werror - # The initial set of options for javadoc JAVADOC_OPTIONS := -use -keywords -notimestamp \ -serialwarn -encoding ISO-8859-1 -docencoding UTF-8 -breakiterator \ @@ -322,7 +318,9 @@ define SetupApiDocsGenerationBody # Ignore the doclint warnings in certain packages $1_OPTIONS += -Xdoclint/package:$$(call CommaList, $$(addprefix -, \ $$(JAVADOC_DISABLED_DOCLINT_PACKAGES))) - $1_OPTIONS += $$(JAVA_WARNINGS_ARE_ERRORS) + ifeq ($$(JAVA_WARNINGS_AS_ERRORS), true) + $1_OPTIONS += -Werror + endif $1_DOC_TITLE := $$($1_LONG_NAME)
Version $$(VERSION_SPECIFICATION) API \ Specification diff --git a/make/autoconf/configure.ac b/make/autoconf/configure.ac index fffe17daad875..e05b5ae3b90f0 100644 --- a/make/autoconf/configure.ac +++ b/make/autoconf/configure.ac @@ -261,6 +261,7 @@ JDKOPT_ENABLE_DISABLE_CDS_ARCHIVE_COH JDKOPT_ENABLE_DISABLE_COMPATIBLE_CDS_ALIGNMENT JDKOPT_SETUP_MACOSX_SIGNING JDKOPT_SETUP_SIGNING_HOOK +JDKOPT_SETUP_JAVA_WARNINGS ################################################################################ # diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index 72e731e7ffc0c..79e44dd4ad17e 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -988,6 +988,18 @@ AC_DEFUN([JDKOPT_SETUP_SIGNING_HOOK], AC_SUBST(SIGNING_HOOK) ]) +################################################################################ +# +# Setup how javac should handle warnings. +# +AC_DEFUN([JDKOPT_SETUP_JAVA_WARNINGS], +[ + UTIL_ARG_ENABLE(NAME: java-warnings-as-errors, DEFAULT: true, + RESULT: JAVA_WARNINGS_AS_ERRORS, + DESC: [consider java warnings to be an error]) + AC_SUBST(JAVA_WARNINGS_AS_ERRORS) +]) + ################################################################################ # # fallback linker diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template index 17a913a2d90e1..907a60290ecf9 100644 --- a/make/autoconf/spec.gmk.template +++ b/make/autoconf/spec.gmk.template @@ -517,6 +517,7 @@ DISABLED_WARNINGS_CXX := @DISABLED_WARNINGS_CXX@ # A global flag (true or false) determining if native warnings are considered errors. WARNINGS_AS_ERRORS := @WARNINGS_AS_ERRORS@ +JAVA_WARNINGS_AS_ERRORS := @JAVA_WARNINGS_AS_ERRORS@ CFLAGS_CCACHE := @CFLAGS_CCACHE@ ADLC_LANGSTD_CXXFLAGS := @ADLC_LANGSTD_CXXFLAGS@ diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk index f48aefcd51700..70b3557baea2c 100644 --- a/make/common/JavaCompilation.gmk +++ b/make/common/JavaCompilation.gmk @@ -264,15 +264,16 @@ define SetupJavaCompilationBody $$(error Invalid value for COMPILER in SetupJavaCompilation for $1: '$$($1_COMPILER)') endif - # Allow overriding on the command line - JAVA_WARNINGS_ARE_ERRORS ?= -Werror - # Tell javac to do exactly as told and no more PARANOIA_FLAGS := -implicit:none -Xprefer:source -XDignore.symbol.file=true -encoding ascii - $1_FLAGS += -g -Xlint:all $$($1_TARGET_RELEASE) $$(PARANOIA_FLAGS) $$(JAVA_WARNINGS_ARE_ERRORS) + $1_FLAGS += -g -Xlint:all $$($1_TARGET_RELEASE) $$(PARANOIA_FLAGS) $1_FLAGS += $$($1_JAVAC_FLAGS) + ifeq ($$(JAVA_WARNINGS_AS_ERRORS), true) + $1_FLAGS += -Werror + endif + ifneq ($$($1_DISABLED_WARNINGS), ) $1_FLAGS += -Xlint:$$(call CommaList, $$(addprefix -, $$($1_DISABLED_WARNINGS))) endif From 6c93ad42f38b49ea96155340c4b6bbedfcef2a90 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Wed, 9 Apr 2025 12:36:35 +0000 Subject: [PATCH 0488/1101] 8351927: Change VirtualThread implementation to use use FJP delayed task handling Reviewed-by: vklang --- .../share/classes/java/lang/System.java | 4 - .../classes/java/lang/VirtualThread.java | 104 ++++++++------ .../jdk/internal/access/JavaLangAccess.java | 8 +- .../jdk/internal/vm/JcmdVThreadCommands.java | 15 +- .../dcmd/thread/VThreadCommandsTest.java | 8 +- .../bench/java/lang/VirtualThreadParking.java | 98 +++++++++++++ .../bench/java/lang/VirtualThreadSleep.java | 70 ++++++++++ .../java/util/concurrent/DelayedTasks.java | 130 ++++++++++++++++++ 8 files changed, 364 insertions(+), 73 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/lang/VirtualThreadParking.java create mode 100644 test/micro/org/openjdk/bench/java/lang/VirtualThreadSleep.java create mode 100644 test/micro/org/openjdk/bench/java/util/concurrent/DelayedTasks.java diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 241e479458d02..903f6e34e2ee1 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2290,10 +2290,6 @@ public Executor virtualThreadDefaultScheduler() { return VirtualThread.defaultScheduler(); } - public Stream virtualThreadDelayedTaskSchedulers() { - return VirtualThread.delayedTaskSchedulers(); - } - public StackWalker newStackWalkerInstance(Set options, ContinuationScope contScope, Continuation continuation) { diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index dc8c6a852d047..964a5360ad689 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ */ package java.lang; -import java.util.Arrays; import java.util.Locale; import java.util.Objects; import java.util.concurrent.CountDownLatch; @@ -38,7 +37,6 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import java.util.stream.Stream; import jdk.internal.event.VirtualThreadEndEvent; import jdk.internal.event.VirtualThreadStartEvent; import jdk.internal.event.VirtualThreadSubmitFailedEvent; @@ -66,7 +64,6 @@ final class VirtualThread extends BaseVirtualThread { private static final Unsafe U = Unsafe.getUnsafe(); private static final ContinuationScope VTHREAD_SCOPE = new ContinuationScope("VirtualThreads"); private static final ForkJoinPool DEFAULT_SCHEDULER = createDefaultScheduler(); - private static final ScheduledExecutorService[] DELAYED_TASK_SCHEDULERS = createDelayedTaskSchedulers(); private static final long STATE = U.objectFieldOffset(VirtualThread.class, "state"); private static final long PARK_PERMIT = U.objectFieldOffset(VirtualThread.class, "parkPermit"); @@ -193,13 +190,6 @@ static Executor defaultScheduler() { return DEFAULT_SCHEDULER; } - /** - * Returns a stream of the delayed task schedulers used to support timed operations. - */ - static Stream delayedTaskSchedulers() { - return Arrays.stream(DELAYED_TASK_SCHEDULERS); - } - /** * Returns the continuation scope used for virtual threads. */ @@ -567,8 +557,9 @@ private void afterYield() { setState(newState = PARKED); } else { // schedule unpark + long timeout = this.timeout; assert timeout > 0; - timeoutTask = schedule(this::unpark, timeout, NANOSECONDS); + timeoutTask = schedule(this::parkTimeoutExpired, timeout, NANOSECONDS); setState(newState = TIMED_PARKED); } @@ -618,6 +609,7 @@ private void afterYield() { // the timeout task to coordinate access to the sequence number and to // ensure the timeout task doesn't execute until the thread has got to // the TIMED_WAIT state. + long timeout = this.timeout; assert timeout > 0; synchronized (timedWaitLock()) { byte seqNo = ++timedWaitSeqNo; @@ -890,7 +882,19 @@ private void unblock() { } /** - * Invoked by timer thread when wait timeout for virtual thread has expired. + * Invoked by FJP worker thread or STPE thread when park timeout expires. + */ + private void parkTimeoutExpired() { + assert !VirtualThread.currentThread().isVirtual(); + if (!getAndSetParkPermit(true) + && (state() == TIMED_PARKED) + && compareAndSetState(TIMED_PARKED, UNPARKED)) { + lazySubmitRunContinuation(); + } + } + + /** + * Invoked by FJP worker thread or STPE thread when wait timeout expires. * If the virtual thread is in timed-wait then this method will unblock the thread * and submit its task so that it continues and attempts to reenter the monitor. * This method does nothing if the thread has been woken by notify or interrupt. @@ -913,7 +917,7 @@ private void waitTimeoutExpired(byte seqNo) { } } if (unblocked) { - submitRunContinuation(); + lazySubmitRunContinuation(); return; } // need to retry when thread is suspended in time-wait @@ -1444,40 +1448,54 @@ private static ForkJoinPool createDefaultScheduler() { /** * Schedule a runnable task to run after a delay. */ - private static Future schedule(Runnable command, long delay, TimeUnit unit) { - long tid = Thread.currentThread().threadId(); - int index = (int) tid & (DELAYED_TASK_SCHEDULERS.length - 1); - return DELAYED_TASK_SCHEDULERS[index].schedule(command, delay, unit); + private Future schedule(Runnable command, long delay, TimeUnit unit) { + if (scheduler instanceof ForkJoinPool pool) { + return pool.schedule(command, delay, unit); + } else { + return DelayedTaskSchedulers.schedule(command, delay, unit); + } } /** - * Creates the ScheduledThreadPoolExecutors used to execute delayed tasks. + * Supports scheduling a runnable task to run after a delay. It uses a number + * of ScheduledThreadPoolExecutor instances to reduce contention on the delayed + * work queue used. This class is used when using a custom scheduler. */ - private static ScheduledExecutorService[] createDelayedTaskSchedulers() { - String propName = "jdk.virtualThreadScheduler.timerQueues"; - String propValue = System.getProperty(propName); - int queueCount; - if (propValue != null) { - queueCount = Integer.parseInt(propValue); - if (queueCount != Integer.highestOneBit(queueCount)) { - throw new RuntimeException("Value of " + propName + " must be power of 2"); - } - } else { - int ncpus = Runtime.getRuntime().availableProcessors(); - queueCount = Math.max(Integer.highestOneBit(ncpus / 4), 1); + private static class DelayedTaskSchedulers { + private static final ScheduledExecutorService[] INSTANCE = createDelayedTaskSchedulers(); + + static Future schedule(Runnable command, long delay, TimeUnit unit) { + long tid = Thread.currentThread().threadId(); + int index = (int) tid & (INSTANCE.length - 1); + return INSTANCE[index].schedule(command, delay, unit); } - var schedulers = new ScheduledExecutorService[queueCount]; - for (int i = 0; i < queueCount; i++) { - ScheduledThreadPoolExecutor stpe = (ScheduledThreadPoolExecutor) - Executors.newScheduledThreadPool(1, task -> { - Thread t = InnocuousThread.newThread("VirtualThread-unparker", task); - t.setDaemon(true); - return t; - }); - stpe.setRemoveOnCancelPolicy(true); - schedulers[i] = stpe; + + private static ScheduledExecutorService[] createDelayedTaskSchedulers() { + String propName = "jdk.virtualThreadScheduler.timerQueues"; + String propValue = System.getProperty(propName); + int queueCount; + if (propValue != null) { + queueCount = Integer.parseInt(propValue); + if (queueCount != Integer.highestOneBit(queueCount)) { + throw new RuntimeException("Value of " + propName + " must be power of 2"); + } + } else { + int ncpus = Runtime.getRuntime().availableProcessors(); + queueCount = Math.max(Integer.highestOneBit(ncpus / 4), 1); + } + var schedulers = new ScheduledExecutorService[queueCount]; + for (int i = 0; i < queueCount; i++) { + ScheduledThreadPoolExecutor stpe = (ScheduledThreadPoolExecutor) + Executors.newScheduledThreadPool(1, task -> { + Thread t = InnocuousThread.newThread("VirtualThread-unparker", task); + t.setDaemon(true); + return t; + }); + stpe.setRemoveOnCancelPolicy(true); + schedulers[i] = stpe; + } + return schedulers; } - return schedulers; } /** @@ -1514,4 +1532,4 @@ private static void unblockVirtualThreads() { unblocker.setDaemon(true); unblocker.start(); } -} +} \ No newline at end of file diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index 077683a3bf2a7..8edeb731cee42 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ScheduledExecutorService; import java.util.stream.Stream; import jdk.internal.loader.NativeLibraries; @@ -586,11 +585,6 @@ public interface JavaLangAccess { */ Executor virtualThreadDefaultScheduler(); - /** - * Returns a stream of the delayed task schedulers used for virtual threads. - */ - Stream virtualThreadDelayedTaskSchedulers(); - /** * Creates a new StackWalker */ diff --git a/src/java.base/share/classes/jdk/internal/vm/JcmdVThreadCommands.java b/src/java.base/share/classes/jdk/internal/vm/JcmdVThreadCommands.java index 66ac6c2aca9fc..b97deb942bcf4 100644 --- a/src/java.base/share/classes/jdk/internal/vm/JcmdVThreadCommands.java +++ b/src/java.base/share/classes/jdk/internal/vm/JcmdVThreadCommands.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,19 +50,6 @@ private static byte[] printScheduler() { sb.append(JLA.virtualThreadDefaultScheduler()) .append(System.lineSeparator()); - // break - sb.append(System.lineSeparator()); - - // delayed task schedulers - sb.append("Delayed task schedulers:").append(System.lineSeparator()); - var delayedTaskSchedulers = JLA.virtualThreadDelayedTaskSchedulers().toList(); - IntStream.range(0, delayedTaskSchedulers.size()) - .forEach(i -> sb.append('[') - .append(i) - .append("] ") - .append(delayedTaskSchedulers.get(i)) - .append(System.lineSeparator())); - return sb.toString().getBytes(StandardCharsets.UTF_8); } diff --git a/test/hotspot/jtreg/serviceability/dcmd/thread/VThreadCommandsTest.java b/test/hotspot/jtreg/serviceability/dcmd/thread/VThreadCommandsTest.java index de2b72496124b..3d3ca813540e5 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/thread/VThreadCommandsTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/thread/VThreadCommandsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,13 +59,11 @@ class VThreadCommandsTest { */ @Test void testVThreadScheduler() { - // ensure default scheduler and timeout schedulers are initialized + // ensure default scheduler is initialized Thread.startVirtualThread(() -> { }); jcmd("Thread.vthread_scheduler") - .shouldContain(Objects.toIdentityString(defaultScheduler())) - .shouldContain("Delayed task schedulers:") - .shouldContain("[0] " + ScheduledThreadPoolExecutor.class.getName()); + .shouldContain(Objects.toIdentityString(defaultScheduler())); } /** diff --git a/test/micro/org/openjdk/bench/java/lang/VirtualThreadParking.java b/test/micro/org/openjdk/bench/java/lang/VirtualThreadParking.java new file mode 100644 index 0000000000000..ad6233fd4bd24 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/VirtualThreadParking.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.LockSupport; +import org.openjdk.jmh.annotations.*; + +@BenchmarkMode(Mode.Throughput) +@State(Scope.Benchmark) +@Warmup(iterations = 5, time = 10, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 10, timeUnit = TimeUnit.SECONDS) +@Fork(value = 3) +@OutputTimeUnit(TimeUnit.SECONDS) +public class VirtualThreadParking { + + @Param({"100", "1000", "10000"}) + int threadCount; + + /** + * Starts N threads that time-park, main thread unparks. + */ + @Benchmark + public void timedParkAndUnpark1() throws Exception { + var threads = new Thread[threadCount]; + var unparked = new boolean[threadCount]; + for (int i = 0; i < threadCount; i++) { + threads[i] = Thread.ofVirtual().start(() -> { + LockSupport.parkNanos(Long.MAX_VALUE); + }); + } + int remaining = threadCount; + while (remaining > 0) { + for (int i = 0; i < threadCount; i++) { + if (!unparked[i]) { + Thread t = threads[i]; + if (t.getState() == Thread.State.TIMED_WAITING) { + LockSupport.unpark(t); + unparked[i] = true; + remaining--; + } + } + } + if (remaining > 0) { + Thread.yield(); + } + } + for (Thread t : threads) { + t.join(); + } + } + + /** + * Starts N threads that time-park, start another N threads to unpark. + */ + @Benchmark + public void timedParkAndUnpark2() throws Exception { + var threads = new Thread[threadCount * 2]; + for (int i = 0; i < threadCount; i++) { + threads[i] = Thread.ofVirtual().start(() -> { + LockSupport.parkNanos(Long.MAX_VALUE); + }); + } + for (int i = 0; i < threadCount; i++) { + Thread thread1 = threads[i]; + Thread thread2 = Thread.ofVirtual().start(() -> { + while (thread1.getState() != Thread.State.TIMED_WAITING) { + Thread.yield(); + } + LockSupport.unpark(thread1); + }); + threads[threadCount + i] = thread2; + } + for (Thread t : threads) { + t.join(); + } + } +} \ No newline at end of file diff --git a/test/micro/org/openjdk/bench/java/lang/VirtualThreadSleep.java b/test/micro/org/openjdk/bench/java/lang/VirtualThreadSleep.java new file mode 100644 index 0000000000000..7b7e47f5b59ce --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/VirtualThreadSleep.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang; + +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.*; + +@BenchmarkMode(Mode.Throughput) +@State(Scope.Benchmark) +@Warmup(iterations = 5, time = 10, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 10, timeUnit = TimeUnit.SECONDS) +@Fork(value = 3) +//@OutputTimeUnit(TimeUnit.SECONDS) +public class VirtualThreadSleep { + + @Param({"1000", "10000", "100000"}) + int threadCount; + + @Benchmark + public void sleep10() throws Exception { + var threads = new Thread[threadCount]; + for (int i = 0; i < threadCount; i++) { + threads[i] = Thread.ofVirtual().start(() -> { + try { + Thread.sleep(10); + } catch (InterruptedException e) { } + }); + } + for (Thread t : threads) { + t.join(); + } + } + + @Benchmark + public void sleep10x10() throws Exception { + var threads = new Thread[threadCount]; + for (int i = 0; i < threadCount; i++) { + threads[i] = Thread.ofVirtual().start(() -> { + try { + for (int k = 0; k < 10; k++) { + Thread.sleep(10); + } + } catch (InterruptedException e) { } + }); + } + for (Thread t : threads) { + t.join(); + } + } +} \ No newline at end of file diff --git a/test/micro/org/openjdk/bench/java/util/concurrent/DelayedTasks.java b/test/micro/org/openjdk/bench/java/util/concurrent/DelayedTasks.java new file mode 100644 index 0000000000000..1798459d6e8f5 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/util/concurrent/DelayedTasks.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.util.concurrent; + +import java.util.*; +import java.util.concurrent.*; +import java.util.function.Supplier; +import org.openjdk.jmh.annotations.*; + +/** + * Benchmark to compare delayed task scheduling with ScheduledThreadPoolExcutor and ForkJoinPool. + */ + +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +@Fork(value = 3) +@Warmup(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS) +@State(Scope.Thread) +public class DelayedTasks { + + private Supplier stpeSupplier; + private Supplier fjpSupplier; + + @Setup + public void setup() { + stpeSupplier = () -> { + ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); + ((ScheduledThreadPoolExecutor) executor).setRemoveOnCancelPolicy(true); + return executor; + }; + int nprocs = Runtime.getRuntime().availableProcessors(); + fjpSupplier = () -> new ForkJoinPool(nprocs); + } + + @Param({"100", "1000", "10000"}) + int delayedTasks; + + // delayed tasks cancelled by main thread + private void mainThreadCancels(Supplier supplier) { + try (ScheduledExecutorService ses = supplier.get()) { + var futures = new ScheduledFuture[delayedTasks]; + for (int i = 0; i < delayedTasks; i++) { + futures[i] = ses.schedule(() -> { }, 30L, TimeUnit.MINUTES); + } + for (ScheduledFuture f : futures) { + f.cancel(false); + } + } + } + + // delayed tasks cancelled by virtual threads + private void virtualThreadCancels(Supplier supplier) throws Exception { + try (ScheduledExecutorService ses = supplier.get()) { + var futures = new ScheduledFuture[delayedTasks]; + var threads = new Thread[delayedTasks]; + for (int i = 0; i < delayedTasks; i++) { + ScheduledFuture future = ses.schedule(() -> { }, 30L, TimeUnit.MINUTES); + futures[i] = future; + threads[i] = Thread.ofVirtual().start(() -> future.cancel(false)); + } + for (Thread t : threads) { + t.join(); + } + } + } + + // delayed task executes + private void delayedTaskExecutes(Supplier supplier) throws Exception { + try (ScheduledExecutorService ses = supplier.get()) { + var futures = new ScheduledFuture[delayedTasks]; + for (int i = 0; i < delayedTasks; i++) { + futures[i] = ses.schedule(() -> { }, 10L, TimeUnit.MILLISECONDS); + } + for (ScheduledFuture f : futures) { + f.get(); + } + } + } + + @Benchmark + public void spteMainThreadCancels() { + mainThreadCancels(stpeSupplier); + } + + @Benchmark + public void spteVirtualThreadCancels() throws Exception { + virtualThreadCancels(stpeSupplier); + } + + @Benchmark + public void spteDelayedTaskExecutes() throws Exception { + delayedTaskExecutes(stpeSupplier); + } + + @Benchmark + public void fjpMainThreadCancels() { + mainThreadCancels(fjpSupplier); + } + + @Benchmark + public void fjpVirtualThreadCancels() throws Exception { + virtualThreadCancels(fjpSupplier); + } + + @Benchmark + public void fjpDelayedTaskExecutes() throws Exception { + delayedTaskExecutes(fjpSupplier); + } +} \ No newline at end of file From f9d705b17e5d90f7bc5f9759f692182bb4da3445 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Wed, 9 Apr 2025 12:44:47 +0000 Subject: [PATCH 0489/1101] 8351757: Test java/foreign/TestDeadlock.java#FileChannel_map timed out after passing Reviewed-by: djelinski, rriggs --- test/jdk/java/foreign/TestDeadlock.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/foreign/TestDeadlock.java b/test/jdk/java/foreign/TestDeadlock.java index 9144fad3830b2..8511a01d2f50b 100644 --- a/test/jdk/java/foreign/TestDeadlock.java +++ b/test/jdk/java/foreign/TestDeadlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,12 @@ /* * @test id=Arena_allocateFrom - * @run main/othervm/timeout=5 --enable-native-access=ALL-UNNAMED -Xlog:class+init TestDeadlock Arena + * @run main/othervm/timeout=10 --enable-native-access=ALL-UNNAMED -Xlog:class+init TestDeadlock Arena */ /* * @test id=FileChannel_map - * @run main/othervm/timeout=5 --enable-native-access=ALL-UNNAMED -Xlog:class+init TestDeadlock FileChannel + * @run main/othervm/timeout=60 --enable-native-access=ALL-UNNAMED -Xlog:class+init TestDeadlock FileChannel */ import java.lang.foreign.*; From da462cf2255f55c1059f9d9bf479231408a72b55 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Wed, 9 Apr 2025 12:58:00 +0000 Subject: [PATCH 0490/1101] 8353692: Relax memory constraint on updating ObjectMonitorTable's item count Reviewed-by: rkennke, dholmes --- src/hotspot/share/runtime/lightweightSynchronizer.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/runtime/lightweightSynchronizer.cpp b/src/hotspot/share/runtime/lightweightSynchronizer.cpp index 471a5c00e2016..c2a4e73f034ff 100644 --- a/src/hotspot/share/runtime/lightweightSynchronizer.cpp +++ b/src/hotspot/share/runtime/lightweightSynchronizer.cpp @@ -115,15 +115,16 @@ class ObjectMonitorTable : AllStatic { }; static void inc_items_count() { - Atomic::inc(&_items_count); + Atomic::inc(&_items_count, memory_order_relaxed); } static void dec_items_count() { - Atomic::dec(&_items_count); + Atomic::dec(&_items_count, memory_order_relaxed); } static double get_load_factor() { - return (double)_items_count / (double)_table_size; + size_t count = Atomic::load(&_items_count); + return (double)count / (double)_table_size; } static size_t table_size(Thread* current = Thread::current()) { From 9d8b93b6e2fa7a6c81d96f82ae8f5de222027879 Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Wed, 9 Apr 2025 13:08:21 +0000 Subject: [PATCH 0491/1101] 8354181: [Backout] 8334046: Set different values for CompLevel_any and CompLevel_all Reviewed-by: thartmann, chagedorn --- src/hotspot/share/compiler/compilerDefinitions.hpp | 2 +- .../jtreg/compiler/whitebox/CompilerWhiteBoxTest.java | 8 +++----- test/lib/jdk/test/whitebox/WhiteBox.java | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/compiler/compilerDefinitions.hpp b/src/hotspot/share/compiler/compilerDefinitions.hpp index 2c1ae85af8ab3..bdaa6dffb8f5f 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.hpp +++ b/src/hotspot/share/compiler/compilerDefinitions.hpp @@ -53,7 +53,7 @@ enum MethodCompilation { // Enumeration to distinguish tiers of compilation enum CompLevel : s1 { - CompLevel_any = -2, // Used for querying the state + CompLevel_any = -1, // Used for querying the state CompLevel_all = -1, // Used for changing the state CompLevel_none = 0, // Interpreter CompLevel_simple = 1, // C1 diff --git a/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java b/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java index dde2b3cdfd01f..f87292be019c0 100644 --- a/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java +++ b/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java @@ -41,10 +41,8 @@ public abstract class CompilerWhiteBoxTest { /** {@code CompLevel::CompLevel_none} -- Interpreter */ public static final int COMP_LEVEL_NONE = 0; - /** {@code CompLevel::CompLevel_any} */ - public static final int COMP_LEVEL_ANY = -2; - /** {@code CompLevel::CompLevel_all} */ - public static final int COMP_LEVEL_ALL = -1; + /** {@code CompLevel::CompLevel_any}, {@code CompLevel::CompLevel_all} */ + public static final int COMP_LEVEL_ANY = -1; /** {@code CompLevel::CompLevel_simple} -- C1 */ public static final int COMP_LEVEL_SIMPLE = 1; /** {@code CompLevel::CompLevel_limited_profile} -- C1, invocation & backedge counters */ @@ -286,7 +284,7 @@ protected final boolean isCompilable(int compLevel) { } protected final void makeNotCompilable() { - WHITE_BOX.makeMethodNotCompilable(method, COMP_LEVEL_ALL, + WHITE_BOX.makeMethodNotCompilable(method, COMP_LEVEL_ANY, testCase.isOsr()); } diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 2744978b8a935..f0e164d94b518 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -345,7 +345,7 @@ public boolean isMethodCompiled(Executable method, boolean isOsr){ return isMethodCompiled0(method, isOsr); } public boolean isMethodCompilable(Executable method) { - return isMethodCompilable(method, -2 /*any*/); + return isMethodCompilable(method, -1 /*any*/); } public boolean isMethodCompilable(Executable method, int compLevel) { return isMethodCompilable(method, compLevel, false /*not osr*/); @@ -393,7 +393,7 @@ public int deoptimizeMethod(Executable method, boolean isOsr) { return deoptimizeMethod0(method, isOsr); } public void makeMethodNotCompilable(Executable method) { - makeMethodNotCompilable(method, -1 /*all*/); + makeMethodNotCompilable(method, -1 /*any*/); } public void makeMethodNotCompilable(Executable method, int compLevel) { makeMethodNotCompilable(method, compLevel, false /*not osr*/); From c3e043956e72996a56a7ae9822782ba4dfdc0607 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Wed, 9 Apr 2025 13:47:24 +0000 Subject: [PATCH 0492/1101] 8354121: Use a record class rather than a lambda in AbstractMemorySegmentImpl::cleanupAction Reviewed-by: liach --- .../foreign/AbstractMemorySegmentImpl.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java index 83fb6881a411c..d7636032c2823 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -162,9 +162,19 @@ private NativeMemorySegmentImpl reinterpretInternal(Class callerClass, long n // Using a static helper method ensures there is no unintended lambda capturing of `this` private static Runnable cleanupAction(long address, long newSize, Consumer cleanup) { - return cleanup != null ? - () -> cleanup.accept(SegmentFactories.makeNativeSegmentUnchecked(address, newSize)) : - null; + + record CleanupAction(long address, long newSize, Consumer cleanup) implements Runnable { + @Override + public void run() { + cleanup().accept(SegmentFactories.makeNativeSegmentUnchecked(address(), newSize())); + } + } + + return cleanup != null + // Use a record (which is always static) instead of a lambda to avoid + // capturing and to enable early use in the init sequence. + ? new CleanupAction(address, newSize, cleanup) + : null; } private AbstractMemorySegmentImpl asSliceNoCheck(long offset, long newSize) { From 7a7b9ed7fe4a10bca155b0877c3e731f9d343b92 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Wed, 9 Apr 2025 14:49:04 +0000 Subject: [PATCH 0493/1101] 8353727: HeapDumpPath doesn't expand %p Reviewed-by: stuefe, lmesnik --- src/hotspot/share/services/heapDumper.cpp | 76 ++++++------------- .../TestHeapDumpOnOutOfMemoryError.java | 19 +++-- 2 files changed, 34 insertions(+), 61 deletions(-) diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index b30b042864861..7a2c8d5296985 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -43,6 +43,7 @@ #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" +#include "runtime/arguments.hpp" #include "runtime/continuationWrapper.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" @@ -2747,71 +2748,45 @@ void HeapDumper::dump_heap() { void HeapDumper::dump_heap(bool oome) { static char base_path[JVM_MAXPATHLEN] = {'\0'}; static uint dump_file_seq = 0; - char* my_path; + char my_path[JVM_MAXPATHLEN]; const int max_digit_chars = 20; - - const char* dump_file_name = "java_pid"; - const char* dump_file_ext = HeapDumpGzipLevel > 0 ? ".hprof.gz" : ".hprof"; + const char* dump_file_name = HeapDumpGzipLevel > 0 ? "java_pid%p.hprof.gz" : "java_pid%p.hprof"; // The dump file defaults to java_pid.hprof in the current working // directory. HeapDumpPath= can be used to specify an alternative // dump file name or a directory where dump file is created. if (dump_file_seq == 0) { // first time in, we initialize base_path - // Calculate potentially longest base path and check if we have enough - // allocated statically. - const size_t total_length = - (HeapDumpPath == nullptr ? 0 : strlen(HeapDumpPath)) + - strlen(os::file_separator()) + max_digit_chars + - strlen(dump_file_name) + strlen(dump_file_ext) + 1; - if (total_length > sizeof(base_path)) { + // Set base path (name or directory, default or custom, without seq no), doing %p substitution. + const char *path_src = (HeapDumpPath != nullptr && HeapDumpPath[0] != '\0') ? HeapDumpPath : dump_file_name; + if (!Arguments::copy_expand_pid(path_src, strlen(path_src), base_path, JVM_MAXPATHLEN - max_digit_chars)) { warning("Cannot create heap dump file. HeapDumpPath is too long."); return; } - - bool use_default_filename = true; - if (HeapDumpPath == nullptr || HeapDumpPath[0] == '\0') { - // HeapDumpPath= not specified - } else { - strcpy(base_path, HeapDumpPath); - // check if the path is a directory (must exist) - DIR* dir = os::opendir(base_path); - if (dir == nullptr) { - use_default_filename = false; - } else { - // HeapDumpPath specified a directory. We append a file separator - // (if needed). - os::closedir(dir); - size_t fs_len = strlen(os::file_separator()); - if (strlen(base_path) >= fs_len) { - char* end = base_path; - end += (strlen(base_path) - fs_len); - if (strcmp(end, os::file_separator()) != 0) { - strcat(base_path, os::file_separator()); - } + // Check if the path is an existing directory + DIR* dir = os::opendir(base_path); + if (dir != nullptr) { + os::closedir(dir); + // Path is a directory. Append a file separator (if needed). + size_t fs_len = strlen(os::file_separator()); + if (strlen(base_path) >= fs_len) { + char* end = base_path; + end += (strlen(base_path) - fs_len); + if (strcmp(end, os::file_separator()) != 0) { + strcat(base_path, os::file_separator()); } } + // Then add the default name, with %p substitution. Use my_path temporarily. + if (!Arguments::copy_expand_pid(dump_file_name, strlen(dump_file_name), my_path, JVM_MAXPATHLEN - max_digit_chars)) { + warning("Cannot create heap dump file. HeapDumpPath is too long."); + return; + } + const size_t dlen = strlen(base_path); + jio_snprintf(&base_path[dlen], sizeof(base_path) - dlen, "%s", my_path); } - // If HeapDumpPath wasn't a file name then we append the default name - if (use_default_filename) { - const size_t dlen = strlen(base_path); // if heap dump dir specified - jio_snprintf(&base_path[dlen], sizeof(base_path)-dlen, "%s%d%s", - dump_file_name, os::current_process_id(), dump_file_ext); - } - const size_t len = strlen(base_path) + 1; - my_path = (char*)os::malloc(len, mtInternal); - if (my_path == nullptr) { - warning("Cannot create heap dump file. Out of system memory."); - return; - } - strncpy(my_path, base_path, len); + strncpy(my_path, base_path, JVM_MAXPATHLEN); } else { // Append a sequence number id for dumps following the first const size_t len = strlen(base_path) + max_digit_chars + 2; // for '.' and \0 - my_path = (char*)os::malloc(len, mtInternal); - if (my_path == nullptr) { - warning("Cannot create heap dump file. Out of system memory."); - return; - } jio_snprintf(my_path, len, "%s.%d", base_path, dump_file_seq); } dump_file_seq++; // increment seq number for next time we dump @@ -2819,5 +2794,4 @@ void HeapDumper::dump_heap(bool oome) { HeapDumper dumper(false /* no GC before heap dump */, oome /* pass along out-of-memory-error flag */); dumper.dump(my_path, tty, HeapDumpGzipLevel); - os::free(my_path); } diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/TestHeapDumpOnOutOfMemoryError.java b/test/hotspot/jtreg/runtime/ErrorHandling/TestHeapDumpOnOutOfMemoryError.java index fb098bd27fec7..66df532983a46 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/TestHeapDumpOnOutOfMemoryError.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/TestHeapDumpOnOutOfMemoryError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,10 +71,12 @@ public static void main(String[] args) throws Exception { } } test(args[1]); + System.out.println("PASSED"); } static void test(String type) throws Exception { - String heapdumpFilename = type + ".hprof"; + // Test using %p pid substitution in HeapDumpPath: + String heapdumpFilename = type + ".%p.hprof"; ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=" + heapdumpFilename, // Note: When trying to provoke a metaspace OOM we may generate a lot of classes. In debug VMs this @@ -94,13 +96,10 @@ static void test(String type) throws Exception { OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.stdoutShouldNotBeEmpty(); - output.shouldContain("Dumping heap to " + type + ".hprof"); - File dump = new File(heapdumpFilename); - Asserts.assertTrue(dump.exists() && dump.isFile(), - "Could not find dump file " + dump.getAbsolutePath()); - - HprofParser.parse(new File(heapdumpFilename)); - System.out.println("PASSED"); + String expectedHeapdumpFilename = type + "." + output.pid() + ".hprof"; + output.shouldContain("Dumping heap to " + expectedHeapdumpFilename); + File dump = new File(expectedHeapdumpFilename); + Asserts.assertTrue(dump.exists() && dump.isFile(), "Expected heap dump file " + dump.getAbsolutePath()); + HprofParser.parse(new File(expectedHeapdumpFilename)); } - } From 4dc9e58906772bf8ee444cb1618aa43f66593d79 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 9 Apr 2025 14:51:15 +0000 Subject: [PATCH 0494/1101] 8310310: Migrate CreateSymbols tool in make/langtools to Classfile API Reviewed-by: ihse, jlahoda --- .../tools/symbolgenerator/CreateSymbols.java | 1349 +++++------------ make/modules/jdk.compiler/Gendata.gmk | 1 - make/scripts/generate-symbol-data.sh | 3 +- .../platform/CanHandleClassFilesTest.java | 9 +- .../createsymbols/CreateSymbolsTest.java | 6 +- 5 files changed, 357 insertions(+), 1011 deletions(-) diff --git a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java index 6faefecd4247a..db8924c79fbf4 100644 --- a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java +++ b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,18 @@ import java.io.OutputStream; import java.io.StringWriter; import java.io.Writer; +import java.lang.classfile.*; +import java.lang.classfile.attribute.*; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.constantpool.ConstantValueEntry; +import java.lang.classfile.constantpool.IntegerEntry; +import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.constant.ModuleDesc; +import java.lang.constant.PackageDesc; +import java.lang.reflect.AccessFlag; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.FileVisitResult; @@ -88,63 +100,6 @@ import javax.tools.StandardLocation; import com.sun.source.util.JavacTask; -import com.sun.tools.classfile.AccessFlags; -import com.sun.tools.classfile.Annotation; -import com.sun.tools.classfile.Annotation.Annotation_element_value; -import com.sun.tools.classfile.Annotation.Array_element_value; -import com.sun.tools.classfile.Annotation.Class_element_value; -import com.sun.tools.classfile.Annotation.Enum_element_value; -import com.sun.tools.classfile.Annotation.Primitive_element_value; -import com.sun.tools.classfile.Annotation.element_value; -import com.sun.tools.classfile.Annotation.element_value_pair; -import com.sun.tools.classfile.AnnotationDefault_attribute; -import com.sun.tools.classfile.Attribute; -import com.sun.tools.classfile.Attributes; -import com.sun.tools.classfile.ClassFile; -import com.sun.tools.classfile.ClassWriter; -import com.sun.tools.classfile.ConstantPool; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Float_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Integer_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Long_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Module_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Package_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_String_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info; -import com.sun.tools.classfile.ConstantPool.CPInfo; -import com.sun.tools.classfile.ConstantPool.InvalidIndex; -import com.sun.tools.classfile.ConstantPoolException; -import com.sun.tools.classfile.ConstantValue_attribute; -import com.sun.tools.classfile.Deprecated_attribute; -import com.sun.tools.classfile.Descriptor; -import com.sun.tools.classfile.Exceptions_attribute; -import com.sun.tools.classfile.Field; -import com.sun.tools.classfile.InnerClasses_attribute; -import com.sun.tools.classfile.InnerClasses_attribute.Info; -import com.sun.tools.classfile.Method; -import com.sun.tools.classfile.ModulePackages_attribute; -import com.sun.tools.classfile.MethodParameters_attribute; -import com.sun.tools.classfile.ModuleMainClass_attribute; -import com.sun.tools.classfile.ModuleResolution_attribute; -import com.sun.tools.classfile.ModuleTarget_attribute; -import com.sun.tools.classfile.Module_attribute; -import com.sun.tools.classfile.Module_attribute.ExportsEntry; -import com.sun.tools.classfile.Module_attribute.OpensEntry; -import com.sun.tools.classfile.Module_attribute.ProvidesEntry; -import com.sun.tools.classfile.Module_attribute.RequiresEntry; -import com.sun.tools.classfile.NestHost_attribute; -import com.sun.tools.classfile.NestMembers_attribute; -import com.sun.tools.classfile.PermittedSubclasses_attribute; -import com.sun.tools.classfile.Record_attribute; -import com.sun.tools.classfile.Record_attribute.ComponentInfo; -import com.sun.tools.classfile.RuntimeAnnotations_attribute; -import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute; -import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute; -import com.sun.tools.classfile.RuntimeParameterAnnotations_attribute; -import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute; -import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute; -import com.sun.tools.classfile.Signature_attribute; import com.sun.tools.javac.api.JavacTool; import com.sun.tools.javac.jvm.Target; import com.sun.tools.javac.util.Assert; @@ -154,13 +109,15 @@ import java.util.Optional; import java.util.function.Consumer; +import static java.lang.classfile.ClassFile.ACC_PROTECTED; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; + /** * A tool for processing the .sym.txt files. * * To add historical data for JDK N, N >= 11, do the following: * * cd /src/jdk.compiler/share/data/symbols - * * /bin/java --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \ - * --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ + * * /bin/java --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ * --add-exports jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \ * --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \ * --add-modules jdk.jdeps \ @@ -409,7 +366,7 @@ LoadDescriptions load(Path ctDescriptionWithExtraContent, Path ctDescriptionOpen reader.moveNext(); break; default: - throw new IllegalStateException("Unknown key: " + reader.lineKey); + throw new IllegalArgumentException("Unknown key: " + reader.lineKey); } } } @@ -432,7 +389,7 @@ LoadDescriptions load(Path ctDescriptionWithExtraContent, Path ctDescriptionOpen reader.moveNext(); break; default: - throw new IllegalStateException("Unknown key: " + reader.lineKey); + throw new IllegalArgumentException("Unknown key: " + reader.lineKey); } } } @@ -830,31 +787,12 @@ void writeModule(Map> directory2FileData, ModuleHeaderDescription header, char version, Function version2ModuleVersion) throws IOException { - List constantPool = new ArrayList<>(); - constantPool.add(null); - int currentClass = addClass(constantPool, "module-info"); - int superclass = 0; - int[] interfaces = new int[0]; - AccessFlags flags = new AccessFlags(header.flags); - Map attributesMap = new HashMap<>(); - String versionString = Character.toString(version); - addAttributes(moduleDescription, header, constantPool, attributesMap, - version2ModuleVersion.apply(version)); - Attributes attributes = new Attributes(attributesMap); - CPInfo[] cpData = constantPool.toArray(new CPInfo[constantPool.size()]); - ConstantPool cp = new ConstantPool(cpData); - ClassFile classFile = new ClassFile(0xCAFEBABE, - Target.DEFAULT.minorVersion, - Target.DEFAULT.majorVersion, - cp, - flags, - currentClass, - superclass, - interfaces, - new Field[0], - new Method[0], - attributes); + var classFile = ClassFile.of().build(ClassDesc.of("module-info"), clb -> { + clb.withFlags(header.flags); + addAttributes(moduleDescription, header, clb, version2ModuleVersion.apply(version)); + }); + String versionString = Character.toString(version); doWrite(directory2FileData, versionString, moduleDescription.name, "module-info" + EXTENSION, classFile); } @@ -863,57 +801,26 @@ void writeClass(Map> directory2FileData, ClassHeaderDescription header, String module, String version) throws IOException { - List constantPool = new ArrayList<>(); - constantPool.add(null); - List methods = new ArrayList<>(); - for (MethodDescription methDesc : classDescription.methods) { - if (disjoint(methDesc.versions, version)) - continue; - Descriptor descriptor = new Descriptor(addString(constantPool, methDesc.descriptor)); - //TODO: LinkedHashMap to avoid param annotations vs. Signature problem in javac's ClassReader: - Map attributesMap = new LinkedHashMap<>(); - addAttributes(methDesc, constantPool, attributesMap); - Attributes attributes = new Attributes(attributesMap); - AccessFlags flags = new AccessFlags(methDesc.flags); - int nameString = addString(constantPool, methDesc.name); - methods.add(new Method(flags, nameString, descriptor, attributes)); - } - List fields = new ArrayList<>(); - for (FieldDescription fieldDesc : classDescription.fields) { - if (disjoint(fieldDesc.versions, version)) - continue; - Descriptor descriptor = new Descriptor(addString(constantPool, fieldDesc.descriptor)); - Map attributesMap = new HashMap<>(); - addAttributes(fieldDesc, constantPool, attributesMap); - Attributes attributes = new Attributes(attributesMap); - AccessFlags flags = new AccessFlags(fieldDesc.flags); - int nameString = addString(constantPool, fieldDesc.name); - fields.add(new Field(flags, nameString, descriptor, attributes)); - } - int currentClass = addClass(constantPool, classDescription.name); - int superclass = header.extendsAttr != null ? addClass(constantPool, header.extendsAttr) : 0; - int[] interfaces = new int[header.implementsAttr.size()]; - int i = 0; - for (String intf : header.implementsAttr) { - interfaces[i++] = addClass(constantPool, intf); - } - AccessFlags flags = new AccessFlags(header.flags); - Map attributesMap = new HashMap<>(); - addAttributes(header, constantPool, attributesMap); - Attributes attributes = new Attributes(attributesMap); - ConstantPool cp = new ConstantPool(constantPool.toArray(new CPInfo[constantPool.size()])); - ClassFile classFile = new ClassFile(0xCAFEBABE, - Target.DEFAULT.minorVersion, - Target.DEFAULT.majorVersion, - cp, - flags, - currentClass, - superclass, - interfaces, - fields.toArray(new Field[0]), - methods.toArray(new Method[0]), - attributes); - + var classFile = ClassFile.of().build(ClassDesc.ofInternalName(classDescription.name), clb -> { + if (header.extendsAttr != null) + clb.withSuperclass(ClassDesc.ofInternalName(header.extendsAttr)); + clb.withInterfaceSymbols(header.implementsAttr.stream().map(ClassDesc::ofInternalName).collect(Collectors.toList())) + .withFlags(header.flags); + for (FieldDescription fieldDesc : classDescription.fields) { + if (disjoint(fieldDesc.versions, version)) + continue; + clb.withField(fieldDesc.name, ClassDesc.ofDescriptor(fieldDesc.descriptor), fb -> { + addAttributes(fieldDesc, fb); + fb.withFlags(fieldDesc.flags); + }); + } + for (MethodDescription methDesc : classDescription.methods) { + if (disjoint(methDesc.versions, version)) + continue; + clb.withMethod(methDesc.name, MethodTypeDesc.ofDescriptor(methDesc.descriptor), methDesc.flags, mb -> addAttributes(methDesc, mb)); + } + addAttributes(header, clb); + }); doWrite(directory2FileData, version, module, classDescription.name + EXTENSION, classFile); } @@ -921,19 +828,13 @@ private void doWrite(Map> directory2FileData, String version, String moduleName, String fileName, - ClassFile classFile) throws IOException { + byte[] classFile) throws IOException { int lastSlash = fileName.lastIndexOf('/'); String pack = lastSlash != (-1) ? fileName.substring(0, lastSlash + 1) : "/"; String directory = version + "/" + moduleName + "/" + pack; String fullFileName = version + "/" + moduleName + "/" + fileName; - try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { - ClassWriter w = new ClassWriter(); - - w.write(classFile, out); - - openDirectory(directory2FileData, directory) - .add(new FileData(fullFileName, out.toByteArray())); - } + openDirectory(directory2FileData, directory) + .add(new FileData(fullFileName, classFile)); } private Set openDirectory(Map> directory2FileData, @@ -955,278 +856,147 @@ public FileData(String fileName, byte[] fileData) { private void addAttributes(ModuleDescription md, ModuleHeaderDescription header, - List cp, - Map attributes, + ClassBuilder builder, String moduleVersion) { - addGenericAttributes(header, cp, attributes); + addGenericAttributes(header, builder); if (header.moduleResolution != null) { - int attrIdx = addString(cp, Attribute.ModuleResolution); - final ModuleResolution_attribute resIdx = - new ModuleResolution_attribute(attrIdx, - header.moduleResolution); - attributes.put(Attribute.ModuleResolution, resIdx); + builder.with(ModuleResolutionAttribute.of(header.moduleResolution)); } if (header.moduleTarget != null) { - int attrIdx = addString(cp, Attribute.ModuleTarget); - int targetIdx = addString(cp, header.moduleTarget); - attributes.put(Attribute.ModuleTarget, - new ModuleTarget_attribute(attrIdx, targetIdx)); + builder.with(ModuleTargetAttribute.of(header.moduleTarget)); } if (header.moduleMainClass != null) { - int attrIdx = addString(cp, Attribute.ModuleMainClass); - int targetIdx = addClassName(cp, header.moduleMainClass); - attributes.put(Attribute.ModuleMainClass, - new ModuleMainClass_attribute(attrIdx, targetIdx)); - } - int versionIdx = addString(cp, moduleVersion); - int attrIdx = addString(cp, Attribute.Module); - attributes.put(Attribute.Module, - new Module_attribute(attrIdx, - addModuleName(cp, md.name), - 0, - versionIdx, - header.requires - .stream() - .map(r -> createRequiresEntry(cp, r)) - .collect(Collectors.toList()) - .toArray(new RequiresEntry[0]), - header.exports - .stream() - .map(e -> createExportsEntry(cp, e)) - .collect(Collectors.toList()) - .toArray(new ExportsEntry[0]), - header.opens - .stream() - .map(e -> createOpensEntry(cp, e)) - .collect(Collectors.toList()) - .toArray(new OpensEntry[0]), - header.uses - .stream() - .mapToInt(u -> addClassName(cp, u)) - .toArray(), - header.provides - .stream() - .map(p -> createProvidesEntry(cp, p)) - .collect(Collectors.toList()) - .toArray(new ProvidesEntry[0]))); - addInnerClassesAttribute(header, cp, attributes); - } - - private static RequiresEntry createRequiresEntry(List cp, - RequiresDescription r) { - final int idx = addModuleName(cp, r.moduleName); - return new RequiresEntry(idx, - r.flags, - r.version != null - ? addString(cp, r.version) - : 0); - } - - private static ExportsEntry createExportsEntry(List cp, - ExportsDescription export) { - int[] to; - if (export.isQualified()) { - to = export.to.stream() - .mapToInt(module -> addModuleName(cp, module)) - .toArray(); - } else { - to = new int[0]; + builder.with(ModuleMainClassAttribute.of(ClassDesc.ofInternalName(header.moduleMainClass))); } - return new ExportsEntry(addPackageName(cp, export.packageName()), 0, to); - } - - private static OpensEntry createOpensEntry(List cp, String e) { - return new OpensEntry(addPackageName(cp, e), 0, new int[0]); - } - - private static ProvidesEntry createProvidesEntry(List cp, - ModuleHeaderDescription.ProvidesDescription p) { - final int idx = addClassName(cp, p.interfaceName); - return new ProvidesEntry(idx, p.implNames - .stream() - .mapToInt(i -> addClassName(cp, i)) - .toArray()); + builder.with(ModuleAttribute.of(ModuleDesc.of(md.name), mb -> { + mb.moduleVersion(moduleVersion); + for (var req : header.requires) { + mb.requires(ModuleDesc.of(req.moduleName), req.flags, req.version); // nullable version + } + for (var exp : header.exports) { + if (exp.isQualified()) { + mb.exports(PackageDesc.ofInternalName(exp.packageName()), 0, exp.to.stream().map(ModuleDesc::of).toArray(ModuleDesc[]::new)); + } else { + mb.exports(PackageDesc.ofInternalName(exp.packageName()), 0); + } + } + for (var open : header.opens) { + mb.opens(PackageDesc.ofInternalName(open), 0); + } + for (var use : header.uses) { + mb.uses(ClassDesc.ofInternalName(use)); + } + for (var provide : header.provides) { + mb.provides(ClassDesc.ofInternalName(provide.interfaceName), + provide.implNames.stream().map(ClassDesc::ofInternalName).toArray(ClassDesc[]::new)); + } + })); + addInnerClassesAttribute(header, builder); } - private void addAttributes(ClassHeaderDescription header, - List constantPool, Map attributes) { - addGenericAttributes(header, constantPool, attributes); + private void addAttributes(ClassHeaderDescription header, ClassBuilder builder) { + addGenericAttributes(header, builder); if (header.nestHost != null) { - int attributeString = addString(constantPool, Attribute.NestHost); - int nestHost = addClass(constantPool, header.nestHost); - attributes.put(Attribute.NestHost, - new NestHost_attribute(attributeString, nestHost)); + builder.with(NestHostAttribute.of(ClassDesc.ofInternalName(header.nestHost))); } if (header.nestMembers != null && !header.nestMembers.isEmpty()) { - int attributeString = addString(constantPool, Attribute.NestMembers); - int[] nestMembers = new int[header.nestMembers.size()]; - int i = 0; - for (String intf : header.nestMembers) { - nestMembers[i++] = addClass(constantPool, intf); - } - attributes.put(Attribute.NestMembers, - new NestMembers_attribute(attributeString, nestMembers)); + builder.with(NestMembersAttribute.ofSymbols(header.nestMembers.stream().map(ClassDesc::ofInternalName).collect(Collectors.toList()))); } if (header.isRecord) { - assert header.recordComponents != null; - int attributeString = addString(constantPool, Attribute.Record); - ComponentInfo[] recordComponents = new ComponentInfo[header.recordComponents.size()]; - int i = 0; - for (RecordComponentDescription rcd : header.recordComponents) { - int name = addString(constantPool, rcd.name); - Descriptor desc = new Descriptor(addString(constantPool, rcd.descriptor)); - Map nestedAttrs = new HashMap<>(); - addGenericAttributes(rcd, constantPool, nestedAttrs); - Attributes attrs = new Attributes(nestedAttrs); - recordComponents[i++] = new ComponentInfo(name, desc, attrs); - } - attributes.put(Attribute.Record, - new Record_attribute(attributeString, recordComponents)); + builder.with(RecordAttribute.of(header.recordComponents.stream().map(desc -> { + List> attributes = new ArrayList<>(); + addGenericAttributes(desc, attributes::add, builder.constantPool()); + return RecordComponentInfo.of(desc.name, ClassDesc.ofDescriptor(desc.descriptor), attributes); + }).collect(Collectors.toList()))); } if (header.isSealed) { - int attributeString = addString(constantPool, Attribute.PermittedSubclasses); - int[] subclasses = new int[header.permittedSubclasses.size()]; - int i = 0; - for (String intf : header.permittedSubclasses) { - subclasses[i++] = addClass(constantPool, intf); - } - attributes.put(Attribute.PermittedSubclasses, - new PermittedSubclasses_attribute(attributeString, subclasses)); + builder.with(PermittedSubclassesAttribute.ofSymbols(header.permittedSubclasses.stream().map(ClassDesc::ofInternalName).collect(Collectors.toList()))); } - addInnerClassesAttribute(header, constantPool, attributes); + addInnerClassesAttribute(header, builder); } - private void addInnerClassesAttribute(HeaderDescription header, - List constantPool, Map attributes) { + private void addInnerClassesAttribute(HeaderDescription header, ClassBuilder builder) { if (header.innerClasses != null && !header.innerClasses.isEmpty()) { - Info[] innerClasses = new Info[header.innerClasses.size()]; - int i = 0; - for (InnerClassInfo info : header.innerClasses) { - innerClasses[i++] = - new Info(info.innerClass == null ? 0 : addClass(constantPool, info.innerClass), - info.outerClass == null ? 0 : addClass(constantPool, info.outerClass), - info.innerClassName == null ? 0 : addString(constantPool, info.innerClassName), - new AccessFlags(info.innerClassFlags)); - } - int attributeString = addString(constantPool, Attribute.InnerClasses); - attributes.put(Attribute.InnerClasses, - new InnerClasses_attribute(attributeString, innerClasses)); + builder.with(InnerClassesAttribute.of(header.innerClasses.stream() + .map(info -> java.lang.classfile.attribute.InnerClassInfo.of( + ClassDesc.ofInternalName(info.innerClass), + Optional.ofNullable(info.outerClass).map(ClassDesc::ofInternalName), + Optional.ofNullable(info.innerClassName), + info.innerClassFlags + )).collect(Collectors.toList()))); } } - private void addAttributes(MethodDescription desc, List constantPool, Map attributes) { - addGenericAttributes(desc, constantPool, attributes); + private void addAttributes(MethodDescription desc, MethodBuilder builder) { + addGenericAttributes(desc, builder); if (desc.thrownTypes != null) { - int[] exceptions = new int[desc.thrownTypes.size()]; - int i = 0; - for (String exc : desc.thrownTypes) { - exceptions[i++] = addClass(constantPool, exc); - } - int attributeString = addString(constantPool, Attribute.Exceptions); - attributes.put(Attribute.Exceptions, - new Exceptions_attribute(attributeString, exceptions)); + builder.with(ExceptionsAttribute.ofSymbols(desc.thrownTypes.stream() + .map(ClassDesc::ofInternalName).collect(Collectors.toList()))); } if (desc.annotationDefaultValue != null) { - int attributeString = addString(constantPool, Attribute.AnnotationDefault); - element_value attributeValue = createAttributeValue(constantPool, - desc.annotationDefaultValue); - attributes.put(Attribute.AnnotationDefault, - new AnnotationDefault_attribute(attributeString, attributeValue)); + builder.with(AnnotationDefaultAttribute.of(createAttributeValue(desc.annotationDefaultValue))); } if (desc.classParameterAnnotations != null && !desc.classParameterAnnotations.isEmpty()) { - int attributeString = - addString(constantPool, Attribute.RuntimeInvisibleParameterAnnotations); - Annotation[][] annotations = - createParameterAnnotations(constantPool, desc.classParameterAnnotations); - attributes.put(Attribute.RuntimeInvisibleParameterAnnotations, - new RuntimeInvisibleParameterAnnotations_attribute(attributeString, - annotations)); + builder.with(RuntimeInvisibleParameterAnnotationsAttribute.of(createParameterAnnotations(desc.classParameterAnnotations))); } if (desc.runtimeParameterAnnotations != null && !desc.runtimeParameterAnnotations.isEmpty()) { - int attributeString = - addString(constantPool, Attribute.RuntimeVisibleParameterAnnotations); - Annotation[][] annotations = - createParameterAnnotations(constantPool, desc.runtimeParameterAnnotations); - attributes.put(Attribute.RuntimeVisibleParameterAnnotations, - new RuntimeVisibleParameterAnnotations_attribute(attributeString, - annotations)); + builder.with(RuntimeVisibleParameterAnnotationsAttribute.of(createParameterAnnotations(desc.runtimeParameterAnnotations))); } if (desc.methodParameters != null && !desc.methodParameters.isEmpty()) { - int attributeString = - addString(constantPool, Attribute.MethodParameters); - MethodParameters_attribute.Entry[] entries = - desc.methodParameters - .stream() - .map(p -> new MethodParameters_attribute.Entry(p.name == null || p.name.isEmpty() ? 0 - : addString(constantPool, p.name), - p.flags)) - .toArray(s -> new MethodParameters_attribute.Entry[s]); - attributes.put(Attribute.MethodParameters, - new MethodParameters_attribute(attributeString, entries)); + builder.with(MethodParametersAttribute.of(desc.methodParameters.stream() + .map(mp -> MethodParameterInfo.ofParameter(Optional.ofNullable(mp.name), mp.flags)).collect(Collectors.toList()))); } } - private void addAttributes(FieldDescription desc, List constantPool, Map attributes) { - addGenericAttributes(desc, constantPool, attributes); + private void addAttributes(FieldDescription desc, FieldBuilder builder) { + addGenericAttributes(desc, builder); if (desc.constantValue != null) { - Pair constantPoolEntry = - addConstant(constantPool, desc.constantValue, false); - Assert.checkNonNull(constantPoolEntry); - int constantValueString = addString(constantPool, Attribute.ConstantValue); - attributes.put(Attribute.ConstantValue, - new ConstantValue_attribute(constantValueString, constantPoolEntry.fst)); + var cp = builder.constantPool(); + ConstantValueEntry entry = switch (desc.constantValue) { + case Boolean v -> cp.intEntry(v ? 1 : 0); + case Character v -> cp.intEntry(v); + case Integer v -> cp.intEntry(v); + case Long v -> cp.longEntry(v); + case Float v -> cp.floatEntry(v); + case Double v -> cp.doubleEntry(v); + case String v -> cp.stringEntry(v); + default -> throw new IllegalArgumentException(desc.constantValue.getClass().toString()); + }; + builder.with(ConstantValueAttribute.of(entry)); } } - private void addGenericAttributes(FeatureDescription desc, List constantPool, Map attributes) { + @SuppressWarnings("unchecked") + private void addGenericAttributes(FeatureDescription desc, ClassFileBuilder builder) { + addGenericAttributes(desc, (Consumer>) builder, builder.constantPool()); + } + + private void addGenericAttributes(FeatureDescription desc, Consumer> sink, ConstantPoolBuilder cpb) { + @SuppressWarnings("unchecked") + var builder = (Consumer>) sink; if (desc.deprecated) { - int attributeString = addString(constantPool, Attribute.Deprecated); - attributes.put(Attribute.Deprecated, - new Deprecated_attribute(attributeString)); + builder.accept(DeprecatedAttribute.of()); } if (desc.signature != null) { - int attributeString = addString(constantPool, Attribute.Signature); - int signatureString = addString(constantPool, desc.signature); - attributes.put(Attribute.Signature, - new Signature_attribute(attributeString, signatureString)); + builder.accept(SignatureAttribute.of(cpb.utf8Entry(desc.signature))); } if (desc.classAnnotations != null && !desc.classAnnotations.isEmpty()) { - int attributeString = addString(constantPool, Attribute.RuntimeInvisibleAnnotations); - Annotation[] annotations = createAnnotations(constantPool, desc.classAnnotations); - attributes.put(Attribute.RuntimeInvisibleAnnotations, - new RuntimeInvisibleAnnotations_attribute(attributeString, annotations)); + builder.accept(RuntimeInvisibleAnnotationsAttribute.of(createAnnotations(desc.classAnnotations))); } if (desc.runtimeAnnotations != null && !desc.runtimeAnnotations.isEmpty()) { - int attributeString = addString(constantPool, Attribute.RuntimeVisibleAnnotations); - Annotation[] annotations = createAnnotations(constantPool, desc.runtimeAnnotations); - attributes.put(Attribute.RuntimeVisibleAnnotations, - new RuntimeVisibleAnnotations_attribute(attributeString, annotations)); + builder.accept(RuntimeVisibleAnnotationsAttribute.of(createAnnotations(desc.runtimeAnnotations))); } } - private Annotation[] createAnnotations(List constantPool, List desc) { - Annotation[] result = new Annotation[desc.size()]; - int i = 0; - - for (AnnotationDescription ad : desc) { - result[i++] = createAnnotation(constantPool, ad); - } - - return result; + private List createAnnotations(List desc) { + return desc.stream().map(this::createAnnotation).collect(Collectors.toList()); } - private Annotation[][] createParameterAnnotations(List constantPool, List> desc) { - Annotation[][] result = new Annotation[desc.size()][]; - int i = 0; - - for (List paramAnnos : desc) { - result[i++] = createAnnotations(constantPool, paramAnnos); - } - - return result; + private List> createParameterAnnotations(List> desc) { + return desc.stream().map(this::createAnnotations).collect(Collectors.toList()); } - private Annotation createAnnotation(List constantPool, AnnotationDescription desc) { + private Annotation createAnnotation(AnnotationDescription desc) { String annotationType = desc.annotationType; Map values = desc.values; @@ -1257,184 +1027,33 @@ private Annotation createAnnotation(List constantPool, AnnotationDescrip annotationType = RESTRICTED_ANNOTATION_INTERNAL; } - return new Annotation(null, - addString(constantPool, annotationType), - createElementPairs(constantPool, values)); - } - - private element_value_pair[] createElementPairs(List constantPool, Map annotationAttributes) { - element_value_pair[] pairs = new element_value_pair[annotationAttributes.size()]; - int i = 0; - - for (Entry e : annotationAttributes.entrySet()) { - int elementNameString = addString(constantPool, e.getKey()); - element_value value = createAttributeValue(constantPool, e.getValue()); - pairs[i++] = new element_value_pair(elementNameString, value); - } - - return pairs; + return Annotation.of(ClassDesc.ofDescriptor(annotationType), + createElementPairs(values)); } - private element_value createAttributeValue(List constantPool, Object value) { - Pair constantPoolEntry = addConstant(constantPool, value, true); - if (constantPoolEntry != null) { - return new Primitive_element_value(constantPoolEntry.fst, constantPoolEntry.snd); - } else if (value instanceof EnumConstant) { - EnumConstant ec = (EnumConstant) value; - return new Enum_element_value(addString(constantPool, ec.type), - addString(constantPool, ec.constant), - 'e'); - } else if (value instanceof ClassConstant) { - ClassConstant cc = (ClassConstant) value; - return new Class_element_value(addString(constantPool, cc.type), 'c'); - } else if (value instanceof AnnotationDescription) { - Annotation annotation = createAnnotation(constantPool, ((AnnotationDescription) value)); - return new Annotation_element_value(annotation, '@'); - } else if (value instanceof Collection) { - @SuppressWarnings("unchecked") - Collection array = (Collection) value; - element_value[] values = new element_value[array.size()]; - int i = 0; - - for (Object elem : array) { - values[i++] = createAttributeValue(constantPool, elem); - } - - return new Array_element_value(values, '['); - } - throw new IllegalStateException(value.getClass().getName()); + private List createElementPairs(Map annotationAttributes) { + return annotationAttributes.entrySet().stream() + .map(e -> AnnotationElement.of(e.getKey(), createAttributeValue(e.getValue()))) + .collect(Collectors.toList()); } - private static Pair addConstant(List constantPool, Object value, boolean annotation) { - if (value instanceof Boolean) { - return Pair.of(addToCP(constantPool, new CONSTANT_Integer_info(((Boolean) value) ? 1 : 0)), 'Z'); - } else if (value instanceof Byte) { - return Pair.of(addToCP(constantPool, new CONSTANT_Integer_info((byte) value)), 'B'); - } else if (value instanceof Character) { - return Pair.of(addToCP(constantPool, new CONSTANT_Integer_info((char) value)), 'C'); - } else if (value instanceof Short) { - return Pair.of(addToCP(constantPool, new CONSTANT_Integer_info((short) value)), 'S'); - } else if (value instanceof Integer) { - return Pair.of(addToCP(constantPool, new CONSTANT_Integer_info((int) value)), 'I'); - } else if (value instanceof Long) { - return Pair.of(addToCP(constantPool, new CONSTANT_Long_info((long) value)), 'J'); - } else if (value instanceof Float) { - return Pair.of(addToCP(constantPool, new CONSTANT_Float_info((float) value)), 'F'); - } else if (value instanceof Double) { - return Pair.of(addToCP(constantPool, new CONSTANT_Double_info((double) value)), 'D'); - } else if (value instanceof String) { - int stringIndex = addString(constantPool, (String) value); - if (annotation) { - return Pair.of(stringIndex, 's'); - } else { - return Pair.of(addToCP(constantPool, new CONSTANT_String_info(null, stringIndex)), 's'); - } - } - - return null; - } - - private static int addString(List constantPool, String string) { - Assert.checkNonNull(string); - - int i = 0; - for (CPInfo info : constantPool) { - if (info instanceof CONSTANT_Utf8_info) { - if (((CONSTANT_Utf8_info) info).value.equals(string)) { - return i; - } - } - i++; - } - - return addToCP(constantPool, new CONSTANT_Utf8_info(string)); - } - - private static int addInt(List constantPool, int value) { - int i = 0; - for (CPInfo info : constantPool) { - if (info instanceof CONSTANT_Integer_info) { - if (((CONSTANT_Integer_info) info).value == value) { - return i; - } - } - i++; - } - - return addToCP(constantPool, new CONSTANT_Integer_info(value)); - } - - private static int addModuleName(List constantPool, String moduleName) { - int nameIdx = addString(constantPool, moduleName); - int i = 0; - for (CPInfo info : constantPool) { - if (info instanceof CONSTANT_Module_info) { - if (((CONSTANT_Module_info) info).name_index == nameIdx) { - return i; - } - } - i++; - } - - return addToCP(constantPool, new CONSTANT_Module_info(null, nameIdx)); - } - - private static int addPackageName(List constantPool, String packageName) { - int nameIdx = addString(constantPool, packageName); - int i = 0; - for (CPInfo info : constantPool) { - if (info instanceof CONSTANT_Package_info) { - if (((CONSTANT_Package_info) info).name_index == nameIdx) { - return i; - } - } - i++; - } - - return addToCP(constantPool, new CONSTANT_Package_info(null, nameIdx)); - } - - private static int addClassName(List constantPool, String className) { - int nameIdx = addString(constantPool, className); - int i = 0; - for (CPInfo info : constantPool) { - if (info instanceof CONSTANT_Class_info) { - if (((CONSTANT_Class_info) info).name_index == nameIdx) { - return i; - } - } - i++; - } - - return addToCP(constantPool, new CONSTANT_Class_info(null, nameIdx)); - } - - private static int addToCP(List constantPool, CPInfo entry) { - int result = constantPool.size(); - - constantPool.add(entry); - - if (entry.size() > 1) { - constantPool.add(null); - } - - return result; - } - - private static int addClass(List constantPool, String className) { - int classNameIndex = addString(constantPool, className); - - int i = 0; - for (CPInfo info : constantPool) { - if (info instanceof CONSTANT_Class_info) { - if (((CONSTANT_Class_info) info).name_index == classNameIndex) { - return i; - } - } - i++; - } - - return addToCP(constantPool, new CONSTANT_Class_info(null, classNameIndex)); + private AnnotationValue createAttributeValue(Object value) { + return switch (value) { + case Boolean v -> AnnotationValue.ofBoolean(v); + case Byte v -> AnnotationValue.ofByte(v); + case Character v -> AnnotationValue.ofChar(v); + case Short v -> AnnotationValue.ofShort(v); + case Integer v -> AnnotationValue.ofInt(v); + case Long v -> AnnotationValue.ofLong(v); + case Float v -> AnnotationValue.ofFloat(v); + case Double v -> AnnotationValue.ofDouble(v); + case String v -> AnnotationValue.ofString(v); + case EnumConstant v -> AnnotationValue.ofEnum(ClassDesc.ofDescriptor(v.type), v.constant); + case ClassConstant v -> AnnotationValue.ofClass(ClassDesc.ofDescriptor(v.type)); + case AnnotationDescription v -> AnnotationValue.ofAnnotation(createAnnotation(v)); + case Collection v -> AnnotationValue.ofArray(v.stream().map(this::createAttributeValue).collect(Collectors.toList())); + default -> throw new IllegalArgumentException(value.getClass().getName()); + }; } // // @@ -1509,7 +1128,7 @@ private Iterable loadClassData(String path) { classFileData.add(data.toByteArray()); } } catch (IOException ex) { - throw new IllegalStateException(ex); + throw new IllegalArgumentException(ex); } return classFileData; @@ -1525,12 +1144,8 @@ private void loadVersionClasses(ClassList classes, new HashMap<>(); for (byte[] classFileData : classData) { - try (InputStream in = new ByteArrayInputStream(classFileData)) { - inspectModuleInfoClassFile(in, - currentVersionModules, version); - } catch (IOException | ConstantPoolException ex) { - throw new IllegalStateException(ex); - } + inspectModuleInfoClassFile(classFileData, + currentVersionModules, version); } ExcludeIncludeList currentEIList; @@ -1561,28 +1176,25 @@ private void loadVersionClasses(ClassList classes, try (InputStream in = new ByteArrayInputStream(classFileData)) { inspectClassFile(in, currentVersionClasses, currentEIList, version, - cf -> { - PermittedSubclasses_attribute permitted = (PermittedSubclasses_attribute) cf.getAttribute(Attribute.PermittedSubclasses); + cm -> { + var permitted = cm.findAttribute(Attributes.permittedSubclasses()).orElse(null); if (permitted != null) { - try { - String currentPack = cf.getName().substring(0, cf.getName().lastIndexOf('/')); + var name = cm.thisClass().asInternalName(); + String currentPack = name.substring(0, name.lastIndexOf('/')); - for (int i = 0; i < permitted.subtypes.length; i++) { - String permittedClassName = cf.constant_pool.getClassInfo(permitted.subtypes[i]).getName(); - if (!currentEIList.accepts(permittedClassName, false)) { - String permittedPack = permittedClassName.substring(0, permittedClassName.lastIndexOf('/')); + for (var sub : permitted.permittedSubclasses()) { + String permittedClassName = sub.asInternalName(); + if (!currentEIList.accepts(permittedClassName, false)) { + String permittedPack = permittedClassName.substring(0, permittedClassName.lastIndexOf('/')); - extraModulesPackagesToDerive.computeIfAbsent(permittedPack, x -> new HashSet<>()) - .add(currentPack); - } + extraModulesPackagesToDerive.computeIfAbsent(permittedPack, x -> new HashSet<>()) + .add(currentPack); } - } catch (ConstantPoolException ex) { - throw new IllegalStateException(ex); } } }); - } catch (IOException | ConstantPoolException ex) { - throw new IllegalStateException(ex); + } catch (IOException ex) { + throw new IllegalArgumentException(ex); } } @@ -1648,12 +1260,8 @@ private void loadVersionClassesFromDirectory(ClassList classes, Path moduleInfo = p.resolve("module-info.class"); if (Files.isReadable(moduleInfo)) { - ModuleDescription md; - - try (InputStream in = Files.newInputStream(moduleInfo)) { - md = inspectModuleInfoClassFile(in, + ModuleDescription md = inspectModuleInfoClassFile(Files.readAllBytes(moduleInfo), currentVersionModules, version); - } if (md == null) { continue; } @@ -1715,8 +1323,8 @@ private void loadVersionClassesFromDirectory(ClassList classes, } } } - } catch (IOException | ConstantPoolException ex) { - throw new IllegalStateException(ex); + } catch (IOException ex) { + throw new IllegalArgumentException(ex); } finishClassLoading(classes, modules, currentVersionModules, currentVersionClasses, currentEIList, version, baseline); @@ -1724,7 +1332,7 @@ private void loadVersionClassesFromDirectory(ClassList classes, private void loadFromDirectoryHandleClassFile(Path path, ClassList currentVersionClasses, ExcludeIncludeList currentEIList, String version, - List todo) throws IOException, ConstantPoolException { + List todo) throws IOException { try (InputStream in = Files.newInputStream(path)) { inspectClassFile(in, currentVersionClasses, currentEIList, version, @@ -2244,45 +1852,41 @@ private JavaFileManager setupJavac(String... options) { public static String PROFILE_ANNOTATION = "Ljdk/Profile+Annotation;"; public static boolean ALLOW_NON_EXISTING_CLASSES = false; - private void inspectClassFile(InputStream in, ClassList classes, ExcludeIncludeList excludesIncludes, String version) throws IOException, ConstantPoolException { + private void inspectClassFile(InputStream in, ClassList classes, ExcludeIncludeList excludesIncludes, String version) throws IOException { inspectClassFile(in, classes, excludesIncludes, version, cf -> {}); } private void inspectClassFile(InputStream in, ClassList classes, ExcludeIncludeList excludesIncludes, String version, - Consumer extraTask) throws IOException, ConstantPoolException { - ClassFile cf = ClassFile.read(in); + Consumer extraTask) throws IOException { + ClassModel cm = ClassFile.of().parse(in.readAllBytes()); - if (cf.access_flags.is(AccessFlags.ACC_MODULE)) { + if (cm.isModuleInfo()) { return ; } - if (!excludesIncludes.accepts(cf.getName(), true)) { + if (!excludesIncludes.accepts(cm.thisClass().asInternalName(), true)) { return ; } - extraTask.accept(cf); + extraTask.accept(cm); ClassHeaderDescription headerDesc = new ClassHeaderDescription(); - headerDesc.flags = cf.access_flags.flags; + headerDesc.flags = cm.flags().flagsMask(); - if (cf.super_class != 0) { - headerDesc.extendsAttr = cf.getSuperclassName(); - } - List interfaces = new ArrayList<>(); - for (int i = 0; i < cf.interfaces.length; i++) { - interfaces.add(cf.getInterfaceName(i)); + if (cm.superclass().isPresent()) { + headerDesc.extendsAttr = cm.superclass().get().asInternalName(); } - headerDesc.implementsAttr = interfaces; - for (Attribute attr : cf.attributes) { - if (!readAttribute(cf, headerDesc, attr)) + headerDesc.implementsAttr = cm.interfaces().stream().map(ClassEntry::asInternalName).collect(Collectors.toList()); + for (var attr : cm.attributes()) { + if (!readAttribute(headerDesc, attr)) return ; } ClassDescription clazzDesc = null; for (ClassDescription cd : classes) { - if (cd.name.equals(cf.getName())) { + if (cd.name.equals(cm.thisClass().asInternalName())) { clazzDesc = cd; break; } @@ -2290,54 +1894,54 @@ private void inspectClassFile(InputStream in, ClassList classes, ExcludeIncludeL if (clazzDesc == null) { clazzDesc = new ClassDescription(); - clazzDesc.name = cf.getName(); + clazzDesc.name = cm.thisClass().asInternalName(); classes.add(clazzDesc); } addClassHeader(clazzDesc, headerDesc, version, null); - for (Method m : cf.methods) { - if (!include(m.access_flags.flags)) + for (var m : cm.methods()) { + if (!include(m.flags().flagsMask())) continue; MethodDescription methDesc = new MethodDescription(); - methDesc.flags = m.access_flags.flags; - methDesc.name = m.getName(cf.constant_pool); - methDesc.descriptor = m.descriptor.getValue(cf.constant_pool); - for (Attribute attr : m.attributes) { - readAttribute(cf, methDesc, attr); + methDesc.flags = m.flags().flagsMask(); + methDesc.name = m.methodName().stringValue(); + methDesc.descriptor = m.methodType().stringValue(); + for (var attr : m.attributes()) { + readAttribute(methDesc, attr); } addMethod(clazzDesc, methDesc, version, null); } - for (Field f : cf.fields) { - if (!include(f.access_flags.flags)) + for (var f : cm.fields()) { + if (!include(f.flags().flagsMask())) continue; FieldDescription fieldDesc = new FieldDescription(); - fieldDesc.flags = f.access_flags.flags; - fieldDesc.name = f.getName(cf.constant_pool); - fieldDesc.descriptor = f.descriptor.getValue(cf.constant_pool); - for (Attribute attr : f.attributes) { - readAttribute(cf, fieldDesc, attr); + fieldDesc.flags = f.flags().flagsMask(); + fieldDesc.name = f.fieldName().stringValue(); + fieldDesc.descriptor = f.fieldType().stringValue(); + for (var attr : f.attributes()) { + readAttribute(fieldDesc, attr); } addField(clazzDesc, fieldDesc, version, null); } } - private ModuleDescription inspectModuleInfoClassFile(InputStream in, + private ModuleDescription inspectModuleInfoClassFile(byte[] data, Map modules, - String version) throws IOException, ConstantPoolException { - ClassFile cf = ClassFile.read(in); + String version) { + ClassModel cm = ClassFile.of().parse(data); - if (!cf.access_flags.is(AccessFlags.ACC_MODULE)) { + if (!cm.flags().has(AccessFlag.MODULE)) { return null; } ModuleHeaderDescription headerDesc = new ModuleHeaderDescription(); headerDesc.versions = version; - headerDesc.flags = cf.access_flags.flags; + headerDesc.flags = cm.flags().flagsMask(); - for (Attribute attr : cf.attributes) { - if (!readAttribute(cf, headerDesc, attr)) + for (var attr : cm.attributes()) { + if (!readAttribute(headerDesc, attr)) return null; } @@ -2361,56 +1965,46 @@ private Set enhancedIncludesListBasedOnClassHeaders(ClassList classes, Set additionalIncludes = new HashSet<>(); for (byte[] classFileData : classData) { - try (InputStream in = new ByteArrayInputStream(classFileData)) { - ClassFile cf = ClassFile.read(in); - - additionalIncludes.addAll(otherRelevantTypesWithOwners(cf)); - } catch (IOException | ConstantPoolException ex) { - throw new IllegalStateException(ex); - } + additionalIncludes.addAll(otherRelevantTypesWithOwners(ClassFile.of().parse(classFileData))); } return additionalIncludes; } - private Set otherRelevantTypesWithOwners(ClassFile cf) { + private Set otherRelevantTypesWithOwners(ClassModel cm) { Set supertypes = new HashSet<>(); - try { - if (cf.access_flags.is(AccessFlags.ACC_MODULE)) { - return supertypes; - } + if (cm.flags().has(AccessFlag.MODULE)) { + return supertypes; + } - Set additionalClasses = new HashSet<>(); + Set additionalClasses = new HashSet<>(); - if (cf.super_class != 0) { - additionalClasses.add(cf.getSuperclassName()); - } - for (int i = 0; i < cf.interfaces.length; i++) { - additionalClasses.add(cf.getInterfaceName(i)); - } - PermittedSubclasses_attribute permitted = (PermittedSubclasses_attribute) cf.getAttribute(Attribute.PermittedSubclasses); - if (permitted != null) { - for (int i = 0; i < permitted.subtypes.length; i++) { - additionalClasses.add(cf.constant_pool.getClassInfo(permitted.subtypes[i]).getName()); - } + if (cm.superclass().isPresent()) { + additionalClasses.add(cm.superclass().get().asInternalName()); + } + for (var iface : cm.interfaces()) { + additionalClasses.add(iface.asInternalName()); + } + var permitted = cm.findAttribute(Attributes.permittedSubclasses()).orElse(null); + if (permitted != null) { + for (var sub : permitted.permittedSubclasses()) { + additionalClasses.add(sub.asInternalName()); } + } - for (String additional : additionalClasses) { - int dollar; + for (String additional : additionalClasses) { + int dollar; - supertypes.add(additional); + supertypes.add(additional); - while ((dollar = additional.lastIndexOf('$')) != (-1)) { - additional = additional.substring(0, dollar); - supertypes.add(additional); - } + while ((dollar = additional.lastIndexOf('$')) != (-1)) { + additional = additional.substring(0, dollar); + supertypes.add(additional); } - - return supertypes; - } catch (ConstantPoolException ex) { - throw new IllegalStateException(ex); } + + return supertypes; } private void addModuleHeader(ModuleDescription moduleDesc, @@ -2435,7 +2029,7 @@ private void addModuleHeader(ModuleDescription moduleDesc, } private boolean include(int accessFlags) { - return (accessFlags & (AccessFlags.ACC_PUBLIC | AccessFlags.ACC_PROTECTED)) != 0; + return (accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) != 0; } private void addClassHeader(ClassDescription clazzDesc, ClassHeaderDescription headerDesc, String version, String baseline) { @@ -2531,367 +2125,135 @@ private void addField(ClassDescription clazzDesc, FieldDescription fieldDesc, St } } - private boolean readAttribute(ClassFile cf, FeatureDescription feature, Attribute attr) throws ConstantPoolException { - String attrName = attr.getName(cf.constant_pool); - switch (attrName) { - case Attribute.AnnotationDefault: - assert feature instanceof MethodDescription; - element_value defaultValue = ((AnnotationDefault_attribute) attr).default_value; - ((MethodDescription) feature).annotationDefaultValue = - convertElementValue(cf.constant_pool, defaultValue); - break; - case "Deprecated": - feature.deprecated = true; - break; - case "Exceptions": - assert feature instanceof MethodDescription; - List thrownTypes = new ArrayList<>(); - Exceptions_attribute exceptionAttr = (Exceptions_attribute) attr; - for (int i = 0; i < exceptionAttr.exception_index_table.length; i++) { - thrownTypes.add(exceptionAttr.getException(i, cf.constant_pool)); - } - ((MethodDescription) feature).thrownTypes = thrownTypes; - break; - case Attribute.InnerClasses: + private boolean readAttribute(FeatureDescription feature, Attribute attr) { + switch (attr) { + case AnnotationDefaultAttribute a -> + ((MethodDescription) feature).annotationDefaultValue = convertElementValue(a.defaultValue()); + case DeprecatedAttribute _ -> feature.deprecated = true; + case ExceptionsAttribute a -> ((MethodDescription) feature).thrownTypes = a.exceptions().stream().map(ClassEntry::asInternalName).collect(Collectors.toList()); + case InnerClassesAttribute a -> { if (feature instanceof ModuleHeaderDescription) break; //XXX - assert feature instanceof ClassHeaderDescription; - List innerClasses = new ArrayList<>(); - InnerClasses_attribute innerClassesAttr = (InnerClasses_attribute) attr; - for (int i = 0; i < innerClassesAttr.number_of_classes; i++) { - CONSTANT_Class_info outerClassInfo = - innerClassesAttr.classes[i].getOuterClassInfo(cf.constant_pool); - InnerClassInfo info = new InnerClassInfo(); - CONSTANT_Class_info innerClassInfo = - innerClassesAttr.classes[i].getInnerClassInfo(cf.constant_pool); - info.innerClass = innerClassInfo != null ? innerClassInfo.getName() : null; - info.outerClass = outerClassInfo != null ? outerClassInfo.getName() : null; - info.innerClassName = innerClassesAttr.classes[i].getInnerName(cf.constant_pool); - info.innerClassFlags = innerClassesAttr.classes[i].inner_class_access_flags.flags; - innerClasses.add(info); - } - ((ClassHeaderDescription) feature).innerClasses = innerClasses; - break; - case "RuntimeInvisibleAnnotations": - feature.classAnnotations = annotations2Description(cf.constant_pool, attr); - break; - case "RuntimeVisibleAnnotations": - feature.runtimeAnnotations = annotations2Description(cf.constant_pool, attr); - break; - case "Signature": - feature.signature = ((Signature_attribute) attr).getSignature(cf.constant_pool); - break; - case "ConstantValue": - assert feature instanceof FieldDescription; - Object value = convertConstantValue(cf.constant_pool.get(((ConstantValue_attribute) attr).constantvalue_index), ((FieldDescription) feature).descriptor); - if (((FieldDescription) feature).descriptor.equals("C")) { - value = (char) (int) value; - } - ((FieldDescription) feature).constantValue = value; - break; - case "SourceFile": - //ignore, not needed - break; - case "BootstrapMethods": - //ignore, not needed - break; - case "Code": - //ignore, not needed - break; - case "EnclosingMethod": + ((ClassHeaderDescription) feature).innerClasses = a.classes().stream().map(cfi -> { + var info = new InnerClassInfo(); + info.innerClass = cfi.innerClass().asInternalName(); + info.outerClass = cfi.outerClass().map(ClassEntry::asInternalName).orElse(null); + info.innerClassName = cfi.innerName().map(Utf8Entry::stringValue).orElse(null); + info.innerClassFlags = cfi.flagsMask(); + return info; + }).collect(Collectors.toList()); + } + case RuntimeInvisibleAnnotationsAttribute a -> feature.classAnnotations = annotations2Description(a.annotations()); + case RuntimeVisibleAnnotationsAttribute a -> feature.runtimeAnnotations = annotations2Description(a.annotations()); + case SignatureAttribute a -> feature.signature = a.signature().stringValue(); + case ConstantValueAttribute a -> { + var f = (FieldDescription) feature; + f.constantValue = convertConstantValue(a.constant(), f.descriptor); + } + case SourceFileAttribute _, BootstrapMethodsAttribute _, CodeAttribute _, SyntheticAttribute _ -> {} + case EnclosingMethodAttribute _ -> { return false; - case "Synthetic": - break; - case "RuntimeVisibleParameterAnnotations": - assert feature instanceof MethodDescription; - ((MethodDescription) feature).runtimeParameterAnnotations = - parameterAnnotations2Description(cf.constant_pool, attr); - break; - case "RuntimeInvisibleParameterAnnotations": - assert feature instanceof MethodDescription; - ((MethodDescription) feature).classParameterAnnotations = - parameterAnnotations2Description(cf.constant_pool, attr); - break; - case Attribute.Module: { - assert feature instanceof ModuleHeaderDescription; - ModuleHeaderDescription header = - (ModuleHeaderDescription) feature; - Module_attribute mod = (Module_attribute) attr; - - header.name = cf.constant_pool - .getModuleInfo(mod.module_name) - .getName(); - - header.exports = - Arrays.stream(mod.exports) - .map(ee -> ExportsDescription.create(cf, ee)) - .collect(Collectors.toList()); + } + case RuntimeVisibleParameterAnnotationsAttribute a -> ((MethodDescription) feature).runtimeParameterAnnotations = parameterAnnotations2Description(a.parameterAnnotations()); + case RuntimeInvisibleParameterAnnotationsAttribute a -> ((MethodDescription) feature).classParameterAnnotations = parameterAnnotations2Description(a.parameterAnnotations()); + case ModuleAttribute a -> { + ModuleHeaderDescription header = (ModuleHeaderDescription) feature; + header.name = a.moduleName().name().stringValue(); + header.exports = a.exports().stream().map(ExportsDescription::create).collect(Collectors.toList()); if (header.extraModulePackages != null) { header.exports.forEach(ed -> header.extraModulePackages.remove(ed.packageName())); } - header.requires = - Arrays.stream(mod.requires) - .map(r -> RequiresDescription.create(cf, r)) - .collect(Collectors.toList()); - header.uses = Arrays.stream(mod.uses_index) - .mapToObj(use -> getClassName(cf, use)) - .collect(Collectors.toList()); - header.provides = - Arrays.stream(mod.provides) - .map(p -> ProvidesDescription.create(cf, p)) - .collect(Collectors.toList()); - break; - } - case Attribute.ModuleTarget: { - assert feature instanceof ModuleHeaderDescription; - ModuleHeaderDescription header = - (ModuleHeaderDescription) feature; - ModuleTarget_attribute mod = (ModuleTarget_attribute) attr; - if (mod.target_platform_index != 0) { - header.moduleTarget = - cf.constant_pool - .getUTF8Value(mod.target_platform_index); - } - break; - } - case Attribute.ModuleResolution: { - assert feature instanceof ModuleHeaderDescription; - ModuleHeaderDescription header = - (ModuleHeaderDescription) feature; - ModuleResolution_attribute mod = - (ModuleResolution_attribute) attr; - header.moduleResolution = mod.resolution_flags; - break; - } - case Attribute.ModulePackages: - assert feature instanceof ModuleHeaderDescription; - ModuleHeaderDescription header = - (ModuleHeaderDescription) feature; - ModulePackages_attribute mod = - (ModulePackages_attribute) attr; - header.extraModulePackages = new ArrayList<>(); - for (int i = 0; i < mod.packages_count; i++) { - String packageName = getPackageName(cf, mod.packages_index[i]); + header.requires = a.requires().stream().map(RequiresDescription::create).collect(Collectors.toList()); + header.uses = a.uses().stream().map(ClassEntry::asInternalName).collect(Collectors.toList()); + header.provides = a.provides().stream().map(ProvidesDescription::create).collect(Collectors.toList()); + } + case ModuleTargetAttribute a -> ((ModuleHeaderDescription) feature).moduleTarget = a.targetPlatform().stringValue(); + case ModuleResolutionAttribute a -> ((ModuleHeaderDescription) feature).moduleResolution = a.resolutionFlags(); + case ModulePackagesAttribute a -> { + var header = (ModuleHeaderDescription) feature; + header.extraModulePackages = a.packages().stream().mapMulti((packageItem, sink) -> { + var packageName = packageItem.name().stringValue(); if (header.exports == null || - header.exports.stream().noneMatch(ed -> ed.packageName().equals(packageName))) { - header.extraModulePackages.add(packageName); + header.exports.stream().noneMatch(ed -> ed.packageName().equals(packageName))) { + sink.accept(packageName); } - } - break; - case Attribute.ModuleHashes: - break; - case Attribute.NestHost: { - assert feature instanceof ClassHeaderDescription; - NestHost_attribute nestHost = (NestHost_attribute) attr; - ClassHeaderDescription chd = (ClassHeaderDescription) feature; - chd.nestHost = nestHost.getNestTop(cf.constant_pool).getName(); - break; - } - case Attribute.NestMembers: { - assert feature instanceof ClassHeaderDescription; - NestMembers_attribute nestMembers = (NestMembers_attribute) attr; - ClassHeaderDescription chd = (ClassHeaderDescription) feature; - chd.nestMembers = Arrays.stream(nestMembers.members_indexes) - .mapToObj(i -> getClassName(cf, i)) - .collect(Collectors.toList()); - break; + }).collect(Collectors.toList()); } - case Attribute.Record: { - assert feature instanceof ClassHeaderDescription; - Record_attribute record = (Record_attribute) attr; - List components = new ArrayList<>(); - for (ComponentInfo info : record.component_info_arr) { - RecordComponentDescription rcd = new RecordComponentDescription(); - rcd.name = info.getName(cf.constant_pool); - rcd.descriptor = info.descriptor.getValue(cf.constant_pool); - for (Attribute nestedAttr : info.attributes) { - readAttribute(cf, rcd, nestedAttr); - } - components.add(rcd); - } - ClassHeaderDescription chd = (ClassHeaderDescription) feature; + case ModuleHashesAttribute _ -> {} + case NestHostAttribute a -> ((ClassHeaderDescription) feature).nestHost = a.nestHost().asInternalName(); + case NestMembersAttribute a -> ((ClassHeaderDescription) feature).nestMembers = a.nestMembers().stream().map(ClassEntry::asInternalName).collect(Collectors.toList()); + case RecordAttribute a -> { + var chd = (ClassHeaderDescription) feature; chd.isRecord = true; - chd.recordComponents = components; - break; - } - case Attribute.MethodParameters: { - assert feature instanceof MethodDescription; - MethodParameters_attribute params = (MethodParameters_attribute) attr; - MethodDescription method = (MethodDescription) feature; - method.methodParameters = new ArrayList<>(); - for (MethodParameters_attribute.Entry e : params.method_parameter_table) { - String name = e.name_index == 0 ? null - : cf.constant_pool.getUTF8Value(e.name_index); - MethodDescription.MethodParam param = - new MethodDescription.MethodParam(e.flags, name); - method.methodParameters.add(param); - } - break; - } - case Attribute.PermittedSubclasses: { - assert feature instanceof ClassHeaderDescription; - PermittedSubclasses_attribute permittedSubclasses = (PermittedSubclasses_attribute) attr; - ClassHeaderDescription chd = (ClassHeaderDescription) feature; - chd.permittedSubclasses = Arrays.stream(permittedSubclasses.subtypes) - .mapToObj(i -> getClassName(cf, i)) - .collect(Collectors.toList()); + chd.recordComponents = a.components().stream().map(rci -> { + var rcd = new RecordComponentDescription(); + rcd.name = rci.name().stringValue(); + rcd.descriptor = rci.descriptor().stringValue(); + rci.attributes().forEach(child -> readAttribute(rcd, child)); + return rcd; + }).collect(Collectors.toList()); + } + case MethodParametersAttribute a -> ((MethodDescription) feature).methodParameters = a.parameters().stream() + .map(mpi -> new MethodDescription.MethodParam(mpi.flagsMask(), mpi.name().map(Utf8Entry::stringValue).orElse(null))) + .collect(Collectors.toList()); + case PermittedSubclassesAttribute a -> { + var chd = (ClassHeaderDescription) feature; chd.isSealed = true; - break; + chd.permittedSubclasses = a.permittedSubclasses().stream().map(ClassEntry::asInternalName).collect(Collectors.toList()); } - case Attribute.ModuleMainClass: { - ModuleMainClass_attribute moduleMainClass = (ModuleMainClass_attribute) attr; - assert feature instanceof ModuleHeaderDescription; - ModuleHeaderDescription mhd = (ModuleHeaderDescription) feature; - mhd.moduleMainClass = moduleMainClass.getMainClassName(cf.constant_pool); - break; - } - default: - throw new IllegalStateException("Unhandled attribute: " + - attrName); + case ModuleMainClassAttribute a -> ((ModuleHeaderDescription) feature).moduleMainClass = a.mainClass().asInternalName(); + default -> throw new IllegalArgumentException("Unhandled attribute: " + attr.attributeName()); // Do nothing } return true; } - private static String getClassName(ClassFile cf, int idx) { - try { - return cf.constant_pool.getClassInfo(idx).getName(); - } catch (InvalidIndex ex) { - throw new IllegalStateException(ex); - } catch (ConstantPool.UnexpectedEntry ex) { - throw new IllegalStateException(ex); - } catch (ConstantPoolException ex) { - throw new IllegalStateException(ex); - } - } - - private static String getPackageName(ClassFile cf, int idx) { - try { - return cf.constant_pool.getPackageInfo(idx).getName(); - } catch (InvalidIndex ex) { - throw new IllegalStateException(ex); - } catch (ConstantPool.UnexpectedEntry ex) { - throw new IllegalStateException(ex); - } catch (ConstantPoolException ex) { - throw new IllegalStateException(ex); - } - } - - private static String getModuleName(ClassFile cf, int idx) { - try { - return cf.constant_pool.getModuleInfo(idx).getName(); - } catch (InvalidIndex ex) { - throw new IllegalStateException(ex); - } catch (ConstantPool.UnexpectedEntry ex) { - throw new IllegalStateException(ex); - } catch (ConstantPoolException ex) { - throw new IllegalStateException(ex); - } - } - public static String INJECTED_VERSION = null; - private static String getVersion(ClassFile cf, int idx) { + private static String getVersion(Optional version) { if (INJECTED_VERSION != null) { return INJECTED_VERSION; } - if (idx == 0) - return null; - try { - return ((CONSTANT_Utf8_info) cf.constant_pool.get(idx)).value; - } catch (InvalidIndex ex) { - throw new IllegalStateException(ex); - } + return version.map(Utf8Entry::stringValue).orElse(null); } - Object convertConstantValue(CPInfo info, String descriptor) throws ConstantPoolException { - if (info instanceof CONSTANT_Integer_info) { - if ("Z".equals(descriptor)) - return ((CONSTANT_Integer_info) info).value == 1; - else - return ((CONSTANT_Integer_info) info).value; - } else if (info instanceof CONSTANT_Long_info) { - return ((CONSTANT_Long_info) info).value; - } else if (info instanceof CONSTANT_Float_info) { - return ((CONSTANT_Float_info) info).value; - } else if (info instanceof CONSTANT_Double_info) { - return ((CONSTANT_Double_info) info).value; - } else if (info instanceof CONSTANT_String_info) { - return ((CONSTANT_String_info) info).getString(); - } - throw new IllegalStateException(info.getClass().getName()); + Object convertConstantValue(ConstantValueEntry info, String descriptor) { + if (descriptor.length() == 1 && info instanceof IntegerEntry ie) { + var i = ie.intValue(); + return switch (descriptor.charAt(0)) { + case 'I', 'B', 'S' -> i; + case 'C' -> (char) i; + case 'Z' -> i == 1; + default -> throw new IllegalArgumentException(descriptor); + }; + } + return info.constantValue(); } - Object convertElementValue(ConstantPool cp, element_value val) throws InvalidIndex, ConstantPoolException { - switch (val.tag) { - case 'Z': - return ((CONSTANT_Integer_info) cp.get(((Primitive_element_value) val).const_value_index)).value != 0; - case 'B': - return (byte) ((CONSTANT_Integer_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - case 'C': - return (char) ((CONSTANT_Integer_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - case 'S': - return (short) ((CONSTANT_Integer_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - case 'I': - return ((CONSTANT_Integer_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - case 'J': - return ((CONSTANT_Long_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - case 'F': - return ((CONSTANT_Float_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - case 'D': - return ((CONSTANT_Double_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - case 's': - return ((CONSTANT_Utf8_info) cp.get(((Primitive_element_value) val).const_value_index)).value; - - case 'e': - return new EnumConstant(cp.getUTF8Value(((Enum_element_value) val).type_name_index), - cp.getUTF8Value(((Enum_element_value) val).const_name_index)); - case 'c': - return new ClassConstant(cp.getUTF8Value(((Class_element_value) val).class_info_index)); - - case '@': - return annotation2Description(cp, ((Annotation_element_value) val).annotation_value); - - case '[': - List values = new ArrayList<>(); - for (element_value elem : ((Array_element_value) val).values) { - values.add(convertElementValue(cp, elem)); - } - return values; - default: - throw new IllegalStateException("Currently unhandled tag: " + val.tag); - } + Object convertElementValue(AnnotationValue val) { + return switch (val) { + case AnnotationValue.OfConstant oc -> oc.resolvedValue(); + case AnnotationValue.OfEnum oe -> new EnumConstant(oe.className().stringValue(), oe.constantName().stringValue()); + case AnnotationValue.OfClass oc -> new ClassConstant(oc.className().stringValue()); + case AnnotationValue.OfArray oa -> oa.values().stream().map(this::convertElementValue).collect(Collectors.toList()); + case AnnotationValue.OfAnnotation oa -> annotation2Description(oa.annotation()); + }; } - private List annotations2Description(ConstantPool cp, Attribute attr) throws ConstantPoolException { - RuntimeAnnotations_attribute annotationsAttr = (RuntimeAnnotations_attribute) attr; - List descs = new ArrayList<>(); - for (Annotation a : annotationsAttr.annotations) { - descs.add(annotation2Description(cp, a)); - } - return descs; + private List annotations2Description(List annos) { + return annos.stream().map(this::annotation2Description).collect(Collectors.toList()); } - private List> parameterAnnotations2Description(ConstantPool cp, Attribute attr) throws ConstantPoolException { - RuntimeParameterAnnotations_attribute annotationsAttr = - (RuntimeParameterAnnotations_attribute) attr; - List> descs = new ArrayList<>(); - for (Annotation[] attrAnnos : annotationsAttr.parameter_annotations) { - List paramDescs = new ArrayList<>(); - for (Annotation ann : attrAnnos) { - paramDescs.add(annotation2Description(cp, ann)); - } - descs.add(paramDescs); - } - return descs; + private List> parameterAnnotations2Description(List> annos) { + return annos.stream().map(this::annotations2Description).collect(Collectors.toList()); } - private AnnotationDescription annotation2Description(ConstantPool cp, Annotation a) throws ConstantPoolException { - String annotationType = cp.getUTF8Value(a.type_index); + private AnnotationDescription annotation2Description(java.lang.classfile.Annotation a) { + String annotationType = a.className().stringValue(); Map values = new HashMap<>(); - for (element_value_pair e : a.element_value_pairs) { - values.put(cp.getUTF8Value(e.element_name_index), convertElementValue(cp, e.value)); + for (var e : a.elements()) { + values.put(e.name().stringValue(), convertElementValue(e.value())); } return new AnnotationDescription(annotationType, values); @@ -3181,7 +2543,7 @@ public void read(LineBasedReader reader, String baselineVersion, case "-module": break OUTER; default: - throw new IllegalStateException(reader.lineKey); + throw new IllegalArgumentException(reader.lineKey); } } } @@ -3396,15 +2758,11 @@ public static ExportsDescription deserialize(String data) { return new ExportsDescription(packageName, to); } - public static ExportsDescription create(ClassFile cf, - ExportsEntry ee) { - String packageName = getPackageName(cf, ee.exports_index); + public static ExportsDescription create(ModuleExportInfo ee) { + String packageName = ee.exportedPackage().name().stringValue(); List to = null; - if (ee.exports_to_count > 0) { - to = new ArrayList<>(); - for (int moduleIndex : ee.exports_to_index) { - to.add(getModuleName(cf, moduleIndex)); - } + if (!ee.exportsTo().isEmpty()) { + to = ee.exportsTo().stream().map(m -> m.name().stringValue()).collect(Collectors.toList()); } return new ExportsDescription(packageName, to); } @@ -3447,12 +2805,11 @@ public static RequiresDescription deserialize(String data) { ver); } - public static RequiresDescription create(ClassFile cf, - RequiresEntry req) { - String mod = getModuleName(cf, req.requires_index); - String ver = getVersion(cf, req.requires_version_index); + public static RequiresDescription create(ModuleRequireInfo req) { + String mod = req.requires().name().stringValue(); + String ver = getVersion(req.requiresVersion()); return new RequiresDescription(mod, - req.requires_flags, + req.requiresFlagsMask(), ver); } @@ -3515,13 +2872,9 @@ public static ProvidesDescription deserialize(String data) { implsList); } - public static ProvidesDescription create(ClassFile cf, - ProvidesEntry prov) { - String api = getClassName(cf, prov.provides_index); - List impls = - Arrays.stream(prov.with_index) - .mapToObj(wi -> getClassName(cf, wi)) - .collect(Collectors.toList()); + public static ProvidesDescription create(ModuleProvideInfo prov) { + String api = prov.provides().asInternalName(); + List impls = prov.providesWith().stream().map(ClassEntry::asInternalName).collect(Collectors.toList()); return new ProvidesDescription(api, impls); } @@ -3676,7 +3029,7 @@ public void read(LineBasedReader reader, String baselineVersion, case "-module": break OUTER; default: - throw new IllegalStateException(reader.lineKey); + throw new IllegalArgumentException(reader.lineKey); } } } @@ -4073,7 +3426,7 @@ public MethodParam(int flags, String name) { static class FieldDescription extends FeatureDescription { String name; String descriptor; - Object constantValue; + Object constantValue; // Uses (unsigned) Integer for byte/short String keyName = "field"; @Override @@ -4149,7 +3502,7 @@ public boolean read(LineBasedReader reader) throws IOException { case "D": constantValue = Double.parseDouble(inConstantValue); break; case "Ljava/lang/String;": constantValue = inConstantValue; break; default: - throw new IllegalStateException("Unrecognized field type: " + descriptor); + throw new IllegalArgumentException("Unrecognized field type: " + descriptor); } } @@ -4416,7 +3769,7 @@ public ClassDescription find(String name, boolean allowNull) { if (desc != null || allowNull) return desc; - throw new IllegalStateException("Cannot find: " + name); + throw new IllegalArgumentException("Cannot find: " + name); } private static final ClassDescription NONE = new ClassDescription(); @@ -4565,7 +3918,7 @@ private static Object parseAnnotationValue(String value, int[] valuePointer) { valuePointer[0] += 5; return false; } else { - throw new IllegalStateException("Unrecognized boolean structure: " + value); + throw new IllegalArgumentException("Unrecognized boolean structure: " + value); } case 'B': return Byte.parseByte(readDigits(value, valuePointer)); case 'C': return value.charAt(valuePointer[0]++); @@ -4593,7 +3946,7 @@ private static Object parseAnnotationValue(String value, int[] valuePointer) { case '@': return parseAnnotation(value, valuePointer); default: - throw new IllegalStateException("Unrecognized signature type: " + value.charAt(valuePointer[0] - 1) + "; value=" + value); + throw new IllegalArgumentException("Unrecognized signature type: " + value.charAt(valuePointer[0] - 1) + "; value=" + value); } } diff --git a/make/modules/jdk.compiler/Gendata.gmk b/make/modules/jdk.compiler/Gendata.gmk index 739625a5732a1..5bbd28b803794 100644 --- a/make/modules/jdk.compiler/Gendata.gmk +++ b/make/modules/jdk.compiler/Gendata.gmk @@ -53,7 +53,6 @@ COMPILECREATESYMBOLS_ADD_EXPORTS := \ --add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \ - --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \ # # TODO: Unify with jdk.javadoc-gendata. Should only compile this once and share. diff --git a/make/scripts/generate-symbol-data.sh b/make/scripts/generate-symbol-data.sh index 015beb582fdaf..6f38d8730093c 100644 --- a/make/scripts/generate-symbol-data.sh +++ b/make/scripts/generate-symbol-data.sh @@ -68,8 +68,7 @@ if [ "`git status --porcelain=v1 .`x" != "x" ] ; then exit 1 fi; -$1/bin/java --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \ - --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ +$1/bin/java --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \ --add-modules jdk.jdeps \ diff --git a/test/langtools/tools/javac/platform/CanHandleClassFilesTest.java b/test/langtools/tools/javac/platform/CanHandleClassFilesTest.java index a8d4747babb2d..f91d9ea02b186 100644 --- a/test/langtools/tools/javac/platform/CanHandleClassFilesTest.java +++ b/test/langtools/tools/javac/platform/CanHandleClassFilesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.compiler/com.sun.tools.javac.jvm:+open * jdk.compiler/com.sun.tools.javac.util:+open - * jdk.jdeps/com.sun.tools.classfile:+open * @build toolbox.ToolBox toolbox.JavacTask toolbox.Task * @run main CanHandleClassFilesTest */ @@ -76,8 +75,7 @@ void run() throws Exception { try (ToolBox.MemoryFileManager mfm = new ToolBox.MemoryFileManager()) { ToolBox tb = new ToolBox(); new JavacTask(tb) - .options("--add-exports", "jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", + .options("--add-exports", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", "--add-modules", "jdk.jdeps") @@ -102,8 +100,7 @@ protected Class findClass(String name) throws ClassNotFoundException { Module targetModule = cl.getUnnamedModule(); Stream.of("jdk.compiler/com.sun.tools.javac.api", "jdk.compiler/com.sun.tools.javac.jvm", - "jdk.compiler/com.sun.tools.javac.util", - "jdk.jdeps/com.sun.tools.classfile") + "jdk.compiler/com.sun.tools.javac.util") .forEach(p -> open(p, targetModule)); var createSymbolsClass = Class.forName("build.tools.symbolgenerator.CreateSymbols", false, cl); diff --git a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTest.java b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTest.java index 97def1b148003..76c13582b73cd 100644 --- a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTest.java +++ b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * jdk.compiler/com.sun.tools.javac.jvm * jdk.compiler/com.sun.tools.javac.main * jdk.compiler/com.sun.tools.javac.util - * jdk.jdeps/com.sun.tools.classfile * @clean * * @run main/othervm CreateSymbolsTest */ @@ -107,8 +106,7 @@ void doRun() throws Exception { "--add-exports", "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", - "--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", - "--add-exports", "jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED"), + "--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED"), null, fm.getJavaFileObjectsFromPaths(files) ).call(); From 567c6885a377e5641deef9cd3498f79c5346cd6a Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 9 Apr 2025 15:03:38 +0000 Subject: [PATCH 0495/1101] 8353597: Refactor handling VM options for AOT cache input and output Reviewed-by: kvn, asmehra --- src/hotspot/share/cds/cdsConfig.cpp | 195 ++++++++++++------ src/hotspot/share/cds/cdsConfig.hpp | 44 ++-- src/hotspot/share/cds/dynamicArchive.cpp | 28 +-- src/hotspot/share/cds/dynamicArchive.hpp | 3 +- src/hotspot/share/cds/filemap.cpp | 19 +- src/hotspot/share/cds/filemap.hpp | 8 +- src/hotspot/share/cds/metaspaceShared.cpp | 26 +-- src/hotspot/share/cds/metaspaceShared.hpp | 1 - src/hotspot/share/memory/universe.cpp | 3 +- src/hotspot/share/runtime/arguments.cpp | 2 +- src/hotspot/share/runtime/java.cpp | 3 +- .../share/native/libsaproc/ps_core_common.c | 6 +- .../jtreg/runtime/cds/appcds/AOTFlags.java | 56 +++++ .../TestAutoCreateSharedArchive.java | 2 +- ...toCreateSharedArchiveNoDefaultArchive.java | 6 +- 15 files changed, 254 insertions(+), 148 deletions(-) diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index 47613e090086c..64ad07b0cf816 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -51,9 +51,10 @@ bool CDSConfig::_old_cds_flags_used = false; bool CDSConfig::_new_aot_flags_used = false; bool CDSConfig::_disable_heap_dumping = false; -char* CDSConfig::_default_archive_path = nullptr; -char* CDSConfig::_static_archive_path = nullptr; -char* CDSConfig::_dynamic_archive_path = nullptr; +const char* CDSConfig::_default_archive_path = nullptr; +const char* CDSConfig::_input_static_archive_path = nullptr; +const char* CDSConfig::_input_dynamic_archive_path = nullptr; +const char* CDSConfig::_output_archive_path = nullptr; JavaThread* CDSConfig::_dumper_thread = nullptr; @@ -66,7 +67,11 @@ int CDSConfig::get_status() { (is_using_archive() ? IS_USING_ARCHIVE : 0); } -void CDSConfig::initialize() { +DEBUG_ONLY(static bool _cds_ergo_initialize_started = false); + +void CDSConfig::ergo_initialize() { + DEBUG_ONLY(_cds_ergo_initialize_started = true); + if (is_dumping_static_archive() && !is_dumping_final_static_archive()) { // Note: -Xshare and -XX:AOTMode flags are mutually exclusive. // - Classic workflow: -Xshare:on and -Xshare:dump cannot take effect at the same time. @@ -83,10 +88,12 @@ void CDSConfig::initialize() { // Initialize shared archive paths which could include both base and dynamic archive paths // This must be after set_ergonomics_flags() called so flag UseCompressedOops is set properly. - // - // UseSharedSpaces may be disabled if -XX:SharedArchiveFile is invalid. if (is_dumping_static_archive() || is_using_archive()) { - init_shared_archive_paths(); + if (new_aot_flags_used()) { + ergo_init_aot_paths(); + } else { + ergo_init_classic_archive_paths(); + } } if (!is_dumping_heap()) { @@ -94,7 +101,10 @@ void CDSConfig::initialize() { } } -char* CDSConfig::default_archive_path() { +const char* CDSConfig::default_archive_path() { + // The path depends on UseCompressedOops, etc, which are set by GC ergonomics just + // before CDSConfig::ergo_initialize() is called. + assert(_cds_ergo_initialize_started, "sanity"); if (_default_archive_path == nullptr) { stringStream tmp; const char* subdir = WINDOWS_ONLY("bin") NOT_WINDOWS("lib"); @@ -116,12 +126,12 @@ char* CDSConfig::default_archive_path() { return _default_archive_path; } -int CDSConfig::num_archives(const char* archive_path) { - if (archive_path == nullptr) { +int CDSConfig::num_archive_paths(const char* path_spec) { + if (path_spec == nullptr) { return 0; } int npaths = 1; - char* p = (char*)archive_path; + char* p = (char*)path_spec; while (*p != '\0') { if (*p == os::path_separator()[0]) { npaths++; @@ -131,9 +141,9 @@ int CDSConfig::num_archives(const char* archive_path) { return npaths; } -void CDSConfig::extract_shared_archive_paths(const char* archive_path, - char** base_archive_path, - char** top_archive_path) { +void CDSConfig::extract_archive_paths(const char* archive_path, + const char** base_archive_path, + const char** top_archive_path) { char* begin_ptr = (char*)archive_path; char* end_ptr = strchr((char*)archive_path, os::path_separator()[0]); if (end_ptr == nullptr || end_ptr == begin_ptr) { @@ -157,7 +167,8 @@ void CDSConfig::extract_shared_archive_paths(const char* archive_path, *top_archive_path = cur_path; } -void CDSConfig::init_shared_archive_paths() { +void CDSConfig::ergo_init_classic_archive_paths() { + assert(_cds_ergo_initialize_started, "sanity"); if (ArchiveClassesAtExit != nullptr) { assert(!RecordDynamicDumpInfo, "already checked"); if (is_dumping_static_archive()) { @@ -172,21 +183,24 @@ void CDSConfig::init_shared_archive_paths() { } if (SharedArchiveFile == nullptr) { - _static_archive_path = default_archive_path(); + _input_static_archive_path = default_archive_path(); + if (is_dumping_static_archive()) { + _output_archive_path = _input_static_archive_path; + } } else { - int archives = num_archives(SharedArchiveFile); - assert(archives > 0, "must be"); + int num_archives = num_archive_paths(SharedArchiveFile); + assert(num_archives > 0, "must be"); - if (is_dumping_archive() && archives > 1) { + if (is_dumping_archive() && num_archives > 1) { vm_exit_during_initialization( "Cannot have more than 1 archive file specified in -XX:SharedArchiveFile during CDS dumping"); } if (is_dumping_static_archive()) { - assert(archives == 1, "must be"); + assert(num_archives == 1, "just checked above"); // Static dump is simple: only one archive is allowed in SharedArchiveFile. This file - // will be overwritten no matter regardless of its contents - _static_archive_path = os::strdup_check_oom(SharedArchiveFile, mtArguments); + // will be overwritten regardless of its contents + _output_archive_path = SharedArchiveFile; } else { // SharedArchiveFile may specify one or two files. In case (c), the path for base.jsa // is read from top.jsa @@ -197,48 +211,49 @@ void CDSConfig::init_shared_archive_paths() { // However, if either RecordDynamicDumpInfo or ArchiveClassesAtExit is used, we do not // allow cases (b) and (c). Case (b) is already checked above. - if (archives > 2) { + if (num_archives > 2) { vm_exit_during_initialization( "Cannot have more than 2 archive files specified in the -XX:SharedArchiveFile option"); } - if (archives == 1) { - char* base_archive_path = nullptr; + + if (num_archives == 1) { + const char* base_archive_path = nullptr; bool success = FileMapInfo::get_base_archive_name_from_header(SharedArchiveFile, &base_archive_path); if (!success) { // If +AutoCreateSharedArchive and the specified shared archive does not exist, // regenerate the dynamic archive base on default archive. if (AutoCreateSharedArchive && !os::file_exists(SharedArchiveFile)) { - enable_dumping_dynamic_archive(); - ArchiveClassesAtExit = const_cast(SharedArchiveFile); - _static_archive_path = default_archive_path(); - SharedArchiveFile = nullptr; - } else { + enable_dumping_dynamic_archive(SharedArchiveFile); + FLAG_SET_ERGO(ArchiveClassesAtExit, SharedArchiveFile); + _input_static_archive_path = default_archive_path(); + FLAG_SET_ERGO(SharedArchiveFile, nullptr); + } else { if (AutoCreateSharedArchive) { warning("-XX:+AutoCreateSharedArchive is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info."); AutoCreateSharedArchive = false; } - log_error(cds)("Not a valid %s (%s)", new_aot_flags_used() ? "AOT cache" : "archive", SharedArchiveFile); + log_error(cds)("Not a valid archive (%s)", SharedArchiveFile); Arguments::no_shared_spaces("invalid archive"); } } else if (base_archive_path == nullptr) { // User has specified a single archive, which is a static archive. - _static_archive_path = const_cast(SharedArchiveFile); + _input_static_archive_path = SharedArchiveFile; } else { // User has specified a single archive, which is a dynamic archive. - _dynamic_archive_path = const_cast(SharedArchiveFile); - _static_archive_path = base_archive_path; // has been c-heap allocated. + _input_dynamic_archive_path = SharedArchiveFile; + _input_static_archive_path = base_archive_path; // has been c-heap allocated. } } else { - extract_shared_archive_paths((const char*)SharedArchiveFile, - &_static_archive_path, &_dynamic_archive_path); - if (_static_archive_path == nullptr) { - assert(_dynamic_archive_path == nullptr, "must be"); + extract_archive_paths(SharedArchiveFile, + &_input_static_archive_path, &_input_dynamic_archive_path); + if (_input_static_archive_path == nullptr) { + assert(_input_dynamic_archive_path == nullptr, "must be"); Arguments::no_shared_spaces("invalid archive"); } } - if (_dynamic_archive_path != nullptr) { + if (_input_dynamic_archive_path != nullptr) { // Check for case (c) if (RecordDynamicDumpInfo) { vm_exit_during_initialization("-XX:+RecordDynamicDumpInfo is unsupported when a dynamic CDS archive is specified in -XX:SharedArchiveFile", @@ -353,14 +368,22 @@ bool CDSConfig::has_unsupported_runtime_module_options() { return false; } -#define CHECK_ALIAS(f) check_flag_alias(FLAG_IS_DEFAULT(f), #f) +#define CHECK_NEW_FLAG(f) check_new_flag(FLAG_IS_DEFAULT(f), #f) -void CDSConfig::check_flag_alias(bool alias_is_default, const char* alias_name) { - if (old_cds_flags_used() && !alias_is_default) { +void CDSConfig::check_new_flag(bool new_flag_is_default, const char* new_flag_name) { + if (old_cds_flags_used() && !new_flag_is_default) { vm_exit_during_initialization(err_msg("Option %s cannot be used at the same time with " "-Xshare:on, -Xshare:auto, -Xshare:off, -Xshare:dump, " "DumpLoadedClassList, SharedClassListFile, or SharedArchiveFile", - alias_name)); + new_flag_name)); + } +} + +#define CHECK_SINGLE_PATH(f) check_flag_single_path(#f, f) + +void CDSConfig::check_flag_single_path(const char* flag_name, const char* value) { + if (value != nullptr && num_archive_paths(value) != 1) { + vm_exit_during_initialization(err_msg("Option %s must specify a single file name", flag_name)); } } @@ -371,9 +394,13 @@ void CDSConfig::check_aot_flags() { _old_cds_flags_used = true; } - CHECK_ALIAS(AOTCache); - CHECK_ALIAS(AOTConfiguration); - CHECK_ALIAS(AOTMode); + // "New" AOT flags must not be mixed with "classic" flags such as -Xshare:dump + CHECK_NEW_FLAG(AOTCache); + CHECK_NEW_FLAG(AOTConfiguration); + CHECK_NEW_FLAG(AOTMode); + + CHECK_SINGLE_PATH(AOTCache); + CHECK_SINGLE_PATH(AOTConfiguration); if (FLAG_IS_DEFAULT(AOTCache) && FLAG_IS_DEFAULT(AOTConfiguration) && FLAG_IS_DEFAULT(AOTMode)) { // AOTCache/AOTConfiguration/AOTMode not used. @@ -411,11 +438,6 @@ void CDSConfig::check_aotmode_auto_or_on() { vm_exit_during_initialization("AOTConfiguration can only be used with -XX:AOTMode=record or -XX:AOTMode=create"); } - if (!FLAG_IS_DEFAULT(AOTCache)) { - assert(FLAG_IS_DEFAULT(SharedArchiveFile), "already checked"); - FLAG_SET_ERGO(SharedArchiveFile, AOTCache); - } - UseSharedSpaces = true; if (FLAG_IS_DEFAULT(AOTMode) || (strcmp(AOTMode, "auto") == 0)) { RequireSharedSpaces = false; @@ -430,10 +452,6 @@ void CDSConfig::check_aotmode_record() { vm_exit_during_initialization("AOTCache must not be specified when using -XX:AOTMode=record"); } - assert(FLAG_IS_DEFAULT(DumpLoadedClassList), "already checked"); - assert(FLAG_IS_DEFAULT(SharedArchiveFile), "already checked"); - FLAG_SET_ERGO(SharedArchiveFile, AOTConfiguration); - FLAG_SET_ERGO(DumpLoadedClassList, nullptr); UseSharedSpaces = false; RequireSharedSpaces = false; _is_dumping_static_archive = true; @@ -449,10 +467,7 @@ void CDSConfig::check_aotmode_create() { vm_exit_during_initialization("AOTCache must be specified when using -XX:AOTMode=create"); } - assert(FLAG_IS_DEFAULT(SharedArchiveFile), "already checked"); - _is_dumping_final_static_archive = true; - FLAG_SET_ERGO(SharedArchiveFile, AOTConfiguration); UseSharedSpaces = true; RequireSharedSpaces = true; @@ -463,7 +478,29 @@ void CDSConfig::check_aotmode_create() { CDSConfig::enable_dumping_static_archive(); } +void CDSConfig::ergo_init_aot_paths() { + assert(_cds_ergo_initialize_started, "sanity"); + if (is_dumping_static_archive()) { + if (is_dumping_preimage_static_archive()) { + _output_archive_path = AOTConfiguration; + } else { + assert(is_dumping_final_static_archive(), "must be"); + _input_static_archive_path = AOTConfiguration; + _output_archive_path = AOTCache; + } + } else if (is_using_archive()) { + if (FLAG_IS_DEFAULT(AOTCache)) { + // Only -XX:AOTMode={auto,on} is specified + _input_static_archive_path = default_archive_path(); + } else { + _input_static_archive_path = AOTCache; + } + } +} + bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_flag_cmd_line) { + assert(!_cds_ergo_initialize_started, "This is called earlier than CDSConfig::ergo_initialize()"); + check_aot_flags(); if (!FLAG_IS_DEFAULT(AOTMode)) { @@ -514,7 +551,7 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla if (ArchiveClassesAtExit == nullptr && !RecordDynamicDumpInfo) { disable_dumping_dynamic_archive(); } else { - enable_dumping_dynamic_archive(); + enable_dumping_dynamic_archive(ArchiveClassesAtExit); } if (AutoCreateSharedArchive) { @@ -546,6 +583,34 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla return true; } +void CDSConfig::prepare_for_dumping() { + assert(CDSConfig::is_dumping_archive(), "sanity"); + + if (is_dumping_dynamic_archive() && !is_using_archive()) { + assert(!is_dumping_static_archive(), "cannot be dumping both static and dynamic archives"); + + // This could happen if SharedArchiveFile has failed to load: + // - -Xshare:off was specified + // - SharedArchiveFile points to an non-existent file. + // - SharedArchiveFile points to an archive that has failed CRC check + // - SharedArchiveFile is not specified and the VM doesn't have a compatible default archive + +#define __THEMSG " is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info." + if (RecordDynamicDumpInfo) { + log_error(cds)("-XX:+RecordDynamicDumpInfo%s", __THEMSG); + MetaspaceShared::unrecoverable_loading_error(); + } else { + assert(ArchiveClassesAtExit != nullptr, "sanity"); + log_warning(cds)("-XX:ArchiveClassesAtExit" __THEMSG); + } +#undef __THEMSG + disable_dumping_dynamic_archive(); + return; + } + + check_unsupported_dumping_module_options(); +} + bool CDSConfig::is_dumping_classic_static_archive() { return _is_dumping_static_archive && !is_dumping_preimage_static_archive() && @@ -560,6 +625,18 @@ bool CDSConfig::is_dumping_final_static_archive() { return _is_dumping_final_static_archive; } +void CDSConfig::enable_dumping_dynamic_archive(const char* output_path) { + _is_dumping_dynamic_archive = true; + if (output_path == nullptr) { + // output_path can be null when the VM is started with -XX:+RecordDynamicDumpInfo + // in anticipation of "jcmd VM.cds dynamic_dump", which will provide the actual + // output path. + _output_archive_path = nullptr; + } else { + _output_archive_path = os::strdup_check_oom(output_path, mtArguments); + } +} + bool CDSConfig::allow_only_single_java_thread() { // See comments in JVM_StartThread() return is_dumping_classic_static_archive() || is_dumping_final_static_archive(); diff --git a/src/hotspot/share/cds/cdsConfig.hpp b/src/hotspot/share/cds/cdsConfig.hpp index f02258eb6feaa..e96291f653487 100644 --- a/src/hotspot/share/cds/cdsConfig.hpp +++ b/src/hotspot/share/cds/cdsConfig.hpp @@ -42,9 +42,10 @@ class CDSConfig : public AllStatic { static bool _is_using_full_module_graph; static bool _has_aot_linked_classes; - static char* _default_archive_path; - static char* _static_archive_path; - static char* _dynamic_archive_path; + const static char* _default_archive_path; + const static char* _input_static_archive_path; + const static char* _input_dynamic_archive_path; + const static char* _output_archive_path; static bool _old_cds_flags_used; static bool _new_aot_flags_used; @@ -53,17 +54,24 @@ class CDSConfig : public AllStatic { static JavaThread* _dumper_thread; #endif - static void extract_shared_archive_paths(const char* archive_path, - char** base_archive_path, - char** top_archive_path); - static void init_shared_archive_paths(); + static void extract_archive_paths(const char* archive_path, + const char** base_archive_path, + const char** top_archive_path); + static int num_archive_paths(const char* path_spec); + static void check_flag_single_path(const char* flag_name, const char* value); - static void check_flag_alias(bool alias_is_default, const char* alias_name); + // Checks before Arguments::apply_ergo() + static void check_new_flag(bool new_flag_is_default, const char* new_flag_name); static void check_aot_flags(); static void check_aotmode_off(); static void check_aotmode_auto_or_on(); static void check_aotmode_record(); static void check_aotmode_create(); + static void check_unsupported_dumping_module_options(); + + // Called after Arguments::apply_ergo() has started + static void ergo_init_classic_archive_paths(); + static void ergo_init_aot_paths(); public: // Used by jdk.internal.misc.CDS.getCDSConfigStatus(); @@ -76,24 +84,25 @@ class CDSConfig : public AllStatic { static int get_status() NOT_CDS_RETURN_(0); // Initialization and command-line checking - static void initialize() NOT_CDS_RETURN; + static void ergo_initialize() NOT_CDS_RETURN; static void set_old_cds_flags_used() { CDS_ONLY(_old_cds_flags_used = true); } static bool old_cds_flags_used() { return CDS_ONLY(_old_cds_flags_used) NOT_CDS(false); } static bool new_aot_flags_used() { return CDS_ONLY(_new_aot_flags_used) NOT_CDS(false); } static void check_internal_module_property(const char* key, const char* value) NOT_CDS_RETURN; static void check_incompatible_property(const char* key, const char* value) NOT_CDS_RETURN; - static void check_unsupported_dumping_module_options() NOT_CDS_RETURN; static bool has_unsupported_runtime_module_options() NOT_CDS_RETURN_(false); static bool check_vm_args_consistency(bool patch_mod_javabase, bool mode_flag_cmd_line) NOT_CDS_RETURN_(true); static const char* type_of_archive_being_loaded(); static const char* type_of_archive_being_written(); + static void prepare_for_dumping(); // --- Basic CDS features // archive(s) in general static bool is_dumping_archive() { return is_dumping_static_archive() || is_dumping_dynamic_archive(); } + + // input archive(s) static bool is_using_archive() NOT_CDS_RETURN_(false); - static int num_archives(const char* archive_path) NOT_CDS_RETURN_(0); // static_archive static bool is_dumping_static_archive() { return CDS_ONLY(_is_dumping_static_archive) NOT_CDS(false); } @@ -125,7 +134,7 @@ class CDSConfig : public AllStatic { // dynamic_archive static bool is_dumping_dynamic_archive() { return CDS_ONLY(_is_dumping_dynamic_archive) NOT_CDS(false); } - static void enable_dumping_dynamic_archive() { CDS_ONLY(_is_dumping_dynamic_archive = true); } + static void enable_dumping_dynamic_archive(const char* output_path) NOT_CDS_RETURN; static void disable_dumping_dynamic_archive() { CDS_ONLY(_is_dumping_dynamic_archive = false); } // Misc CDS features @@ -147,12 +156,11 @@ class CDSConfig : public AllStatic { // archive_path - // Points to the classes.jsa in $JAVA_HOME - static char* default_archive_path() NOT_CDS_RETURN_(nullptr); - // The actual static archive (if any) selected at runtime - static const char* static_archive_path() { return CDS_ONLY(_static_archive_path) NOT_CDS(nullptr); } - // The actual dynamic archive (if any) selected at runtime - static const char* dynamic_archive_path() { return CDS_ONLY(_dynamic_archive_path) NOT_CDS(nullptr); } + // Points to the classes.jsa in $JAVA_HOME (could be input or output) + static const char* default_archive_path() NOT_CDS_RETURN_(nullptr); + static const char* input_static_archive_path() { return CDS_ONLY(_input_static_archive_path) NOT_CDS(nullptr); } + static const char* input_dynamic_archive_path() { return CDS_ONLY(_input_dynamic_archive_path) NOT_CDS(nullptr); } + static const char* output_archive_path() { return CDS_ONLY(_output_archive_path) NOT_CDS(nullptr); } // --- Archived java objects diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index c3a6db9e9b973..bf4257253e853 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -97,8 +97,6 @@ class DynamicArchiveBuilder : public ArchiveBuilder { void gather_array_klasses(); public: - DynamicArchiveBuilder() : ArchiveBuilder() { } - // Do this before and after the archive dump to see if any corruption // is caused by dynamic dumping. void verify_universe(const char* info) { @@ -348,7 +346,7 @@ void DynamicArchiveBuilder::write_archive(char* serialized_data, AOTClassLocatio FileMapInfo* dynamic_info = FileMapInfo::dynamic_info(); assert(dynamic_info != nullptr, "Sanity"); - dynamic_info->open_for_write(); + dynamic_info->open_as_output(); ArchiveHeapInfo no_heap_for_dynamic_dump; ArchiveBuilder::write_archive(dynamic_info, &no_heap_for_dynamic_dump); @@ -476,27 +474,6 @@ int DynamicArchive::num_array_klasses() { return _array_klasses != nullptr ? _array_klasses->length() : 0; } -void DynamicArchive::check_for_dynamic_dump() { - if (CDSConfig::is_dumping_dynamic_archive() && !CDSConfig::is_using_archive()) { - // This could happen if SharedArchiveFile has failed to load: - // - -Xshare:off was specified - // - SharedArchiveFile points to an non-existent file. - // - SharedArchiveFile points to an archive that has failed CRC check - // - SharedArchiveFile is not specified and the VM doesn't have a compatible default archive - -#define __THEMSG " is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info." - if (RecordDynamicDumpInfo) { - log_error(cds)("-XX:+RecordDynamicDumpInfo%s", __THEMSG); - MetaspaceShared::unrecoverable_loading_error(); - } else { - assert(ArchiveClassesAtExit != nullptr, "sanity"); - log_warning(cds)("-XX:ArchiveClassesAtExit" __THEMSG); - } -#undef __THEMSG - CDSConfig::disable_dumping_dynamic_archive(); - } -} - void DynamicArchive::dump_impl(bool jcmd_request, const char* archive_name, TRAPS) { MetaspaceShared::link_shared_classes(CHECK); if (!jcmd_request && CDSConfig::is_dumping_regenerated_lambdaform_invokers()) { @@ -507,11 +484,12 @@ void DynamicArchive::dump_impl(bool jcmd_request, const char* archive_name, TRAP VMThread::execute(&op); } -void DynamicArchive::dump_at_exit(JavaThread* current, const char* archive_name) { +void DynamicArchive::dump_at_exit(JavaThread* current) { ExceptionMark em(current); ResourceMark rm(current); CDSConfig::DumperThreadMark dumper_thread_mark(current); + const char* archive_name = CDSConfig::output_archive_path(); if (!CDSConfig::is_dumping_dynamic_archive() || archive_name == nullptr) { return; } diff --git a/src/hotspot/share/cds/dynamicArchive.hpp b/src/hotspot/share/cds/dynamicArchive.hpp index 905c511c4e0ac..8c23750734c35 100644 --- a/src/hotspot/share/cds/dynamicArchive.hpp +++ b/src/hotspot/share/cds/dynamicArchive.hpp @@ -63,9 +63,8 @@ class DynamicArchive : AllStatic { static GrowableArray* _array_klasses; static Array* _dynamic_archive_array_klasses; public: - static void check_for_dynamic_dump(); static void dump_for_jcmd(const char* archive_name, TRAPS); - static void dump_at_exit(JavaThread* current, const char* archive_name); + static void dump_at_exit(JavaThread* current); static void dump_impl(bool jcmd_request, const char* archive_name, TRAPS); static bool is_mapped() { return FileMapInfo::dynamic_info() != nullptr; } static bool validate(FileMapInfo* dynamic_info); diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index ebcd33f8bd521..580699b60b583 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -173,7 +173,7 @@ void FileMapInfo::populate_header(size_t core_region_alignment) { header_size = c_header_size; const char* default_base_archive_name = CDSConfig::default_archive_path(); - const char* current_base_archive_name = CDSConfig::static_archive_path(); + const char* current_base_archive_name = CDSConfig::input_static_archive_path(); if (!os::same_files(current_base_archive_name, default_base_archive_name)) { base_archive_name_size = strlen(current_base_archive_name) + 1; header_size += base_archive_name_size; @@ -209,7 +209,7 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment, if (!info->is_static() && base_archive_name_size != 0) { // copy base archive name - copy_base_archive_name(CDSConfig::static_archive_path()); + copy_base_archive_name(CDSConfig::input_static_archive_path()); } _core_region_alignment = core_region_alignment; _obj_alignment = ObjectAlignmentInBytes; @@ -563,7 +563,7 @@ class FileHeaderHelper { // true && (*base_archive_name) != nullptr: // is a valid dynamic archive. bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name, - char** base_archive_name) { + const char** base_archive_name) { FileHeaderHelper file_helper(archive_name, false); *base_archive_name = nullptr; @@ -619,7 +619,7 @@ bool FileMapInfo::init_from_file(int fd) { // Good } else { if (CDSConfig::new_aot_flags_used()) { - log_warning(cds)("Not a valid %s %s", file_type, _full_path); + log_warning(cds)("Not a valid %s (%s)", file_type, _full_path); } else { log_warning(cds)("Not a base shared archive: %s", _full_path); } @@ -729,7 +729,7 @@ bool FileMapInfo::open_for_read() { // Write the FileMapInfo information to the file. -void FileMapInfo::open_for_write() { +void FileMapInfo::open_as_output() { LogMessage(cds) msg; if (msg.is_info()) { if (CDSConfig::is_dumping_preimage_static_archive()) { @@ -1759,7 +1759,7 @@ bool FileMapInfo::_memory_mapping_failed = false; // [1] validate_header() - done here. // [2] validate_shared_path_table - this is done later, because the table is in the RO // region of the archive, which is not mapped yet. -bool FileMapInfo::initialize() { +bool FileMapInfo::open_as_input() { assert(CDSConfig::is_using_archive(), "UseSharedSpaces expected."); assert(Arguments::has_jimage(), "The shared archive file cannot be used with an exploded module build."); @@ -1774,13 +1774,12 @@ bool FileMapInfo::initialize() { if (!open_for_read() || !init_from_file(_fd) || !validate_header()) { if (_is_static) { - log_info(cds)("Initialize static archive failed."); + log_info(cds)("Loading static archive failed."); return false; } else { - log_info(cds)("Initialize dynamic archive failed."); + log_info(cds)("Loading dynamic archive failed."); if (AutoCreateSharedArchive) { - CDSConfig::enable_dumping_dynamic_archive(); - ArchiveClassesAtExit = CDSConfig::dynamic_archive_path(); + CDSConfig::enable_dumping_dynamic_archive(_full_path); } return false; } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 50af87a5da768..8793e110948b4 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -268,7 +268,7 @@ class FileMapInfo : public CHeapObj { public: FileMapHeader *header() const { return _header; } static bool get_base_archive_name_from_header(const char* archive_name, - char** base_archive_name); + const char** base_archive_name); static bool is_preimage_static_archive(const char* file); bool init_from_file(int fd); @@ -346,9 +346,8 @@ class FileMapInfo : public CHeapObj { static void assert_mark(bool check); // File manipulation. - bool initialize() NOT_CDS_RETURN_(false); - bool open_for_read(); - void open_for_write(); + bool open_as_input() NOT_CDS_RETURN_(false); + void open_as_output(); void write_header(); void write_region(int region, char* base, size_t size, bool read_only, bool allow_exec); @@ -425,6 +424,7 @@ class FileMapInfo : public CHeapObj { } private: + bool open_for_read(); void seek_to_position(size_t pos); bool map_heap_region_impl() NOT_CDS_JAVA_HEAP_RETURN_(false); void dealloc_heap_region() NOT_CDS_JAVA_HEAP_RETURN; diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 85916ced3cfac..ef2a6dcb8e63c 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -678,14 +678,11 @@ void VM_PopulateDumpSharedSpace::doit() { CppVtables::zero_archived_vtables(); // Write the archive file - const char* static_archive; if (CDSConfig::is_dumping_final_static_archive()) { - static_archive = AOTCache; - FileMapInfo::free_current_info(); - } else { - static_archive = CDSConfig::static_archive_path(); + FileMapInfo::free_current_info(); // FIXME: should not free current info } - assert(static_archive != nullptr, "SharedArchiveFile not set?"); + const char* static_archive = CDSConfig::output_archive_path(); + assert(static_archive != nullptr, "sanity"); _map_info = new FileMapInfo(static_archive, true); _map_info->populate_header(MetaspaceShared::core_region_alignment()); _map_info->set_early_serialized_data(early_serialized_data); @@ -789,11 +786,6 @@ void MetaspaceShared::link_shared_classes(TRAPS) { } } -void MetaspaceShared::prepare_for_dumping() { - assert(CDSConfig::is_dumping_archive(), "sanity"); - CDSConfig::check_unsupported_dumping_module_options(); -} - // Preload classes from a list, populate the shared spaces and dump to a // file. void MetaspaceShared::preload_and_dump(TRAPS) { @@ -1023,7 +1015,7 @@ bool MetaspaceShared::write_static_archive(ArchiveBuilder* builder, FileMapInfo* // without runtime relocation. builder->relocate_to_requested(); - map_info->open_for_write(); + map_info->open_as_output(); if (!map_info->is_open()) { return false; } @@ -1214,10 +1206,10 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { } FileMapInfo* MetaspaceShared::open_static_archive() { - const char* static_archive = CDSConfig::static_archive_path(); + const char* static_archive = CDSConfig::input_static_archive_path(); assert(static_archive != nullptr, "sanity"); FileMapInfo* mapinfo = new FileMapInfo(static_archive, true); - if (!mapinfo->initialize()) { + if (!mapinfo->open_as_input()) { delete(mapinfo); return nullptr; } @@ -1228,13 +1220,13 @@ FileMapInfo* MetaspaceShared::open_dynamic_archive() { if (CDSConfig::is_dumping_dynamic_archive()) { return nullptr; } - const char* dynamic_archive = CDSConfig::dynamic_archive_path(); + const char* dynamic_archive = CDSConfig::input_dynamic_archive_path(); if (dynamic_archive == nullptr) { return nullptr; } FileMapInfo* mapinfo = new FileMapInfo(dynamic_archive, false); - if (!mapinfo->initialize()) { + if (!mapinfo->open_as_input()) { delete(mapinfo); if (RequireSharedSpaces) { MetaspaceShared::unrecoverable_loading_error("Failed to initialize dynamic archive"); @@ -1817,7 +1809,7 @@ void MetaspaceShared::initialize_shared_spaces() { if (PrintSharedArchiveAndExit) { // Print archive names if (dynamic_mapinfo != nullptr) { - tty->print_cr("\n\nBase archive name: %s", CDSConfig::static_archive_path()); + tty->print_cr("\n\nBase archive name: %s", CDSConfig::input_static_archive_path()); tty->print_cr("Base archive version %d", static_mapinfo->version()); } else { tty->print_cr("Static archive name: %s", static_mapinfo->full_path()); diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp index 8881dc6d6fd0a..e03994be1b993 100644 --- a/src/hotspot/share/cds/metaspaceShared.hpp +++ b/src/hotspot/share/cds/metaspaceShared.hpp @@ -71,7 +71,6 @@ class MetaspaceShared : AllStatic { n_regions = 4 // total number of regions }; - static void prepare_for_dumping() NOT_CDS_RETURN; static void preload_and_dump(TRAPS) NOT_CDS_RETURN; #ifdef _LP64 static void adjust_heap_sizes_for_dumping() NOT_CDS_JAVA_HEAP_RETURN; diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index fe9c960b7f237..6f415ab93a46f 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -897,14 +897,13 @@ jint universe_init() { ClassLoaderData::init_null_class_loader_data(); #if INCLUDE_CDS - DynamicArchive::check_for_dynamic_dump(); if (CDSConfig::is_using_archive()) { // Read the data structures supporting the shared spaces (shared // system dictionary, symbol table, etc.) MetaspaceShared::initialize_shared_spaces(); } if (CDSConfig::is_dumping_archive()) { - MetaspaceShared::prepare_for_dumping(); + CDSConfig::prepare_for_dumping(); } #endif diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 0927e87c74853..d2e3df71dc4b1 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -3708,7 +3708,7 @@ jint Arguments::apply_ergo() { CompressedKlassPointers::pre_initialize(); } - CDSConfig::initialize(); + CDSConfig::ergo_initialize(); // Initialize Metaspace flags and alignments Metaspace::ergo_initialize(); diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index bcf99c84ba465..b3ad15ae3ff68 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -426,11 +426,10 @@ void before_exit(JavaThread* thread, bool halt) { #if INCLUDE_CDS // Dynamic CDS dumping must happen whilst we can still reliably // run Java code. - DynamicArchive::dump_at_exit(thread, ArchiveClassesAtExit); + DynamicArchive::dump_at_exit(thread); assert(!thread->has_pending_exception(), "must be"); #endif - // Actual shutdown logic begins here. #if INCLUDE_JVMCI diff --git a/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c b/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c index bcce23f12216a..3c244aab0f379 100644 --- a/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c +++ b/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -265,7 +265,7 @@ bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t siz #ifdef LINUX // mangled name of CDSConfig::_static_archive_path -#define SHARED_ARCHIVE_PATH_SYM "_ZN9CDSConfig20_static_archive_pathE" +#define SHARED_ARCHIVE_PATH_SYM "_ZN9CDSConfig26_input_static_archive_pathE" #define USE_SHARED_SPACES_SYM "UseSharedSpaces" #define SHARED_BASE_ADDRESS_SYM "SharedBaseAddress" #define LIBJVM_NAME "/libjvm.so" @@ -273,7 +273,7 @@ bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t siz #ifdef __APPLE__ // mangled name of CDSConfig::_static_archive_path -#define SHARED_ARCHIVE_PATH_SYM "__ZN9CDSConfig20_static_archive_pathE" +#define SHARED_ARCHIVE_PATH_SYM "__ZN9CDSConfig26_input_static_archive_pathE" #define USE_SHARED_SPACES_SYM "_UseSharedSpaces" #define SHARED_BASE_ADDRESS_SYM "_SharedBaseAddress" #define LIBJVM_NAME "/libjvm.dylib" diff --git a/test/hotspot/jtreg/runtime/cds/appcds/AOTFlags.java b/test/hotspot/jtreg/runtime/cds/appcds/AOTFlags.java index aeb0476346dde..46f76fab36859 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/AOTFlags.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/AOTFlags.java @@ -26,12 +26,14 @@ * @test * @summary "AOT" aliases for traditional CDS command-line options * @requires vm.cds + * @requires vm.flagless * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes * @build Hello * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello.jar Hello * @run driver AOTFlags */ +import java.io.File; import jdk.test.lib.cds.CDSTestUtils; import jdk.test.lib.helpers.ClassFileInstaller; import jdk.test.lib.process.OutputAnalyzer; @@ -298,6 +300,60 @@ static void negativeTests() throws Exception { "specified when the AOTConfiguration file was recorded"); out.shouldContain("Unable to use create AOT cache"); out.shouldHaveExitValue(1); + + //---------------------------------------------------------------------- + printTestCase("Cannot use multiple paths in AOTConfiguration"); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:AOTMode=record", + "-XX:AOTConfiguration=" + aotConfigFile + File.pathSeparator + "dummy", + "-cp", "noSuchJar.jar"); + + out = CDSTestUtils.executeAndLog(pb, "neg"); + out.shouldContain("Option AOTConfiguration must specify a single file name"); + out.shouldHaveExitValue(1); + + //---------------------------------------------------------------------- + printTestCase("Cannot use multiple paths in AOTCache"); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:AOTMode=create", + "-XX:AOTConfiguration=" + aotConfigFile, + "-XX:AOTCache=" + aotCacheFile + File.pathSeparator + "dummy", + "-cp", "noSuchJar.jar"); + + out = CDSTestUtils.executeAndLog(pb, "neg"); + out.shouldContain("Option AOTCache must specify a single file name"); + out.shouldHaveExitValue(1); + + //---------------------------------------------------------------------- + printTestCase("Cannot use a dynamic CDS archive for -XX:AOTCache"); + String staticArchive = "static.jsa"; + String dynamicArchive = "dynamic.jsa"; + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xshare:dump", + "-XX:SharedArchiveFile=" + staticArchive); + out = CDSTestUtils.executeAndLog(pb, "static"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:SharedArchiveFile=" + staticArchive, + "-XX:ArchiveClassesAtExit=" + dynamicArchive, + "--version"); + out = CDSTestUtils.executeAndLog(pb, "dynamic"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:cds", + "-XX:AOTMode=on", + "-XX:AOTCache=" + dynamicArchive, + "--version"); + + out = CDSTestUtils.executeAndLog(pb, "neg"); + out.shouldContain("Unable to use AOT cache."); + out.shouldContain("Not a valid AOT cache (dynamic.jsa)"); + out.shouldHaveExitValue(1); } static int testNum = 0; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchive.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchive.java index c8a04027a3dd9..3bc1e395b17dd 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchive.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchive.java @@ -337,7 +337,7 @@ private static void testAutoCreateSharedArchive() throws Exception { .shouldContain(HELLO_WORLD) .shouldContain("The shared archive file version " + hex(version2) + " does not match the required version " + hex(currentCDSVersion)) .shouldContain("The shared archive file has the wrong version") - .shouldContain("Initialize dynamic archive failed") + .shouldContain("Loading dynamic archive failed") .shouldContain("Dumping shared data to file"); }); ft2 = Files.getLastModifiedTime(Paths.get(modVersion)); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveNoDefaultArchive.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveNoDefaultArchive.java index 133f44521d53a..4806f571dc6d5 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveNoDefaultArchive.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveNoDefaultArchive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,7 +112,7 @@ public static void main(String[] args) throws Exception { "-version"); TestCommon.executeAndLog(pb, "show-version") .shouldHaveExitValue(0) - .shouldContain("Initialize static archive failed") + .shouldContain("Loading static archive failed") .shouldContain("Unable to map shared spaces") .shouldNotContain("sharing"); } @@ -132,7 +132,7 @@ public static void main(String[] args) throws Exception { mainClass); TestCommon.executeAndLog(pb, "no-default-archive") .shouldHaveExitValue(0) - .shouldContain("Initialize static archive failed") + .shouldContain("Loading static archive failed") .shouldContain("Unable to map shared spaces") .shouldNotContain("Dumping shared data to file"); if (jsaFile.exists()) { From 1f21da75eb5d5eb7460b2953517514a0aa26b5de Mon Sep 17 00:00:00 2001 From: Raffaello Giulietti Date: Wed, 9 Apr 2025 15:16:02 +0000 Subject: [PATCH 0496/1101] 8351462: Improve robustness of String concatenation Reviewed-by: liach, pminborg, rriggs --- .../share/classes/java/lang/StringConcatHelper.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index 13ada0637bae1..3b057ecb02859 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -52,6 +52,9 @@ static abstract class StringConcatBase { byte coder = String.LATIN1; for (String c : constants) { length += c.length(); + if (length < 0) { + throw new OutOfMemoryError("Total length of constants is out of range"); + } coder |= c.coder(); } this.constants = constants; From 5f2a604b633c0cd24f897f828a7c928c3d2b651c Mon Sep 17 00:00:00 2001 From: Danish Nawab Date: Wed, 9 Apr 2025 15:25:24 +0000 Subject: [PATCH 0497/1101] 8353840: JNativeScan should not abort for missing classes Reviewed-by: jvernee, liach --- .../tools/jnativescan/JNativeScanTask.java | 21 +++++++-- .../com/sun/tools/jnativescan/Main.java | 2 +- .../tools/jnativescan/NativeMethodFinder.java | 43 ++++++++++--------- .../jnativescan/TestMissingSystemClass.java | 14 ++++-- .../cases/classpath/missingsystem/App.java | 1 + 5 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java index 2ff172e9c1b71..c57e033427ead 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java @@ -42,15 +42,17 @@ class JNativeScanTask { private final PrintWriter out; + private final PrintWriter err; private final List classPaths; private final List modulePaths; private final List cmdRootModules; private final Runtime.Version version; private final Action action; - public JNativeScanTask(PrintWriter out, List classPaths, List modulePaths, + public JNativeScanTask(PrintWriter out, PrintWriter err, List classPaths, List modulePaths, List cmdRootModules, Runtime.Version version, Action action) { this.out = out; + this.err = err; this.classPaths = classPaths; this.modulePaths = modulePaths; this.version = version; @@ -71,10 +73,13 @@ public void run() throws JNativeScanFatalError { toScan.add(new ClassFileSource.Module(m.reference())); } + Set errors = new LinkedHashSet<>(); + Diagnostics diagnostics = (context, error) -> + errors.add("Error while processing method: " + context + ": " + error.getMessage()); SortedMap>> allRestrictedMethods; try(ClassResolver classesToScan = ClassResolver.forClassFileSources(toScan, version); ClassResolver systemClassResolver = ClassResolver.forSystemModules(version)) { - NativeMethodFinder finder = NativeMethodFinder.create(classesToScan, systemClassResolver); + NativeMethodFinder finder = NativeMethodFinder.create(diagnostics, classesToScan, systemClassResolver); allRestrictedMethods = finder.findAll(); } catch (IOException e) { throw new RuntimeException(e); @@ -82,7 +87,7 @@ public void run() throws JNativeScanFatalError { switch (action) { case PRINT -> printNativeAccess(allRestrictedMethods); - case DUMP_ALL -> dumpAll(allRestrictedMethods); + case DUMP_ALL -> dumpAll(allRestrictedMethods, errors); } } @@ -156,7 +161,7 @@ private void printNativeAccess(SortedMap>> allRestrictedMethods) { + private void dumpAll(SortedMap>> allRestrictedMethods, Set errors) { if (allRestrictedMethods.isEmpty()) { out.println(" "); } else { @@ -177,6 +182,10 @@ private void dumpAll(SortedMap err.println(" " + error)); + } } private static boolean isJarFile(Path path) throws JNativeScanFatalError { @@ -192,4 +201,8 @@ public static String qualName(ClassDesc desc) { String packagePrefix = desc.packageName().isEmpty() ? "" : desc.packageName() + "."; return packagePrefix + desc.displayName(); } + + interface Diagnostics { + void error(MethodRef context, JNativeScanFatalError error); + } } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java index 425a106d599f0..9aa77a947a98f 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java @@ -165,7 +165,7 @@ private void parseOptionsAndRun(String[] expandedArgs) throws JNativeScanFatalEr action = JNativeScanTask.Action.PRINT; } - new JNativeScanTask(out, classPathJars, modulePaths, rootModules, version, action).run(); + new JNativeScanTask(out, err, classPathJars, modulePaths, rootModules, version, action).run(); } private static String[] expandArgFiles(String[] args) throws JNativeScanFatalError { diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java index 681b954d4cdd9..b89c9db285826 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java @@ -24,6 +24,7 @@ */ package com.sun.tools.jnativescan; +import com.sun.tools.jnativescan.JNativeScanTask.Diagnostics; import com.sun.tools.jnativescan.RestrictedUse.NativeMethodDecl; import com.sun.tools.jnativescan.RestrictedUse.RestrictedMethodRefs; @@ -44,16 +45,19 @@ class NativeMethodFinder { private static final String RESTRICTED_NAME = "Ljdk/internal/javac/Restricted+Annotation;"; private final Map cache = new HashMap<>(); + private final Diagnostics diagnostics; private final ClassResolver classesToScan; private final ClassResolver systemClassResolver; - private NativeMethodFinder(ClassResolver classesToScan, ClassResolver systemClassResolver) { + private NativeMethodFinder(Diagnostics diagnostics, ClassResolver classesToScan, ClassResolver systemClassResolver) { + this.diagnostics = diagnostics; this.classesToScan = classesToScan; this.systemClassResolver = systemClassResolver; } - public static NativeMethodFinder create(ClassResolver classesToScan, ClassResolver systemClassResolver) throws JNativeScanFatalError, IOException { - return new NativeMethodFinder(classesToScan, systemClassResolver); + public static NativeMethodFinder create(Diagnostics diagnostics, ClassResolver classesToScan, + ClassResolver systemClassResolver) throws JNativeScanFatalError, IOException { + return new NativeMethodFinder(diagnostics, classesToScan, systemClassResolver); } public SortedMap>> findAll() throws JNativeScanFatalError { @@ -68,23 +72,22 @@ public SortedMap>> fin } else { SortedSet perMethod = new TreeSet<>(Comparator.comparing(MethodRef::toString)); methodModel.code().ifPresent(code -> { - try { - code.forEach(e -> { - switch (e) { - case InvokeInstruction invoke -> { - MethodRef ref = MethodRef.ofInvokeInstruction(invoke); - if (isRestrictedMethod(ref)) { - perMethod.add(ref); - } - } - default -> { - } - } - }); - } catch (JNativeScanFatalError e) { - throw new JNativeScanFatalError("Error while processing method: " + - MethodRef.ofModel(methodModel), e); - } + code.forEach(e -> { + switch (e) { + case InvokeInstruction invoke -> { + MethodRef ref = MethodRef.ofInvokeInstruction(invoke); + try { + if (isRestrictedMethod(ref)) { + perMethod.add(ref); + } + } catch (JNativeScanFatalError ex) { + diagnostics.error(MethodRef.ofModel(methodModel), ex); + } + } + default -> { + } + } + }); }); if (!perMethod.isEmpty()) { perClass.add(new RestrictedMethodRefs(MethodRef.ofModel(methodModel), perMethod)); diff --git a/test/langtools/tools/jnativescan/TestMissingSystemClass.java b/test/langtools/tools/jnativescan/TestMissingSystemClass.java index 5806590d0e081..8b6266aa5d71c 100644 --- a/test/langtools/tools/jnativescan/TestMissingSystemClass.java +++ b/test/langtools/tools/jnativescan/TestMissingSystemClass.java @@ -35,6 +35,9 @@ import java.io.IOException; import java.nio.file.Path; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class TestMissingSystemClass extends JNativeScanTestBase { @@ -49,12 +52,15 @@ public static void before() throws IOException { @Test public void testSingleJarClassPath() { - assertFailure(jnativescan("--class-path", MISSING_SYSTEM.toString(), "--release", "21")) - .stdoutShouldBeEmpty() + List stderr = assertSuccess(jnativescan("--class-path", MISSING_SYSTEM.toString(), "--release", "21")) + .stdoutShouldContain("") + .stderrShouldContain("Error(s) while processing classes") .stderrShouldContain("Error while processing method") .stderrShouldContain("missingsystem.App::main(String[])void") - .stderrShouldContain("CAUSED BY:") .stderrShouldContain("System class can not be found") - .stderrShouldContain("java.lang.Compiler"); + .stderrShouldContain("java.lang.Compiler") + .stderrAsLines(); + + assertEquals(2, stderr.size(), "Unexpected number of lines in stderr"); } } diff --git a/test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java b/test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java index 0e20fe81eecd0..05812be45ce87 100644 --- a/test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java +++ b/test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java @@ -28,5 +28,6 @@ public static void main(String[] args) { // if we compile with --release 20, but run jnativescan // with --release 21, we should get an error java.lang.Compiler.enable(); + java.lang.Compiler.enable(); // should be de-duplicated in the error logs } } From 6352ee1a6e55e428db0eca97ecf8125770dc4a08 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 9 Apr 2025 17:43:11 +0000 Subject: [PATCH 0498/1101] 8349007: The jtreg test ResolvedMethodTableHash takes excessive time Reviewed-by: lmesnik, matsaave --- .../share/prims/resolvedMethodTable.cpp | 8 +- .../MemberName/ResolvedMethodTableHash.java | 121 ++++++++++-------- 2 files changed, 78 insertions(+), 51 deletions(-) diff --git a/src/hotspot/share/prims/resolvedMethodTable.cpp b/src/hotspot/share/prims/resolvedMethodTable.cpp index 5b9b07c5842bb..cdd41730dea5a 100644 --- a/src/hotspot/share/prims/resolvedMethodTable.cpp +++ b/src/hotspot/share/prims/resolvedMethodTable.cpp @@ -175,7 +175,13 @@ oop ResolvedMethodTable::find_method(const Method* method) { ResolvedMethodTableLookup lookup(thread, method_hash(method), method); ResolvedMethodGet rmg(thread, method); - _local_table->get(thread, lookup, rmg); + bool rehash_warning = false; + _local_table->get(thread, lookup, rmg, &rehash_warning); + if (rehash_warning) { + // if load factor is low but we need to rehash that's a problem with the hash function. + log_info(membername, table)("Rehash warning, load factor %g", get_load_factor()); + trigger_concurrent_work(); + } return rmg.get_res_oop(); } diff --git a/test/hotspot/jtreg/runtime/MemberName/ResolvedMethodTableHash.java b/test/hotspot/jtreg/runtime/MemberName/ResolvedMethodTableHash.java index 8abc4d41b16e4..9ee6a808e24db 100644 --- a/test/hotspot/jtreg/runtime/MemberName/ResolvedMethodTableHash.java +++ b/test/hotspot/jtreg/runtime/MemberName/ResolvedMethodTableHash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,11 @@ * @test * @bug 8249719 * @summary ResolvedMethodTable hash function should take method class into account - * @run main/othervm/manual -Xmx256m -XX:MaxMetaspaceSize=256m ResolvedMethodTableHash 200000 + * @requires vm.flagless + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @run driver ResolvedMethodTableHash */ import java.lang.invoke.MethodHandle; @@ -35,34 +39,38 @@ import java.util.ArrayList; import java.util.List; -// The test generates thousands MethodHandles to the methods of the same name -// and the same signature. This should not take too long, unless Method hash +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +// The test generates a thousand MethodHandles to the methods of the same name +// and the same signature. The rehash warning shouldn't be returned, unless Method hash // function takes only the name and the signature as an input. -public class ResolvedMethodTableHash extends ClassLoader { +public class ResolvedMethodTableHash { - // Generate a MethodHandle for ClassName.m() - private MethodHandle generate(String className) throws ReflectiveOperationException { - byte[] buf = new byte[100]; - int size = writeClass(buf, className); - Class cls = defineClass(null, buf, 0, size); - return MethodHandles.publicLookup().findStatic(cls, "m", MethodType.methodType(void.class)); - } + public static class ResolvedMethodTableHashTest extends ClassLoader { + // Generate a MethodHandle for ClassName.m() + private MethodHandle generate(String className) throws ReflectiveOperationException { + byte[] buf = new byte[100]; + int size = writeClass(buf, className); + Class cls = defineClass(null, buf, 0, size); + return MethodHandles.publicLookup().findStatic(cls, "m", MethodType.methodType(void.class)); + } - private MethodHandle generateWithSameName() throws ReflectiveOperationException { - byte[] buf = new byte[100]; - int size = writeClass(buf, "MH$$"); - // use different classloader instances to load the classes with the same name - Class cls = new ResolvedMethodTableHash().defineClass(null, buf, 0, size); - return MethodHandles.publicLookup().findStatic(cls, "m", MethodType.methodType(void.class)); - } + private MethodHandle generateWithSameName() throws ReflectiveOperationException { + byte[] buf = new byte[100]; + int size = writeClass(buf, "MH$$"); + // use different classloader instances to load the classes with the same name + Class cls = new ResolvedMethodTableHashTest().defineClass(null, buf, 0, size); + return MethodHandles.publicLookup().findStatic(cls, "m", MethodType.methodType(void.class)); + } - // Produce a class file with the given name and a single method: - // public static native void m(); - private int writeClass(byte[] buf, String className) { - return ByteBuffer.wrap(buf) - .putInt(0xCAFEBABE) // magic - .putInt(50) // version: 50 - .putShort((short) 7) // constant_pool_count: 7 + // Produce a class file with the given name and a single method: + // public static native void m(); + private int writeClass(byte[] buf, String className) { + return ByteBuffer.wrap(buf) + .putInt(0xCAFEBABE) // magic + .putInt(50) // version: 50 + .putShort((short) 7) // constant_pool_count: 7 .put((byte) 7).putShort((short) 2) .put((byte) 1).putShort((short) className.length()).put(className.getBytes()) .put((byte) 7).putShort((short) 4) @@ -70,37 +78,50 @@ private int writeClass(byte[] buf, String className) { .put((byte) 1).putShort((short) 1).put("m".getBytes()) .put((byte) 1).putShort((short) 3).put("()V".getBytes()) .putShort((short) 0x21) // access_flags: public super - .putShort((short) 1) // this_class: #1 - .putShort((short) 3) // super_class: #3 - .putShort((short) 0) // interfaces_count: 0 - .putShort((short) 0) // fields_count: 0 - .putShort((short) 1) // methods_count: 1 + .putShort((short) 1) // this_class: #1 + .putShort((short) 3) // super_class: #3 + .putShort((short) 0) // interfaces_count: 0 + .putShort((short) 0) // fields_count: 0 + .putShort((short) 1) // methods_count: 1 .putShort((short) 0x109) // access_flags: public static native - .putShort((short) 5) // name_index: #5 - .putShort((short) 6) // descriptor_index: #6 - .putShort((short) 0) // attributes_count: 0 - .putShort((short) 0) // attributes_count: 0 + .putShort((short) 5) // name_index: #5 + .putShort((short) 6) // descriptor_index: #6 + .putShort((short) 0) // attributes_count: 0 + .putShort((short) 0) // attributes_count: 0 .position(); - } + } - public static void main(String[] args) throws Exception { - ResolvedMethodTableHash generator = new ResolvedMethodTableHash(); - List handles = new ArrayList<>(); + public static void main(String[] args) throws Exception { - int count = args.length > 0 ? Integer.parseInt(args[0]) : 200000; + ResolvedMethodTableHashTest generator = new ResolvedMethodTableHashTest(); + List handles = new ArrayList<>(); - for (int i = 0; i < count; i++) { - // prevents metaspace oom - if (i % 20 != 0) { - handles.add(generator.generate("MH$" + i)); - } else { - handles.add(generator.generateWithSameName()); - } - if (i % 1000 == 0) { - System.out.println("Generated " + i + " handles"); + int count = 1001; + + for (int i = 0; i < count; i++) { + // prevents metaspace oom + if (i % 20 != 0) { + handles.add(generator.generate("MH$" + i)); + } else { + handles.add(generator.generateWithSameName()); + } + if (i % 1000 == 0) { + System.out.println("Generated " + i + " handles"); + } } + + System.out.println("Test passed"); } + } + + public static void main(String[] args) throws Exception { - System.out.println("Test passed"); + // Running the table with only 1000 entries should not provoke a needs rehash warning, unless the hash code is bad. + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xlog:membername+table", + ResolvedMethodTableHashTest.class.getName()); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("[membername,table] Rehash warning, load factor"); + output.shouldContain("Generated 1000 handles"); + output.shouldHaveExitValue(0); } } From faacbd96a3dc1116f3af590439585844ff8048a1 Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Wed, 9 Apr 2025 17:47:47 +0000 Subject: [PATCH 0499/1101] 8353938: hotspot/jtreg/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java fails on static JDK Reviewed-by: alanb --- .../jtreg/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java b/test/hotspot/jtreg/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java index 725bf086b3bee..39068a47e95c5 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ * * @test * @bug 8147388 + * @requires !jdk.static * @library /test/lib * @modules java.base/jdk.internal.misc * java.compiler From cc546e7a283faad40b75183887f6a1f433a2407f Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Wed, 9 Apr 2025 17:49:18 +0000 Subject: [PATCH 0500/1101] 8353549: Open source events tests batch2 Reviewed-by: honkar, kizune --- .../event/MouseEvent/DragMouseEventTest.java | 438 ++++++++++++++++++ .../MouseEvent/MouseEventsDuringDrag.java | 307 ++++++++++++ .../event/MouseEvent/MouseModifierTest.java | 181 ++++++++ .../awt/event/MouseEvent/MouseRButTest.java | 97 ++++ .../MouseEvent/TitleBarGetsMousePressed.java | 78 ++++ 5 files changed, 1101 insertions(+) create mode 100644 test/jdk/java/awt/event/MouseEvent/DragMouseEventTest.java create mode 100644 test/jdk/java/awt/event/MouseEvent/MouseEventsDuringDrag.java create mode 100644 test/jdk/java/awt/event/MouseEvent/MouseModifierTest.java create mode 100644 test/jdk/java/awt/event/MouseEvent/MouseRButTest.java create mode 100644 test/jdk/java/awt/event/MouseEvent/TitleBarGetsMousePressed.java diff --git a/test/jdk/java/awt/event/MouseEvent/DragMouseEventTest.java b/test/jdk/java/awt/event/MouseEvent/DragMouseEventTest.java new file mode 100644 index 0000000000000..3f8d10651ff19 --- /dev/null +++ b/test/jdk/java/awt/event/MouseEvent/DragMouseEventTest.java @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4327618 4327623 4327639 4327654 4327664 4327666 4327676 4327679 4507822 + * @summary Tests that MouseDragged and MouseReleased are triggered by Button, + * Checkbox, Choice, Label, List, Scrollbar, TextArea, TextField + * for Left, Middle and Right mouse buttons + * @key headful + * @library /lib/client /java/awt/regtesthelpers + * @build ExtendedRobot Util + * @run main/othervm -Dsun.java2d.uiScale=1 DragMouseEventTest +*/ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.List; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.Arrays; + +import test.java.awt.regtesthelpers.Util; + +public class DragMouseEventTest { + private static ExtendedRobot robot; + private static DragMouseEventFrame dmef; + private static final int DELAY = 200; + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(DragMouseEventTest::createAndShowGUI); + test(); + } finally { + EventQueue.invokeAndWait(() -> { + if (dmef != null) { + dmef.dispose(); + } + }); + } + } + + private static void createAndShowGUI() { + dmef = new DragMouseEventFrame(); + dmef.setVisible(true); + } + + private static void test() throws Exception { + robot = new ExtendedRobot(); + robot.waitForIdle(); + robot.delay(500); + + testComponent(dmef.scrollbar); + testComponent(dmef.choice); + testComponent(dmef.textarea); + testComponent(dmef.textfield); + testComponent(dmef.checkbox); + testComponent(dmef.label); + testComponent(dmef.list); + testComponent(dmef.button); + } + + private static void testComponent(Component component) throws Exception { + Rectangle componentBounds = Util.invokeOnEDT(() -> { + Point locationOnScreen = component.getLocationOnScreen(); + Dimension size = component.getSize(); + return new Rectangle(locationOnScreen, size); + }); + + Rectangle frameBounds = Util.invokeOnEDT(() -> dmef.getBounds()); + + Point start = new Point(componentBounds.x + 10, componentBounds.y + 10); + + Adapter adapter = getAdapterFromComponent(component); + + testItemStateChanged(component, adapter, start, componentBounds); + testActionListener(component, adapter, start); + + Point mid = getEndPoint(start, frameBounds, 3); + Point end = getEndPoint(start, frameBounds, 15); + + testButtonDrag(component, adapter, MouseEvent.BUTTON1_DOWN_MASK, start, mid, end); + testButtonDrag(component, adapter, MouseEvent.BUTTON2_DOWN_MASK, start, mid, end); + testButtonDrag(component, adapter, MouseEvent.BUTTON3_DOWN_MASK, start, mid, end); + } + + private static Adapter getAdapterFromComponent(Component component) { + return (Adapter) Arrays + .stream(component.getMouseListeners()) + .filter((m) -> m instanceof Adapter) + .findFirst() + .orElseThrow(); + } + + private static void testItemStateChanged(Component component, + Adapter adapter, + Point start, + Rectangle componentBounds) { + if (!(component instanceof Choice + || component instanceof Checkbox + || component instanceof List)) { + return; + } + + System.out.println("\ntestItemStateChanged " + component); + + adapter.reset(); + robot.mouseMove(start.x, start.y); + robot.waitForIdle(); + robot.click(); + + if (component instanceof Choice) { + robot.mouseMove(start.x, componentBounds.y + componentBounds.height + 25); + robot.waitForIdle(); + robot.click(); + } + + robot.waitForIdle(); + + if (!adapter.itemStateChangedReceived) { + throw new RuntimeException("itemStateChanged was not received for " + component); + } + } + + private static void testActionListener(Component component, + Adapter adapter, + Point start) { + if (!(component instanceof Button || component instanceof List)) { + // skip for not applicable components + return; + } + + System.out.println("\ntestActionListener " + component); + adapter.reset(); + + robot.mouseMove(start.x, start.y); + robot.waitForIdle(); + + if (component instanceof List) { + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); + robot.delay(25); + robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); + robot.delay(25); + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); + robot.delay(25); + robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(DELAY); + } else { + robot.click(); + } + + robot.waitForIdle(); + robot.delay(DELAY); + + if (!adapter.actionPerformedReceived) { + throw new RuntimeException("actionPerformed was not received for " + component); + } + } + + private static String getButtonName(int button) { + return switch (button) { + case MouseEvent.BUTTON1_DOWN_MASK -> "BUTTON1"; + case MouseEvent.BUTTON2_DOWN_MASK -> "BUTTON2"; + case MouseEvent.BUTTON3_DOWN_MASK -> "BUTTON3"; + default -> throw new IllegalStateException("Unexpected value: " + button); + }; + } + + private static void testButtonDrag(Component component, + Adapter adapter, + int button, + Point start, Point mid, Point end) { + String buttonName = getButtonName(button); + System.out.printf("\n> testButtonDrag: %s on %s\n", + buttonName, component); + + robot.mouseMove(start.x, start.y); + robot.waitForIdle(); + + robot.mousePress(button); + robot.waitForIdle(); + + System.out.printf("> gliding from (%d,%d) to (%d,%d)\n", + start.x, start.y, mid.x, mid.y); + robot.glide(start, mid); + robot.waitForIdle(); + robot.delay(DELAY); + + + // Catch events only after we leave the frame boundaries + adapter.reset(); + + System.out.printf("> gliding after crossing the border (%d,%d) to (%d,%d)\n", + mid.x, mid.y, end.x, end.y); + robot.glide(mid, end); + + robot.mouseRelease(button); + robot.waitForIdle(); + robot.delay(DELAY); + System.out.printf("> %s released\n", buttonName); + + boolean mouseDraggedReceived = adapter.mouseDraggedReceived; + boolean mouseReleasedReceived = adapter.mouseReleasedReceived; + + if (component instanceof Choice) { + // Close the popup if it is still open + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.delay(25); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.waitForIdle(); + robot.delay(DELAY); + } + + + if (!mouseDraggedReceived || !mouseReleasedReceived) { + throw new RuntimeException(("%d: Mouse drag or release was not received\n" + + "mouseDraggedReceived %b mouseReleasedReceived %b") + .formatted(button, mouseDraggedReceived, mouseReleasedReceived)); + } + } + + /* + * returns the closest border point with a specified offset + */ + private static Point getEndPoint(Point start, Rectangle bounds, int offset) { + int left = bounds.x; + int right = bounds.x + bounds.width; + int top = bounds.y; + int bottom = bounds.y + bounds.height; + + int distanceLeft = start.x - left; + int distanceRight = right - start.x; + int distanceTop = start.y - top; + int distanceBottom = bottom - start.y; + + int minDistance = Math.min( + Math.min(distanceLeft, distanceRight), + Math.min(distanceTop, distanceBottom) + ); + + if (minDistance == distanceLeft) { + return new Point(left - offset, start.y); + } else if (minDistance == distanceRight) { + return new Point(right + offset, start.y); + } else if (minDistance == distanceTop) { + return new Point(start.x, top - offset); + } else { + return new Point(start.x, bottom + offset); + } + } + + private static class DragMouseEventFrame extends Frame { + TextArea textarea = new TextArea("TextArea", 20, 30); + Label label = new Label("Label"); + Panel panel = new Panel(); + List list = new List(); + Choice choice = new Choice(); + Button button = new Button("Button"); + TextField textfield = new TextField("TextField"); + Checkbox checkbox = new Checkbox("CheckBox"); + Scrollbar scrollbar = new Scrollbar(); + Panel centerPanel = new Panel(); + + public DragMouseEventFrame() { + setTitle("DragMouseEventTest"); + + add(centerPanel, BorderLayout.CENTER); + centerPanel.setLayout(new FlowLayout()); + + add(panel, BorderLayout.NORTH); + panel.setLayout(new FlowLayout()); + + choice.add("choice item 1"); + choice.add("choice item 2"); + choice.add("choice item 3"); + panel.add(choice); + + Adapter adapter = new Adapter(); + choice.addMouseMotionListener(adapter); + choice.addMouseListener(adapter); + choice.addItemListener(adapter); + + adapter = new Adapter(); + panel.add(label); + label.addMouseMotionListener(adapter); + label.addMouseListener(adapter); + + adapter = new Adapter(); + panel.add(button); + button.addMouseMotionListener(adapter); + button.addMouseListener(adapter); + button.addActionListener(adapter); + + adapter = new Adapter(); + panel.add(checkbox); + checkbox.addMouseMotionListener(adapter); + checkbox.addMouseListener(adapter); + checkbox.addItemListener(adapter); + + adapter = new Adapter(); + panel.add(textfield, BorderLayout.EAST); + textfield.addMouseMotionListener(adapter); + textfield.addMouseListener(adapter); + textfield.addActionListener(adapter); + + adapter = new Adapter(); + add(textarea, BorderLayout.EAST); + textarea.addMouseMotionListener(adapter); + textarea.addMouseListener(adapter); + + adapter = new Adapter(); + list.add("list item 1"); + list.add("list item 2"); + add(list, BorderLayout.SOUTH); + list.addMouseMotionListener(adapter); + list.addMouseListener(adapter); + list.addActionListener(adapter); + list.addItemListener(adapter); + + adapter = new Adapter(); + add(scrollbar, BorderLayout.WEST); + scrollbar.addMouseMotionListener(adapter); + scrollbar.addMouseListener(adapter); + + setSize(500, 400); + setLocationRelativeTo(null); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + DragMouseEventFrame.this.dispose(); + } + }); + } + } + + private static class Adapter extends MouseAdapter + implements ActionListener, ItemListener { + + public volatile boolean mouseDraggedReceived = false; + public volatile boolean mouseReleasedReceived = false; + public volatile boolean itemStateChangedReceived = false; + public volatile boolean actionPerformedReceived = false; + + + public void mouseDragged(MouseEvent me) { + mouseDraggedReceived = true; + System.out.println(me.paramString()); + } + + private void consumeIfNeeded(MouseEvent me) { + Component c = me.getComponent(); + // do not show popup menu for the following components, + // as it may interfere with the testing. + if (c instanceof TextArea + || c instanceof TextField + || c instanceof Scrollbar) { + if (me.isPopupTrigger()) { + System.out.println("CONSUMED: " + me); + me.consume(); + } + } + } + + public void mouseReleased(MouseEvent me) { + consumeIfNeeded(me); + mouseReleasedReceived = true; + System.out.println(me.paramString()); + } + + public void mousePressed(MouseEvent me) { + consumeIfNeeded(me); + System.out.println(me.paramString()); + } + + public void mouseClicked(MouseEvent me) { + System.out.println(me.paramString()); + } + + public void actionPerformed(ActionEvent e) { + actionPerformedReceived = true; + System.out.println(e.paramString()); + } + + public void itemStateChanged(ItemEvent e) { + itemStateChangedReceived = true; + System.out.println(e.paramString()); + } + + public void reset() { + mouseDraggedReceived = false; + mouseReleasedReceived = false; + itemStateChangedReceived = false; + actionPerformedReceived = false; + } + } +} diff --git a/test/jdk/java/awt/event/MouseEvent/MouseEventsDuringDrag.java b/test/jdk/java/awt/event/MouseEvent/MouseEventsDuringDrag.java new file mode 100644 index 0000000000000..4a4c9d36af169 --- /dev/null +++ b/test/jdk/java/awt/event/MouseEvent/MouseEventsDuringDrag.java @@ -0,0 +1,307 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4017222 + * @summary Checks whether mouse events are reported correctly during drag. + * @author Stuart Lawrence, Brent Christian: area=event + * @key headful + * @library /lib/client /java/awt/regtesthelpers + * @build ExtendedRobot Util + * @run main MouseEventsDuringDrag + */ + + +/* + * MouseEventsDuringDrag.java + * + * summary: + * On Solaris drag enter/exit events are only reported for the + * component where drag started, they're not reported on other + * components. On Win32 enter/exit events are reported correctly. + */ + +import test.java.awt.regtesthelpers.Util; + +import java.awt.Canvas; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.Label; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +public class MouseEventsDuringDrag { + + private static ExtendedRobot robot; + private static Frame frame; + + private static final MouseHandler mouseHandler = new MouseHandler(); + + static Label lab; + static Canvas c1, c2; + static Choice choice; + + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(MouseEventsDuringDrag::createAndShowGUI); + test(); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void test() throws Exception { + robot = new ExtendedRobot(); + robot.waitForIdle(); + robot.delay(500); + + // Part 1: Press and hold down the mouse button inside the red box. + // Drag the mouse over to the blue box (whilst still holding down + // the mouse button). + // Whilst dragging the mouse from the red box, enter and exit + // events should be reported for the blue box. + testcase(c2, "c1 to c2"); + + // Part 2: Again, press and hold down the mouse button inside the red box. + // This time drag the mouse over to the Choice menu. + // Enter and exit events should be reported for the Choice menu. + testcase(choice, "c1 to choice"); + } + + private static void testcase(Component moveTo, String message) throws Exception { + System.out.println("\ntestcase: " + message); + Rectangle c1bounds = getBounds(c1); + Rectangle moveToBound = getBounds(moveTo); + + Point startDragLocation = + new Point(c1bounds.x + c1bounds.width - 10, + c1bounds.y + c1bounds.height / 2); + + Point endDragLocation = + new Point(moveToBound.x + 10, moveToBound.y + moveToBound.height / 2); + + robot.mouseMove(startDragLocation); + robot.waitForIdle(); + robot.delay(200); + mouseHandler.reset(); + + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + + robot.glide(startDragLocation, endDragLocation); + robot.waitForIdle(); + + robot.glide(endDragLocation.x, endDragLocation.y, endDragLocation.x - 20, endDragLocation.y); + + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + robot.waitForIdle(); + robot.delay(200); + + List actual = mouseHandler.getRecordedEvents(); + + List expected = List.of( + new EventRecord(MouseEvent.MOUSE_PRESSED, c1), + new EventRecord(MouseEvent.MOUSE_EXITED, c1), + new EventRecord(MouseEvent.MOUSE_ENTERED, moveTo), + new EventRecord(MouseEvent.MOUSE_EXITED, moveTo), + new EventRecord(MouseEvent.MOUSE_RELEASED, c1) + ); + + System.out.println("Expected:\n" + expected); + System.out.println("Actual:\n" + actual); + if (!actual.equals(expected)) { + throw new RuntimeException("Mismatch between expected and actual events\n%s\n%s" + .formatted(expected, actual)); + } + } + + private static Rectangle getBounds(Component c) throws Exception { + return Util.invokeOnEDT(() -> { + Point locationOnScreen = c.getLocationOnScreen(); + Dimension size = c.getSize(); + return new Rectangle(locationOnScreen.x, locationOnScreen.y, size.width, size.height); + }); + } + + private static void createAndShowGUI() { + frame = new Frame(); + MouseHandler mouseHandler = new MouseHandler(); + frame.setLayout(new GridBagLayout()); + + int canvasSize = 100; + c1 = new Canvas(); + c1.setPreferredSize(new Dimension(canvasSize, canvasSize)); + c1.setBackground(Color.red); + c1.addMouseListener(mouseHandler); + + c2 = new Canvas(); + c2.setPreferredSize(new Dimension(canvasSize, canvasSize)); + c2.setBackground(Color.blue); + c2.addMouseListener(mouseHandler); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.insets = new Insets(5, 5, 5, 5); + + gbc.gridx = 0; + gbc.gridy = 0; + frame.add(c1, gbc); + + gbc.gridx = 2; + frame.add(c2, gbc); + + Panel p1 = new Panel(); + p1.setLayout(new FlowLayout()); + choice = new Choice(); + choice.addItem("Choice"); + choice.addItem("One"); + choice.addItem("Two"); + choice.addMouseListener(mouseHandler); + p1.add(choice); + + gbc.gridx = 1; + gbc.gridy = 1; + frame.add(p1, gbc); + + lab = new Label(); + + gbc.gridx = 0; + gbc.gridy = 2; + gbc.gridwidth = 3; + frame.add(lab, gbc); + + frame.pack(); + frame.setLocationRelativeTo(null); + + frame.setVisible(true); + } + + record EventRecord(int eventId, Component component) { + + @Override + public String toString() { + StringBuilder str = new StringBuilder(80); + switch(eventId) { + case MouseEvent.MOUSE_PRESSED: + str.append("MOUSE_PRESSED"); + break; + case MouseEvent.MOUSE_RELEASED: + str.append("MOUSE_RELEASED"); + break; + case MouseEvent.MOUSE_CLICKED: + str.append("MOUSE_CLICKED"); + break; + case MouseEvent.MOUSE_ENTERED: + str.append("MOUSE_ENTERED"); + break; + case MouseEvent.MOUSE_EXITED: + str.append("MOUSE_EXITED"); + break; + case MouseEvent.MOUSE_MOVED: + str.append("MOUSE_MOVED"); + break; + case MouseEvent.MOUSE_DRAGGED: + str.append("MOUSE_DRAGGED"); + break; + case MouseEvent.MOUSE_WHEEL: + str.append("MOUSE_WHEEL"); + break; + default: + str.append("unknown type"); + } + return str.append(" ").append(component).toString(); + } + } + + static class MouseHandler extends MouseAdapter { + static final List list = new CopyOnWriteArrayList<>(); + + public void mousePressed(MouseEvent e) { + list.add(new EventRecord(e.getID(), e.getComponent())); + if (e.getSource() == c1) { + lab.setText("Mouse pressed in red box"); + } else if (e.getSource() == c2) { + lab.setText("Mouse pressed in blue box"); + } else if (e.getSource() == choice) { + lab.setText("Mouse pressed in choice"); + } + } + + public void mouseReleased(MouseEvent e) { + list.add(new EventRecord(e.getID(), e.getComponent())); + lab.setText("Mouse released"); + } + + public void mouseEntered(MouseEvent e) { + list.add(new EventRecord(e.getID(), e.getComponent())); + if (e.getSource() == c1) { + lab.setText("Mouse entered red box"); + } else if (e.getSource() == c2) { + lab.setText("Mouse entered blue box"); + } else if (e.getSource() == choice) { + lab.setText("Mouse entered choice"); + } + } + + public void mouseExited(MouseEvent e) { + list.add(new EventRecord(e.getID(), e.getComponent())); + if (e.getSource() == c1) { + lab.setText("Mouse exited red box"); + } else if (e.getSource() == c2) { + lab.setText("Mouse exited blue box"); + } else if (e.getSource() == choice) { + lab.setText("Mouse exited choice"); + } + } + + public void reset() { + list.clear(); + } + + public List getRecordedEvents() { + return new ArrayList<>(list); + } + } +} diff --git a/test/jdk/java/awt/event/MouseEvent/MouseModifierTest.java b/test/jdk/java/awt/event/MouseEvent/MouseModifierTest.java new file mode 100644 index 0000000000000..5b8f0f62f7b0a --- /dev/null +++ b/test/jdk/java/awt/event/MouseEvent/MouseModifierTest.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4117523 + * @summary Solaris: MousePressed event has modifier=0 when left button is pressed + * @key headful + * @library /javax/swing/regtesthelpers /test/lib + * @build Util jdk.test.lib.Platform + * @run main MouseModifierTest +*/ + + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import jdk.test.lib.Platform; + +public class MouseModifierTest { + private static Frame frame; + private static volatile MouseEvent lastMousePressedEvent = null; + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(MouseModifierTest::createAndShowGUI); + test(); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void test() throws Exception { + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(500); + + Point centerPoint = Util.getCenterPoint(frame); + + System.out.println("MOUSE1 press case"); + + robot.mouseMove(centerPoint.x, centerPoint.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(25); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(300); + + if (lastMousePressedEvent == null + || lastMousePressedEvent.getModifiers() != InputEvent.BUTTON1_MASK) { + throw new RuntimeException("Test failed"); + } + + if (Platform.isWindows()) { + System.out.println("Windows: Testing ALT + MOUSE1 press case"); + lastMousePressedEvent = null; + robot.waitForIdle(); + robot.delay(300); + + robot.keyPress(KeyEvent.VK_ALT); + robot.delay(25); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(25); + robot.keyRelease(KeyEvent.VK_ALT); + robot.delay(25); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(300); + + int expectedModifiers = InputEvent.BUTTON1_MASK + | InputEvent.BUTTON2_MASK + | InputEvent.ALT_MASK; + if (lastMousePressedEvent == null + || lastMousePressedEvent.getModifiers() != expectedModifiers) { + throw new RuntimeException("Test failed"); + } + } + } + + private static void createAndShowGUI() { + frame = new Frame("MouseModifierTest"); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + frame.addMouseListener(new MouseHandler()); + frame.setVisible(true); + } + + private static class MouseHandler extends MouseAdapter { + public void mouseClicked(MouseEvent e) { + System.out.println("\nmouseClicked:"); + printMouseEventDetail(e); + } + + public void mousePressed(MouseEvent e) { + lastMousePressedEvent = e; + System.out.println("\nmousePressed:"); + printMouseEventDetail(e); + } + + public void mouseReleased(MouseEvent e) { + System.out.println("\nmouseReleased:"); + printMouseEventDetail(e); + } + + public void mouseEntered(MouseEvent e) { + System.out.println("\nmouseEntered:"); + printMouseEventDetail(e); + } + + public void mouseExited(MouseEvent e) { + System.out.println("\nmouseExited:"); + printMouseEventDetail(e); + } + + private void printMouseEventDetail(MouseEvent e) { + System.out.println(e.toString()); + System.out.println("Modifiers: "); + printModifiers(e); + } + + private void printModifiers(MouseEvent e) { + if (e == null) { + return; + } + + int mod = e.getModifiers(); + + if ((mod & InputEvent.ALT_MASK) != 0) { + System.out.println("\tALT_MASK"); + } + if ((mod & InputEvent.BUTTON1_MASK) != 0) { + System.out.println("\tBUTTON1_MASK"); + } + if ((mod & InputEvent.BUTTON2_MASK) != 0) { + System.out.println("\tBUTTON2_MASK"); + } + if ((mod & InputEvent.BUTTON3_MASK) != 0) { + System.out.println("\tBUTTON3_MASK"); + } + if ((mod & InputEvent.CTRL_MASK) != 0) { + System.out.println("\tCTRL_MASK"); + } + if ((mod & InputEvent.META_MASK) != 0) { + System.out.println("\tMETA_MASK"); + } + if ((mod & InputEvent.SHIFT_MASK) != 0) { + System.out.println("\tSHIFT_MASK"); + } + } + } +} diff --git a/test/jdk/java/awt/event/MouseEvent/MouseRButTest.java b/test/jdk/java/awt/event/MouseEvent/MouseRButTest.java new file mode 100644 index 0000000000000..e5cb1195bae84 --- /dev/null +++ b/test/jdk/java/awt/event/MouseEvent/MouseRButTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4037521 + * @summary Mouse Right button does not send mouseClick action + * @key headful + * @library /javax/swing/regtesthelpers + * @build Util + * @run main MouseRButTest + */ + +import java.awt.Button; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class MouseRButTest { + private static Frame frame; + private static Button button; + private static final CountDownLatch latch = new CountDownLatch(1); + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + try { + EventQueue.invokeAndWait(MouseRButTest::createAndShowGUI); + + robot.waitForIdle(); + robot.delay(500); + + Point point = Util.getCenterPoint(button); + robot.mouseMove(point.x, point.y); + robot.waitForIdle(); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.delay(50); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + + if (!latch.await(2, TimeUnit.SECONDS)) { + throw new RuntimeException("mouse click action was not sent"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createAndShowGUI() { + button = new Button("Click Me"); + button.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + System.out.println(e); + if (e.getModifiers() == e.BUTTON3_MASK) { + System.out.println("right mouse button clicked"); + latch.countDown(); + } + } + }); + + frame = new Frame(); + frame.setLayout(new FlowLayout()); + frame.add(button); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } +} diff --git a/test/jdk/java/awt/event/MouseEvent/TitleBarGetsMousePressed.java b/test/jdk/java/awt/event/MouseEvent/TitleBarGetsMousePressed.java new file mode 100644 index 0000000000000..35f071a9e6da6 --- /dev/null +++ b/test/jdk/java/awt/event/MouseEvent/TitleBarGetsMousePressed.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Frame; +import java.awt.Window; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4074498 + * @summary Test: MOUSE_PRESSED events in the title bar of a frame + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TitleBarGetsMousePressed + */ +public class TitleBarGetsMousePressed { + private static final String INSTRUCTIONS = """ + 1. You will see a Frame window next to this window with instructions + 2. Clicking in the title bar of the Frame and even moving around the Frame + should not generate MOUSE_PRESSED / MOUSE_RELEASED / MOUSE_CLICKED events. + (printed below in the log area). + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TitleBarGetsMousePressed Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(TitleBarGetsMousePressed::createTestUI) + .logArea(5) + .build() + .awaitAndCheck(); + } + + private static Window createTestUI() { + Frame frame = new Frame("TitleBarGetsMousePressed"); + frame.setSize(300, 200); + frame.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent ev) { + PassFailJFrame.log("mouseClicked at x:" + ev.getX() + + " y:" + ev.getY()); + } + + public void mousePressed(MouseEvent ev) { + PassFailJFrame.log("mousePressed at x:" + ev.getX() + + " y:" + ev.getY()); + } + + public void mouseReleased(MouseEvent ev) { + PassFailJFrame.log("mouseReleased at x:" + ev.getX() + + " y:" + ev.getY()); + } + }); + + return frame; + } +} From 776e1cf1dfefd7cb1a0190ab71f71ad5ff25d0e4 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Wed, 9 Apr 2025 20:06:49 +0000 Subject: [PATCH 0501/1101] 8353041: NeverBranchNode causes incorrect block frequency calculation Reviewed-by: thartmann, rcastanedalo --- src/hotspot/share/opto/domgraph.cpp | 14 +++++++++++++- src/hotspot/share/opto/gcm.cpp | 7 ++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/domgraph.cpp b/src/hotspot/share/opto/domgraph.cpp index a80358e1d0f7d..b52f4232c4edd 100644 --- a/src/hotspot/share/opto/domgraph.cpp +++ b/src/hotspot/share/opto/domgraph.cpp @@ -233,9 +233,21 @@ uint Block_Stack::most_frequent_successor( Block *b ) { case Op_Jump: case Op_Root: case Op_Goto: - case Op_NeverBranch: freq_idx = 0; // fall thru break; + case Op_NeverBranch: { + Node* succ = n->as_NeverBranch()->proj_out(0)->unique_ctrl_out(); + int succ_idx = 0; // normal case + if (succ == b->_succs[1]->head()) { + // Edges swapped, rare case. May happen due to an unusual matcher + // traversal order for peeled infinite loops. + succ_idx = 1; + } else { + assert(succ == b->_succs[0]->head(), "succ not found"); + } + freq_idx = succ_idx; + break; + } case Op_TailCall: case Op_TailJump: case Op_ForwardException: diff --git a/src/hotspot/share/opto/gcm.cpp b/src/hotspot/share/opto/gcm.cpp index eeab96de3fa0c..a8080d5adb96e 100644 --- a/src/hotspot/share/opto/gcm.cpp +++ b/src/hotspot/share/opto/gcm.cpp @@ -2160,8 +2160,13 @@ float Block::succ_prob(uint i) { // Pass frequency straight thru to target return 1.0f; - case Op_NeverBranch: + case Op_NeverBranch: { + Node* succ = n->as_NeverBranch()->proj_out(0)->unique_ctrl_out(); + if (_succs[i]->head() == succ) { + return 1.0f; + } return 0.0f; + } case Op_TailCall: case Op_TailJump: From 4a242e3a65f13c41c699d42b100ba2b252d7faaa Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Wed, 9 Apr 2025 20:14:10 +0000 Subject: [PATCH 0502/1101] 8354213: Restore pointless unicode characters to ASCII Reviewed-by: naoto, erikj, iris --- CONTRIBUTING.md | 2 +- doc/hotspot-unit-tests.md | 14 +++++++------- src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp | 2 +- .../gc/shared/barrierSetAssembler_riscv.cpp | 2 +- src/hotspot/cpu/riscv/macroAssembler_riscv.hpp | 6 +++--- src/hotspot/cpu/s390/disassembler_s390.cpp | 4 ++-- src/hotspot/cpu/s390/s390.ad | 2 +- src/hotspot/os/aix/libperfstat_aix.hpp | 2 +- .../linux_aarch64/atomic_linux_aarch64.S | 2 +- .../os_cpu/linux_aarch64/copy_linux_aarch64.S | 2 +- .../linux_aarch64/safefetch_linux_aarch64.S | 2 +- .../linux_aarch64/threadLS_linux_aarch64.S | 2 +- .../linux_riscv/orderAccess_linux_riscv.hpp | 4 ++-- src/hotspot/share/cds/archiveUtils.hpp | 2 +- src/hotspot/share/oops/method.cpp | 2 +- test/hotspot/gtest/gc/g1/test_g1CardSet.cpp | 2 +- test/hotspot/gtest/runtime/test_os_windows.cpp | 4 ++-- .../gcbarriers/TestZGCBarrierElision.java | 18 +++++++++--------- .../compiler/lib/generators/Generators.java | 2 +- .../JniArmHFTestGenerator.java.txt | 8 ++++---- .../java/awt/image/DrawImage/TiledImage.java | 2 +- test/jdk/jdk/jfr/tool/jfr.xsd | 4 ++-- 22 files changed, 45 insertions(+), 45 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4a338235c1d22..98ede25b88df5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,3 @@ # Contributing to the JDK -Please see the [OpenJDK Developers’ Guide](https://openjdk.org/guide/). +Please see the [OpenJDK Developers' Guide](https://openjdk.org/guide/). diff --git a/doc/hotspot-unit-tests.md b/doc/hotspot-unit-tests.md index e1222baa2e3a4..69a9530710987 100644 --- a/doc/hotspot-unit-tests.md +++ b/doc/hotspot-unit-tests.md @@ -106,7 +106,7 @@ Prefer having checks inside test code. Not only does having test logic outside, e.g. verification method, depending on asserts in product code contradict with several items -above but also decreases test’s readability and stability. It is much +above but also decreases test's readability and stability. It is much easier to understand that a test is testing when all testing logic is located inside a test or nearby in shared test libraries. As a rule of thumb, the closer a check to a test, the better. @@ -119,7 +119,7 @@ Prefer `EXPECT` over `ASSERT` if possible. This is related to the [informativeness](#informativeness) property of tests, information for other checks can help to better localize a -defect’s root-cause. One should use `ASSERT` if it is impossible to +defect's root-cause. One should use `ASSERT` if it is impossible to continue test execution or if it does not make much sense. Later in the text, `EXPECT` forms will be used to refer to both `ASSERT/EXPECT`. @@ -160,7 +160,7 @@ value of the difference between `v1` and `v2` is not greater than `eps`. Use string special macros for C strings comparisons. -`EXPECT_EQ` just compares pointers’ values, which is hardly what one +`EXPECT_EQ` just compares pointers' values, which is hardly what one wants comparing C strings. GoogleTest provides `EXPECT_STREQ` and `EXPECT_STRNE` macros to compare C string contents. There are also case-insensitive versions `EXPECT_STRCASEEQ`, `EXPECT_STRCASENE`. @@ -226,7 +226,7 @@ subsystem, etc. This naming scheme helps to find tests, filter them and simplifies test failure analysis. For example, class `Foo` - test group `Foo`, -compiler logging subsystem - test group `CompilerLogging`, G1 GC — test +compiler logging subsystem - test group `CompilerLogging`, G1 GC - test group `G1GC`, and so forth. ### Filename @@ -287,7 +287,7 @@ Fixture classes should be named after tested classes, subsystems, etc All test purpose friends should have either `Test` or `Testable` suffix. -It greatly simplifies understanding of friendship’s purpose and allows +It greatly simplifies understanding of friendship's purpose and allows statically check that private members are not exposed unexpectedly. Having `FooTest` as a friend of `Foo` without any comments will be understood as a necessary evil to get testability. @@ -397,7 +397,7 @@ and filter out inapplicable tests. Restore changed flags. It is quite common for tests to configure JVM in a certain way -changing flags’ values. GoogleTest provides two ways to set up +changing flags' values. GoogleTest provides two ways to set up environment before a test and restore it afterward: using either constructor and destructor or `SetUp` and `TearDown` functions. Both ways require to use a test fixture class, which sometimes is too wordy. The @@ -406,7 +406,7 @@ be used in such cases to restore/set values. Caveats: -* Changing a flag’s value could break the invariants between flags' values and hence could lead to unexpected/unsupported JVM state. +* Changing a flag's value could break the invariants between flags' values and hence could lead to unexpected/unsupported JVM state. * `FLAG_SET_*` macros can change more than one flag (in order to maintain invariants) so it is hard to predict what flags will be diff --git a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp index b9bd7b356fa6b..d55521823ecdc 100644 --- a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp @@ -87,7 +87,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ mv(t1, _array->as_pointer_register()); stub_id = C1StubId::throw_range_check_failed_id; } - // t0 and t1 are used as args in generate_exception_throw, + // t0 and t1 are used as args in generate_exception_throw, // so use x1/ra as the tmp register for rt_call. __ rt_call(Runtime1::entry_for(stub_id), ra); ce->add_call_info_here(_info); diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index d66a86c750a26..5b3c926cfa96b 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -275,7 +275,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo // order, while allowing other independent instructions to be reordered. // Note: This may be slower than using a membar(load|load) (fence r,r). // Because processors will not start the second load until the first comes back. - // This means you can’t overlap the two loads, + // This means you can't overlap the two loads, // which is stronger than needed for ordering (stronger than TSO). __ srli(ra, t0, 32); __ orr(t1, t1, ra); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 153b6d77f9937..e145639bbe731 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -670,9 +670,9 @@ class MacroAssembler: public Assembler { // JALR, return address stack updates: // | rd is x1/x5 | rs1 is x1/x5 | rd=rs1 | RAS action // | ----------- | ------------ | ------ |------------- - // | No | No | — | None - // | No | Yes | — | Pop - // | Yes | No | — | Push + // | No | No | - | None + // | No | Yes | - | Pop + // | Yes | No | - | Push // | Yes | Yes | No | Pop, then push // | Yes | Yes | Yes | Push // diff --git a/src/hotspot/cpu/s390/disassembler_s390.cpp b/src/hotspot/cpu/s390/disassembler_s390.cpp index 98cff15f2ae78..a69851cfdba24 100644 --- a/src/hotspot/cpu/s390/disassembler_s390.cpp +++ b/src/hotspot/cpu/s390/disassembler_s390.cpp @@ -62,7 +62,7 @@ address Disassembler::decode_instruction0(address here, outputStream * st, addre if (Assembler::is_z_nop((long)instruction_2bytes)) { #if 1 - st->print("nop "); // fill up to operand column, leads to better code comment alignment + st->print("nop "); // fill up to operand column, leads to better code comment alignment next = here + 2; #else // Compact disassembler output. Does not work the easy way. @@ -76,7 +76,7 @@ address Disassembler::decode_instruction0(address here, outputStream * st, addre instruction_2bytes = *(uint16_t*)(here+2*n_nops); } if (n_nops <= 4) { // do not group few subsequent nops - st->print("nop "); // fill up to operand column, leads to better code comment alignment + st->print("nop "); // fill up to operand column, leads to better code comment alignment next = here + 2; } else { st->print("nop count=%d", n_nops); diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index fc7de7e70e909..ea1bdb9e231ea 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -6581,7 +6581,7 @@ instruct mulHiL_reg_reg(revenRegL Rdst, roddRegL Rsrc1, iRegL Rsrc2, iRegL Rtmp1 Register tmp1 = $Rtmp1$$Register; Register tmp2 = $Rdst$$Register; // z/Architecture has only unsigned multiply (64 * 64 -> 128). - // implementing mulhs(a,b) = mulhu(a,b) – (a & (b>>63)) – (b & (a>>63)) + // implementing mulhs(a,b) = mulhu(a,b) - (a & (b>>63)) - (b & (a>>63)) __ z_srag(tmp2, src1, 63); // a>>63 __ z_srag(tmp1, src2, 63); // b>>63 __ z_ngr(tmp2, src2); // b & (a>>63) diff --git a/src/hotspot/os/aix/libperfstat_aix.hpp b/src/hotspot/os/aix/libperfstat_aix.hpp index f35f517b489f9..a984440e57976 100644 --- a/src/hotspot/os/aix/libperfstat_aix.hpp +++ b/src/hotspot/os/aix/libperfstat_aix.hpp @@ -332,7 +332,7 @@ typedef struct { /* component perfstat_cpu_t from AIX 7.2 documentation */ u_longlong_t busy_stolen_purr; /* Number of busy cycles stolen by the hypervisor from a dedicated partition. */ u_longlong_t busy_stolen_spurr; /* Number of busy spurr cycles stolen by the hypervisor from a dedicated partition.*/ u_longlong_t shcpus_in_sys; /* Number of physical processors allocated for shared processor use, across all shared processors pools. */ - u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partition’s pool. */ + u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partition's pool. */ u_longlong_t pool_max_time; /* Summation of maximum time that can be consumed by the pool (nanoseconds). */ u_longlong_t pool_busy_time; /* Summation of busy (nonidle) time accumulated across all partitions in the pool (nanoseconds). */ u_longlong_t pool_scaled_busy_time; /* Scaled summation of busy (nonidle) time accumulated across all partitions in the pool (nanoseconds). */ diff --git a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S index b3e7f64397970..9ae19fa0cd9a8 100644 --- a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S +++ b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S @@ -295,7 +295,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_8_relaxed_default_impl): ret /* Emit .note.gnu.property section in case of PAC or BTI being enabled. - * For more details see "ELF for the Arm® 64-bit Architecture (AArch64)". + * For more details see "ELF for the Arm(R) 64-bit Architecture (AArch64)". * https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst */ #ifdef __ARM_FEATURE_BTI_DEFAULT diff --git a/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S index 33fe81d920653..8abf9f4905750 100644 --- a/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S +++ b/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S @@ -269,7 +269,7 @@ bwd_copy_drain: ret /* Emit .note.gnu.property section in case of PAC or BTI being enabled. - * For more details see "ELF for the Arm® 64-bit Architecture (AArch64)". + * For more details see "ELF for the Arm(R) 64-bit Architecture (AArch64)". * https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst */ #ifdef __ARM_FEATURE_BTI_DEFAULT diff --git a/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S index a26aab44ac43d..ffffb7550bfdf 100644 --- a/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S +++ b/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S @@ -50,7 +50,7 @@ DECLARE_FUNC(_SafeFetchN_continuation): ret /* Emit .note.gnu.property section in case of PAC or BTI being enabled. - * For more details see "ELF for the Arm® 64-bit Architecture (AArch64)". + * For more details see "ELF for the Arm(R) 64-bit Architecture (AArch64)". * https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst */ #ifdef __ARM_FEATURE_BTI_DEFAULT diff --git a/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S index 55a252301d793..451c13773be60 100644 --- a/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S +++ b/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S @@ -46,7 +46,7 @@ DECLARE_FUNC(_ZN10JavaThread25aarch64_get_thread_helperEv): .size _ZN10JavaThread25aarch64_get_thread_helperEv, .-_ZN10JavaThread25aarch64_get_thread_helperEv /* Emit .note.gnu.property section in case of PAC or BTI being enabled. - * For more details see "ELF for the Arm® 64-bit Architecture (AArch64)". + * For more details see "ELF for the Arm(R) 64-bit Architecture (AArch64)". * https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst */ #ifdef __ARM_FEATURE_BTI_DEFAULT diff --git a/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp index f46380aaac6f4..828a603577d0f 100644 --- a/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp +++ b/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp @@ -54,13 +54,13 @@ inline void OrderAccess::fence() { } inline void OrderAccess::cross_modify_fence_impl() { - // From 3 “Zifencei” Instruction-Fetch Fence, Version 2.0 + // From 3 "Zifencei" Instruction-Fetch Fence, Version 2.0 // "RISC-V does not guarantee that stores to instruction memory will be made // visible to instruction fetches on a RISC-V hart until that hart executes a // FENCE.I instruction. A FENCE.I instruction ensures that a subsequent // instruction fetch on a RISC-V hart will see any previous data stores // already visible to the same RISC-V hart. FENCE.I does not ensure that other - // RISC-V harts’ instruction fetches will observe the local hart’s stores in a + // RISC-V harts' instruction fetches will observe the local hart's stores in a // multiprocessor system." // // Hence to be able to use fence.i directly we need a kernel that supports diff --git a/src/hotspot/share/cds/archiveUtils.hpp b/src/hotspot/share/cds/archiveUtils.hpp index 59146547aca9f..56d28ec910ce7 100644 --- a/src/hotspot/share/cds/archiveUtils.hpp +++ b/src/hotspot/share/cds/archiveUtils.hpp @@ -106,7 +106,7 @@ class ArchivePtrMarker : AllStatic { // within the archive (e.g., InstanceKlass::_name points to a Symbol in the archive). During dumping, we // built a bitmap that marks the locations of all these pointers (using ArchivePtrMarker, see comments above). // -// The contents of the archive assumes that it’s mapped at the default SharedBaseAddress (e.g. 0x800000000). +// The contents of the archive assumes that it's mapped at the default SharedBaseAddress (e.g. 0x800000000). // If the archive ends up being mapped at a different address (e.g. 0x810000000), SharedDataRelocator // is used to shift each marked pointer by a delta (0x10000000 in this example), so that it points to // the actually mapped location of the target object. diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 012420aaf5063..0c4430b44c3f5 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -433,7 +433,7 @@ void Method::set_itable_index(int index) { // itable index should be the same as the runtime index. assert(_vtable_index == itable_index_max - index, "archived itable index is different from runtime index"); - return; // don’t write into the shared class + return; // don't write into the shared class } else { _vtable_index = itable_index_max - index; } diff --git a/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp b/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp index 1e4e478db79e6..958561dc15e51 100644 --- a/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp @@ -70,7 +70,7 @@ class G1CardSetTest : public ::testing::Test { ~G1CardSetTest() { } static uint next_random(uint& seed, uint i) { - // Park–Miller random number generator + // Park-Miller random number generator seed = (seed * 279470273u) % 0xfffffffb; return (seed % i); } diff --git a/test/hotspot/gtest/runtime/test_os_windows.cpp b/test/hotspot/gtest/runtime/test_os_windows.cpp index d539f20cbeb75..83771368b57b4 100644 --- a/test/hotspot/gtest/runtime/test_os_windows.cpp +++ b/test/hotspot/gtest/runtime/test_os_windows.cpp @@ -82,7 +82,7 @@ void TestReserveMemorySpecial_test() { // Instead try reserving after the first reservation. expected_location = result + large_allocation_size; actual_location = os::reserve_memory_special(expected_allocation_size, os::large_page_size(), os::large_page_size(), expected_location, false); - EXPECT_TRUE(actual_location != nullptr) << "Unexpected reservation failure, can’t verify correct location"; + EXPECT_TRUE(actual_location != nullptr) << "Unexpected reservation failure, can't verify correct location"; EXPECT_TRUE(actual_location == expected_location) << "Reservation must be at requested location"; MemoryReleaser m2(actual_location, os::large_page_size()); @@ -90,7 +90,7 @@ void TestReserveMemorySpecial_test() { const size_t alignment = os::large_page_size() * 2; const size_t new_large_size = alignment * 4; char* aligned_request = os::reserve_memory_special(new_large_size, alignment, os::large_page_size(), nullptr, false); - EXPECT_TRUE(aligned_request != nullptr) << "Unexpected reservation failure, can’t verify correct alignment"; + EXPECT_TRUE(aligned_request != nullptr) << "Unexpected reservation failure, can't verify correct alignment"; EXPECT_TRUE(is_aligned(aligned_request, alignment)) << "Returned address must be aligned"; MemoryReleaser m3(aligned_request, new_large_size); } diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestZGCBarrierElision.java b/test/hotspot/jtreg/compiler/gcbarriers/TestZGCBarrierElision.java index d8bec5e4368a1..4c94cd62c42d0 100644 --- a/test/hotspot/jtreg/compiler/gcbarriers/TestZGCBarrierElision.java +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestZGCBarrierElision.java @@ -191,7 +191,7 @@ void runControlFlowTests() { static void testAllocateThenAtomic(Inner i) { Outer o = new Outer(); Common.blackhole(o); - Common.field1VarHandle.getAndSet​(o, i); + Common.field1VarHandle.getAndSet(o, i); } @Test @@ -199,14 +199,14 @@ static void testAllocateThenAtomic(Inner i) { @IR(counts = { IRNode.Z_GET_AND_SET_P_WITH_BARRIER_FLAG, Common.REMAINING, "1" }, phase = CompilePhase.FINAL_CODE) static void testLoadThenAtomic(Outer o, Inner i) { Common.blackhole(o.field1); - Common.field1VarHandle.getAndSet​(o, i); + Common.field1VarHandle.getAndSet(o, i); } @Test @IR(counts = { IRNode.Z_GET_AND_SET_P_WITH_BARRIER_FLAG, Common.REMAINING, "2" }, phase = CompilePhase.FINAL_CODE) static void testAtomicThenAtomicAnotherField(Outer o, Inner i) { - Common.field1VarHandle.getAndSet​(o, i); - Common.field2VarHandle.getAndSet​(o, i); + Common.field1VarHandle.getAndSet(o, i); + Common.field2VarHandle.getAndSet(o, i); } @Test @@ -390,14 +390,14 @@ void runControlFlowTests() { @IR(counts = { IRNode.Z_GET_AND_SET_P_WITH_BARRIER_FLAG, Common.ELIDED, "1" }, phase = CompilePhase.FINAL_CODE) static void testStoreThenAtomic(Outer o, Inner i) { o.field1 = i; - Common.field1VarHandle.getAndSet​(o, i); + Common.field1VarHandle.getAndSet(o, i); } @Test @IR(counts = { IRNode.Z_GET_AND_SET_P_WITH_BARRIER_FLAG, Common.REMAINING, "1" }, phase = CompilePhase.FINAL_CODE) @IR(counts = { IRNode.Z_LOAD_P_WITH_BARRIER_FLAG, Common.ELIDED, "1" }, phase = CompilePhase.FINAL_CODE) static void testAtomicThenLoad(Outer o, Inner i) { - Common.field1VarHandle.getAndSet​(o, i); + Common.field1VarHandle.getAndSet(o, i); Common.blackhole(o.field1); } @@ -405,7 +405,7 @@ static void testAtomicThenLoad(Outer o, Inner i) { @IR(counts = { IRNode.Z_GET_AND_SET_P_WITH_BARRIER_FLAG, Common.REMAINING, "1" }, phase = CompilePhase.FINAL_CODE) @IR(counts = { IRNode.Z_STORE_P_WITH_BARRIER_FLAG, Common.ELIDED, "1" }, phase = CompilePhase.FINAL_CODE) static void testAtomicThenStore(Outer o, Inner i) { - Common.field1VarHandle.getAndSet​(o, i); + Common.field1VarHandle.getAndSet(o, i); o.field1 = i; } @@ -413,8 +413,8 @@ static void testAtomicThenStore(Outer o, Inner i) { @IR(counts = { IRNode.Z_GET_AND_SET_P_WITH_BARRIER_FLAG, Common.REMAINING, "1" }, phase = CompilePhase.FINAL_CODE) @IR(counts = { IRNode.Z_GET_AND_SET_P_WITH_BARRIER_FLAG, Common.ELIDED, "1" }, phase = CompilePhase.FINAL_CODE) static void testAtomicThenAtomic(Outer o, Inner i) { - Common.field1VarHandle.getAndSet​(o, i); - Common.field1VarHandle.getAndSet​(o, i); + Common.field1VarHandle.getAndSet(o, i); + Common.field1VarHandle.getAndSet(o, i); } @Test diff --git a/test/hotspot/jtreg/compiler/lib/generators/Generators.java b/test/hotspot/jtreg/compiler/lib/generators/Generators.java index 16f1b6be9b17c..231b9822990af 100644 --- a/test/hotspot/jtreg/compiler/lib/generators/Generators.java +++ b/test/hotspot/jtreg/compiler/lib/generators/Generators.java @@ -100,7 +100,7 @@ *

* Unless you have reasons to pick a specific distribution, you are encouraged to rely on {@link #ints()}, * {@link #longs()}, {@link #doubles()} and {@link #floats()}, which will randomly pick an interesting distribution. - * This is best practice, because that allows the test to be run under different conditions – maybe only a single + * This is best practice, because that allows the test to be run under different conditions - maybe only a single * distribution can trigger a bug. */ public final class Generators { diff --git a/test/hotspot/jtreg/vmTestbase/vm/jit/LongTransitions/JniArmHFTestGenerator.java.txt b/test/hotspot/jtreg/vmTestbase/vm/jit/LongTransitions/JniArmHFTestGenerator.java.txt index 9bd6f0b930835..91d5129f1eb33 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/jit/LongTransitions/JniArmHFTestGenerator.java.txt +++ b/test/hotspot/jtreg/vmTestbase/vm/jit/LongTransitions/JniArmHFTestGenerator.java.txt @@ -435,7 +435,7 @@ enum NumberType { this.rndFnc = rndFnc; } - public String getСType() { + public String getCType() { return cType; } @@ -443,7 +443,7 @@ enum NumberType { return jType; } - public String getСConv() { + public String getCConv() { return cConv; } @@ -792,9 +792,9 @@ class ParameterListGenerator { String randomVal = list.get(type).getFnc(); - String ctype = list.get(type).getСType(); + String ctype = list.get(type).getCType(); String jtype = list.get(type).getJType(); - String cconv = list.get(type).getСConv(); + String cconv = list.get(type).getCConv(); String jconv = list.get(type).getJConv(); String varName = "p" + cnt; diff --git a/test/jdk/java/awt/image/DrawImage/TiledImage.java b/test/jdk/java/awt/image/DrawImage/TiledImage.java index 8faca3aec6ab9..bd64edc37fdf8 100644 --- a/test/jdk/java/awt/image/DrawImage/TiledImage.java +++ b/test/jdk/java/awt/image/DrawImage/TiledImage.java @@ -91,7 +91,7 @@ * This bug is largely unnoticed because most {@code Raster.create} * methods actually create {@link WritableRaster} instances, even * when the user did not asked for writable raster. To make this - * bug apparent, we need to invoke {@code Raster.createRaster(…)} + * bug apparent, we need to invoke {@code Raster.createRaster(...)} * with a sample model for which no optimization is provided. */ public class TiledImage implements RenderedImage { diff --git a/test/jdk/jdk/jfr/tool/jfr.xsd b/test/jdk/jdk/jfr/tool/jfr.xsd index adf44493f8615..8a8382a540a58 100644 --- a/test/jdk/jdk/jfr/tool/jfr.xsd +++ b/test/jdk/jdk/jfr/tool/jfr.xsd @@ -1,4 +1,4 @@ - + @@ -78,4 +78,4 @@ - \ No newline at end of file + From 4954a336f88865a4c9b269ed2c152658275e9221 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Wed, 9 Apr 2025 20:20:15 +0000 Subject: [PATCH 0503/1101] 8350563: C2 compilation fails because PhaseCCP does not reach a fixpoint Co-authored-by: Matthias Ernst Reviewed-by: chagedorn, epeter --- src/hotspot/share/opto/mulnode.cpp | 7 ++- src/hotspot/share/opto/phaseX.cpp | 17 ++++-- .../jtreg/compiler/ccp/TestAndConZeroCCP.java | 59 +++++++++++++++++++ 3 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/ccp/TestAndConZeroCCP.java diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 3dbff5ca7bc15..1d046583ee04b 100644 --- a/src/hotspot/share/opto/mulnode.cpp +++ b/src/hotspot/share/opto/mulnode.cpp @@ -2201,12 +2201,17 @@ const Type* RotateRightNode::Value(PhaseGVN* phase) const { // Returns a lower bound on the number of trailing zeros in expr. static jint AndIL_min_trailing_zeros(const PhaseGVN* phase, const Node* expr, BasicType bt) { - expr = expr->uncast(); const TypeInteger* type = phase->type(expr)->isa_integer(bt); if (type == nullptr) { return 0; } + expr = expr->uncast(); + type = phase->type(expr)->isa_integer(bt); + if (type == nullptr) { + return 0; + } + if (type->is_con()) { jlong con = type->get_con_as_long(bt); return con == 0L ? (type2aelembytes(bt) * BitsPerByte) : count_trailing_zeros(con); diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index ad6d8b4112f53..ae6e49e2c4e41 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1993,14 +1993,19 @@ void PhaseCCP::push_load_barrier(Unique_Node_List& worklist, const BarrierSetC2* } } -// AndI/L::Value() optimizes patterns similar to (v << 2) & 3 to zero if they are bitwise disjoint. -// Add the AndI/L nodes back to the worklist to re-apply Value() in case the shift value changed. -// Pattern: parent -> LShift (use) -> (ConstraintCast | ConvI2L)* -> And +// AndI/L::Value() optimizes patterns similar to (v << 2) & 3, or CON & 3 to zero if they are bitwise disjoint. +// Add the AndI/L nodes back to the worklist to re-apply Value() in case the value is now a constant or shift +// value changed. void PhaseCCP::push_and(Unique_Node_List& worklist, const Node* parent, const Node* use) const { + const TypeInteger* parent_type = type(parent)->isa_integer(type(parent)->basic_type()); uint use_op = use->Opcode(); - if ((use_op == Op_LShiftI || use_op == Op_LShiftL) - && use->in(2) == parent) { // is shift value (right-hand side of LShift) - auto push_and_uses_to_worklist = [&](Node* n){ + if ( + // Pattern: parent (now constant) -> (ConstraintCast | ConvI2L)* -> And + (parent_type != nullptr && parent_type->is_con()) || + // Pattern: parent -> LShift (use) -> (ConstraintCast | ConvI2L)* -> And + ((use_op == Op_LShiftI || use_op == Op_LShiftL) && use->in(2) == parent)) { + + auto push_and_uses_to_worklist = [&](Node* n) { uint opc = n->Opcode(); if (opc == Op_AndI || opc == Op_AndL) { push_if_not_bottom_type(worklist, n); diff --git a/test/hotspot/jtreg/compiler/ccp/TestAndConZeroCCP.java b/test/hotspot/jtreg/compiler/ccp/TestAndConZeroCCP.java new file mode 100644 index 0000000000000..4304db5489c6f --- /dev/null +++ b/test/hotspot/jtreg/compiler/ccp/TestAndConZeroCCP.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8350563 + * @summary Test that And nodes are monotonic and added to the CCP worklist if they have a constant as input. + * @run main/othervm -Xbatch -XX:-TieredCompilation compiler.ccp.TestAndConZeroCCP + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:RepeatCompilation=300 -XX:+StressIGVN -XX:+StressCCP -Xcomp + * -XX:CompileOnly=java.lang.Integer::parseInt compiler.ccp.TestAndConZeroCCP compileonly + * @run main compiler.ccp.TestAndConZeroCCP + */ +package compiler.ccp; + +import java.util.Arrays; + +public class TestAndConZeroCCP { + + public static void main(String[] args) { + Integer.parseInt("1"); + if (args.length != 0) { + return; + } + + for (int i = 0; i < 10000; ++i) { + run(); + } + } + + private static void run() { + for (int cp = 0; cp <= 1 << 16; cp++) { + Arrays.binarySearch(array, cp); + Character.getType(cp); + Character.isAlphabetic(cp); + } + } + + private static final int[] array = new int[3]; +} From e3f26b056e6b8403e6744b8a4cf59ccf4d217d89 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 9 Apr 2025 20:57:15 +0000 Subject: [PATCH 0504/1101] 8351319: AOT cache support for custom class loaders broken since JDK-8348426 Reviewed-by: ccheung, matsaave, jrose --- src/hotspot/share/cds/aotArtifactFinder.cpp | 11 ++- .../share/cds/dumpTimeClassInfo.inline.hpp | 8 ++- src/hotspot/share/cds/finalImageRecipes.cpp | 6 +- .../classfile/systemDictionaryShared.cpp | 17 ++++- .../classfile/systemDictionaryShared.hpp | 1 + src/hotspot/share/oops/constantPool.cpp | 16 ++++- src/hotspot/share/oops/klass.cpp | 12 +++- .../aotClassLinking/BulkLoaderTest.java | 71 ++++++++++++++++--- .../dynamicArchive/LambdaCustomLoader.java | 4 +- .../LambdaProxyCallerIsHidden.java | 6 +- .../dynamicArchive/RegularHiddenClass.java | 4 +- .../cds/appcds/test-classes/SimpleCusty.java | 30 ++++++++ test/lib/jdk/test/lib/cds/CDSAppTester.java | 33 +++++++-- 13 files changed, 185 insertions(+), 34 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/test-classes/SimpleCusty.java diff --git a/src/hotspot/share/cds/aotArtifactFinder.cpp b/src/hotspot/share/cds/aotArtifactFinder.cpp index 6a7faee51330c..95d242c2089cd 100644 --- a/src/hotspot/share/cds/aotArtifactFinder.cpp +++ b/src/hotspot/share/cds/aotArtifactFinder.cpp @@ -152,10 +152,11 @@ void AOTArtifactFinder::find_artifacts() { SystemDictionaryShared::dumptime_table()->iterate_all_live_classes([&] (InstanceKlass* k, DumpTimeClassInfo& info) { if (!info.is_excluded() && _seen_classes->get(k) == nullptr) { info.set_excluded(); - if (log_is_enabled(Info, cds)) { + info.set_has_checked_exclusion(); + if (log_is_enabled(Debug, cds)) { ResourceMark rm; - log_info(cds)("Skipping %s: %s class", k->name()->as_C_string(), - k->is_hidden() ? "Hidden" : "AOT tooling"); + log_debug(cds)("Skipping %s: %s class", k->name()->as_C_string(), + k->is_hidden() ? "Unreferenced hidden" : "AOT tooling"); } } }); @@ -211,6 +212,10 @@ void AOTArtifactFinder::add_cached_instance_class(InstanceKlass* ik) { _seen_classes->put_if_absent(ik, &created); if (created) { _all_cached_classes->append(ik); + if (CDSConfig::is_dumping_final_static_archive() && ik->is_shared_unregistered_class()) { + // The following are not appliable to unregistered classes + return; + } scan_oops_in_instance_class(ik); if (ik->is_hidden() && CDSConfig::is_initing_classes_at_dump_time()) { bool succeed = AOTClassLinker::try_add_candidate(ik); diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp b/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp index 042a0dadb201f..6f5ca6d791567 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "cds/dumpTimeClassInfo.hpp" +#include "cds/cdsConfig.hpp" #include "classfile/systemDictionaryShared.hpp" #include "classfile/classLoaderData.inline.hpp" #include "oops/instanceKlass.hpp" @@ -44,7 +45,10 @@ void DumpTimeSharedClassTable::iterate_all_live_classes(Function function) const auto wrapper = [&] (InstanceKlass* k, DumpTimeClassInfo& info) { assert(SafepointSynchronize::is_at_safepoint(), "invariant"); assert_lock_strong(DumpTimeTable_lock); - if (k->is_loader_alive()) { + if (CDSConfig::is_dumping_final_static_archive() && !k->is_loaded()) { + assert(k->is_shared_unregistered_class(), "must be"); + function(k, info); + } else if (k->is_loader_alive()) { function(k, info); assert(k->is_loader_alive(), "must not change"); } else { diff --git a/src/hotspot/share/cds/finalImageRecipes.cpp b/src/hotspot/share/cds/finalImageRecipes.cpp index 55855679a1cfa..bdfd261355bf3 100644 --- a/src/hotspot/share/cds/finalImageRecipes.cpp +++ b/src/hotspot/share/cds/finalImageRecipes.cpp @@ -102,7 +102,11 @@ void FinalImageRecipes::load_all_classes(TRAPS) { Klass* k = _all_klasses->at(i); if (k->is_instance_klass()) { InstanceKlass* ik = InstanceKlass::cast(k); - if (!ik->is_shared_unregistered_class() && !ik->is_hidden()) { + if (ik->is_shared_unregistered_class()) { + SystemDictionaryShared::init_dumptime_info(ik); + SystemDictionaryShared::add_unregistered_class(THREAD, ik); + SystemDictionaryShared::copy_unregistered_class_size_and_crc32(ik); + } else if (!ik->is_hidden()) { Klass* actual = SystemDictionary::resolve_or_fail(ik->name(), class_loader, true, CHECK); if (actual != ik) { ResourceMark rm(THREAD); diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 2fbee502b9372..5c4ee3f9452ad 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -465,6 +465,21 @@ bool SystemDictionaryShared::add_unregistered_class(Thread* current, InstanceKla return (klass == *v); } +void SystemDictionaryShared::copy_unregistered_class_size_and_crc32(InstanceKlass* klass) { + precond(CDSConfig::is_dumping_final_static_archive()); + precond(klass->is_shared()); + + // A shared class must have a RunTimeClassInfo record + const RunTimeClassInfo* record = find_record(&_static_archive._unregistered_dictionary, + nullptr, klass->name()); + precond(record != nullptr); + precond(record->klass() == klass); + + DumpTimeClassInfo* info = get_info(klass); + info->_clsfile_size = record->crc()->_clsfile_size; + info->_clsfile_crc32 = record->crc()->_clsfile_crc32; +} + void SystemDictionaryShared::set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs) { assert(CDSConfig::is_dumping_archive(), "sanity"); assert(!is_builtin(k), "must be unregistered class"); @@ -667,7 +682,7 @@ bool SystemDictionaryShared::should_be_excluded(Klass* k) { } void SystemDictionaryShared::finish_exclusion_checks() { - if (CDSConfig::is_dumping_dynamic_archive()) { + if (CDSConfig::is_dumping_dynamic_archive() || CDSConfig::is_dumping_preimage_static_archive()) { // Do this first -- if a base class is excluded due to duplication, // all of its subclasses will also be excluded. ResourceMark rm; diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index e910bfb5d472e..22fc3fd825dc6 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -248,6 +248,7 @@ class SystemDictionaryShared: public SystemDictionary { return (k->shared_classpath_index() != UNREGISTERED_INDEX); } static bool add_unregistered_class(Thread* current, InstanceKlass* k); + static void copy_unregistered_class_size_and_crc32(InstanceKlass* klass); static void finish_exclusion_checks(); static DumpTimeSharedClassTable* dumptime_table() { return _dumptime_table; } diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index 0b6f3543b7a7c..f6a94a984cef6 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -476,9 +476,23 @@ void ConstantPool::remove_unshareable_info() { return; } + bool update_resolved_reference = true; + if (CDSConfig::is_dumping_final_static_archive()) { + ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(this); + InstanceKlass* src_holder = src_cp->pool_holder(); + if (src_holder->is_shared_unregistered_class()) { + // Unregistered classes are not loaded in the AOT assembly phase. The resolved reference length + // is already saved during the training run. + precond(!src_holder->is_loaded()); + precond(resolved_reference_length() >= 0); + precond(resolved_references() == nullptr); + update_resolved_reference = false; + } + } + // resolved_references(): remember its length. If it cannot be restored // from the archived heap objects at run time, we need to dynamically allocate it. - if (cache() != nullptr) { + if (update_resolved_reference && cache() != nullptr) { set_resolved_reference_length( resolved_references() != nullptr ? resolved_references()->length() : 0); set_resolved_references(OopHandle()); diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index 9f166e13751a7..71da5e1da095b 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -828,9 +828,15 @@ void Klass::remove_java_mirror() { if (CDSConfig::is_dumping_heap()) { Klass* src_k = ArchiveBuilder::current()->get_source_addr(this); oop orig_mirror = src_k->java_mirror(); - oop scratch_mirror = HeapShared::scratch_java_mirror(orig_mirror); - if (scratch_mirror != nullptr) { - _archived_mirror_index = HeapShared::append_root(scratch_mirror); + if (orig_mirror == nullptr) { + assert(CDSConfig::is_dumping_final_static_archive(), "sanity"); + assert(is_instance_klass(), "sanity"); + assert(InstanceKlass::cast(this)->is_shared_unregistered_class(), "sanity"); + } else { + oop scratch_mirror = HeapShared::scratch_java_mirror(orig_mirror); + if (scratch_mirror != nullptr) { + _archived_mirror_index = HeapShared::append_root(scratch_mirror); + } } } #endif diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java index 9db886e20a5b6..cbc4644d5ca88 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java @@ -31,11 +31,14 @@ * @requires vm.cds.supports.aot.class.linking * @comment work around JDK-8345635 * @requires !vm.jvmci.enabled - * @library /test/jdk/lib/testlibrary /test/lib + * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes * @build InitiatingLoaderTester BadOldClassA BadOldClassB - * @build BulkLoaderTest + * @build jdk.test.whitebox.WhiteBox BulkLoaderTest SimpleCusty * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar BulkLoaderTestApp.jar BulkLoaderTestApp MyUtil InitiatingLoaderTester * BadOldClassA BadOldClassB + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar cust.jar + * SimpleCusty + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar WhiteBox.jar jdk.test.whitebox.WhiteBox * @run driver BulkLoaderTest STATIC */ @@ -44,13 +47,15 @@ * @requires vm.cds.supports.aot.class.linking * @comment work around JDK-8345635 * @requires !vm.jvmci.enabled - * @library /test/jdk/lib/testlibrary /test/lib + * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes * @build InitiatingLoaderTester BadOldClassA BadOldClassB - * @build jdk.test.whitebox.WhiteBox BulkLoaderTest + * @build jdk.test.whitebox.WhiteBox BulkLoaderTest SimpleCusty * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar BulkLoaderTestApp.jar BulkLoaderTestApp MyUtil InitiatingLoaderTester * BadOldClassA BadOldClassB - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. BulkLoaderTest DYNAMIC + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar cust.jar + * SimpleCusty + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar WhiteBox.jar jdk.test.whitebox.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:WhiteBox.jar BulkLoaderTest DYNAMIC */ /* @@ -58,16 +63,21 @@ * @requires vm.cds.supports.aot.class.linking * @comment work around JDK-8345635 * @requires !vm.jvmci.enabled - * @library /test/jdk/lib/testlibrary /test/lib - * @build InitiatingLoaderTester BadOldClassA BadOldClassB - * @build BulkLoaderTest + * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes + * @build jdk.test.whitebox.WhiteBox InitiatingLoaderTester BadOldClassA BadOldClassB + * @build BulkLoaderTest SimpleCusty * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar BulkLoaderTestApp.jar BulkLoaderTestApp MyUtil InitiatingLoaderTester * BadOldClassA BadOldClassB + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar WhiteBox.jar jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar cust.jar + * SimpleCusty * @run driver BulkLoaderTest AOT */ import java.io.File; import java.lang.StackWalker.StackFrame; +import java.net.URL; +import java.net.URLClassLoader; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -76,6 +86,7 @@ import jdk.test.lib.cds.CDSAppTester; import jdk.test.lib.helpers.ClassFileInstaller; import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.whitebox.WhiteBox; public class BulkLoaderTest { static final String appJar = ClassFileInstaller.getJarPath("BulkLoaderTestApp.jar"); @@ -114,6 +125,7 @@ public static void main(String[] args) throws Exception { static class Tester extends CDSAppTester { public Tester() { super(mainClass); + useWhiteBox(ClassFileInstaller.getJarPath("WhiteBox.jar")); } @Override @@ -124,7 +136,7 @@ public String classpath(RunMode runMode) { @Override public String[] vmArgs(RunMode runMode) { return new String[] { - "-Xlog:cds,cds+aot+load", + "-Xlog:cds,cds+aot+load,cds+class=debug", "-XX:+AOTClassLinking", }; } @@ -140,6 +152,12 @@ public String[] appCommandLine(RunMode runMode) { public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { if (isAOTWorkflow() && runMode == RunMode.TRAINING) { out.shouldContain("Skipping BadOldClassA: Unlinked class not supported by AOTConfiguration"); + out.shouldContain("Skipping SimpleCusty: Duplicated unregistered class"); + } + + if (isDumping(runMode)) { + // Check that we are archiving classes for custom class loaders. + out.shouldMatch("cds,class.* SimpleCusty"); } } } @@ -152,6 +170,7 @@ public static void main(String args[]) throws Exception { checkClasses(); checkInitiatingLoader(); checkOldClasses(); + checkCustomLoader(); } // Check the ClassLoader/Module/Package/ProtectionDomain/CodeSource of classes that are aot-linked @@ -275,6 +294,38 @@ static void checkOldClasses() throws Exception { System.out.println("Caught VerifyError for BadOldClassB: " + e); } } + + + static void checkCustomLoader() throws Exception { + WhiteBox wb = WhiteBox.getWhiteBox(); + for (int i = 0; i < 2; i++) { + Object o = initFromCustomLoader(); + System.out.println(o); + Class c = o.getClass(); + if (wb.isSharedClass(BulkLoaderTestApp.class)) { + // We are running with BulkLoaderTestApp from the AOT cache (or CDS achive) + if (i == 0) { + if (!wb.isSharedClass(c)) { + throw new RuntimeException("The first loader should load SimpleCusty from AOT cache (or CDS achive)"); + } + } else { + if (wb.isSharedClass(c)) { + throw new RuntimeException("The second loader should not load SimpleCusty from AOT cache (or CDS achive)"); + } + } + } + } + } + + static Object initFromCustomLoader() throws Exception { + String path = "cust.jar"; + URL url = new File(path).toURI().toURL(); + URL[] urls = new URL[] {url}; + URLClassLoader urlClassLoader = + new URLClassLoader("MyLoader", urls, null); + Class c = Class.forName("SimpleCusty", true, urlClassLoader); + return c.newInstance(); + } } class MyUtil { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaCustomLoader.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaCustomLoader.java index 205901e376998..4563aa60c89f5 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaCustomLoader.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaCustomLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ static void test() throws Exception { "-Xlog:class+load,cds=debug,cds+dynamic", "-cp", appJar, mainClass, appJar, "init", "keep-alive") .assertNormalExit(output -> { - output.shouldMatch("Skipping.LambHello[$][$]Lambda.*0x.*:.Hidden.class") + output.shouldMatch("Skipping.LambHello[$][$]Lambda.*0x.*:.Unreferenced.hidden.class") .shouldHaveExitValue(0); }); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaProxyCallerIsHidden.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaProxyCallerIsHidden.java index 0c8cad0b3a604..4ec7e81737891 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaProxyCallerIsHidden.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/LambdaProxyCallerIsHidden.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,8 +59,8 @@ static void test() throws Exception { "-Xlog:class+load,cds+dynamic,cds=debug", "-cp", appJar, mainClass) .assertNormalExit(output -> { - output.shouldMatch("Skipping.LambdaHello_0x.*[$][$]Lambda.*:.Hidden.class") - .shouldMatch("Skipping.LambdaHello.0x.*:.Hidden.class") + output.shouldMatch("Skipping.LambdaHello_0x.*[$][$]Lambda.*:.Unreferenced.hidden.class") + .shouldMatch("Skipping.LambdaHello.0x.*:.Unreferenced.hidden.class") .shouldHaveExitValue(0); }); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RegularHiddenClass.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RegularHiddenClass.java index 957e4cb647979..7793fd07bc366 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RegularHiddenClass.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/RegularHiddenClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,7 @@ static void test() throws Exception { "-Xlog:class+load=debug,cds+dynamic,cds=debug", "-cp", appJar, mainClass, "keep-alive") .assertNormalExit(output -> { - output.shouldMatch("cds.*Skipping.TestClass.0x.*Hidden.class") + output.shouldMatch("cds.*Skipping.TestClass.0x.*Unreferenced.hidden.class") .shouldNotMatch("cds.dynamic.*Archiving.hidden.TestClass.*") .shouldHaveExitValue(0); }); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/SimpleCusty.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/SimpleCusty.java new file mode 100644 index 0000000000000..9c82e0eb15d23 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/SimpleCusty.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// This class is to be loaded by a custom class loader. +public class SimpleCusty { + public String toString() { + return "Instance of SimpleCusty"; + } +} diff --git a/test/lib/jdk/test/lib/cds/CDSAppTester.java b/test/lib/jdk/test/lib/cds/CDSAppTester.java index 4de6778e4c25b..f08cbf0e7e2fb 100644 --- a/test/lib/jdk/test/lib/cds/CDSAppTester.java +++ b/test/lib/jdk/test/lib/cds/CDSAppTester.java @@ -50,6 +50,7 @@ abstract public class CDSAppTester { private final String dynamicArchiveFileLog; private final String tempBaseArchiveFile; private int numProductionRuns = 0; + private String whiteBoxJar = null; public CDSAppTester(String name) { if (CDSTestUtils.DYNAMIC_DUMP) { @@ -150,6 +151,10 @@ public final void setCheckExitValue(boolean b) { checkExitValue = b; } + public final void useWhiteBox(String whiteBoxJar) { + this.whiteBoxJar = whiteBoxJar; + } + public final boolean isStaticWorkflow() { return workflow == Workflow.STATIC; } @@ -199,6 +204,12 @@ private OutputAnalyzer executeAndCheck(String[] cmdLine, RunMode runMode, String return output; } + private String[] addCommonVMArgs(RunMode runMode, String[] cmdLine) { + cmdLine = addClassOrModulePath(runMode, cmdLine); + cmdLine = addWhiteBox(cmdLine); + return cmdLine; + } + private String[] addClassOrModulePath(RunMode runMode, String[] cmdLine) { String cp = classpath(runMode); if (cp == null) { @@ -214,6 +225,16 @@ private String[] addClassOrModulePath(RunMode runMode, String[] cmdLine) { return cmdLine; } + private String[] addWhiteBox(String[] cmdLine) { + if (whiteBoxJar != null) { + cmdLine = StringArrayUtils.concat(cmdLine, + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-Xbootclasspath/a:" + whiteBoxJar); + } + return cmdLine; + } + private OutputAnalyzer recordAOTConfiguration() throws Exception { RunMode runMode = RunMode.TRAINING; String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode), @@ -223,7 +244,7 @@ private OutputAnalyzer recordAOTConfiguration() throws Exception { "class+load=debug", "cds=debug", "cds+class=debug")); - cmdLine = addClassOrModulePath(runMode, cmdLine); + cmdLine = addCommonVMArgs(runMode, cmdLine); cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode)); return executeAndCheck(cmdLine, runMode, aotConfigurationFile, aotConfigurationFileLog); } @@ -235,7 +256,7 @@ private OutputAnalyzer createClassList() throws Exception { "-XX:DumpLoadedClassList=" + classListFile, logToFile(classListFileLog, "class+load=debug")); - cmdLine = addClassOrModulePath(runMode, cmdLine); + cmdLine = addCommonVMArgs(runMode, cmdLine); cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode)); return executeAndCheck(cmdLine, runMode, classListFile, classListFileLog); } @@ -253,7 +274,7 @@ private OutputAnalyzer dumpStaticArchive() throws Exception { "cds+class=debug", "cds+heap=warning", "cds+resolve=debug")); - cmdLine = addClassOrModulePath(runMode, cmdLine); + cmdLine = addCommonVMArgs(runMode, cmdLine); cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode)); return executeAndCheck(cmdLine, runMode, staticArchiveFile, staticArchiveFileLog); } @@ -271,7 +292,7 @@ private OutputAnalyzer createAOTCache() throws Exception { "cds+class=debug", "cds+heap=warning", "cds+resolve=debug")); - cmdLine = addClassOrModulePath(runMode, cmdLine); + cmdLine = addCommonVMArgs(runMode, cmdLine); cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode)); return executeAndCheck(cmdLine, runMode, aotCacheFile, aotCacheFileLog); } @@ -317,7 +338,7 @@ private OutputAnalyzer dumpDynamicArchive() throws Exception { "cds+class=debug", "cds+resolve=debug", "class+load=debug")); - cmdLine = addClassOrModulePath(runMode, cmdLine); + cmdLine = addCommonVMArgs(runMode, cmdLine); } if (baseArchive != null) { cmdLine = StringArrayUtils.concat(cmdLine, "-XX:SharedArchiveFile=" + baseArchive); @@ -342,7 +363,7 @@ public OutputAnalyzer productionRun(String[] extraVmArgs, String[] extraAppArgs) "-XX:+UnlockDiagnosticVMOptions", "-XX:VerifyArchivedFields=2", // make sure archived heap objects are good. logToFile(productionRunLog(), "cds")); - cmdLine = addClassOrModulePath(runMode, cmdLine); + cmdLine = addCommonVMArgs(runMode, cmdLine); if (isStaticWorkflow()) { cmdLine = StringArrayUtils.concat(cmdLine, "-Xshare:on", "-XX:SharedArchiveFile=" + staticArchiveFile); From e87ff328d5cc66454213dee44cf2faeb0e76262f Mon Sep 17 00:00:00 2001 From: Ferenc Rakoczi Date: Wed, 9 Apr 2025 21:15:45 +0000 Subject: [PATCH 0505/1101] 8351034: Add AVX-512 intrinsics for ML-DSA Reviewed-by: sviswanathan, lmesnik, vpaprotski, jbhateja --- src/hotspot/cpu/x86/stubDeclarations_x86.hpp | 2 +- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 2 + src/hotspot/cpu/x86/stubGenerator_x86_64.hpp | 3 +- .../x86/stubGenerator_x86_64_dilithium.cpp | 1034 +++++++++++++++++ .../cpu/x86/stubGenerator_x86_64_sha3.cpp | 245 +++- src/hotspot/cpu/x86/vm_version_x86.cpp | 14 + src/hotspot/share/classfile/vmIntrinsics.hpp | 2 +- .../share/runtime/stubDeclarations.hpp | 4 +- .../classes/sun/security/provider/ML_DSA.java | 6 +- .../sun/security/provider/acvp/Launcher.java | 10 + 10 files changed, 1280 insertions(+), 42 deletions(-) create mode 100644 src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp diff --git a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp index 9f6c1ec60ef19..ea20976c4ead9 100644 --- a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp +++ b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp @@ -85,7 +85,7 @@ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(compiler, 20000 LP64_ONLY(+64000) WINDOWS_ONLY(+2000)) \ + do_arch_blob(compiler, 20000 LP64_ONLY(+89000) WINDOWS_ONLY(+2000)) \ do_stub(compiler, vector_float_sign_mask) \ do_arch_entry(x86, compiler, vector_float_sign_mask, \ vector_float_sign_mask, vector_float_sign_mask) \ diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 9fcb044b09a42..b480c78f79d53 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -4204,6 +4204,8 @@ void StubGenerator::generate_compiler_stubs() { generate_chacha_stubs(); + generate_dilithium_stubs(); + generate_sha3_stubs(); // data cache line writeback diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index 2263188216c41..c08b0168796e4 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -489,8 +489,9 @@ class StubGenerator: public StubCodeGenerator { // SHA3 stubs void generate_sha3_stubs(); - address generate_sha3_implCompress(StubGenStubId stub_id); + // Dilithium stubs and helper functions + void generate_dilithium_stubs(); // BASE64 stubs address base64_shuffle_addr(); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp new file mode 100644 index 0000000000000..7121db2ab9165 --- /dev/null +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp @@ -0,0 +1,1034 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "asm/assembler.hpp" +#include "asm/assembler.inline.hpp" +#include "runtime/stubRoutines.hpp" +#include "macroAssembler_x86.hpp" +#include "stubGenerator_x86_64.hpp" + +#define __ _masm-> + +#define xmm(i) as_XMMRegister(i) + +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif // PRODUCT + +#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") + +#define XMMBYTES 64 + +// Constants +// +ATTRIBUTE_ALIGNED(64) static const uint32_t dilithiumAvx512Consts[] = { + 58728449, // montQInvModR + 8380417, // dilithium_q + 2365951, // montRSquareModQ + 5373807 // Barrett addend for modular reduction +}; + +const int montQInvModRIdx = 0; +const int dilithium_qIdx = 4; +const int montRSquareModQIdx = 8; +const int barrettAddendIdx = 12; + +static address dilithiumAvx512ConstsAddr(int offset) { + return ((address) dilithiumAvx512Consts) + offset; +} + +const Register scratch = r10; +const XMMRegister montMulPerm = xmm28; +const XMMRegister montQInvModR = xmm30; +const XMMRegister dilithium_q = xmm31; + + +ATTRIBUTE_ALIGNED(64) static const uint32_t dilithiumAvx512Perms[] = { + // collect montmul results into the destination register + 17, 1, 19, 3, 21, 5, 23, 7, 25, 9, 27, 11, 29, 13, 31, 15, + // ntt + // level 4 + 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23, + 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31, + // level 5 + 0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 24, 25, 26, 27, + 4, 5, 6, 7, 20, 21, 22, 23, 12, 13, 14, 15, 28, 29, 30, 31, + // level 6 + 0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29, + 2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31, + // level 7 + 0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30, + 1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31, + 0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23, + 8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31, + + // ntt inverse + // level 0 + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, + 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, + // level 1 + 0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30, + 1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31, + // level 2 + 0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29, + 2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31, + // level 3 + 0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 24, 25, 26, 27, + 4, 5, 6, 7, 20, 21, 22, 23, 12, 13, 14, 15, 28, 29, 30, 31, + // level 4 + 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23, + 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31 +}; + +const int montMulPermsIdx = 0; +const int nttL4PermsIdx = 64; +const int nttL5PermsIdx = 192; +const int nttL6PermsIdx = 320; +const int nttL7PermsIdx = 448; +const int nttInvL0PermsIdx = 704; +const int nttInvL1PermsIdx = 832; +const int nttInvL2PermsIdx = 960; +const int nttInvL3PermsIdx = 1088; +const int nttInvL4PermsIdx = 1216; + +static address dilithiumAvx512PermsAddr() { + return (address) dilithiumAvx512Perms; +} + +// We do Montgomery multiplications of two vectors of 16 ints each in 4 steps: +// 1. Do the multiplications of the corresponding even numbered slots into +// the odd numbered slots of a third register. +// 2. Swap the even and odd numbered slots of the original input registers. +// 3. Similar to step 1, but into a different output register. +// 4. Combine the outputs of step 1 and step 3 into the output of the Montgomery +// multiplication. +// (For levels 0-6 in the Ntt and levels 1-7 of the inverse Ntt we only swap the +// odd-even slots of the first multiplicand as in the second (zetas) the +// odd slots contain the same number as the corresponding even one.) +// The indexes of the registers to be multiplied +// are in inputRegs1[] and inputRegs[2]. +// The results go to the registers whose indexes are in outputRegs. +// scratchRegs should contain 12 different register indexes. +// The set in outputRegs should not overlap with the set of the middle four +// scratch registers. +// The sets in inputRegs1 and inputRegs2 cannot overlap with the set of the +// first eight scratch registers. +// In most of the cases, the odd and the corresponding even slices of the +// registers indexed by the numbers in inputRegs2 will contain the same number, +// this should be indicated by calling this function with +// input2NeedsShuffle=false . +// +static void montMul64(int outputRegs[], int inputRegs1[], int inputRegs2[], + int scratchRegs[], bool input2NeedsShuffle, + MacroAssembler *_masm) { + + for (int i = 0; i < 4; i++) { + __ vpmuldq(xmm(scratchRegs[i]), xmm(inputRegs1[i]), xmm(inputRegs2[i]), + Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ vpmulld(xmm(scratchRegs[i + 4]), xmm(scratchRegs[i]), montQInvModR, + Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ vpmuldq(xmm(scratchRegs[i + 4]), xmm(scratchRegs[i + 4]), dilithium_q, + Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ evpsubd(xmm(scratchRegs[i + 4]), k0, xmm(scratchRegs[i]), + xmm(scratchRegs[i + 4]), false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 4; i++) { + __ vpshufd(xmm(inputRegs1[i]), xmm(inputRegs1[i]), 0xB1, + Assembler::AVX_512bit); + if (input2NeedsShuffle) { + __ vpshufd(xmm(inputRegs2[i]), xmm(inputRegs2[i]), 0xB1, + Assembler::AVX_512bit); + } + } + + for (int i = 0; i < 4; i++) { + __ vpmuldq(xmm(scratchRegs[i]), xmm(inputRegs1[i]), xmm(inputRegs2[i]), + Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ vpmulld(xmm(scratchRegs[i + 8]), xmm(scratchRegs[i]), montQInvModR, + Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ vpmuldq(xmm(scratchRegs[i + 8]), xmm(scratchRegs[i + 8]), dilithium_q, + Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ evpsubd(xmm(outputRegs[i]), k0, xmm(scratchRegs[i]), + xmm(scratchRegs[i + 8]), false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 4; i++) { + __ evpermt2d(xmm(outputRegs[i]), montMulPerm, xmm(scratchRegs[i + 4]), + Assembler::AVX_512bit); + } +} + +static void montMul64(int outputRegs[], int inputRegs1[], int inputRegs2[], + int scratchRegs[], MacroAssembler *_masm) { + montMul64(outputRegs, inputRegs1, inputRegs2, scratchRegs, false, _masm); +} + +static void sub_add(int subResult[], int addResult[], + int input1[], int input2[], MacroAssembler *_masm) { + + for (int i = 0; i < 4; i++) { + __ evpsubd(xmm(subResult[i]), k0, xmm(input1[i]), xmm(input2[i]), false, + Assembler::AVX_512bit); + } + + for (int i = 0; i < 4; i++) { + __ evpaddd(xmm(addResult[i]), k0, xmm(input1[i]), xmm(input2[i]), false, + Assembler::AVX_512bit); + } +} + +static void loadPerm(int destinationRegs[], Register perms, + int offset, MacroAssembler *_masm) { + __ evmovdqul(xmm(destinationRegs[0]), Address(perms, offset), + Assembler::AVX_512bit); + for (int i = 1; i < 4; i++) { + __ evmovdqul(xmm(destinationRegs[i]), xmm(destinationRegs[0]), + Assembler::AVX_512bit); + } +} + +static void load4Xmms(int destinationRegs[], Register source, int offset, + MacroAssembler *_masm) { + for (int i = 0; i < 4; i++) { + __ evmovdqul(xmm(destinationRegs[i]), Address(source, offset + i * XMMBYTES), + Assembler::AVX_512bit); + } +} + +static void loadXmm29(Register source, int offset, MacroAssembler *_masm) { + __ evmovdqul(xmm29, Address(source, offset), Assembler::AVX_512bit); +} + +static void store4Xmms(Register destination, int offset, int xmmRegs[], + MacroAssembler *_masm) { + for (int i = 0; i < 4; i++) { + __ evmovdqul(Address(destination, offset + i * XMMBYTES), xmm(xmmRegs[i]), + Assembler::AVX_512bit); + } +} + +static int xmm0_3[] = {0, 1, 2, 3}; +static int xmm0145[] = {0, 1, 4, 5}; +static int xmm0246[] = {0, 2, 4, 6}; +static int xmm0426[] = {0, 4, 2, 6}; +static int xmm1357[] = {1, 3, 5, 7}; +static int xmm1537[] = {1, 5, 3, 7}; +static int xmm2367[] = {2, 3, 6, 7}; +static int xmm4_7[] = {4, 5, 6, 7}; +static int xmm8_11[] = {8, 9, 10, 11}; +static int xmm12_15[] = {12, 13, 14, 15}; +static int xmm16_19[] = {16, 17, 18, 19}; +static int xmm20_23[] = {20, 21, 22, 23}; +static int xmm20222426[] = {20, 22, 24, 26}; +static int xmm21232527[] = {21, 23, 25, 27}; +static int xmm24_27[] = {24, 25, 26, 27}; +static int xmm4_20_24[] = {4, 5, 6, 7, 20, 21, 22, 23, 24, 25, 26, 27}; +static int xmm16_27[] = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27}; +static int xmm29_29[] = {29, 29, 29, 29}; + +// Dilithium NTT function except for the final "normalization" to |coeff| < Q. +// Implements +// static int implDilithiumAlmostNtt(int[] coeffs, int zetas[]) {} +// +// coeffs (int[256]) = c_rarg0 +// zetas (int[256]) = c_rarg1 +// +// +static address generate_dilithiumAlmostNtt_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = dilithiumAlmostNtt_id; + StubCodeMark mark(stubgen, stub_id); + address start = __ pc(); + __ enter(); + + Label L_loop, L_end; + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + const Register iterations = c_rarg2; + + const Register perms = r11; + + __ lea(perms, ExternalAddress(dilithiumAvx512PermsAddr())); + + __ evmovdqul(montMulPerm, Address(perms, montMulPermsIdx), Assembler::AVX_512bit); + + // Each level represents one iteration of the outer for loop of the Java version + // In each of these iterations half of the coefficients are (Montgomery) + // multiplied by a zeta corresponding to the coefficient and then these + // products will be added to and subtracted from the other half of the + // coefficients. In each level we just collect the coefficients (using + // evpermi2d() instructions where necessary, i.e. in levels 4-7) that need to + // be multiplied by the zetas in one set, the rest to another set of vector + // registers, then redistribute the addition/substraction results. + + // For levels 0 and 1 the zetas are not different within the 4 xmm registers + // that we would use for them, so we use only one, xmm29. + loadXmm29(zetas, 0, _masm); + __ vpbroadcastd(montQInvModR, + ExternalAddress(dilithiumAvx512ConstsAddr(montQInvModRIdx)), + Assembler::AVX_512bit, scratch); // q^-1 mod 2^32 + __ vpbroadcastd(dilithium_q, + ExternalAddress(dilithiumAvx512ConstsAddr(dilithium_qIdx)), + Assembler::AVX_512bit, scratch); // q + + // load all coefficients into the vector registers Zmm_0-Zmm_15, + // 16 coefficients into each + load4Xmms(xmm0_3, coeffs, 0, _masm); + load4Xmms(xmm4_7, coeffs, 4 * XMMBYTES, _masm); + load4Xmms(xmm8_11, coeffs, 8 * XMMBYTES, _masm); + load4Xmms(xmm12_15, coeffs, 12 * XMMBYTES, _masm); + + // level 0 and 1 can be done entirely in registers as the zetas on these + // levels are the same for all the montmuls that we can do in parallel + + // level 0 + montMul64(xmm16_19, xmm8_11, xmm29_29, xmm16_27, _masm); + sub_add(xmm8_11, xmm0_3, xmm0_3, xmm16_19, _masm); + montMul64(xmm16_19, xmm12_15, xmm29_29, xmm16_27, _masm); + loadXmm29(zetas, 512, _masm); // for level 1 + sub_add(xmm12_15, xmm4_7, xmm4_7, xmm16_19, _masm); + + // level 1 + + montMul64(xmm16_19, xmm4_7, xmm29_29, xmm16_27, _masm); + loadXmm29(zetas, 768, _masm); + sub_add(xmm4_7, xmm0_3, xmm0_3, xmm16_19, _masm); + montMul64(xmm16_19, xmm12_15, xmm29_29, xmm16_27, _masm); + sub_add(xmm12_15, xmm8_11, xmm8_11, xmm16_19, _masm); + + // levels 2 to 7 are done in 2 batches, by first saving half of the coefficients + // from level 1 into memory, doing all the level 2 to level 7 computations + // on the remaining half in the vector registers, saving the result to + // memory after level 7, then loading back the coefficients that we saved after + // level 1 and do the same computation with those + + store4Xmms(coeffs, 8 * XMMBYTES, xmm8_11, _masm); + store4Xmms(coeffs, 12 * XMMBYTES, xmm12_15, _masm); + + __ movl(iterations, 2); + + __ align(OptoLoopAlignment); + __ BIND(L_loop); + + __ subl(iterations, 1); + + // level 2 + load4Xmms(xmm12_15, zetas, 2 * 512, _masm); + montMul64(xmm16_19, xmm2367, xmm12_15, xmm16_27, _masm); + load4Xmms(xmm12_15, zetas, 3 * 512, _masm); // for level 3 + sub_add(xmm2367, xmm0145, xmm0145, xmm16_19, _masm); + + // level 3 + + montMul64(xmm16_19, xmm1357, xmm12_15, xmm16_27, _masm); + sub_add(xmm1357, xmm0246, xmm0246, xmm16_19, _masm); + + // level 4 + loadPerm(xmm16_19, perms, nttL4PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttL4PermsIdx + 64, _masm); + load4Xmms(xmm24_27, zetas, 4 * 512, _masm); + + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i/2 + 16), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i / 2 + 12), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + + montMul64(xmm12_15, xmm12_15, xmm24_27, xmm4_20_24, _masm); + sub_add(xmm1357, xmm0246, xmm16_19, xmm12_15, _masm); + + // level 5 + loadPerm(xmm16_19, perms, nttL5PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttL5PermsIdx + 64, _masm); + load4Xmms(xmm24_27, zetas, 5 * 512, _masm); + + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i/2 + 16), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i / 2 + 12), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + + montMul64(xmm12_15, xmm12_15, xmm24_27, xmm4_20_24, _masm); + sub_add(xmm1357, xmm0246, xmm16_19, xmm12_15, _masm); + + // level 6 + loadPerm(xmm16_19, perms, nttL6PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttL6PermsIdx + 64, _masm); + load4Xmms(xmm24_27, zetas, 6 * 512, _masm); + + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i/2 + 16), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i / 2 + 12), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + + montMul64(xmm12_15, xmm12_15, xmm24_27, xmm4_20_24, _masm); + sub_add(xmm1357, xmm0246, xmm16_19, xmm12_15, _masm); + + // level 7 + loadPerm(xmm16_19, perms, nttL7PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttL7PermsIdx + 64, _masm); + load4Xmms(xmm24_27, zetas, 7 * 512, _masm); + + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i / 2 + 16), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i / 2 + 12), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + + montMul64(xmm12_15, xmm12_15, xmm24_27, xmm4_20_24, true, _masm); + loadPerm(xmm0246, perms, nttL7PermsIdx + 2 * XMMBYTES, _masm); + loadPerm(xmm1357, perms, nttL7PermsIdx + 3 * XMMBYTES, _masm); + sub_add(xmm21232527, xmm20222426, xmm16_19, xmm12_15, _masm); + + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i), xmm(i + 20), xmm(i + 21), Assembler::AVX_512bit); + __ evpermi2d(xmm(i + 1), xmm(i + 20), xmm(i + 21), Assembler::AVX_512bit); + } + + __ cmpl(iterations, 0); + __ jcc(Assembler::equal, L_end); + + store4Xmms(coeffs, 0, xmm0_3, _masm); + store4Xmms(coeffs, 4 * XMMBYTES, xmm4_7, _masm); + + load4Xmms(xmm0_3, coeffs, 8 * XMMBYTES, _masm); + load4Xmms(xmm4_7, coeffs, 12 * XMMBYTES, _masm); + + __ addptr(zetas, 4 * XMMBYTES); + + __ jmp(L_loop); + + __ BIND(L_end); + + store4Xmms(coeffs, 8 * XMMBYTES, xmm0_3, _masm); + store4Xmms(coeffs, 12 * XMMBYTES, xmm4_7, _masm); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Dilithium Inverse NTT function except the final mod Q division by 2^256. +// Implements +// static int implDilithiumAlmostInverseNtt(int[] coeffs, int[] zetas) {} +// +// coeffs (int[256]) = c_rarg0 +// zetas (int[256]) = c_rarg1 +static address generate_dilithiumAlmostInverseNtt_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = dilithiumAlmostInverseNtt_id; + StubCodeMark mark(stubgen, stub_id); + address start = __ pc(); + __ enter(); + + Label L_loop, L_end; + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + + const Register iterations = c_rarg2; + + const Register perms = r11; + + __ lea(perms, ExternalAddress(dilithiumAvx512PermsAddr())); + + __ evmovdqul(montMulPerm, Address(perms, montMulPermsIdx), Assembler::AVX_512bit); + __ vpbroadcastd(montQInvModR, + ExternalAddress(dilithiumAvx512ConstsAddr(montQInvModRIdx)), + Assembler::AVX_512bit, scratch); // q^-1 mod 2^32 + __ vpbroadcastd(dilithium_q, + ExternalAddress(dilithiumAvx512ConstsAddr(dilithium_qIdx)), + Assembler::AVX_512bit, scratch); // q + + // Each level represents one iteration of the outer for loop of the + // Java version. + // In each of these iterations half of the coefficients are added to and + // subtracted from the other half of the coefficients then the result of + // the substartion is (Montgomery) multiplied by the corresponding zetas. + // In each level we just collect the coefficients (using evpermi2d() + // instructions where necessary, i.e. on levels 0-4) so that the results of + // the additions and subtractions go to the vector registers so that they + // align with each other and the zetas. + + // We do levels 0-6 in two batches, each batch entirely in the vector registers + load4Xmms(xmm0_3, coeffs, 0, _masm); + load4Xmms(xmm4_7, coeffs, 4 * XMMBYTES, _masm); + + __ movl(iterations, 2); + + __ align(OptoLoopAlignment); + __ BIND(L_loop); + + __ subl(iterations, 1); + + // level 0 + loadPerm(xmm8_11, perms, nttInvL0PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttInvL0PermsIdx + 64, _masm); + + for (int i = 0; i < 8; i += 2) { + __ evpermi2d(xmm(i / 2 + 8), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + __ evpermi2d(xmm(i / 2 + 12), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + } + + load4Xmms(xmm4_7, zetas, 0, _masm); + sub_add(xmm24_27, xmm0_3, xmm8_11, xmm12_15, _masm); + montMul64(xmm4_7, xmm4_7, xmm24_27, xmm16_27, true, _masm); + + // level 1 + loadPerm(xmm8_11, perms, nttInvL1PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttInvL1PermsIdx + 64, _masm); + + for (int i = 0; i < 4; i++) { + __ evpermi2d(xmm(i + 8), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + __ evpermi2d(xmm(i + 12), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + } + + load4Xmms(xmm4_7, zetas, 512, _masm); + sub_add(xmm24_27, xmm0_3, xmm8_11, xmm12_15, _masm); + montMul64(xmm4_7, xmm24_27, xmm4_7, xmm16_27, _masm); + + // level 2 + loadPerm(xmm8_11, perms, nttInvL2PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttInvL2PermsIdx + 64, _masm); + + for (int i = 0; i < 4; i++) { + __ evpermi2d(xmm(i + 8), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + __ evpermi2d(xmm(i + 12), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + } + + load4Xmms(xmm4_7, zetas, 2 * 512, _masm); + sub_add(xmm24_27, xmm0_3, xmm8_11, xmm12_15, _masm); + montMul64(xmm4_7, xmm24_27, xmm4_7, xmm16_27, _masm); + + // level 3 + loadPerm(xmm8_11, perms, nttInvL3PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttInvL3PermsIdx + 64, _masm); + + for (int i = 0; i < 4; i++) { + __ evpermi2d(xmm(i + 8), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + __ evpermi2d(xmm(i + 12), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + } + + load4Xmms(xmm4_7, zetas, 3 * 512, _masm); + sub_add(xmm24_27, xmm0_3, xmm8_11, xmm12_15, _masm); + montMul64(xmm4_7, xmm24_27, xmm4_7, xmm16_27, _masm); + + // level 4 + loadPerm(xmm8_11, perms, nttInvL4PermsIdx, _masm); + loadPerm(xmm12_15, perms, nttInvL4PermsIdx + 64, _masm); + + for (int i = 0; i < 4; i++) { + __ evpermi2d(xmm(i + 8), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + __ evpermi2d(xmm(i + 12), xmm(i), xmm(i + 4), Assembler::AVX_512bit); + } + + load4Xmms(xmm4_7, zetas, 4 * 512, _masm); + sub_add(xmm24_27, xmm0_3, xmm8_11, xmm12_15, _masm); + montMul64(xmm4_7, xmm24_27, xmm4_7, xmm16_27, _masm); + + // level 5 + load4Xmms(xmm12_15, zetas, 5 * 512, _masm); + sub_add(xmm8_11, xmm0_3, xmm0426, xmm1537, _masm); + montMul64(xmm4_7, xmm8_11, xmm12_15, xmm16_27, _masm); + + // level 6 + load4Xmms(xmm12_15, zetas, 6 * 512, _masm); + sub_add(xmm8_11, xmm0_3, xmm0145, xmm2367, _masm); + montMul64(xmm4_7, xmm8_11, xmm12_15, xmm16_27, _masm); + + __ cmpl(iterations, 0); + __ jcc(Assembler::equal, L_end); + + // save the coefficients of the first batch, adjust the zetas + // and load the second batch of coefficients + store4Xmms(coeffs, 0, xmm0_3, _masm); + store4Xmms(coeffs, 4 * XMMBYTES, xmm4_7, _masm); + + __ addptr(zetas, 4 * XMMBYTES); + + load4Xmms(xmm0_3, coeffs, 8 * XMMBYTES, _masm); + load4Xmms(xmm4_7, coeffs, 12 * XMMBYTES, _masm); + + __ jmp(L_loop); + + __ BIND(L_end); + + // load the coeffs of the first batch of coefficients that were saved after + // level 6 into Zmm_8-Zmm_15 and do the last level entirely in the vector + // registers + load4Xmms(xmm8_11, coeffs, 0, _masm); + load4Xmms(xmm12_15, coeffs, 4 * XMMBYTES, _masm); + + // level 7 + + loadXmm29(zetas, 7 * 512, _masm); + + for (int i = 0; i < 8; i++) { + __ evpaddd(xmm(i + 16), k0, xmm(i), xmm(i + 8), false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpsubd(xmm(i), k0, xmm(i + 8), xmm(i), false, Assembler::AVX_512bit); + } + + store4Xmms(coeffs, 0, xmm16_19, _masm); + store4Xmms(coeffs, 4 * XMMBYTES, xmm20_23, _masm); + montMul64(xmm0_3, xmm0_3, xmm29_29, xmm16_27, _masm); + montMul64(xmm4_7, xmm4_7, xmm29_29, xmm16_27, _masm); + store4Xmms(coeffs, 8 * XMMBYTES, xmm0_3, _masm); + store4Xmms(coeffs, 12 * XMMBYTES, xmm4_7, _masm); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Dilithium multiply polynomials in the NTT domain. +// Implements +// static int implDilithiumNttMult( +// int[] result, int[] ntta, int[] nttb {} +// +// result (int[256]) = c_rarg0 +// poly1 (int[256]) = c_rarg1 +// poly2 (int[256]) = c_rarg2 +static address generate_dilithiumNttMult_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = dilithiumNttMult_id; + StubCodeMark mark(stubgen, stub_id); + address start = __ pc(); + __ enter(); + + Label L_loop; + + const Register result = c_rarg0; + const Register poly1 = c_rarg1; + const Register poly2 = c_rarg2; + + const Register perms = r10; // scratch reused after not needed any more + const Register len = r11; + + const XMMRegister montRSquareModQ = xmm29; + + __ vpbroadcastd(montQInvModR, + ExternalAddress(dilithiumAvx512ConstsAddr(montQInvModRIdx)), + Assembler::AVX_512bit, scratch); // q^-1 mod 2^32 + __ vpbroadcastd(dilithium_q, + ExternalAddress(dilithiumAvx512ConstsAddr(dilithium_qIdx)), + Assembler::AVX_512bit, scratch); // q + __ vpbroadcastd(montRSquareModQ, + ExternalAddress(dilithiumAvx512ConstsAddr(montRSquareModQIdx)), + Assembler::AVX_512bit, scratch); // 2^64 mod q + + __ lea(perms, ExternalAddress(dilithiumAvx512PermsAddr())); + __ evmovdqul(montMulPerm, Address(perms, montMulPermsIdx), Assembler::AVX_512bit); + + __ movl(len, 4); + + __ align(OptoLoopAlignment); + __ BIND(L_loop); + + load4Xmms(xmm4_7, poly2, 0, _masm); + load4Xmms(xmm0_3, poly1, 0, _masm); + montMul64(xmm4_7, xmm4_7, xmm29_29, xmm16_27, _masm); + montMul64(xmm0_3, xmm0_3, xmm4_7, xmm16_27, true, _masm); + store4Xmms(result, 0, xmm0_3, _masm); + + __ subl(len, 1); + __ addptr(poly1, 4 * XMMBYTES); + __ addptr(poly2, 4 * XMMBYTES); + __ addptr(result, 4 * XMMBYTES); + __ cmpl(len, 0); + __ jcc(Assembler::notEqual, L_loop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Dilithium Motgomery multiply an array by a constant. +// Implements +// static int implDilithiumMontMulByConstant(int[] coeffs, int constant) {} +// +// coeffs (int[256]) = c_rarg0 +// constant (int) = c_rarg1 +static address generate_dilithiumMontMulByConstant_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = dilithiumMontMulByConstant_id; + StubCodeMark mark(stubgen, stub_id); + address start = __ pc(); + __ enter(); + + Label L_loop; + + const Register coeffs = c_rarg0; + const Register rConstant = c_rarg1; + + const Register perms = c_rarg2; // not used for argument + const Register len = r11; + + const XMMRegister constant = xmm29; + + __ lea(perms, ExternalAddress(dilithiumAvx512PermsAddr())); + + // the following four vector registers are used in montMul64 + __ vpbroadcastd(montQInvModR, + ExternalAddress(dilithiumAvx512ConstsAddr(montQInvModRIdx)), + Assembler::AVX_512bit, scratch); // q^-1 mod 2^32 + __ vpbroadcastd(dilithium_q, + ExternalAddress(dilithiumAvx512ConstsAddr(dilithium_qIdx)), + Assembler::AVX_512bit, scratch); // q + __ evmovdqul(montMulPerm, Address(perms, montMulPermsIdx), Assembler::AVX_512bit); + __ evpbroadcastd(constant, rConstant, Assembler::AVX_512bit); // constant multiplier + + __ movl(len, 2); + + __ align(OptoLoopAlignment); + __ BIND(L_loop); + + load4Xmms(xmm0_3, coeffs, 0, _masm); + load4Xmms(xmm4_7, coeffs, 4 * XMMBYTES, _masm); + montMul64(xmm0_3, xmm0_3, xmm29_29, xmm16_27, _masm); + montMul64(xmm4_7, xmm4_7, xmm29_29, xmm16_27, _masm); + store4Xmms(coeffs, 0, xmm0_3, _masm); + store4Xmms(coeffs, 4 * XMMBYTES, xmm4_7, _masm); + + __ subl(len, 1); + __ addptr(coeffs, 512); + __ cmpl(len, 0); + __ jcc(Assembler::notEqual, L_loop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Dilithium decompose poly. +// Implements +// static int implDilithiumDecomposePoly(int[] coeffs, int constant) {} +// +// input (int[256]) = c_rarg0 +// lowPart (int[256]) = c_rarg1 +// highPart (int[256]) = c_rarg2 +// twoGamma2 (int) = c_rarg3 +// multiplier (int) = c_rarg4 +static address generate_dilithiumDecomposePoly_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = dilithiumDecomposePoly_id; + StubCodeMark mark(stubgen, stub_id); + address start = __ pc(); + __ enter(); + + Label L_loop; + + const Register input = c_rarg0; + const Register lowPart = c_rarg1; + const Register highPart = c_rarg2; + const Register rTwoGamma2 = c_rarg3; + + const Register len = r11; + const XMMRegister zero = xmm24; + const XMMRegister one = xmm25; + const XMMRegister qMinus1 = xmm26; + const XMMRegister gamma2 = xmm27; + const XMMRegister twoGamma2 = xmm28; + const XMMRegister barrettMultiplier = xmm29; + const XMMRegister barrettAddend = xmm30; + + __ vpxor(zero, zero, zero, Assembler::AVX_512bit); // 0 + __ vpternlogd(xmm0, 0xff, xmm0, xmm0, Assembler::AVX_512bit); // -1 + __ vpsubd(one, zero, xmm0, Assembler::AVX_512bit); // 1 + __ vpbroadcastd(dilithium_q, + ExternalAddress(dilithiumAvx512ConstsAddr(dilithium_qIdx)), + Assembler::AVX_512bit, scratch); // q + __ vpbroadcastd(barrettAddend, + ExternalAddress(dilithiumAvx512ConstsAddr(barrettAddendIdx)), + Assembler::AVX_512bit, scratch); // addend for Barrett reduction + + __ evpbroadcastd(twoGamma2, rTwoGamma2, Assembler::AVX_512bit); // 2 * gamma2 + + #ifndef _WIN64 + const Register rMultiplier = c_rarg4; + #else + const Address multiplier_mem(rbp, 6 * wordSize); + const Register rMultiplier = c_rarg3; // arg3 is already consumed, reused here + __ movptr(rMultiplier, multiplier_mem); + #endif + __ evpbroadcastd(barrettMultiplier, rMultiplier, + Assembler::AVX_512bit); // multiplier for mod 2 * gamma2 reduce + + __ evpsubd(qMinus1, k0, dilithium_q, one, false, Assembler::AVX_512bit); // q - 1 + __ evpsrad(gamma2, k0, twoGamma2, 1, false, Assembler::AVX_512bit); // gamma2 + + __ movl(len, 1024); + + __ align(OptoLoopAlignment); + __ BIND(L_loop); + + load4Xmms(xmm0_3, input, 0, _masm); + + __ addptr(input, 4 * XMMBYTES); + + // rplus in xmm0 + // rplus = rplus - ((rplus + 5373807) >> 23) * dilithium_q; + __ evpaddd(xmm4, k0, xmm0, barrettAddend, false, Assembler::AVX_512bit); + __ evpaddd(xmm5, k0, xmm1, barrettAddend, false, Assembler::AVX_512bit); + __ evpaddd(xmm6, k0, xmm2, barrettAddend, false, Assembler::AVX_512bit); + __ evpaddd(xmm7, k0, xmm3, barrettAddend, false, Assembler::AVX_512bit); + + __ evpsrad(xmm4, k0, xmm4, 23, false, Assembler::AVX_512bit); + __ evpsrad(xmm5, k0, xmm5, 23, false, Assembler::AVX_512bit); + __ evpsrad(xmm6, k0, xmm6, 23, false, Assembler::AVX_512bit); + __ evpsrad(xmm7, k0, xmm7, 23, false, Assembler::AVX_512bit); + + __ evpmulld(xmm4, k0, xmm4, dilithium_q, false, Assembler::AVX_512bit); + __ evpmulld(xmm5, k0, xmm5, dilithium_q, false, Assembler::AVX_512bit); + __ evpmulld(xmm6, k0, xmm6, dilithium_q, false, Assembler::AVX_512bit); + __ evpmulld(xmm7, k0, xmm7, dilithium_q, false, Assembler::AVX_512bit); + + __ evpsubd(xmm0, k0, xmm0, xmm4, false, Assembler::AVX_512bit); + __ evpsubd(xmm1, k0, xmm1, xmm5, false, Assembler::AVX_512bit); + __ evpsubd(xmm2, k0, xmm2, xmm6, false, Assembler::AVX_512bit); + __ evpsubd(xmm3, k0, xmm3, xmm7, false, Assembler::AVX_512bit); + // rplus in xmm0 + // rplus = rplus + ((rplus >> 31) & dilithium_q); + __ evpsrad(xmm4, k0, xmm0, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm5, k0, xmm1, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm6, k0, xmm2, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm7, k0, xmm3, 31, false, Assembler::AVX_512bit); + + __ evpandd(xmm4, k0, xmm4, dilithium_q, false, Assembler::AVX_512bit); + __ evpandd(xmm5, k0, xmm5, dilithium_q, false, Assembler::AVX_512bit); + __ evpandd(xmm6, k0, xmm6, dilithium_q, false, Assembler::AVX_512bit); + __ evpandd(xmm7, k0, xmm7, dilithium_q, false, Assembler::AVX_512bit); + + __ evpaddd(xmm0, k0, xmm0, xmm4, false, Assembler::AVX_512bit); + __ evpaddd(xmm1, k0, xmm1, xmm5, false, Assembler::AVX_512bit); + __ evpaddd(xmm2, k0, xmm2, xmm6, false, Assembler::AVX_512bit); + __ evpaddd(xmm3, k0, xmm3, xmm7, false, Assembler::AVX_512bit); + // rplus in xmm0 + // int quotient = (rplus * barrettMultiplier) >> 22; + __ evpmulld(xmm4, k0, xmm0, barrettMultiplier, false, Assembler::AVX_512bit); + __ evpmulld(xmm5, k0, xmm1, barrettMultiplier, false, Assembler::AVX_512bit); + __ evpmulld(xmm6, k0, xmm2, barrettMultiplier, false, Assembler::AVX_512bit); + __ evpmulld(xmm7, k0, xmm3, barrettMultiplier, false, Assembler::AVX_512bit); + + __ evpsrad(xmm4, k0, xmm4, 22, false, Assembler::AVX_512bit); + __ evpsrad(xmm5, k0, xmm5, 22, false, Assembler::AVX_512bit); + __ evpsrad(xmm6, k0, xmm6, 22, false, Assembler::AVX_512bit); + __ evpsrad(xmm7, k0, xmm7, 22, false, Assembler::AVX_512bit); + // quotient in xmm4 + // int r0 = rplus - quotient * twoGamma2; + __ evpmulld(xmm8, k0, xmm4, twoGamma2, false, Assembler::AVX_512bit); + __ evpmulld(xmm9, k0, xmm5, twoGamma2, false, Assembler::AVX_512bit); + __ evpmulld(xmm10, k0, xmm6, twoGamma2, false, Assembler::AVX_512bit); + __ evpmulld(xmm11, k0, xmm7, twoGamma2, false, Assembler::AVX_512bit); + + __ evpsubd(xmm8, k0, xmm0, xmm8, false, Assembler::AVX_512bit); + __ evpsubd(xmm9, k0, xmm1, xmm9, false, Assembler::AVX_512bit); + __ evpsubd(xmm10, k0, xmm2, xmm10, false, Assembler::AVX_512bit); + __ evpsubd(xmm11, k0, xmm3, xmm11, false, Assembler::AVX_512bit); + // r0 in xmm8 + // int mask = (twoGamma2 - r0) >> 22; + __ evpsubd(xmm12, k0, twoGamma2, xmm8, false, Assembler::AVX_512bit); + __ evpsubd(xmm13, k0, twoGamma2, xmm9, false, Assembler::AVX_512bit); + __ evpsubd(xmm14, k0, twoGamma2, xmm10, false, Assembler::AVX_512bit); + __ evpsubd(xmm15, k0, twoGamma2, xmm11, false, Assembler::AVX_512bit); + + __ evpsrad(xmm12, k0, xmm12, 22, false, Assembler::AVX_512bit); + __ evpsrad(xmm13, k0, xmm13, 22, false, Assembler::AVX_512bit); + __ evpsrad(xmm14, k0, xmm14, 22, false, Assembler::AVX_512bit); + __ evpsrad(xmm15, k0, xmm15, 22, false, Assembler::AVX_512bit); + // mask in xmm12 + // r0 -= (mask & twoGamma2); + __ evpandd(xmm16, k0, xmm12, twoGamma2, false, Assembler::AVX_512bit); + __ evpandd(xmm17, k0, xmm13, twoGamma2, false, Assembler::AVX_512bit); + __ evpandd(xmm18, k0, xmm14, twoGamma2, false, Assembler::AVX_512bit); + __ evpandd(xmm19, k0, xmm15, twoGamma2, false, Assembler::AVX_512bit); + + __ evpsubd(xmm8, k0, xmm8, xmm16, false, Assembler::AVX_512bit); + __ evpsubd(xmm9, k0, xmm9, xmm17, false, Assembler::AVX_512bit); + __ evpsubd(xmm10, k0, xmm10, xmm18, false, Assembler::AVX_512bit); + __ evpsubd(xmm11, k0, xmm11, xmm19, false, Assembler::AVX_512bit); + // r0 in xmm8 + // quotient += (mask & 1); + __ evpandd(xmm16, k0, xmm12, one, false, Assembler::AVX_512bit); + __ evpandd(xmm17, k0, xmm13, one, false, Assembler::AVX_512bit); + __ evpandd(xmm18, k0, xmm14, one, false, Assembler::AVX_512bit); + __ evpandd(xmm19, k0, xmm15, one, false, Assembler::AVX_512bit); + + __ evpaddd(xmm4, k0, xmm4, xmm16, false, Assembler::AVX_512bit); + __ evpaddd(xmm5, k0, xmm5, xmm17, false, Assembler::AVX_512bit); + __ evpaddd(xmm6, k0, xmm6, xmm18, false, Assembler::AVX_512bit); + __ evpaddd(xmm7, k0, xmm7, xmm19, false, Assembler::AVX_512bit); + + // mask = (twoGamma2 / 2 - r0) >> 31; + __ evpsubd(xmm12, k0, gamma2, xmm8, false, Assembler::AVX_512bit); + __ evpsubd(xmm13, k0, gamma2, xmm9, false, Assembler::AVX_512bit); + __ evpsubd(xmm14, k0, gamma2, xmm10, false, Assembler::AVX_512bit); + __ evpsubd(xmm15, k0, gamma2, xmm11, false, Assembler::AVX_512bit); + + __ evpsrad(xmm12, k0, xmm12, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm13, k0, xmm13, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm14, k0, xmm14, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm15, k0, xmm15, 31, false, Assembler::AVX_512bit); + + // r0 -= (mask & twoGamma2); + __ evpandd(xmm16, k0, xmm12, twoGamma2, false, Assembler::AVX_512bit); + __ evpandd(xmm17, k0, xmm13, twoGamma2, false, Assembler::AVX_512bit); + __ evpandd(xmm18, k0, xmm14, twoGamma2, false, Assembler::AVX_512bit); + __ evpandd(xmm19, k0, xmm15, twoGamma2, false, Assembler::AVX_512bit); + + __ evpsubd(xmm8, k0, xmm8, xmm16, false, Assembler::AVX_512bit); + __ evpsubd(xmm9, k0, xmm9, xmm17, false, Assembler::AVX_512bit); + __ evpsubd(xmm10, k0, xmm10, xmm18, false, Assembler::AVX_512bit); + __ evpsubd(xmm11, k0, xmm11, xmm19, false, Assembler::AVX_512bit); + // r0 in xmm8 + // quotient += (mask & 1); + __ evpandd(xmm16, k0, xmm12, one, false, Assembler::AVX_512bit); + __ evpandd(xmm17, k0, xmm13, one, false, Assembler::AVX_512bit); + __ evpandd(xmm18, k0, xmm14, one, false, Assembler::AVX_512bit); + __ evpandd(xmm19, k0, xmm15, one, false, Assembler::AVX_512bit); + + __ evpaddd(xmm4, k0, xmm4, xmm16, false, Assembler::AVX_512bit); + __ evpaddd(xmm5, k0, xmm5, xmm17, false, Assembler::AVX_512bit); + __ evpaddd(xmm6, k0, xmm6, xmm18, false, Assembler::AVX_512bit); + __ evpaddd(xmm7, k0, xmm7, xmm19, false, Assembler::AVX_512bit); + // quotient in xmm4 + // int r1 = rplus - r0 - (dilithium_q - 1); + __ evpsubd(xmm16, k0, xmm0, xmm8, false, Assembler::AVX_512bit); + __ evpsubd(xmm17, k0, xmm1, xmm9, false, Assembler::AVX_512bit); + __ evpsubd(xmm18, k0, xmm2, xmm10, false, Assembler::AVX_512bit); + __ evpsubd(xmm19, k0, xmm3, xmm11, false, Assembler::AVX_512bit); + + __ evpsubd(xmm16, k0, xmm16, xmm26, false, Assembler::AVX_512bit); + __ evpsubd(xmm17, k0, xmm17, xmm26, false, Assembler::AVX_512bit); + __ evpsubd(xmm18, k0, xmm18, xmm26, false, Assembler::AVX_512bit); + __ evpsubd(xmm19, k0, xmm19, xmm26, false, Assembler::AVX_512bit); + // r1 in xmm16 + // r1 = (r1 | (-r1)) >> 31; // 0 if rplus - r0 == (dilithium_q - 1), -1 otherwise + __ evpsubd(xmm20, k0, zero, xmm16, false, Assembler::AVX_512bit); + __ evpsubd(xmm21, k0, zero, xmm17, false, Assembler::AVX_512bit); + __ evpsubd(xmm22, k0, zero, xmm18, false, Assembler::AVX_512bit); + __ evpsubd(xmm23, k0, zero, xmm19, false, Assembler::AVX_512bit); + + __ evporq(xmm16, k0, xmm16, xmm20, false, Assembler::AVX_512bit); + __ evporq(xmm17, k0, xmm17, xmm21, false, Assembler::AVX_512bit); + __ evporq(xmm18, k0, xmm18, xmm22, false, Assembler::AVX_512bit); + __ evporq(xmm19, k0, xmm19, xmm23, false, Assembler::AVX_512bit); + + __ evpsubd(xmm12, k0, zero, one, false, Assembler::AVX_512bit); // -1 + + __ evpsrad(xmm0, k0, xmm16, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm1, k0, xmm17, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm2, k0, xmm18, 31, false, Assembler::AVX_512bit); + __ evpsrad(xmm3, k0, xmm19, 31, false, Assembler::AVX_512bit); + // r1 in xmm0 + // r0 += ~r1; + __ evpxorq(xmm20, k0, xmm0, xmm12, false, Assembler::AVX_512bit); + __ evpxorq(xmm21, k0, xmm1, xmm12, false, Assembler::AVX_512bit); + __ evpxorq(xmm22, k0, xmm2, xmm12, false, Assembler::AVX_512bit); + __ evpxorq(xmm23, k0, xmm3, xmm12, false, Assembler::AVX_512bit); + + __ evpaddd(xmm8, k0, xmm8, xmm20, false, Assembler::AVX_512bit); + __ evpaddd(xmm9, k0, xmm9, xmm21, false, Assembler::AVX_512bit); + __ evpaddd(xmm10, k0, xmm10, xmm22, false, Assembler::AVX_512bit); + __ evpaddd(xmm11, k0, xmm11, xmm23, false, Assembler::AVX_512bit); + // r0 in xmm8 + // r1 = r1 & quotient; + __ evpandd(xmm0, k0, xmm4, xmm0, false, Assembler::AVX_512bit); + __ evpandd(xmm1, k0, xmm5, xmm1, false, Assembler::AVX_512bit); + __ evpandd(xmm2, k0, xmm6, xmm2, false, Assembler::AVX_512bit); + __ evpandd(xmm3, k0, xmm7, xmm3, false, Assembler::AVX_512bit); + // r1 in xmm0 + // lowPart[m] = r0; + // highPart[m] = r1; + store4Xmms(highPart, 0, xmm0_3, _masm); + store4Xmms(lowPart, 0, xmm8_11, _masm); + + __ addptr(highPart, 4 * XMMBYTES); + __ addptr(lowPart, 4 * XMMBYTES); + __ subl(len, 4 * XMMBYTES); + __ jcc(Assembler::notEqual, L_loop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +void StubGenerator::generate_dilithium_stubs() { + // Generate Dilithium intrinsics code + if (UseDilithiumIntrinsics) { + StubRoutines::_dilithiumAlmostNtt = + generate_dilithiumAlmostNtt_avx512(this, _masm); + StubRoutines::_dilithiumAlmostInverseNtt = + generate_dilithiumAlmostInverseNtt_avx512(this, _masm); + StubRoutines::_dilithiumNttMult = + generate_dilithiumNttMult_avx512(this, _masm); + StubRoutines::_dilithiumMontMulByConstant = + generate_dilithiumMontMulByConstant_avx512(this, _masm); + StubRoutines::_dilithiumDecomposePoly = + generate_dilithiumDecomposePoly_avx512(this, _masm); + } +} diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp index 7d1051711f20c..9f13233f1d217 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp @@ -38,6 +38,8 @@ #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") +#define xmm(i) as_XMMRegister(i) + // Constants ATTRIBUTE_ALIGNED(64) static const uint64_t round_consts_arr[24] = { 0x0000000000000001L, 0x0000000000008082L, 0x800000000000808AL, @@ -79,13 +81,6 @@ static address permsAndRotsAddr() { return (address) permsAndRots; } -void StubGenerator::generate_sha3_stubs() { - if (UseSHA3Intrinsics) { - StubRoutines::_sha3_implCompress = generate_sha3_implCompress(StubGenStubId::sha3_implCompress_id); - StubRoutines::_sha3_implCompressMB = generate_sha3_implCompress(StubGenStubId::sha3_implCompressMB_id); - } -} - // Arguments: // // Inputs: @@ -95,7 +90,9 @@ void StubGenerator::generate_sha3_stubs() { // c_rarg3 - int offset // c_rarg4 - int limit // -address StubGenerator::generate_sha3_implCompress(StubGenStubId stub_id) { +static address generate_sha3_implCompress(StubGenStubId stub_id, + StubGenerator *stubgen, + MacroAssembler *_masm) { bool multiBlock; switch(stub_id) { case sha3_implCompress_id: @@ -109,7 +106,7 @@ address StubGenerator::generate_sha3_implCompress(StubGenStubId stub_id) { } __ align(CodeEntryAlignment); - StubCodeMark mark(this, stub_id); + StubCodeMark mark(stubgen, stub_id); address start = __ pc(); const Register buf = c_rarg0; @@ -154,29 +151,16 @@ address StubGenerator::generate_sha3_implCompress(StubGenStubId stub_id) { __ kshiftrwl(k1, k5, 4); // load the state - __ evmovdquq(xmm0, k5, Address(state, 0), false, Assembler::AVX_512bit); - __ evmovdquq(xmm1, k5, Address(state, 40), false, Assembler::AVX_512bit); - __ evmovdquq(xmm2, k5, Address(state, 80), false, Assembler::AVX_512bit); - __ evmovdquq(xmm3, k5, Address(state, 120), false, Assembler::AVX_512bit); - __ evmovdquq(xmm4, k5, Address(state, 160), false, Assembler::AVX_512bit); + for (int i = 0; i < 5; i++) { + __ evmovdquq(xmm(i), k5, Address(state, i * 40), false, Assembler::AVX_512bit); + } // load the permutation and rotation constants - __ evmovdquq(xmm17, Address(permsAndRots, 0), Assembler::AVX_512bit); - __ evmovdquq(xmm18, Address(permsAndRots, 64), Assembler::AVX_512bit); - __ evmovdquq(xmm19, Address(permsAndRots, 128), Assembler::AVX_512bit); - __ evmovdquq(xmm20, Address(permsAndRots, 192), Assembler::AVX_512bit); - __ evmovdquq(xmm21, Address(permsAndRots, 256), Assembler::AVX_512bit); - __ evmovdquq(xmm22, Address(permsAndRots, 320), Assembler::AVX_512bit); - __ evmovdquq(xmm23, Address(permsAndRots, 384), Assembler::AVX_512bit); - __ evmovdquq(xmm24, Address(permsAndRots, 448), Assembler::AVX_512bit); - __ evmovdquq(xmm25, Address(permsAndRots, 512), Assembler::AVX_512bit); - __ evmovdquq(xmm26, Address(permsAndRots, 576), Assembler::AVX_512bit); - __ evmovdquq(xmm27, Address(permsAndRots, 640), Assembler::AVX_512bit); - __ evmovdquq(xmm28, Address(permsAndRots, 704), Assembler::AVX_512bit); - __ evmovdquq(xmm29, Address(permsAndRots, 768), Assembler::AVX_512bit); - __ evmovdquq(xmm30, Address(permsAndRots, 832), Assembler::AVX_512bit); - __ evmovdquq(xmm31, Address(permsAndRots, 896), Assembler::AVX_512bit); + for (int i = 0; i < 15; i++) { + __ evmovdquq(xmm(i + 17), Address(permsAndRots, i * 64), Assembler::AVX_512bit); + } + __ align(OptoLoopAlignment); __ BIND(sha3_loop); // there will be 24 keccak rounds @@ -231,6 +215,7 @@ address StubGenerator::generate_sha3_implCompress(StubGenStubId stub_id) { // The implementation closely follows the Java version, with the state // array "rows" in the lowest 5 64-bit slots of zmm0 - zmm4, i.e. // each row of the SHA3 specification is located in one zmm register. + __ align(OptoLoopAlignment); __ BIND(rounds24_loop); __ subl(roundsLeft, 1); @@ -257,7 +242,7 @@ address StubGenerator::generate_sha3_implCompress(StubGenStubId stub_id) { // Do the cyclical permutation of the 24 moving state elements // and the required rotations within each element (the combined - // rho and sigma steps). + // rho and pi steps). __ evpermt2q(xmm4, xmm17, xmm3, Assembler::AVX_512bit); __ evpermt2q(xmm3, xmm18, xmm2, Assembler::AVX_512bit); __ evpermt2q(xmm2, xmm17, xmm1, Assembler::AVX_512bit); @@ -279,7 +264,7 @@ address StubGenerator::generate_sha3_implCompress(StubGenStubId stub_id) { __ evpermt2q(xmm2, xmm24, xmm4, Assembler::AVX_512bit); __ evpermt2q(xmm3, xmm25, xmm4, Assembler::AVX_512bit); __ evpermt2q(xmm4, xmm26, xmm5, Assembler::AVX_512bit); - // The combined rho and sigma steps are done. + // The combined rho and pi steps are done. // Do the chi step (the same operation on all 5 rows). // vpternlogq(x, 180, y, z) does x = x ^ (y & ~z). @@ -320,11 +305,9 @@ address StubGenerator::generate_sha3_implCompress(StubGenStubId stub_id) { } // store the state - __ evmovdquq(Address(state, 0), k5, xmm0, true, Assembler::AVX_512bit); - __ evmovdquq(Address(state, 40), k5, xmm1, true, Assembler::AVX_512bit); - __ evmovdquq(Address(state, 80), k5, xmm2, true, Assembler::AVX_512bit); - __ evmovdquq(Address(state, 120), k5, xmm3, true, Assembler::AVX_512bit); - __ evmovdquq(Address(state, 160), k5, xmm4, true, Assembler::AVX_512bit); + for (int i = 0; i < 5; i++) { + __ evmovdquq(Address(state, i * 40), k5, xmm(i), true, Assembler::AVX_512bit); + } __ pop(r14); __ pop(r13); @@ -335,3 +318,193 @@ address StubGenerator::generate_sha3_implCompress(StubGenStubId stub_id) { return start; } + +// Inputs: +// c_rarg0 - long[] state0 +// c_rarg1 - long[] state1 +// +// Performs two keccak() computations in parallel. The steps of the +// two computations are executed interleaved. +static address generate_double_keccak(StubGenerator *stubgen, MacroAssembler *_masm) { + __ align(CodeEntryAlignment); + StubGenStubId stub_id = double_keccak_id; + StubCodeMark mark(stubgen, stub_id); + address start = __ pc(); + + const Register state0 = c_rarg0; + const Register state1 = c_rarg1; + + const Register permsAndRots = c_rarg2; + const Register round_consts = c_rarg3; + const Register constant2use = r10; + const Register roundsLeft = r11; + + Label rounds24_loop; + + __ enter(); + + __ lea(permsAndRots, ExternalAddress(permsAndRotsAddr())); + __ lea(round_consts, ExternalAddress(round_constsAddr())); + + // set up the masks + __ movl(rax, 0x1F); + __ kmovwl(k5, rax); + __ kshiftrwl(k4, k5, 1); + __ kshiftrwl(k3, k5, 2); + __ kshiftrwl(k2, k5, 3); + __ kshiftrwl(k1, k5, 4); + + // load the states + for (int i = 0; i < 5; i++) { + __ evmovdquq(xmm(i), k5, Address(state0, i * 40), false, Assembler::AVX_512bit); + } + for (int i = 0; i < 5; i++) { + __ evmovdquq(xmm(10 + i), k5, Address(state1, i * 40), false, Assembler::AVX_512bit); + } + + // load the permutation and rotation constants + + for (int i = 0; i < 15; i++) { + __ evmovdquq(xmm(17 + i), Address(permsAndRots, i * 64), Assembler::AVX_512bit); + } + + // there will be 24 keccak rounds + // The same operations as the ones in generate_sha3_implCompress are + // performed, but in parallel for two states: one in regs z0-z5, using z6 + // as the scratch register and the other in z10-z15, using z16 as the + // scratch register. + // The permutation and rotation constants, that are loaded into z17-z31, + // are shared between the two computations. + __ movl(roundsLeft, 24); + // load round_constants base + __ movptr(constant2use, round_consts); + + __ align(OptoLoopAlignment); + __ BIND(rounds24_loop); + __ subl( roundsLeft, 1); + + __ evmovdquw(xmm5, xmm0, Assembler::AVX_512bit); + __ evmovdquw(xmm15, xmm10, Assembler::AVX_512bit); + __ vpternlogq(xmm5, 150, xmm1, xmm2, Assembler::AVX_512bit); + __ vpternlogq(xmm15, 150, xmm11, xmm12, Assembler::AVX_512bit); + __ vpternlogq(xmm5, 150, xmm3, xmm4, Assembler::AVX_512bit); + __ vpternlogq(xmm15, 150, xmm13, xmm14, Assembler::AVX_512bit); + __ evprolq(xmm6, xmm5, 1, Assembler::AVX_512bit); + __ evprolq(xmm16, xmm15, 1, Assembler::AVX_512bit); + __ evpermt2q(xmm5, xmm30, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm15, xmm30, xmm15, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm6, Assembler::AVX_512bit); + __ evpermt2q(xmm16, xmm31, xmm16, Assembler::AVX_512bit); + __ vpternlogq(xmm0, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm10, 150, xmm15, xmm16, Assembler::AVX_512bit); + __ vpternlogq(xmm1, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm11, 150, xmm15, xmm16, Assembler::AVX_512bit); + __ vpternlogq(xmm2, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm12, 150, xmm15, xmm16, Assembler::AVX_512bit); + __ vpternlogq(xmm3, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm13, 150, xmm15, xmm16, Assembler::AVX_512bit); + __ vpternlogq(xmm4, 150, xmm5, xmm6, Assembler::AVX_512bit); + __ vpternlogq(xmm14, 150, xmm15, xmm16, Assembler::AVX_512bit); + __ evpermt2q(xmm4, xmm17, xmm3, Assembler::AVX_512bit); + __ evpermt2q(xmm14, xmm17, xmm13, Assembler::AVX_512bit); + __ evpermt2q(xmm3, xmm18, xmm2, Assembler::AVX_512bit); + __ evpermt2q(xmm13, xmm18, xmm12, Assembler::AVX_512bit); + __ evpermt2q(xmm2, xmm17, xmm1, Assembler::AVX_512bit); + __ evpermt2q(xmm12, xmm17, xmm11, Assembler::AVX_512bit); + __ evpermt2q(xmm1, xmm19, xmm0, Assembler::AVX_512bit); + __ evpermt2q(xmm11, xmm19, xmm10, Assembler::AVX_512bit); + __ evpermt2q(xmm4, xmm20, xmm2, Assembler::AVX_512bit); + __ evpermt2q(xmm14, xmm20, xmm12, Assembler::AVX_512bit); + __ evprolvq(xmm1, xmm1, xmm27, Assembler::AVX_512bit); + __ evprolvq(xmm11, xmm11, xmm27, Assembler::AVX_512bit); + __ evprolvq(xmm3, xmm3, xmm28, Assembler::AVX_512bit); + __ evprolvq(xmm13, xmm13, xmm28, Assembler::AVX_512bit); + __ evprolvq(xmm4, xmm4, xmm29, Assembler::AVX_512bit); + __ evprolvq(xmm14, xmm14, xmm29, Assembler::AVX_512bit); + __ evmovdquw(xmm2, xmm1, Assembler::AVX_512bit); + __ evmovdquw(xmm12, xmm11, Assembler::AVX_512bit); + __ evmovdquw(xmm5, xmm3, Assembler::AVX_512bit); + __ evmovdquw(xmm15, xmm13, Assembler::AVX_512bit); + __ evpermt2q(xmm0, xmm21, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm10, xmm21, xmm14, Assembler::AVX_512bit); + __ evpermt2q(xmm1, xmm22, xmm3, Assembler::AVX_512bit); + __ evpermt2q(xmm11, xmm22, xmm13, Assembler::AVX_512bit); + __ evpermt2q(xmm5, xmm22, xmm2, Assembler::AVX_512bit); + __ evpermt2q(xmm15, xmm22, xmm12, Assembler::AVX_512bit); + __ evmovdquw(xmm3, xmm1, Assembler::AVX_512bit); + __ evmovdquw(xmm13, xmm11, Assembler::AVX_512bit); + __ evmovdquw(xmm2, xmm5, Assembler::AVX_512bit); + __ evmovdquw(xmm12, xmm15, Assembler::AVX_512bit); + __ evpermt2q(xmm1, xmm23, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm11, xmm23, xmm14, Assembler::AVX_512bit); + __ evpermt2q(xmm2, xmm24, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm12, xmm24, xmm14, Assembler::AVX_512bit); + __ evpermt2q(xmm3, xmm25, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm13, xmm25, xmm14, Assembler::AVX_512bit); + __ evpermt2q(xmm4, xmm26, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm14, xmm26, xmm15, Assembler::AVX_512bit); + + __ evpermt2q(xmm5, xmm31, xmm0, Assembler::AVX_512bit); + __ evpermt2q(xmm15, xmm31, xmm10, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm16, xmm31, xmm15, Assembler::AVX_512bit); + __ vpternlogq(xmm0, 180, xmm6, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm10, 180, xmm16, xmm15, Assembler::AVX_512bit); + + __ evpermt2q(xmm5, xmm31, xmm1, Assembler::AVX_512bit); + __ evpermt2q(xmm15, xmm31, xmm11, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm16, xmm31, xmm15, Assembler::AVX_512bit); + __ vpternlogq(xmm1, 180, xmm6, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm11, 180, xmm16, xmm15, Assembler::AVX_512bit); + + __ evpxorq(xmm0, k1, xmm0, Address(constant2use, 0), true, Assembler::AVX_512bit); + __ evpxorq(xmm10, k1, xmm10, Address(constant2use, 0), true, Assembler::AVX_512bit); + __ addptr(constant2use, 8); + + __ evpermt2q(xmm5, xmm31, xmm2, Assembler::AVX_512bit); + __ evpermt2q(xmm15, xmm31, xmm12, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm16, xmm31, xmm15, Assembler::AVX_512bit); + __ vpternlogq(xmm2, 180, xmm6, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm12, 180, xmm16, xmm15, Assembler::AVX_512bit); + + __ evpermt2q(xmm5, xmm31, xmm3, Assembler::AVX_512bit); + __ evpermt2q(xmm15, xmm31, xmm13, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm16, xmm31, xmm15, Assembler::AVX_512bit); + __ vpternlogq(xmm3, 180, xmm6, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm13, 180, xmm16, xmm15, Assembler::AVX_512bit); + __ evpermt2q(xmm5, xmm31, xmm4, Assembler::AVX_512bit); + __ evpermt2q(xmm15, xmm31, xmm14, Assembler::AVX_512bit); + __ evpermt2q(xmm6, xmm31, xmm5, Assembler::AVX_512bit); + __ evpermt2q(xmm16, xmm31, xmm15, Assembler::AVX_512bit); + __ vpternlogq(xmm4, 180, xmm6, xmm5, Assembler::AVX_512bit); + __ vpternlogq(xmm14, 180, xmm16, xmm15, Assembler::AVX_512bit); + __ cmpl(roundsLeft, 0); + __ jcc(Assembler::notEqual, rounds24_loop); + + // store the states + for (int i = 0; i < 5; i++) { + __ evmovdquq(Address(state0, i * 40), k5, xmm(i), true, Assembler::AVX_512bit); + } + for (int i = 0; i < 5; i++) { + __ evmovdquq(Address(state1, i * 40), k5, xmm(10 + i), true, Assembler::AVX_512bit); + } + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; +} + +void StubGenerator::generate_sha3_stubs() { + if (UseSHA3Intrinsics) { + StubRoutines::_sha3_implCompress = + generate_sha3_implCompress(StubGenStubId::sha3_implCompress_id, this, _masm); + StubRoutines::_double_keccak = + generate_double_keccak(this, _masm); + StubRoutines::_sha3_implCompressMB = + generate_sha3_implCompress(StubGenStubId::sha3_implCompressMB_id, this, _masm); + } +} diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 4b9c1c3416a5d..c320d4e8a0d0d 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1246,6 +1246,20 @@ void VM_Version::get_processor_features() { } #endif // _LP64 + // Dilithium Intrinsics + // Currently we only have them for AVX512 +#ifdef _LP64 + if (supports_evex() && supports_avx512bw()) { + if (FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) { + UseDilithiumIntrinsics = true; + } + } else +#endif + if (UseDilithiumIntrinsics) { + warning("Intrinsics for ML-DSA are not available on this CPU."); + FLAG_SET_DEFAULT(UseDilithiumIntrinsics, false); + } + // Base64 Intrinsics (Check the condition for which the intrinsic will be active) if (UseAVX >= 2) { if (FLAG_IS_DEFAULT(UseBASE64Intrinsics)) { diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 93b67301b4bad..49446b53b98bb 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -570,7 +570,7 @@ class methodHandle; do_signature(chacha20Block_signature, "([I[B)I") \ \ /* support for sun.security.provider.ML_DSA */ \ - do_class(sun_security_provider_ML_DSA, "sun/security/provider/ML_DSA") \ + do_class(sun_security_provider_ML_DSA, "sun/security/provider/ML_DSA") \ do_signature(IaII_signature, "([II)I") \ do_signature(IaIaI_signature, "([I[I)I") \ do_signature(IaIaIaI_signature, "([I[I[I)I") \ diff --git a/src/hotspot/share/runtime/stubDeclarations.hpp b/src/hotspot/share/runtime/stubDeclarations.hpp index fd86f2ced3fad..c061d0b5daf8c 100644 --- a/src/hotspot/share/runtime/stubDeclarations.hpp +++ b/src/hotspot/share/runtime/stubDeclarations.hpp @@ -740,11 +740,11 @@ do_stub(compiler, sha3_implCompress) \ do_entry(compiler, sha3_implCompress, sha3_implCompress, \ sha3_implCompress) \ + do_stub(compiler, double_keccak) \ + do_entry(compiler, double_keccak, double_keccak, double_keccak) \ do_stub(compiler, sha3_implCompressMB) \ do_entry(compiler, sha3_implCompressMB, sha3_implCompressMB, \ sha3_implCompressMB) \ - do_stub(compiler, double_keccak) \ - do_entry(compiler, double_keccak, double_keccak, double_keccak) \ do_stub(compiler, updateBytesAdler32) \ do_entry(compiler, updateBytesAdler32, updateBytesAdler32, \ updateBytesAdler32) \ diff --git a/src/java.base/share/classes/sun/security/provider/ML_DSA.java b/src/java.base/share/classes/sun/security/provider/ML_DSA.java index 969b8fffa39fa..238b5e9d46a0a 100644 --- a/src/java.base/share/classes/sun/security/provider/ML_DSA.java +++ b/src/java.base/share/classes/sun/security/provider/ML_DSA.java @@ -26,7 +26,6 @@ package sun.security.provider; import jdk.internal.vm.annotation.IntrinsicCandidate; -import sun.security.provider.SHA3.SHAKE128; import sun.security.provider.SHA3.SHAKE256; import sun.security.provider.SHA3Parallel.Shake128Parallel; @@ -1317,6 +1316,7 @@ private int[][] useHint(boolean[][] h, int[][] r) { */ public static void mlDsaNtt(int[] coeffs) { + assert coeffs.length == ML_DSA_N; implDilithiumAlmostNtt(coeffs, MONT_ZETAS_FOR_VECTOR_NTT); implDilithiumMontMulByConstant(coeffs, MONT_R_MOD_Q); } @@ -1343,6 +1343,7 @@ static void implDilithiumAlmostNttJava(int[] coeffs) { } public static void mlDsaInverseNtt(int[] coeffs) { + assert coeffs.length == ML_DSA_N; implDilithiumAlmostInverseNtt(coeffs, MONT_ZETAS_FOR_VECTOR_INVERSE_NTT); implDilithiumMontMulByConstant(coeffs, MONT_DIM_INVERSE); } @@ -1382,6 +1383,7 @@ void mlDsaVectorInverseNtt(int[][] vector) { } public static void mlDsaNttMultiply(int[] product, int[] coeffs1, int[] coeffs2) { + assert (coeffs1.length == ML_DSA_N) && (coeffs2.length == ML_DSA_N); implDilithiumNttMult(product, coeffs1, coeffs2); } @@ -1412,6 +1414,8 @@ static void implDilithiumMontMulByConstantJava(int[] coeffs, int constant) { public static void mlDsaDecomposePoly(int[] input, int[] lowPart, int[] highPart, int twoGamma2, int multiplier) { + assert (input.length == ML_DSA_N) && (lowPart.length == ML_DSA_N) + && (highPart.length == ML_DSA_N); implDilithiumDecomposePoly(input, lowPart, highPart,twoGamma2, multiplier); } diff --git a/test/jdk/sun/security/provider/acvp/Launcher.java b/test/jdk/sun/security/provider/acvp/Launcher.java index 0dfa16678d8a6..c07b7929d89df 100644 --- a/test/jdk/sun/security/provider/acvp/Launcher.java +++ b/test/jdk/sun/security/provider/acvp/Launcher.java @@ -37,6 +37,16 @@ * @bug 8342442 8345057 * @library /test/lib * @modules java.base/sun.security.provider + * @run main Launcher + */ + +/* + * @test + * @summary Test verifying the intrinsic implementation. + * @bug 8342442 8345057 + * @library /test/lib + * @modules java.base/sun.security.provider + * @run main/othervm -Xcomp Launcher */ /// This test runs on `internalProjection.json`-style files generated by NIST's From 5c438c5e6b636a7992cbd737de0735070e480061 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 9 Apr 2025 22:58:44 +0000 Subject: [PATCH 0506/1101] 8352748: Remove com.sun.tools.classfile from the JDK Reviewed-by: ihse, jlahoda, vromero --- make/modules/jdk.compiler/Gendata.gmk | 2 +- make/modules/jdk.javadoc/Gendata.gmk | 2 +- .../com/sun/tools/javac/code/TargetType.java | 3 +- .../javac/code/TypeAnnotationPosition.java | 3 +- .../com/sun/tools/classfile/AccessFlags.java | 259 ---- .../com/sun/tools/classfile/Annotation.java | 276 ----- .../AnnotationDefault_attribute.java | 61 - .../com/sun/tools/classfile/Attribute.java | 222 ---- .../tools/classfile/AttributeException.java | 41 - .../com/sun/tools/classfile/Attributes.java | 112 -- .../classfile/BootstrapMethods_attribute.java | 90 -- .../CharacterRangeTable_attribute.java | 90 -- .../com/sun/tools/classfile/ClassFile.java | 189 --- .../com/sun/tools/classfile/ClassReader.java | 115 -- .../sun/tools/classfile/ClassTranslator.java | 469 -------- .../com/sun/tools/classfile/ClassWriter.java | 1011 ---------------- .../sun/tools/classfile/Code_attribute.java | 154 --- .../classfile/CompilationID_attribute.java | 63 - .../com/sun/tools/classfile/ConstantPool.java | 1053 ----------------- .../classfile/ConstantPoolException.java | 41 - .../classfile/ConstantValue_attribute.java | 59 - .../sun/tools/classfile/DefaultAttribute.java | 64 - .../tools/classfile/Deprecated_attribute.java | 55 - .../com/sun/tools/classfile/Descriptor.java | 198 ---- .../tools/classfile/DescriptorException.java | 36 - .../classfile/EnclosingMethod_attribute.java | 73 -- .../tools/classfile/Exceptions_attribute.java | 69 -- .../com/sun/tools/classfile/FatalError.java | 40 - .../com/sun/tools/classfile/Field.java | 65 - .../classfile/InnerClasses_attribute.java | 109 -- .../com/sun/tools/classfile/Instruction.java | 357 ------ .../classfile/LineNumberTable_attribute.java | 78 -- .../LocalVariableTable_attribute.java | 84 -- .../LocalVariableTypeTable_attribute.java | 84 -- .../com/sun/tools/classfile/Method.java | 65 - .../classfile/MethodParameters_attribute.java | 92 -- .../classfile/ModuleHashes_attribute.java | 95 -- .../classfile/ModuleMainClass_attribute.java | 64 - .../classfile/ModulePackages_attribute.java | 77 -- .../classfile/ModuleResolution_attribute.java | 69 -- .../classfile/ModuleTarget_attribute.java | 55 - .../sun/tools/classfile/Module_attribute.java | 230 ---- .../tools/classfile/NestHost_attribute.java | 63 - .../classfile/NestMembers_attribute.java | 70 -- .../com/sun/tools/classfile/Opcode.java | 472 -------- .../PermittedSubclasses_attribute.java | 65 - .../sun/tools/classfile/Record_attribute.java | 82 -- .../sun/tools/classfile/ReferenceFinder.java | 253 ---- .../RuntimeAnnotations_attribute.java | 61 - ...RuntimeInvisibleAnnotations_attribute.java | 56 - ...visibleParameterAnnotations_attribute.java | 56 - ...imeInvisibleTypeAnnotations_attribute.java | 56 - ...RuntimeParameterAnnotations_attribute.java | 70 -- .../RuntimeTypeAnnotations_attribute.java | 61 - .../RuntimeVisibleAnnotations_attribute.java | 56 - ...VisibleParameterAnnotations_attribute.java | 56 - ...ntimeVisibleTypeAnnotations_attribute.java | 56 - .../com/sun/tools/classfile/Signature.java | 272 ----- .../tools/classfile/Signature_attribute.java | 67 -- .../SourceDebugExtension_attribute.java | 69 -- .../tools/classfile/SourceFile_attribute.java | 63 - .../tools/classfile/SourceID_attribute.java | 62 - .../classfile/StackMapTable_attribute.java | 380 ------ .../tools/classfile/StackMap_attribute.java | 70 -- .../tools/classfile/Synthetic_attribute.java | 55 - .../classes/com/sun/tools/classfile/Type.java | 378 ------ .../sun/tools/classfile/TypeAnnotation.java | 654 ---------- .../com/sun/tools/classfile/package-info.java | 36 - src/jdk.jdeps/share/classes/module-info.java | 4 +- ...ildcardBoundsNotReadFromClassFileTest.java | 4 +- 70 files changed, 6 insertions(+), 10015 deletions(-) delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/AccessFlags.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Annotation.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/AnnotationDefault_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/AttributeException.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Attributes.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/BootstrapMethods_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/CharacterRangeTable_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassFile.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassReader.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassTranslator.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassWriter.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Code_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/CompilationID_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/ConstantPool.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/ConstantPoolException.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/ConstantValue_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/DefaultAttribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Deprecated_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Descriptor.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/DescriptorException.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/EnclosingMethod_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Exceptions_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/FatalError.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Field.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/InnerClasses_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Instruction.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/LineNumberTable_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/LocalVariableTable_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/LocalVariableTypeTable_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Method.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/MethodParameters_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModuleHashes_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModuleMainClass_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModulePackages_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModuleResolution_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModuleTarget_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Module_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/NestHost_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/NestMembers_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Opcode.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/PermittedSubclasses_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Record_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/ReferenceFinder.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeAnnotations_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeInvisibleAnnotations_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeInvisibleParameterAnnotations_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeInvisibleTypeAnnotations_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeParameterAnnotations_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeTypeAnnotations_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeVisibleAnnotations_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeVisibleParameterAnnotations_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeVisibleTypeAnnotations_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Signature.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Signature_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/SourceDebugExtension_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/SourceFile_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/SourceID_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/StackMapTable_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/StackMap_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Synthetic_attribute.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/Type.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/TypeAnnotation.java delete mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/classfile/package-info.java diff --git a/make/modules/jdk.compiler/Gendata.gmk b/make/modules/jdk.compiler/Gendata.gmk index 5bbd28b803794..2afc6e98e3791 100644 --- a/make/modules/jdk.compiler/Gendata.gmk +++ b/make/modules/jdk.compiler/Gendata.gmk @@ -60,7 +60,7 @@ $(eval $(call SetupJavaCompilation, COMPILE_CREATE_SYMBOLS, \ TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK), \ COMPILER := buildjdk, \ SRC := $(TOPDIR)/make/langtools/src/classes, \ - INCLUDES := build/tools/symbolgenerator com/sun/tools/classfile, \ + INCLUDES := build/tools/symbolgenerator, \ BIN := $(BUILDTOOLS_OUTPUTDIR)/create_symbols_javac, \ DISABLED_WARNINGS := options, \ JAVAC_FLAGS := \ diff --git a/make/modules/jdk.javadoc/Gendata.gmk b/make/modules/jdk.javadoc/Gendata.gmk index 2cd812de779ef..a97342ffd049e 100644 --- a/make/modules/jdk.javadoc/Gendata.gmk +++ b/make/modules/jdk.javadoc/Gendata.gmk @@ -51,7 +51,7 @@ $(eval $(call SetupJavaCompilation, COMPILE_CREATE_SYMBOLS, \ TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK), \ SRC := $(TOPDIR)/make/langtools/src/classes \ $(TOPDIR)/src/jdk.jdeps/share/classes, \ - INCLUDES := build/tools/symbolgenerator com/sun/tools/classfile, \ + INCLUDES := build/tools/symbolgenerator, \ BIN := $(BUILDTOOLS_OUTPUTDIR)/create_symbols_javadoc, \ DISABLED_WARNINGS := options, \ JAVAC_FLAGS := \ diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TargetType.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TargetType.java index 0876749335472..bdb08091aa5ab 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TargetType.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TargetType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,6 @@ * This code and its internal interfaces are subject to change or * deletion without notice. */ -// Code duplicated in com.sun.tools.classfile.TypeAnnotation.TargetType public enum TargetType { /** For annotations on a class type parameter declaration. */ CLASS_TYPE_PARAMETER(0x00), diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java index 92fe41adb5b0e..8c88dec51063f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,6 @@ * This code and its internal interfaces are subject to change or * deletion without notice. */ -// Code duplicated in com.sun.tools.classfile.TypeAnnotation.Position public class TypeAnnotationPosition { public enum TypePathEntryKind { diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/AccessFlags.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/AccessFlags.java deleted file mode 100644 index 5e9b6853a4d72..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/AccessFlags.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.Set; - -/** - * See JVMS, sections 4.2, 4.6, 4.7. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class AccessFlags { - public static final int ACC_PUBLIC = 0x0001; // class, inner, field, method - public static final int ACC_PRIVATE = 0x0002; // inner, field, method - public static final int ACC_PROTECTED = 0x0004; // inner, field, method - public static final int ACC_STATIC = 0x0008; // inner, field, method - public static final int ACC_FINAL = 0x0010; // class, inner, field, method - public static final int ACC_SUPER = 0x0020; // class - public static final int ACC_SYNCHRONIZED = 0x0020; // method - public static final int ACC_VOLATILE = 0x0040; // field - public static final int ACC_BRIDGE = 0x0040; // method - public static final int ACC_TRANSIENT = 0x0080; // field - public static final int ACC_VARARGS = 0x0080; // method - public static final int ACC_NATIVE = 0x0100; // method - public static final int ACC_INTERFACE = 0x0200; // class, inner - public static final int ACC_ABSTRACT = 0x0400; // class, inner, method - public static final int ACC_STRICT = 0x0800; // method - public static final int ACC_SYNTHETIC = 0x1000; // class, inner, field, method - public static final int ACC_ANNOTATION = 0x2000; // class, inner - public static final int ACC_ENUM = 0x4000; // class, inner, field - public static final int ACC_MANDATED = 0x8000; // method parameter - public static final int ACC_MODULE = 0x8000; // class - - public static enum Kind { Class, InnerClass, Field, Method} - - AccessFlags(ClassReader cr) throws IOException { - this(cr.readUnsignedShort()); - } - - public AccessFlags(int flags) { - this.flags = flags; - } - - public AccessFlags ignore(int mask) { - return new AccessFlags(flags & ~mask); - } - - public boolean is(int mask) { - return (flags & mask) != 0; - } - - public int byteLength() { - return 2; - } - - private static final int[] classModifiers = { - ACC_PUBLIC, ACC_FINAL, ACC_ABSTRACT - }; - - private static final int[] classFlags = { - ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_INTERFACE, ACC_ABSTRACT, - ACC_SYNTHETIC, ACC_ANNOTATION, ACC_ENUM, ACC_MODULE - }; - - public Set getClassModifiers() { - int f = ((flags & ACC_INTERFACE) != 0 ? flags & ~ACC_ABSTRACT : flags); - return getModifiers(f, classModifiers, Kind.Class); - } - - public Set getClassFlags() { - return getFlags(classFlags, Kind.Class); - } - - private static final int[] innerClassModifiers = { - ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, - ACC_ABSTRACT - }; - - private static final int[] innerClassFlags = { - ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SUPER, - ACC_INTERFACE, ACC_ABSTRACT, ACC_SYNTHETIC, ACC_ANNOTATION, ACC_ENUM - }; - - public Set getInnerClassModifiers() { - int f = ((flags & ACC_INTERFACE) != 0 ? flags & ~ACC_ABSTRACT : flags); - return getModifiers(f, innerClassModifiers, Kind.InnerClass); - } - - public Set getInnerClassFlags() { - return getFlags(innerClassFlags, Kind.InnerClass); - } - - private static final int[] fieldModifiers = { - ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, - ACC_VOLATILE, ACC_TRANSIENT - }; - - private static final int[] fieldFlags = { - ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, - ACC_VOLATILE, ACC_TRANSIENT, ACC_SYNTHETIC, ACC_ENUM - }; - - public Set getFieldModifiers() { - return getModifiers(fieldModifiers, Kind.Field); - } - - public Set getFieldFlags() { - return getFlags(fieldFlags, Kind.Field); - } - - private static final int[] methodModifiers = { - ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, - ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT, ACC_STRICT - }; - - private static final int[] methodFlags = { - ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, - ACC_SYNCHRONIZED, ACC_BRIDGE, ACC_VARARGS, ACC_NATIVE, ACC_ABSTRACT, - ACC_STRICT, ACC_SYNTHETIC - }; - - public Set getMethodModifiers() { - return getModifiers(methodModifiers, Kind.Method); - } - - public Set getMethodFlags() { - return getFlags(methodFlags, Kind.Method); - } - - private Set getModifiers(int[] modifierFlags, Kind t) { - return getModifiers(flags, modifierFlags, t); - } - - private static Set getModifiers(int flags, int[] modifierFlags, Kind t) { - Set s = new LinkedHashSet<>(); - for (int m: modifierFlags) { - if ((flags & m) != 0) - s.add(flagToModifier(m, t)); - } - return s; - } - - private Set getFlags(int[] expectedFlags, Kind t) { - Set s = new LinkedHashSet<>(); - int f = flags; - for (int e: expectedFlags) { - if ((f & e) != 0) { - s.add(flagToName(e, t)); - f = f & ~e; - } - } - while (f != 0) { - int bit = Integer.highestOneBit(f); - s.add("0x" + Integer.toHexString(bit)); - f = f & ~bit; - } - return s; - } - - private static String flagToModifier(int flag, Kind t) { - switch (flag) { - case ACC_PUBLIC: - return "public"; - case ACC_PRIVATE: - return "private"; - case ACC_PROTECTED: - return "protected"; - case ACC_STATIC: - return "static"; - case ACC_FINAL: - return "final"; - case ACC_SYNCHRONIZED: - return "synchronized"; - case 0x80: - return (t == Kind.Field ? "transient" : null); - case ACC_VOLATILE: - return "volatile"; - case ACC_NATIVE: - return "native"; - case ACC_ABSTRACT: - return "abstract"; - case ACC_STRICT: - return "strictfp"; - case ACC_MANDATED: - return "mandated"; - default: - return null; - } - } - - private static String flagToName(int flag, Kind t) { - switch (flag) { - case ACC_PUBLIC: - return "ACC_PUBLIC"; - case ACC_PRIVATE: - return "ACC_PRIVATE"; - case ACC_PROTECTED: - return "ACC_PROTECTED"; - case ACC_STATIC: - return "ACC_STATIC"; - case ACC_FINAL: - return "ACC_FINAL"; - case 0x20: - return (t == Kind.Class ? "ACC_SUPER" : "ACC_SYNCHRONIZED"); - case 0x40: - return (t == Kind.Field ? "ACC_VOLATILE" : "ACC_BRIDGE"); - case 0x80: - return (t == Kind.Field ? "ACC_TRANSIENT" : "ACC_VARARGS"); - case ACC_NATIVE: - return "ACC_NATIVE"; - case ACC_INTERFACE: - return "ACC_INTERFACE"; - case ACC_ABSTRACT: - return "ACC_ABSTRACT"; - case ACC_STRICT: - return "ACC_STRICT"; - case ACC_SYNTHETIC: - return "ACC_SYNTHETIC"; - case ACC_ANNOTATION: - return "ACC_ANNOTATION"; - case ACC_ENUM: - return "ACC_ENUM"; - case 0x8000: - return (t == Kind.Class ? "ACC_MODULE" : "ACC_MANDATED"); - default: - return null; - } - } - - public final int flags; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Annotation.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Annotation.java deleted file mode 100644 index caf148944ab87..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Annotation.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.16. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Annotation { - static class InvalidAnnotation extends AttributeException { - private static final long serialVersionUID = -4620480740735772708L; - InvalidAnnotation(String msg) { - super(msg); - } - } - - Annotation(ClassReader cr) throws IOException, InvalidAnnotation { - type_index = cr.readUnsignedShort(); - num_element_value_pairs = cr.readUnsignedShort(); - element_value_pairs = new element_value_pair[num_element_value_pairs]; - for (int i = 0; i < element_value_pairs.length; i++) - element_value_pairs[i] = new element_value_pair(cr); - } - - public Annotation(ConstantPool constant_pool, - int type_index, - element_value_pair[] element_value_pairs) { - this.type_index = type_index; - num_element_value_pairs = element_value_pairs.length; - this.element_value_pairs = element_value_pairs; - } - - public int length() { - int n = 2 /*type_index*/ + 2 /*num_element_value_pairs*/; - for (element_value_pair pair: element_value_pairs) - n += pair.length(); - return n; - } - - public final int type_index; - public final int num_element_value_pairs; - public final element_value_pair element_value_pairs[]; - - /** - * See JVMS, section 4.8.16.1. - */ - public abstract static class element_value { - public static element_value read(ClassReader cr) - throws IOException, InvalidAnnotation { - int tag = cr.readUnsignedByte(); - switch (tag) { - case 'B': - case 'C': - case 'D': - case 'F': - case 'I': - case 'J': - case 'S': - case 'Z': - case 's': - return new Primitive_element_value(cr, tag); - - case 'e': - return new Enum_element_value(cr, tag); - - case 'c': - return new Class_element_value(cr, tag); - - case '@': - return new Annotation_element_value(cr, tag); - - case '[': - return new Array_element_value(cr, tag); - - default: - throw new InvalidAnnotation("unrecognized tag: " + tag); - } - } - - protected element_value(int tag) { - this.tag = tag; - } - - public abstract int length(); - - public abstract R accept(Visitor visitor, P p); - - public interface Visitor { - R visitPrimitive(Primitive_element_value ev, P p); - R visitEnum(Enum_element_value ev, P p); - R visitClass(Class_element_value ev, P p); - R visitAnnotation(Annotation_element_value ev, P p); - R visitArray(Array_element_value ev, P p); - } - - public final int tag; - } - - public static class Primitive_element_value extends element_value { - Primitive_element_value(ClassReader cr, int tag) throws IOException { - super(tag); - const_value_index = cr.readUnsignedShort(); - } - - public Primitive_element_value(int const_value_index, int tag) { - super(tag); - this.const_value_index = const_value_index; - } - - @Override - public int length() { - return 2; - } - - public R accept(Visitor visitor, P p) { - return visitor.visitPrimitive(this, p); - } - - public final int const_value_index; - - } - - public static class Enum_element_value extends element_value { - Enum_element_value(ClassReader cr, int tag) throws IOException { - super(tag); - type_name_index = cr.readUnsignedShort(); - const_name_index = cr.readUnsignedShort(); - } - - public Enum_element_value(int type_name_index, int const_name_index, int tag) { - super(tag); - this.type_name_index = type_name_index; - this.const_name_index = const_name_index; - } - - @Override - public int length() { - return 4; - } - - public R accept(Visitor visitor, P p) { - return visitor.visitEnum(this, p); - } - - public final int type_name_index; - public final int const_name_index; - } - - public static class Class_element_value extends element_value { - Class_element_value(ClassReader cr, int tag) throws IOException { - super(tag); - class_info_index = cr.readUnsignedShort(); - } - - public Class_element_value(int class_info_index, int tag) { - super(tag); - this.class_info_index = class_info_index; - } - - @Override - public int length() { - return 2; - } - - public R accept(Visitor visitor, P p) { - return visitor.visitClass(this, p); - } - - public final int class_info_index; - } - - public static class Annotation_element_value extends element_value { - Annotation_element_value(ClassReader cr, int tag) - throws IOException, InvalidAnnotation { - super(tag); - annotation_value = new Annotation(cr); - } - - public Annotation_element_value(Annotation annotation_value, int tag) { - super(tag); - this.annotation_value = annotation_value; - } - - @Override - public int length() { - return annotation_value.length(); - } - - public R accept(Visitor visitor, P p) { - return visitor.visitAnnotation(this, p); - } - - public final Annotation annotation_value; - } - - public static class Array_element_value extends element_value { - Array_element_value(ClassReader cr, int tag) - throws IOException, InvalidAnnotation { - super(tag); - num_values = cr.readUnsignedShort(); - values = new element_value[num_values]; - for (int i = 0; i < values.length; i++) - values[i] = element_value.read(cr); - } - - public Array_element_value(element_value[] values, int tag) { - super(tag); - this.num_values = values.length; - this.values = values; - } - - @Override - public int length() { - int n = 2; - for (int i = 0; i < values.length; i++) - n += values[i].length(); - return n; - } - - public R accept(Visitor visitor, P p) { - return visitor.visitArray(this, p); - } - - public final int num_values; - public final element_value[] values; - } - - public static class element_value_pair { - element_value_pair(ClassReader cr) - throws IOException, InvalidAnnotation { - element_name_index = cr.readUnsignedShort(); - value = element_value.read(cr); - } - - public element_value_pair(int element_name_index, element_value value) { - this.element_name_index = element_name_index; - this.value = value; - } - - public int length() { - return 2 + value.length(); - } - - public final int element_name_index; - public final element_value value; - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/AnnotationDefault_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/AnnotationDefault_attribute.java deleted file mode 100644 index 1ca7fc4565c2d..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/AnnotationDefault_attribute.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.15. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class AnnotationDefault_attribute extends Attribute { - AnnotationDefault_attribute(ClassReader cr, int name_index, int length) - throws IOException, Annotation.InvalidAnnotation { - super(name_index, length); - default_value = Annotation.element_value.read(cr); - } - - public AnnotationDefault_attribute(ConstantPool constant_pool, Annotation.element_value default_value) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.AnnotationDefault), default_value); - } - - public AnnotationDefault_attribute(int name_index, Annotation.element_value default_value) { - super(name_index, default_value.length()); - this.default_value = default_value; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitAnnotationDefault(this, data); - } - - public final Annotation.element_value default_value; -} - diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Attribute.java deleted file mode 100644 index 3ab3fce1863b8..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Attribute.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.util.HashMap; -import java.util.Map; - -/** - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ - -public abstract class Attribute { - public static final String AnnotationDefault = "AnnotationDefault"; - public static final String BootstrapMethods = "BootstrapMethods"; - public static final String CharacterRangeTable = "CharacterRangeTable"; - public static final String Code = "Code"; - public static final String ConstantValue = "ConstantValue"; - public static final String CompilationID = "CompilationID"; - public static final String Deprecated = "Deprecated"; - public static final String EnclosingMethod = "EnclosingMethod"; - public static final String Exceptions = "Exceptions"; - public static final String InnerClasses = "InnerClasses"; - public static final String LineNumberTable = "LineNumberTable"; - public static final String LocalVariableTable = "LocalVariableTable"; - public static final String LocalVariableTypeTable = "LocalVariableTypeTable"; - public static final String MethodParameters = "MethodParameters"; - public static final String Module = "Module"; - public static final String ModuleHashes = "ModuleHashes"; - public static final String ModuleMainClass = "ModuleMainClass"; - public static final String ModulePackages = "ModulePackages"; - public static final String ModuleResolution = "ModuleResolution"; - public static final String ModuleTarget = "ModuleTarget"; - public static final String NestHost = "NestHost"; - public static final String NestMembers = "NestMembers"; - public static final String Record = "Record"; - public static final String RuntimeVisibleAnnotations = "RuntimeVisibleAnnotations"; - public static final String RuntimeInvisibleAnnotations = "RuntimeInvisibleAnnotations"; - public static final String RuntimeVisibleParameterAnnotations = "RuntimeVisibleParameterAnnotations"; - public static final String RuntimeInvisibleParameterAnnotations = "RuntimeInvisibleParameterAnnotations"; - public static final String RuntimeVisibleTypeAnnotations = "RuntimeVisibleTypeAnnotations"; - public static final String RuntimeInvisibleTypeAnnotations = "RuntimeInvisibleTypeAnnotations"; - public static final String PermittedSubclasses = "PermittedSubclasses"; - public static final String Signature = "Signature"; - public static final String SourceDebugExtension = "SourceDebugExtension"; - public static final String SourceFile = "SourceFile"; - public static final String SourceID = "SourceID"; - public static final String StackMap = "StackMap"; - public static final String StackMapTable = "StackMapTable"; - public static final String Synthetic = "Synthetic"; - - public static class Factory { - public Factory() { - // defer init of standardAttributeClasses until after options set up - } - - public Attribute createAttribute(ClassReader cr, int name_index, byte[] data) - throws IOException { - if (standardAttributes == null) { - init(); - } - - ConstantPool cp = cr.getConstantPool(); - String reasonForDefaultAttr; - try { - String name = cp.getUTF8Value(name_index); - Class attrClass = standardAttributes.get(name); - if (attrClass != null) { - try { - Class[] constrArgTypes = {ClassReader.class, int.class, int.class}; - Constructor constr = attrClass.getDeclaredConstructor(constrArgTypes); - return constr.newInstance(cr, name_index, data.length); - } catch (Throwable t) { - reasonForDefaultAttr = t.toString(); - // fall through and use DefaultAttribute - // t.printStackTrace(); - } - } else { - reasonForDefaultAttr = "unknown attribute"; - } - } catch (ConstantPoolException e) { - reasonForDefaultAttr = e.toString(); - // fall through and use DefaultAttribute - } - return new DefaultAttribute(cr, name_index, data, reasonForDefaultAttr); - } - - protected void init() { - standardAttributes = new HashMap<>(); - standardAttributes.put(AnnotationDefault, AnnotationDefault_attribute.class); - standardAttributes.put(BootstrapMethods, BootstrapMethods_attribute.class); - standardAttributes.put(CharacterRangeTable, CharacterRangeTable_attribute.class); - standardAttributes.put(Code, Code_attribute.class); - standardAttributes.put(CompilationID, CompilationID_attribute.class); - standardAttributes.put(ConstantValue, ConstantValue_attribute.class); - standardAttributes.put(Deprecated, Deprecated_attribute.class); - standardAttributes.put(EnclosingMethod, EnclosingMethod_attribute.class); - standardAttributes.put(Exceptions, Exceptions_attribute.class); - standardAttributes.put(InnerClasses, InnerClasses_attribute.class); - standardAttributes.put(LineNumberTable, LineNumberTable_attribute.class); - standardAttributes.put(LocalVariableTable, LocalVariableTable_attribute.class); - standardAttributes.put(LocalVariableTypeTable, LocalVariableTypeTable_attribute.class); - standardAttributes.put(MethodParameters, MethodParameters_attribute.class); - standardAttributes.put(Module, Module_attribute.class); - standardAttributes.put(ModuleHashes, ModuleHashes_attribute.class); - standardAttributes.put(ModuleMainClass, ModuleMainClass_attribute.class); - standardAttributes.put(ModulePackages, ModulePackages_attribute.class); - standardAttributes.put(ModuleResolution, ModuleResolution_attribute.class); - standardAttributes.put(ModuleTarget, ModuleTarget_attribute.class); - standardAttributes.put(NestHost, NestHost_attribute.class); - standardAttributes.put(NestMembers, NestMembers_attribute.class); - standardAttributes.put(Record, Record_attribute.class); - standardAttributes.put(RuntimeInvisibleAnnotations, RuntimeInvisibleAnnotations_attribute.class); - standardAttributes.put(RuntimeInvisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations_attribute.class); - standardAttributes.put(RuntimeVisibleAnnotations, RuntimeVisibleAnnotations_attribute.class); - standardAttributes.put(RuntimeVisibleParameterAnnotations, RuntimeVisibleParameterAnnotations_attribute.class); - standardAttributes.put(RuntimeVisibleTypeAnnotations, RuntimeVisibleTypeAnnotations_attribute.class); - standardAttributes.put(RuntimeInvisibleTypeAnnotations, RuntimeInvisibleTypeAnnotations_attribute.class); - standardAttributes.put(PermittedSubclasses, PermittedSubclasses_attribute.class); - standardAttributes.put(Signature, Signature_attribute.class); - standardAttributes.put(SourceDebugExtension, SourceDebugExtension_attribute.class); - standardAttributes.put(SourceFile, SourceFile_attribute.class); - standardAttributes.put(SourceID, SourceID_attribute.class); - standardAttributes.put(StackMap, StackMap_attribute.class); - standardAttributes.put(StackMapTable, StackMapTable_attribute.class); - standardAttributes.put(Synthetic, Synthetic_attribute.class); - } - - private Map> standardAttributes; - } - - public static Attribute read(ClassReader cr) throws IOException { - return cr.readAttribute(); - } - - protected Attribute(int name_index, int length) { - attribute_name_index = name_index; - attribute_length = length; - } - - public String getName(ConstantPool constant_pool) throws ConstantPoolException { - return constant_pool.getUTF8Value(attribute_name_index); - } - - public abstract R accept(Attribute.Visitor visitor, D data); - - public int byteLength() { - return 6 + attribute_length; - } - - public final int attribute_name_index; - public final int attribute_length; - - - public interface Visitor { - R visitBootstrapMethods(BootstrapMethods_attribute attr, P p); - R visitDefault(DefaultAttribute attr, P p); - R visitAnnotationDefault(AnnotationDefault_attribute attr, P p); - R visitCharacterRangeTable(CharacterRangeTable_attribute attr, P p); - R visitCode(Code_attribute attr, P p); - R visitCompilationID(CompilationID_attribute attr, P p); - R visitConstantValue(ConstantValue_attribute attr, P p); - R visitDeprecated(Deprecated_attribute attr, P p); - R visitEnclosingMethod(EnclosingMethod_attribute attr, P p); - R visitExceptions(Exceptions_attribute attr, P p); - R visitInnerClasses(InnerClasses_attribute attr, P p); - R visitLineNumberTable(LineNumberTable_attribute attr, P p); - R visitLocalVariableTable(LocalVariableTable_attribute attr, P p); - R visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, P p); - R visitMethodParameters(MethodParameters_attribute attr, P p); - R visitModule(Module_attribute attr, P p); - R visitModuleHashes(ModuleHashes_attribute attr, P p); - R visitModuleMainClass(ModuleMainClass_attribute attr, P p); - R visitModulePackages(ModulePackages_attribute attr, P p); - R visitModuleResolution(ModuleResolution_attribute attr, P p); - R visitModuleTarget(ModuleTarget_attribute attr, P p); - R visitNestHost(NestHost_attribute attr, P p); - R visitNestMembers(NestMembers_attribute attr, P p); - R visitRecord(Record_attribute attr, P p); - R visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, P p); - R visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, P p); - R visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, P p); - R visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, P p); - R visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, P p); - R visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, P p); - R visitPermittedSubclasses(PermittedSubclasses_attribute attr, P p); - R visitSignature(Signature_attribute attr, P p); - R visitSourceDebugExtension(SourceDebugExtension_attribute attr, P p); - R visitSourceFile(SourceFile_attribute attr, P p); - R visitSourceID(SourceID_attribute attr, P p); - R visitStackMap(StackMap_attribute attr, P p); - R visitStackMapTable(StackMapTable_attribute attr, P p); - R visitSynthetic(Synthetic_attribute attr, P p); - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/AttributeException.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/AttributeException.java deleted file mode 100644 index a4682c02515ef..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/AttributeException.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -/* - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class AttributeException extends Exception { - private static final long serialVersionUID = -4231486387714867770L; - AttributeException() { } - - AttributeException(String msg) { - super(msg); - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Attributes.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Attributes.java deleted file mode 100644 index 0bc75ac1a248a..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Attributes.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -/* - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Attributes implements Iterable { - - public final Attribute[] attrs; - public final Map map; - - Attributes(ClassReader cr) throws IOException { - map = new HashMap<>(); - int attrs_count = cr.readUnsignedShort(); - attrs = new Attribute[attrs_count]; - for (int i = 0; i < attrs_count; i++) { - Attribute attr = Attribute.read(cr); - attrs[i] = attr; - try { - map.put(attr.getName(cr.getConstantPool()), attr); - } catch (ConstantPoolException e) { - // don't enter invalid names in map - } - } - } - - public Attributes(ConstantPool constant_pool, Attribute[] attrs) { - this.attrs = attrs; - map = new HashMap<>(); - for (Attribute attr : attrs) { - try { - map.put(attr.getName(constant_pool), attr); - } catch (ConstantPoolException e) { - // don't enter invalid names in map - } - } - } - - public Attributes(Map attributes) { - this.attrs = attributes.values().toArray(new Attribute[attributes.size()]); - map = attributes; - } - - public Iterator iterator() { - return Arrays.asList(attrs).iterator(); - } - - public Attribute get(int index) { - return attrs[index]; - } - - public Attribute get(String name) { - return map.get(name); - } - - public int getIndex(ConstantPool constant_pool, String name) { - for (int i = 0; i < attrs.length; i++) { - Attribute attr = attrs[i]; - try { - if (attr != null && attr.getName(constant_pool).equals(name)) - return i; - } catch (ConstantPoolException e) { - // ignore invalid entries - } - } - return -1; - } - - public int size() { - return attrs.length; - } - - public int byteLength() { - int length = 2; - for (Attribute a: attrs) - length += a.byteLength(); - return length; - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/BootstrapMethods_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/BootstrapMethods_attribute.java deleted file mode 100644 index 69d034788cc0b..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/BootstrapMethods_attribute.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS 4.7.21 - * http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.21 - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class BootstrapMethods_attribute extends Attribute { - public final BootstrapMethodSpecifier[] bootstrap_method_specifiers; - - BootstrapMethods_attribute(ClassReader cr, int name_index, int length) - throws IOException, AttributeException { - super(name_index, length); - int bootstrap_method_count = cr.readUnsignedShort(); - bootstrap_method_specifiers = new BootstrapMethodSpecifier[bootstrap_method_count]; - for (int i = 0; i < bootstrap_method_specifiers.length; i++) - bootstrap_method_specifiers[i] = new BootstrapMethodSpecifier(cr); - } - - public BootstrapMethods_attribute(int name_index, BootstrapMethodSpecifier[] bootstrap_method_specifiers) { - super(name_index, length(bootstrap_method_specifiers)); - this.bootstrap_method_specifiers = bootstrap_method_specifiers; - } - - public static int length(BootstrapMethodSpecifier[] bootstrap_method_specifiers) { - int n = 2; - for (BootstrapMethodSpecifier b : bootstrap_method_specifiers) - n += b.length(); - return n; - } - - @Override - public R accept(Visitor visitor, P p) { - return visitor.visitBootstrapMethods(this, p); - } - - public static class BootstrapMethodSpecifier { - public int bootstrap_method_ref; - public int[] bootstrap_arguments; - - public BootstrapMethodSpecifier(int bootstrap_method_ref, int[] bootstrap_arguments) { - this.bootstrap_method_ref = bootstrap_method_ref; - this.bootstrap_arguments = bootstrap_arguments; - } - BootstrapMethodSpecifier(ClassReader cr) throws IOException { - bootstrap_method_ref = cr.readUnsignedShort(); - int method_count = cr.readUnsignedShort(); - bootstrap_arguments = new int[method_count]; - for (int i = 0; i < bootstrap_arguments.length; i++) { - bootstrap_arguments[i] = cr.readUnsignedShort(); - } - } - - int length() { - // u2 (method_ref) + u2 (argc) + u2 * argc - return 2 + 2 + (bootstrap_arguments.length * 2); - } - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/CharacterRangeTable_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/CharacterRangeTable_attribute.java deleted file mode 100644 index 2b1425789f40a..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/CharacterRangeTable_attribute.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class CharacterRangeTable_attribute extends Attribute { - public static final int CRT_STATEMENT = 0x0001; - public static final int CRT_BLOCK = 0x0002; - public static final int CRT_ASSIGNMENT = 0x0004; - public static final int CRT_FLOW_CONTROLLER = 0x0008; - public static final int CRT_FLOW_TARGET = 0x0010; - public static final int CRT_INVOKE = 0x0020; - public static final int CRT_CREATE = 0x0040; - public static final int CRT_BRANCH_TRUE = 0x0080; - public static final int CRT_BRANCH_FALSE = 0x0100; - - CharacterRangeTable_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - int character_range_table_length = cr.readUnsignedShort(); - character_range_table = new Entry[character_range_table_length]; - for (int i = 0; i < character_range_table_length; i++) - character_range_table[i] = new Entry(cr); - } - - public CharacterRangeTable_attribute(ConstantPool constant_pool, Entry[] character_range_table) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.CharacterRangeTable), character_range_table); - } - - public CharacterRangeTable_attribute(int name_index, Entry[] character_range_table) { - super(name_index, 2 + character_range_table.length * Entry.length()); - this.character_range_table = character_range_table; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitCharacterRangeTable(this, data); - } - - public final Entry[] character_range_table; - - public static class Entry { - Entry(ClassReader cr) throws IOException { - start_pc = cr.readUnsignedShort(); - end_pc = cr.readUnsignedShort(); - character_range_start = cr.readInt(); - character_range_end = cr.readInt(); - flags = cr.readUnsignedShort(); - } - - public static int length() { - return 14; - } - - public final int start_pc; - public final int end_pc; - public final int character_range_start; - public final int character_range_end; - public final int flags; - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassFile.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassFile.java deleted file mode 100644 index 52aefca546971..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassFile.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; - -import static com.sun.tools.classfile.AccessFlags.*; - -/** - * See JVMS, section 4.2. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class ClassFile { - public static ClassFile read(File file) - throws IOException, ConstantPoolException { - return read(file.toPath(), new Attribute.Factory()); - } - - public static ClassFile read(Path input) - throws IOException, ConstantPoolException { - return read(input, new Attribute.Factory()); - } - - public static ClassFile read(Path input, Attribute.Factory attributeFactory) - throws IOException, ConstantPoolException { - try (InputStream in = Files.newInputStream(input)) { - return new ClassFile(in, attributeFactory); - } - } - - public static ClassFile read(File file, Attribute.Factory attributeFactory) - throws IOException, ConstantPoolException { - return read(file.toPath(), attributeFactory); - } - - public static ClassFile read(InputStream in) - throws IOException, ConstantPoolException { - return new ClassFile(in, new Attribute.Factory()); - } - - public static ClassFile read(InputStream in, Attribute.Factory attributeFactory) - throws IOException, ConstantPoolException { - return new ClassFile(in, attributeFactory); - } - - ClassFile(InputStream in, Attribute.Factory attributeFactory) throws IOException, ConstantPoolException { - ClassReader cr = new ClassReader(this, in, attributeFactory); - magic = cr.readInt(); - minor_version = cr.readUnsignedShort(); - major_version = cr.readUnsignedShort(); - constant_pool = new ConstantPool(cr); - access_flags = new AccessFlags(cr); - this_class = cr.readUnsignedShort(); - super_class = cr.readUnsignedShort(); - - int interfaces_count = cr.readUnsignedShort(); - interfaces = new int[interfaces_count]; - for (int i = 0; i < interfaces_count; i++) - interfaces[i] = cr.readUnsignedShort(); - - int fields_count = cr.readUnsignedShort(); - fields = new Field[fields_count]; - for (int i = 0; i < fields_count; i++) - fields[i] = new Field(cr); - - int methods_count = cr.readUnsignedShort(); - methods = new Method[methods_count]; - for (int i = 0; i < methods_count; i++) - methods[i] = new Method(cr); - - attributes = new Attributes(cr); - } - - public ClassFile(int magic, int minor_version, int major_version, - ConstantPool constant_pool, AccessFlags access_flags, - int this_class, int super_class, int[] interfaces, - Field[] fields, Method[] methods, Attributes attributes) { - this.magic = magic; - this.minor_version = minor_version; - this.major_version = major_version; - this.constant_pool = constant_pool; - this.access_flags = access_flags; - this.this_class = this_class; - this.super_class = super_class; - this.interfaces = interfaces; - this.fields = fields; - this.methods = methods; - this.attributes = attributes; - } - - public String getName() throws ConstantPoolException { - return constant_pool.getClassInfo(this_class).getName(); - } - - public String getSuperclassName() throws ConstantPoolException { - return constant_pool.getClassInfo(super_class).getName(); - } - - public String getInterfaceName(int i) throws ConstantPoolException { - return constant_pool.getClassInfo(interfaces[i]).getName(); - } - - public Attribute getAttribute(String name) { - return attributes.get(name); - } - - public boolean isClass() { - return !isInterface(); - } - - public boolean isInterface() { - return access_flags.is(ACC_INTERFACE); - } - - public int byteLength() { - return 4 + // magic - 2 + // minor - 2 + // major - constant_pool.byteLength() + - 2 + // access flags - 2 + // this_class - 2 + // super_class - byteLength(interfaces) + - byteLength(fields) + - byteLength(methods) + - attributes.byteLength(); - } - - private int byteLength(int[] indices) { - return 2 + 2 * indices.length; - } - - private int byteLength(Field[] fields) { - int length = 2; - for (Field f: fields) - length += f.byteLength(); - return length; - } - - private int byteLength(Method[] methods) { - int length = 2; - for (Method m: methods) - length += m.byteLength(); - return length; - } - - public final int magic; - public final int minor_version; - public final int major_version; - public final ConstantPool constant_pool; - public final AccessFlags access_flags; - public final int this_class; - public final int super_class; - public final int[] interfaces; - public final Field[] fields; - public final Method[] methods; - public final Attributes attributes; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassReader.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassReader.java deleted file mode 100644 index 6511d0f905c09..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassReader.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Objects; - -/** - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class ClassReader { - ClassReader(ClassFile classFile, InputStream in, Attribute.Factory attributeFactory) throws IOException { - this.classFile = Objects.requireNonNull(classFile); - this.attributeFactory = Objects.requireNonNull(attributeFactory); - this.in = new DataInputStream(new BufferedInputStream(in)); - } - - ClassFile getClassFile() { - return classFile; - } - - ConstantPool getConstantPool() { - return classFile.constant_pool; - } - - public Attribute readAttribute() throws IOException { - int name_index = readUnsignedShort(); - int length = readInt(); - if (length < 0) { // we have an overflow as max_value(u4) > max_value(int) - String attrName; - try { - attrName = getConstantPool().getUTF8Value(name_index); - } catch (ConstantPool.InvalidIndex | ConstantPool.UnexpectedEntry e) { - attrName = ""; - } - throw new FatalError(String.format("attribute %s too big to handle", attrName)); - } - byte[] data = new byte[length]; - readFully(data); - - DataInputStream prev = in; - in = new DataInputStream(new ByteArrayInputStream(data)); - try { - return attributeFactory.createAttribute(this, name_index, data); - } finally { - in = prev; - } - } - - public void readFully(byte[] b) throws IOException { - in.readFully(b); - } - - public int readUnsignedByte() throws IOException { - return in.readUnsignedByte(); - } - - public int readUnsignedShort() throws IOException { - return in.readUnsignedShort(); - } - - public int readInt() throws IOException { - return in.readInt(); - } - - public long readLong() throws IOException { - return in.readLong(); - } - - public float readFloat() throws IOException { - return in.readFloat(); - } - - public double readDouble() throws IOException { - return in.readDouble(); - } - - public String readUTF() throws IOException { - return in.readUTF(); - } - - private DataInputStream in; - private ClassFile classFile; - private Attribute.Factory attributeFactory; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassTranslator.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassTranslator.java deleted file mode 100644 index 2725fc3d41861..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassTranslator.java +++ /dev/null @@ -1,469 +0,0 @@ -/* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.util.Map; - -import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Dynamic_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Fieldref_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Float_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Integer_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_InterfaceMethodref_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_InvokeDynamic_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Long_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_MethodHandle_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_MethodType_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Methodref_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Module_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_NameAndType_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Package_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_String_info; -import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info; -import com.sun.tools.classfile.ConstantPool.CPInfo; - -/** - * Rewrites a class file using a map of translations. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class ClassTranslator - implements ConstantPool.Visitor> { - /** - * Create a new ClassFile from {@code cf}, such that for all entries - * {@code k -\> v} in {@code translations}, - * each occurrence of {@code k} in {@code cf} will be replaced by {@code v}. - * in - * @param cf the class file to be processed - * @param translations the set of translations to be applied - * @return a copy of {@code} with the values in {@code translations} substituted - */ - public ClassFile translate(ClassFile cf, Map translations) { - ClassFile cf2 = (ClassFile) translations.get(cf); - if (cf2 == null) { - ConstantPool constant_pool2 = translate(cf.constant_pool, translations); - Field[] fields2 = translate(cf.fields, cf.constant_pool, translations); - Method[] methods2 = translateMethods(cf.methods, cf.constant_pool, translations); - Attributes attributes2 = translateAttributes(cf.attributes, cf.constant_pool, - translations); - - if (constant_pool2 == cf.constant_pool && - fields2 == cf.fields && - methods2 == cf.methods && - attributes2 == cf.attributes) - cf2 = cf; - else - cf2 = new ClassFile( - cf.magic, - cf.minor_version, - cf.major_version, - constant_pool2, - cf.access_flags, - cf.this_class, - cf.super_class, - cf.interfaces, - fields2, - methods2, - attributes2); - translations.put(cf, cf2); - } - return cf2; - } - - ConstantPool translate(ConstantPool cp, Map translations) { - ConstantPool cp2 = (ConstantPool) translations.get(cp); - if (cp2 == null) { - ConstantPool.CPInfo[] pool2 = new ConstantPool.CPInfo[cp.size()]; - boolean eq = true; - for (int i = 0; i < cp.size(); ) { - ConstantPool.CPInfo cpInfo; - try { - cpInfo = cp.get(i); - } catch (ConstantPool.InvalidIndex e) { - throw new IllegalStateException(e); - } - ConstantPool.CPInfo cpInfo2 = translate(cpInfo, translations); - eq &= (cpInfo == cpInfo2); - pool2[i] = cpInfo2; - if (cpInfo.getTag() != cpInfo2.getTag()) - throw new IllegalStateException(); - i += cpInfo.size(); - } - - if (eq) - cp2 = cp; - else - cp2 = new ConstantPool(pool2); - - translations.put(cp, cp2); - } - return cp2; - } - - ConstantPool.CPInfo translate(ConstantPool.CPInfo cpInfo, Map translations) { - ConstantPool.CPInfo cpInfo2 = (ConstantPool.CPInfo) translations.get(cpInfo); - if (cpInfo2 == null) { - cpInfo2 = cpInfo.accept(this, translations); - translations.put(cpInfo, cpInfo2); - } - return cpInfo2; - } - - Field[] translate(Field[] fields, ConstantPool constant_pool, Map translations) { - Field[] fields2 = (Field[]) translations.get(fields); - if (fields2 == null) { - fields2 = new Field[fields.length]; - for (int i = 0; i < fields.length; i++) - fields2[i] = translate(fields[i], constant_pool, translations); - if (equal(fields, fields2)) - fields2 = fields; - translations.put(fields, fields2); - } - return fields2; - } - - Field translate(Field field, ConstantPool constant_pool, Map translations) { - Field field2 = (Field) translations.get(field); - if (field2 == null) { - Attributes attributes2 = translateAttributes(field.attributes, constant_pool, - translations); - - if (attributes2 == field.attributes) - field2 = field; - else - field2 = new Field( - field.access_flags, - field.name_index, - field.descriptor, - attributes2); - translations.put(field, field2); - } - return field2; - } - - Method[] translateMethods(Method[] methods, ConstantPool constant_pool, Map translations) { - Method[] methods2 = (Method[]) translations.get(methods); - if (methods2 == null) { - methods2 = new Method[methods.length]; - for (int i = 0; i < methods.length; i++) - methods2[i] = translate(methods[i], constant_pool, translations); - if (equal(methods, methods2)) - methods2 = methods; - translations.put(methods, methods2); - } - return methods2; - } - - Method translate(Method method, ConstantPool constant_pool, Map translations) { - Method method2 = (Method) translations.get(method); - if (method2 == null) { - Attributes attributes2 = translateAttributes(method.attributes, constant_pool, - translations); - - if (attributes2 == method.attributes) - method2 = method; - else - method2 = new Method( - method.access_flags, - method.name_index, - method.descriptor, - attributes2); - translations.put(method, method2); - } - return method2; - } - - Attributes translateAttributes(Attributes attributes, - ConstantPool constant_pool, Map translations) { - Attributes attributes2 = (Attributes) translations.get(attributes); - if (attributes2 == null) { - Attribute[] attrArray2 = new Attribute[attributes.size()]; - ConstantPool constant_pool2 = translate(constant_pool, translations); - boolean attrsEqual = true; - for (int i = 0; i < attributes.size(); i++) { - Attribute attr = attributes.get(i); - Attribute attr2 = translate(attr, translations); - if (attr2 != attr) - attrsEqual = false; - attrArray2[i] = attr2; - } - if ((constant_pool2 == constant_pool) && attrsEqual) - attributes2 = attributes; - else - attributes2 = new Attributes(constant_pool2, attrArray2); - translations.put(attributes, attributes2); - } - return attributes2; - } - - Attribute translate(Attribute attribute, Map translations) { - Attribute attribute2 = (Attribute) translations.get(attribute); - if (attribute2 == null) { - attribute2 = attribute; // don't support translation within attributes yet - // (what about Code attribute) - translations.put(attribute, attribute2); - } - return attribute2; - } - - private static boolean equal(T[] a1, T[] a2) { - if (a1 == null || a2 == null) - return (a1 == a2); - if (a1.length != a2.length) - return false; - for (int i = 0; i < a1.length; i++) { - if (a1[i] != a2[i]) - return false; - } - return true; - } - - @Override - public CPInfo visitClass(CONSTANT_Class_info info, Map translations) { - CONSTANT_Class_info info2 = (CONSTANT_Class_info) translations.get(info); - if (info2 == null) { - ConstantPool cp2 = translate(info.cp, translations); - if (cp2 == info.cp) - info2 = info; - else - info2 = new CONSTANT_Class_info(cp2, info.name_index); - translations.put(info, info2); - } - return info; - } - - @Override - public CPInfo visitDouble(CONSTANT_Double_info info, Map translations) { - CONSTANT_Double_info info2 = (CONSTANT_Double_info) translations.get(info); - if (info2 == null) { - info2 = info; - translations.put(info, info2); - } - return info; - } - - @Override - public CPInfo visitFieldref(CONSTANT_Fieldref_info info, Map translations) { - CONSTANT_Fieldref_info info2 = (CONSTANT_Fieldref_info) translations.get(info); - if (info2 == null) { - ConstantPool cp2 = translate(info.cp, translations); - if (cp2 == info.cp) - info2 = info; - else - info2 = new CONSTANT_Fieldref_info(cp2, info.class_index, info.name_and_type_index); - translations.put(info, info2); - } - return info; - } - - @Override - public CPInfo visitFloat(CONSTANT_Float_info info, Map translations) { - CONSTANT_Float_info info2 = (CONSTANT_Float_info) translations.get(info); - if (info2 == null) { - info2 = info; - translations.put(info, info2); - } - return info; - } - - @Override - public CPInfo visitInteger(CONSTANT_Integer_info info, Map translations) { - CONSTANT_Integer_info info2 = (CONSTANT_Integer_info) translations.get(info); - if (info2 == null) { - info2 = info; - translations.put(info, info2); - } - return info; - } - - @Override - public CPInfo visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Map translations) { - CONSTANT_InterfaceMethodref_info info2 = (CONSTANT_InterfaceMethodref_info) translations.get(info); - if (info2 == null) { - ConstantPool cp2 = translate(info.cp, translations); - if (cp2 == info.cp) - info2 = info; - else - info2 = new CONSTANT_InterfaceMethodref_info(cp2, info.class_index, info.name_and_type_index); - translations.put(info, info2); - } - return info; - } - - @Override - public CPInfo visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, Map translations) { - CONSTANT_InvokeDynamic_info info2 = (CONSTANT_InvokeDynamic_info) translations.get(info); - if (info2 == null) { - ConstantPool cp2 = translate(info.cp, translations); - if (cp2 == info.cp) { - info2 = info; - } else { - info2 = new CONSTANT_InvokeDynamic_info(cp2, info.bootstrap_method_attr_index, info.name_and_type_index); - } - translations.put(info, info2); - } - return info; - } - - public CPInfo visitDynamicConstant(CONSTANT_Dynamic_info info, Map translations) { - CONSTANT_Dynamic_info info2 = (CONSTANT_Dynamic_info) translations.get(info); - if (info2 == null) { - ConstantPool cp2 = translate(info.cp, translations); - if (cp2 == info.cp) { - info2 = info; - } else { - info2 = new CONSTANT_Dynamic_info(cp2, info.bootstrap_method_attr_index, info.name_and_type_index); - } - translations.put(info, info2); - } - return info; - } - - @Override - public CPInfo visitLong(CONSTANT_Long_info info, Map translations) { - CONSTANT_Long_info info2 = (CONSTANT_Long_info) translations.get(info); - if (info2 == null) { - info2 = info; - translations.put(info, info2); - } - return info; - } - - @Override - public CPInfo visitMethodref(CONSTANT_Methodref_info info, Map translations) { - CONSTANT_Methodref_info info2 = (CONSTANT_Methodref_info) translations.get(info); - if (info2 == null) { - ConstantPool cp2 = translate(info.cp, translations); - if (cp2 == info.cp) - info2 = info; - else - info2 = new CONSTANT_Methodref_info(cp2, info.class_index, info.name_and_type_index); - translations.put(info, info2); - } - return info; - } - - @Override - public CPInfo visitMethodHandle(CONSTANT_MethodHandle_info info, Map translations) { - CONSTANT_MethodHandle_info info2 = (CONSTANT_MethodHandle_info) translations.get(info); - if (info2 == null) { - ConstantPool cp2 = translate(info.cp, translations); - if (cp2 == info.cp) { - info2 = info; - } else { - info2 = new CONSTANT_MethodHandle_info(cp2, info.reference_kind, info.reference_index); - } - translations.put(info, info2); - } - return info; - } - - @Override - public CPInfo visitMethodType(CONSTANT_MethodType_info info, Map translations) { - CONSTANT_MethodType_info info2 = (CONSTANT_MethodType_info) translations.get(info); - if (info2 == null) { - ConstantPool cp2 = translate(info.cp, translations); - if (cp2 == info.cp) { - info2 = info; - } else { - info2 = new CONSTANT_MethodType_info(cp2, info.descriptor_index); - } - translations.put(info, info2); - } - return info; - } - - @Override - public CPInfo visitModule(CONSTANT_Module_info info, Map translations) { - CONSTANT_Module_info info2 = (CONSTANT_Module_info) translations.get(info); - if (info2 == null) { - ConstantPool cp2 = translate(info.cp, translations); - if (cp2 == info.cp) - info2 = info; - else - info2 = new CONSTANT_Module_info(cp2, info.name_index); - translations.put(info, info2); - } - return info; - } - - @Override - public CPInfo visitNameAndType(CONSTANT_NameAndType_info info, Map translations) { - CONSTANT_NameAndType_info info2 = (CONSTANT_NameAndType_info) translations.get(info); - if (info2 == null) { - ConstantPool cp2 = translate(info.cp, translations); - if (cp2 == info.cp) - info2 = info; - else - info2 = new CONSTANT_NameAndType_info(cp2, info.name_index, info.type_index); - translations.put(info, info2); - } - return info; - } - - @Override - public CPInfo visitPackage(CONSTANT_Package_info info, Map translations) { - CONSTANT_Package_info info2 = (CONSTANT_Package_info) translations.get(info); - if (info2 == null) { - ConstantPool cp2 = translate(info.cp, translations); - if (cp2 == info.cp) - info2 = info; - else - info2 = new CONSTANT_Package_info(cp2, info.name_index); - translations.put(info, info2); - } - return info; - } - - @Override - public CPInfo visitString(CONSTANT_String_info info, Map translations) { - CONSTANT_String_info info2 = (CONSTANT_String_info) translations.get(info); - if (info2 == null) { - ConstantPool cp2 = translate(info.cp, translations); - if (cp2 == info.cp) - info2 = info; - else - info2 = new CONSTANT_String_info(cp2, info.string_index); - translations.put(info, info2); - } - return info; - } - - @Override - public CPInfo visitUtf8(CONSTANT_Utf8_info info, Map translations) { - CONSTANT_Utf8_info info2 = (CONSTANT_Utf8_info) translations.get(info); - if (info2 == null) { - info2 = info; - translations.put(info, info2); - } - return info; - } - -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassWriter.java deleted file mode 100644 index a24fb837f4309..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassWriter.java +++ /dev/null @@ -1,1011 +0,0 @@ -/* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package com.sun.tools.classfile; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -import static com.sun.tools.classfile.Annotation.*; -import static com.sun.tools.classfile.ConstantPool.*; -import static com.sun.tools.classfile.StackMapTable_attribute.*; -import static com.sun.tools.classfile.StackMapTable_attribute.verification_type_info.*; - -/** - * Write a ClassFile data structure to a file or stream. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class ClassWriter { - public ClassWriter() { - attributeWriter = new AttributeWriter(); - constantPoolWriter = new ConstantPoolWriter(); - out = new ClassOutputStream(); - } - - /** - * Write a ClassFile data structure to a file. - * @param classFile the classfile object to be written - * @param f the file - * @throws IOException if an error occurs while writing the file - */ - public void write(ClassFile classFile, File f) throws IOException { - try (FileOutputStream f_out = new FileOutputStream(f)) { - write(classFile, f_out); - } - } - - /** - * Write a ClassFile data structure to a stream. - * @param classFile the classfile object to be written - * @param s the stream - * @throws IOException if an error occurs while writing the file - */ - public void write(ClassFile classFile, OutputStream s) throws IOException { - this.classFile = classFile; - out.reset(); - write(); - out.writeTo(s); - } - - protected void write() throws IOException { - writeHeader(); - writeConstantPool(); - writeAccessFlags(classFile.access_flags); - writeClassInfo(); - writeFields(); - writeMethods(); - writeAttributes(classFile.attributes); - } - - protected void writeHeader() { - out.writeInt(classFile.magic); - out.writeShort(classFile.minor_version); - out.writeShort(classFile.major_version); - } - - protected void writeAccessFlags(AccessFlags flags) { - out.writeShort(flags.flags); - } - - protected void writeAttributes(Attributes attributes) { - int size = attributes.size(); - out.writeShort(size); - for (Attribute attr: attributes) - attributeWriter.write(attr, out); - } - - protected void writeClassInfo() { - out.writeShort(classFile.this_class); - out.writeShort(classFile.super_class); - int[] interfaces = classFile.interfaces; - out.writeShort(interfaces.length); - for (int i: interfaces) - out.writeShort(i); - } - - protected void writeDescriptor(Descriptor d) { - out.writeShort(d.index); - } - - protected void writeConstantPool() { - ConstantPool pool = classFile.constant_pool; - int size = pool.size(); - out.writeShort(size); - for (CPInfo cpInfo: pool.entries()) - constantPoolWriter.write(cpInfo, out); - } - - protected void writeFields() throws IOException { - Field[] fields = classFile.fields; - out.writeShort(fields.length); - for (Field f: fields) - writeField(f); - } - - protected void writeField(Field f) throws IOException { - writeAccessFlags(f.access_flags); - out.writeShort(f.name_index); - writeDescriptor(f.descriptor); - writeAttributes(f.attributes); - } - - protected void writeMethods() throws IOException { - Method[] methods = classFile.methods; - out.writeShort(methods.length); - for (Method m: methods) { - writeMethod(m); - } - } - - protected void writeMethod(Method m) throws IOException { - writeAccessFlags(m.access_flags); - out.writeShort(m.name_index); - writeDescriptor(m.descriptor); - writeAttributes(m.attributes); - } - - protected ClassFile classFile; - protected ClassOutputStream out; - protected AttributeWriter attributeWriter; - protected ConstantPoolWriter constantPoolWriter; - - /** - * Subtype of ByteArrayOutputStream with the convenience methods of - * a DataOutputStream. Since ByteArrayOutputStream does not throw - * IOException, there are no exceptions from the additional - * convenience methods either, - */ - protected static class ClassOutputStream extends ByteArrayOutputStream { - public ClassOutputStream() { - d = new DataOutputStream(this); - } - - public void writeByte(int value) { - try { - d.writeByte(value); - } catch (IOException ignore) { - } - } - - public void writeShort(int value) { - try { - d.writeShort(value); - } catch (IOException ignore) { - } - } - - public void writeInt(int value) { - try { - d.writeInt(value); - } catch (IOException ignore) { - } - } - - public void writeLong(long value) { - try { - d.writeLong(value); - } catch (IOException ignore) { - } - } - - public void writeFloat(float value) { - try { - d.writeFloat(value); - } catch (IOException ignore) { - } - } - - public void writeDouble(double value) { - try { - d.writeDouble(value); - } catch (IOException ignore) { - } - } - - public void writeUTF(String value) { - try { - d.writeUTF(value); - } catch (IOException ignore) { - } - } - - public void writeTo(ClassOutputStream s) { - try { - super.writeTo(s); - } catch (IOException ignore) { - } - } - - private final DataOutputStream d; - } - - /** - * Writer for the entries in the constant pool. - */ - protected static class ConstantPoolWriter - implements ConstantPool.Visitor { - protected int write(CPInfo info, ClassOutputStream out) { - out.writeByte(info.getTag()); - return info.accept(this, out); - } - - @Override - public Integer visitClass(CONSTANT_Class_info info, ClassOutputStream out) { - out.writeShort(info.name_index); - return 1; - } - - @Override - public Integer visitDouble(CONSTANT_Double_info info, ClassOutputStream out) { - out.writeDouble(info.value); - return 2; - } - - @Override - public Integer visitFieldref(CONSTANT_Fieldref_info info, ClassOutputStream out) { - writeRef(info, out); - return 1; - } - - @Override - public Integer visitFloat(CONSTANT_Float_info info, ClassOutputStream out) { - out.writeFloat(info.value); - return 1; - } - - @Override - public Integer visitInteger(CONSTANT_Integer_info info, ClassOutputStream out) { - out.writeInt(info.value); - return 1; - } - - @Override - public Integer visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, ClassOutputStream out) { - writeRef(info, out); - return 1; - } - - @Override - public Integer visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, ClassOutputStream out) { - out.writeShort(info.bootstrap_method_attr_index); - out.writeShort(info.name_and_type_index); - return 1; - } - - public Integer visitDynamicConstant(CONSTANT_Dynamic_info info, ClassOutputStream out) { - out.writeShort(info.bootstrap_method_attr_index); - out.writeShort(info.name_and_type_index); - return 1; - } - - @Override - public Integer visitLong(CONSTANT_Long_info info, ClassOutputStream out) { - out.writeLong(info.value); - return 2; - } - - @Override - public Integer visitMethodHandle(CONSTANT_MethodHandle_info info, ClassOutputStream out) { - out.writeByte(info.reference_kind.tag); - out.writeShort(info.reference_index); - return 1; - } - - @Override - public Integer visitMethodType(CONSTANT_MethodType_info info, ClassOutputStream out) { - out.writeShort(info.descriptor_index); - return 1; - } - - @Override - public Integer visitMethodref(CONSTANT_Methodref_info info, ClassOutputStream out) { - return writeRef(info, out); - } - - @Override - public Integer visitModule(CONSTANT_Module_info info, ClassOutputStream out) { - out.writeShort(info.name_index); - return 1; - } - - @Override - public Integer visitNameAndType(CONSTANT_NameAndType_info info, ClassOutputStream out) { - out.writeShort(info.name_index); - out.writeShort(info.type_index); - return 1; - } - - @Override - public Integer visitPackage(CONSTANT_Package_info info, ClassOutputStream out) { - out.writeShort(info.name_index); - return 1; - } - - @Override - public Integer visitString(CONSTANT_String_info info, ClassOutputStream out) { - out.writeShort(info.string_index); - return 1; - } - - @Override - public Integer visitUtf8(CONSTANT_Utf8_info info, ClassOutputStream out) { - out.writeUTF(info.value); - return 1; - } - - protected Integer writeRef(CPRefInfo info, ClassOutputStream out) { - out.writeShort(info.class_index); - out.writeShort(info.name_and_type_index); - return 1; - } - } - - /** - * Writer for the different types of attribute. - */ - protected static class AttributeWriter implements Attribute.Visitor { - public void write(Attributes attributes, ClassOutputStream out) { - int size = attributes.size(); - out.writeShort(size); - for (Attribute a: attributes) - write(a, out); - } - - public void write(Attribute attr, ClassOutputStream out) { - out.writeShort(attr.attribute_name_index); - ClassOutputStream nestedOut = new ClassOutputStream(); - attr.accept(this, nestedOut); - out.writeInt(nestedOut.size()); - nestedOut.writeTo(out); - } - - protected AnnotationWriter annotationWriter = new AnnotationWriter(); - - @Override - public Void visitDefault(DefaultAttribute attr, ClassOutputStream out) { - out.write(attr.info, 0, attr.info.length); - return null; - } - - @Override - public Void visitAnnotationDefault(AnnotationDefault_attribute attr, ClassOutputStream out) { - annotationWriter.write(attr.default_value, out); - return null; - } - - @Override - public Void visitBootstrapMethods(BootstrapMethods_attribute attr, ClassOutputStream out) { - out.writeShort(attr.bootstrap_method_specifiers.length); - for (BootstrapMethods_attribute.BootstrapMethodSpecifier bsm : attr.bootstrap_method_specifiers) { - out.writeShort(bsm.bootstrap_method_ref); - int bsm_args_count = bsm.bootstrap_arguments.length; - out.writeShort(bsm_args_count); - for (int i : bsm.bootstrap_arguments) { - out.writeShort(i); - } - } - return null; - } - - @Override - public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, ClassOutputStream out) { - out.writeShort(attr.character_range_table.length); - for (CharacterRangeTable_attribute.Entry e: attr.character_range_table) - writeCharacterRangeTableEntry(e, out); - return null; - } - - protected void writeCharacterRangeTableEntry(CharacterRangeTable_attribute.Entry entry, ClassOutputStream out) { - out.writeShort(entry.start_pc); - out.writeShort(entry.end_pc); - out.writeInt(entry.character_range_start); - out.writeInt(entry.character_range_end); - out.writeShort(entry.flags); - } - - @Override - public Void visitCode(Code_attribute attr, ClassOutputStream out) { - out.writeShort(attr.max_stack); - out.writeShort(attr.max_locals); - out.writeInt(attr.code.length); - out.write(attr.code, 0, attr.code.length); - out.writeShort(attr.exception_table.length); - for (Code_attribute.Exception_data e: attr.exception_table) - writeExceptionTableEntry(e, out); - new AttributeWriter().write(attr.attributes, out); - return null; - } - - protected void writeExceptionTableEntry(Code_attribute.Exception_data exception_data, ClassOutputStream out) { - out.writeShort(exception_data.start_pc); - out.writeShort(exception_data.end_pc); - out.writeShort(exception_data.handler_pc); - out.writeShort(exception_data.catch_type); - } - - @Override - public Void visitCompilationID(CompilationID_attribute attr, ClassOutputStream out) { - out.writeShort(attr.compilationID_index); - return null; - } - - @Override - public Void visitConstantValue(ConstantValue_attribute attr, ClassOutputStream out) { - out.writeShort(attr.constantvalue_index); - return null; - } - - @Override - public Void visitDeprecated(Deprecated_attribute attr, ClassOutputStream out) { - return null; - } - - @Override - public Void visitEnclosingMethod(EnclosingMethod_attribute attr, ClassOutputStream out) { - out.writeShort(attr.class_index); - out.writeShort(attr.method_index); - return null; - } - - @Override - public Void visitExceptions(Exceptions_attribute attr, ClassOutputStream out) { - out.writeShort(attr.exception_index_table.length); - for (int i: attr.exception_index_table) - out.writeShort(i); - return null; - } - - @Override - public Void visitInnerClasses(InnerClasses_attribute attr, ClassOutputStream out) { - out.writeShort(attr.classes.length); - for (InnerClasses_attribute.Info info: attr.classes) - writeInnerClassesInfo(info, out); - return null; - } - - protected void writeInnerClassesInfo(InnerClasses_attribute.Info info, ClassOutputStream out) { - out.writeShort(info.inner_class_info_index); - out.writeShort(info.outer_class_info_index); - out.writeShort(info.inner_name_index); - writeAccessFlags(info.inner_class_access_flags, out); - } - - @Override - public Void visitLineNumberTable(LineNumberTable_attribute attr, ClassOutputStream out) { - out.writeShort(attr.line_number_table.length); - for (LineNumberTable_attribute.Entry e: attr.line_number_table) - writeLineNumberTableEntry(e, out); - return null; - } - - protected void writeLineNumberTableEntry(LineNumberTable_attribute.Entry entry, ClassOutputStream out) { - out.writeShort(entry.start_pc); - out.writeShort(entry.line_number); - } - - @Override - public Void visitLocalVariableTable(LocalVariableTable_attribute attr, ClassOutputStream out) { - out.writeShort(attr.local_variable_table.length); - for (LocalVariableTable_attribute.Entry e: attr.local_variable_table) - writeLocalVariableTableEntry(e, out); - return null; - } - - protected void writeLocalVariableTableEntry(LocalVariableTable_attribute.Entry entry, ClassOutputStream out) { - out.writeShort(entry.start_pc); - out.writeShort(entry.length); - out.writeShort(entry.name_index); - out.writeShort(entry.descriptor_index); - out.writeShort(entry.index); - } - - @Override - public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, ClassOutputStream out) { - out.writeShort(attr.local_variable_table.length); - for (LocalVariableTypeTable_attribute.Entry e: attr.local_variable_table) - writeLocalVariableTypeTableEntry(e, out); - return null; - } - - protected void writeLocalVariableTypeTableEntry(LocalVariableTypeTable_attribute.Entry entry, ClassOutputStream out) { - out.writeShort(entry.start_pc); - out.writeShort(entry.length); - out.writeShort(entry.name_index); - out.writeShort(entry.signature_index); - out.writeShort(entry.index); - } - - @Override - public Void visitNestHost(NestHost_attribute attr, ClassOutputStream out) { - out.writeShort(attr.top_index); - return null; - } - - @Override - public Void visitMethodParameters(MethodParameters_attribute attr, ClassOutputStream out) { - out.writeByte(attr.method_parameter_table.length); - for (MethodParameters_attribute.Entry e : attr.method_parameter_table) { - out.writeShort(e.name_index); - out.writeShort(e.flags); - } - return null; - } - - @Override - public Void visitModule(Module_attribute attr, ClassOutputStream out) { - out.writeShort(attr.module_name); - out.writeShort(attr.module_flags); - out.writeShort(attr.module_version_index); - - out.writeShort(attr.requires.length); - for (Module_attribute.RequiresEntry e: attr.requires) { - out.writeShort(e.requires_index); - out.writeShort(e.requires_flags); - out.writeShort(e.requires_version_index); - } - - out.writeShort(attr.exports.length); - for (Module_attribute.ExportsEntry e: attr.exports) { - out.writeShort(e.exports_index); - out.writeShort(e.exports_flags); - out.writeShort(e.exports_to_index.length); - for (int index: e.exports_to_index) - out.writeShort(index); - } - - out.writeShort(attr.opens.length); - for (Module_attribute.OpensEntry e: attr.opens) { - out.writeShort(e.opens_index); - out.writeShort(e.opens_flags); - out.writeShort(e.opens_to_index.length); - for (int index: e.opens_to_index) - out.writeShort(index); - } - - out.writeShort(attr.uses_index.length); - for (int index: attr.uses_index) { - out.writeShort(index); - } - - out.writeShort(attr.provides.length); - for (Module_attribute.ProvidesEntry e: attr.provides) { - out.writeShort(e.provides_index); - out.writeShort(e.with_count); - for (int with : e.with_index) { - out.writeShort(with); - } - } - - return null; - } - - @Override - public Void visitModuleHashes(ModuleHashes_attribute attr, ClassOutputStream out) { - out.writeShort(attr.algorithm_index); - out.writeShort(attr.hashes_table.length); - for (ModuleHashes_attribute.Entry e: attr.hashes_table) { - out.writeShort(e.module_name_index); - out.writeShort(e.hash.length); - for (byte b: e.hash) { - out.writeByte(b); - } - } - return null; - } - - @Override - public Void visitModuleMainClass(ModuleMainClass_attribute attr, ClassOutputStream out) { - out.writeShort(attr.main_class_index); - return null; - } - - @Override - public Void visitModulePackages(ModulePackages_attribute attr, ClassOutputStream out) { - out.writeShort(attr.packages_count); - for (int i: attr.packages_index) - out.writeShort(i); - return null; - } - - @Override - public Void visitModuleResolution(ModuleResolution_attribute attr, ClassOutputStream out) { - out.writeShort(attr.resolution_flags); - return null; - } - - @Override - public Void visitModuleTarget(ModuleTarget_attribute attr, ClassOutputStream out) { - out.writeShort(attr.target_platform_index); - return null; - } - - @Override - public Void visitNestMembers(NestMembers_attribute attr, ClassOutputStream out) { - out.writeShort(attr.members_indexes.length); - for (int i : attr.members_indexes) { - out.writeShort(i); - } - return null; - } - - @Override - public Void visitRecord(Record_attribute attr, ClassOutputStream out) { - out.writeShort(attr.component_count); - for (Record_attribute.ComponentInfo info: attr.component_info_arr) { - out.writeShort(info.name_index); - out.writeShort(info.descriptor.index); - int size = info.attributes.size(); - out.writeShort(size); - for (Attribute componentAttr: info.attributes) - write(componentAttr, out); - } - return null; - } - - @Override - public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, ClassOutputStream out) { - annotationWriter.write(attr.annotations, out); - return null; - } - - @Override - public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, ClassOutputStream out) { - out.writeByte(attr.parameter_annotations.length); - for (Annotation[] annos: attr.parameter_annotations) - annotationWriter.write(annos, out); - return null; - } - - @Override - public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, ClassOutputStream out) { - annotationWriter.write(attr.annotations, out); - return null; - } - - @Override - public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out) { - annotationWriter.write(attr.annotations, out); - return null; - } - - @Override - public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, ClassOutputStream out) { - out.writeByte(attr.parameter_annotations.length); - for (Annotation[] annos: attr.parameter_annotations) - annotationWriter.write(annos, out); - return null; - } - - @Override - public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, ClassOutputStream out) { - annotationWriter.write(attr.annotations, out); - return null; - } - - @Override - public Void visitPermittedSubclasses(PermittedSubclasses_attribute attr, ClassOutputStream out) { - int n = attr.subtypes.length; - out.writeShort(n); - for (int i = 0 ; i < n ; i++) { - out.writeShort(attr.subtypes[i]); - } - return null; - } - - @Override - public Void visitSignature(Signature_attribute attr, ClassOutputStream out) { - out.writeShort(attr.signature_index); - return null; - } - - @Override - public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, ClassOutputStream out) { - out.write(attr.debug_extension, 0, attr.debug_extension.length); - return null; - } - - @Override - public Void visitSourceFile(SourceFile_attribute attr, ClassOutputStream out) { - out.writeShort(attr.sourcefile_index); - return null; - } - - @Override - public Void visitSourceID(SourceID_attribute attr, ClassOutputStream out) { - out.writeShort(attr.sourceID_index); - return null; - } - - @Override - public Void visitStackMap(StackMap_attribute attr, ClassOutputStream out) { - if (stackMapWriter == null) - stackMapWriter = new StackMapTableWriter(); - - out.writeShort(attr.entries.length); - for (stack_map_frame f: attr.entries) - stackMapWriter.write(f, out); - return null; - } - - @Override - public Void visitStackMapTable(StackMapTable_attribute attr, ClassOutputStream out) { - if (stackMapWriter == null) - stackMapWriter = new StackMapTableWriter(); - - out.writeShort(attr.entries.length); - for (stack_map_frame f: attr.entries) - stackMapWriter.write(f, out); - return null; - } - - @Override - public Void visitSynthetic(Synthetic_attribute attr, ClassOutputStream out) { - return null; - } - - protected void writeAccessFlags(AccessFlags flags, ClassOutputStream out) { - out.writeShort(flags.flags); - } - - protected StackMapTableWriter stackMapWriter; - } - - /** - * Writer for the frames of StackMap and StackMapTable attributes. - */ - protected static class StackMapTableWriter - implements stack_map_frame.Visitor { - - public void write(stack_map_frame frame, ClassOutputStream out) { - out.write(frame.frame_type); - frame.accept(this, out); - } - - @Override - public Void visit_same_frame(same_frame frame, ClassOutputStream p) { - return null; - } - - @Override - public Void visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, ClassOutputStream out) { - writeVerificationTypeInfo(frame.stack[0], out); - return null; - } - - @Override - public Void visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, ClassOutputStream out) { - out.writeShort(frame.offset_delta); - writeVerificationTypeInfo(frame.stack[0], out); - return null; - } - - @Override - public Void visit_chop_frame(chop_frame frame, ClassOutputStream out) { - out.writeShort(frame.offset_delta); - return null; - } - - @Override - public Void visit_same_frame_extended(same_frame_extended frame, ClassOutputStream out) { - out.writeShort(frame.offset_delta); - return null; - } - - @Override - public Void visit_append_frame(append_frame frame, ClassOutputStream out) { - out.writeShort(frame.offset_delta); - for (verification_type_info l: frame.locals) - writeVerificationTypeInfo(l, out); - return null; - } - - @Override - public Void visit_full_frame(full_frame frame, ClassOutputStream out) { - out.writeShort(frame.offset_delta); - out.writeShort(frame.locals.length); - for (verification_type_info l: frame.locals) - writeVerificationTypeInfo(l, out); - out.writeShort(frame.stack.length); - for (verification_type_info s: frame.stack) - writeVerificationTypeInfo(s, out); - return null; - } - - protected void writeVerificationTypeInfo(verification_type_info info, - ClassOutputStream out) { - out.write(info.tag); - switch (info.tag) { - case ITEM_Top: - case ITEM_Integer: - case ITEM_Float: - case ITEM_Long: - case ITEM_Double: - case ITEM_Null: - case ITEM_UninitializedThis: - break; - - case ITEM_Object: - Object_variable_info o = (Object_variable_info) info; - out.writeShort(o.cpool_index); - break; - - case ITEM_Uninitialized: - Uninitialized_variable_info u = (Uninitialized_variable_info) info; - out.writeShort(u.offset); - break; - - default: - throw new Error(); - } - } - } - - /** - * Writer for annotations and the values they contain. - */ - protected static class AnnotationWriter - implements Annotation.element_value.Visitor { - public void write(Annotation[] annos, ClassOutputStream out) { - out.writeShort(annos.length); - for (Annotation anno: annos) - write(anno, out); - } - - public void write(TypeAnnotation[] annos, ClassOutputStream out) { - out.writeShort(annos.length); - for (TypeAnnotation anno: annos) - write(anno, out); - } - - public void write(Annotation anno, ClassOutputStream out) { - out.writeShort(anno.type_index); - out.writeShort(anno.element_value_pairs.length); - for (element_value_pair p: anno.element_value_pairs) - write(p, out); - } - - public void write(TypeAnnotation anno, ClassOutputStream out) { - write(anno.position, out); - write(anno.annotation, out); - } - - public void write(element_value_pair pair, ClassOutputStream out) { - out.writeShort(pair.element_name_index); - write(pair.value, out); - } - - public void write(element_value ev, ClassOutputStream out) { - out.writeByte(ev.tag); - ev.accept(this, out); - } - - @Override - public Void visitPrimitive(Primitive_element_value ev, ClassOutputStream out) { - out.writeShort(ev.const_value_index); - return null; - } - - @Override - public Void visitEnum(Enum_element_value ev, ClassOutputStream out) { - out.writeShort(ev.type_name_index); - out.writeShort(ev.const_name_index); - return null; - } - - @Override - public Void visitClass(Class_element_value ev, ClassOutputStream out) { - out.writeShort(ev.class_info_index); - return null; - } - - @Override - public Void visitAnnotation(Annotation_element_value ev, ClassOutputStream out) { - write(ev.annotation_value, out); - return null; - } - - @Override - public Void visitArray(Array_element_value ev, ClassOutputStream out) { - out.writeShort(ev.num_values); - for (element_value v: ev.values) - write(v, out); - return null; - } - - // TODO: Move this to TypeAnnotation to be closer with similar logic? - private void write(TypeAnnotation.Position p, ClassOutputStream out) { - out.writeByte(p.type.targetTypeValue()); - switch (p.type) { - // instanceof - case INSTANCEOF: - // new expression - case NEW: - // constructor/method reference receiver - case CONSTRUCTOR_REFERENCE: - case METHOD_REFERENCE: - out.writeShort(p.offset); - break; - // local variable - case LOCAL_VARIABLE: - // resource variable - case RESOURCE_VARIABLE: - int table_length = p.lvarOffset.length; - out.writeShort(table_length); - for (int i = 0; i < table_length; ++i) { - out.writeShort(1); // for table length - out.writeShort(p.lvarOffset[i]); - out.writeShort(p.lvarLength[i]); - out.writeShort(p.lvarIndex[i]); - } - break; - // exception parameter - case EXCEPTION_PARAMETER: - out.writeShort(p.exception_index); - break; - // method receiver - case METHOD_RECEIVER: - // Do nothing - break; - // type parameters - case CLASS_TYPE_PARAMETER: - case METHOD_TYPE_PARAMETER: - out.writeByte(p.parameter_index); - break; - // type parameters bounds - case CLASS_TYPE_PARAMETER_BOUND: - case METHOD_TYPE_PARAMETER_BOUND: - out.writeByte(p.parameter_index); - out.writeByte(p.bound_index); - break; - // class extends or implements clause - case CLASS_EXTENDS: - out.writeShort(p.type_index); - break; - // throws - case THROWS: - out.writeShort(p.type_index); - break; - // method parameter - case METHOD_FORMAL_PARAMETER: - out.writeByte(p.parameter_index); - break; - // type cast - case CAST: - // method/constructor/reference type argument - case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: - case METHOD_INVOCATION_TYPE_ARGUMENT: - case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: - case METHOD_REFERENCE_TYPE_ARGUMENT: - out.writeShort(p.offset); - out.writeByte(p.type_index); - break; - // We don't need to worry about these - case METHOD_RETURN: - case FIELD: - break; - case UNKNOWN: - throw new AssertionError("ClassWriter: UNKNOWN target type should never occur!"); - default: - throw new AssertionError("ClassWriter: Unknown target type for position: " + p); - } - - { // Append location data for generics/arrays. - // TODO: check for overrun? - out.writeByte((byte)p.location.size()); - for (int i : TypeAnnotation.Position.getBinaryFromTypePath(p.location)) - out.writeByte((byte)i); - } - } - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Code_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Code_attribute.java deleted file mode 100644 index dc19fc564aaa7..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Code_attribute.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * See JVMS, section 4.8.3. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Code_attribute extends Attribute { - public static class InvalidIndex extends AttributeException { - private static final long serialVersionUID = -8904527774589382802L; - InvalidIndex(int index) { - this.index = index; - } - - @Override - public String getMessage() { - // i18n - return "invalid index " + index + " in Code attribute"; - } - - public final int index; - } - - Code_attribute(ClassReader cr, int name_index, int length) - throws IOException, ConstantPoolException { - super(name_index, length); - max_stack = cr.readUnsignedShort(); - max_locals = cr.readUnsignedShort(); - code_length = cr.readInt(); - code = new byte[code_length]; - cr.readFully(code); - exception_table_length = cr.readUnsignedShort(); - exception_table = new Exception_data[exception_table_length]; - for (int i = 0; i < exception_table_length; i++) - exception_table[i] = new Exception_data(cr); - attributes = new Attributes(cr); - } - - public int getByte(int offset) throws InvalidIndex { - if (offset < 0 || offset >= code.length) - throw new InvalidIndex(offset); - return code[offset]; - } - - public int getUnsignedByte(int offset) throws InvalidIndex { - if (offset < 0 || offset >= code.length) - throw new InvalidIndex(offset); - return code[offset] & 0xff; - } - - public int getShort(int offset) throws InvalidIndex { - if (offset < 0 || offset + 1 >= code.length) - throw new InvalidIndex(offset); - return (code[offset] << 8) | (code[offset + 1] & 0xFF); - } - - public int getUnsignedShort(int offset) throws InvalidIndex { - if (offset < 0 || offset + 1 >= code.length) - throw new InvalidIndex(offset); - return ((code[offset] << 8) | (code[offset + 1] & 0xFF)) & 0xFFFF; - } - - public int getInt(int offset) throws InvalidIndex { - if (offset < 0 || offset + 3 >= code.length) - throw new InvalidIndex(offset); - return (getShort(offset) << 16) | (getShort(offset + 2) & 0xFFFF); - } - - public R accept(Visitor visitor, D data) { - return visitor.visitCode(this, data); - } - - public Iterable getInstructions() { - return () -> new Iterator() { - - public boolean hasNext() { - return (next != null); - } - - public Instruction next() { - if (next == null) - throw new NoSuchElementException(); - - current = next; - pc += current.length(); - next = (pc < code.length ? new Instruction(code, pc) : null); - return current; - } - - public void remove() { - throw new UnsupportedOperationException("Not supported."); - } - - Instruction current = null; - int pc = 0; - Instruction next = (pc < code.length ? new Instruction(code, pc) : null); - - }; - } - - public final int max_stack; - public final int max_locals; - public final int code_length; - public final byte[] code; - public final int exception_table_length; - public final Exception_data[] exception_table; - public final Attributes attributes; - - public static class Exception_data { - Exception_data(ClassReader cr) throws IOException { - start_pc = cr.readUnsignedShort(); - end_pc = cr.readUnsignedShort(); - handler_pc = cr.readUnsignedShort(); - catch_type = cr.readUnsignedShort(); - } - - public final int start_pc; - public final int end_pc; - public final int handler_pc; - public final int catch_type; - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/CompilationID_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/CompilationID_attribute.java deleted file mode 100644 index 6f2d70508b384..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/CompilationID_attribute.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class CompilationID_attribute extends Attribute { - - CompilationID_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - compilationID_index = cr.readUnsignedShort(); - } - - public CompilationID_attribute(ConstantPool constant_pool, int compilationID_index) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.CompilationID), compilationID_index); - } - - public CompilationID_attribute(int name_index, int compilationID_index) { - super(name_index, 2); - this.compilationID_index = compilationID_index; - } - - String getCompilationID(ConstantPool constant_pool) - throws ConstantPoolException { - return constant_pool.getUTF8Value(compilationID_index); - } - - public R accept(Visitor visitor, D data) { - return visitor.visitCompilationID(this, data); - } - - public final int compilationID_index; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ConstantPool.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ConstantPool.java deleted file mode 100644 index 801220a026c5f..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ConstantPool.java +++ /dev/null @@ -1,1053 +0,0 @@ -/* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Iterator; - -/** - * See JVMS, section 4.5. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class ConstantPool { - - public static class InvalidIndex extends ConstantPoolException { - private static final long serialVersionUID = -4350294289300939730L; - InvalidIndex(int index) { - super(index); - } - - @Override - public String getMessage() { - // i18n - return "invalid index #" + index; - } - } - - public static class UnexpectedEntry extends ConstantPoolException { - private static final long serialVersionUID = 6986335935377933211L; - UnexpectedEntry(int index, int expected_tag, int found_tag) { - super(index); - this.expected_tag = expected_tag; - this.found_tag = found_tag; - } - - @Override - public String getMessage() { - // i18n? - return "unexpected entry at #" + index + " -- expected tag " + expected_tag + ", found " + found_tag; - } - - public final int expected_tag; - public final int found_tag; - } - - public static class InvalidEntry extends ConstantPoolException { - private static final long serialVersionUID = 1000087545585204447L; - InvalidEntry(int index, int tag) { - super(index); - this.tag = tag; - } - - @Override - public String getMessage() { - // i18n? - return "unexpected tag at #" + index + ": " + tag; - } - - public final int tag; - } - - public static class EntryNotFound extends ConstantPoolException { - private static final long serialVersionUID = 2885537606468581850L; - EntryNotFound(Object value) { - super(-1); - this.value = value; - } - - @Override - public String getMessage() { - // i18n? - return "value not found: " + value; - } - - @SuppressWarnings("serial") // Type of field is not Serializable - public final Object value; - } - - public static final int CONSTANT_Utf8 = 1; - public static final int CONSTANT_Integer = 3; - public static final int CONSTANT_Float = 4; - public static final int CONSTANT_Long = 5; - public static final int CONSTANT_Double = 6; - public static final int CONSTANT_Class = 7; - public static final int CONSTANT_String = 8; - public static final int CONSTANT_Fieldref = 9; - public static final int CONSTANT_Methodref = 10; - public static final int CONSTANT_InterfaceMethodref = 11; - public static final int CONSTANT_NameAndType = 12; - public static final int CONSTANT_MethodHandle = 15; - public static final int CONSTANT_MethodType = 16; - public static final int CONSTANT_Dynamic = 17; - public static final int CONSTANT_InvokeDynamic = 18; - public static final int CONSTANT_Module = 19; - public static final int CONSTANT_Package = 20; - - public static enum RefKind { - REF_getField(1), - REF_getStatic(2), - REF_putField(3), - REF_putStatic(4), - REF_invokeVirtual(5), - REF_invokeStatic(6), - REF_invokeSpecial(7), - REF_newInvokeSpecial(8), - REF_invokeInterface(9); - - public final int tag; - - RefKind(int tag) { - this.tag = tag; - } - - static RefKind getRefkind(int tag) { - switch(tag) { - case 1: - return REF_getField; - case 2: - return REF_getStatic; - case 3: - return REF_putField; - case 4: - return REF_putStatic; - case 5: - return REF_invokeVirtual; - case 6: - return REF_invokeStatic; - case 7: - return REF_invokeSpecial; - case 8: - return REF_newInvokeSpecial; - case 9: - return REF_invokeInterface; - default: - return null; - } - } - } - - ConstantPool(ClassReader cr) throws IOException, InvalidEntry { - int count = cr.readUnsignedShort(); - pool = new CPInfo[count]; - for (int i = 1; i < count; i++) { - int tag = cr.readUnsignedByte(); - switch (tag) { - case CONSTANT_Class: - pool[i] = new CONSTANT_Class_info(this, cr); - break; - - case CONSTANT_Double: - pool[i] = new CONSTANT_Double_info(cr); - i++; - break; - - case CONSTANT_Fieldref: - pool[i] = new CONSTANT_Fieldref_info(this, cr); - break; - - case CONSTANT_Float: - pool[i] = new CONSTANT_Float_info(cr); - break; - - case CONSTANT_Integer: - pool[i] = new CONSTANT_Integer_info(cr); - break; - - case CONSTANT_InterfaceMethodref: - pool[i] = new CONSTANT_InterfaceMethodref_info(this, cr); - break; - - case CONSTANT_InvokeDynamic: - pool[i] = new CONSTANT_InvokeDynamic_info(this, cr); - break; - - case CONSTANT_Dynamic: - pool[i] = new CONSTANT_Dynamic_info(this, cr); - break; - - case CONSTANT_Long: - pool[i] = new CONSTANT_Long_info(cr); - i++; - break; - - case CONSTANT_MethodHandle: - pool[i] = new CONSTANT_MethodHandle_info(this, cr); - break; - - case CONSTANT_MethodType: - pool[i] = new CONSTANT_MethodType_info(this, cr); - break; - - case CONSTANT_Methodref: - pool[i] = new CONSTANT_Methodref_info(this, cr); - break; - - case CONSTANT_Module: - pool[i] = new CONSTANT_Module_info(this, cr); - break; - - case CONSTANT_NameAndType: - pool[i] = new CONSTANT_NameAndType_info(this, cr); - break; - - case CONSTANT_Package: - pool[i] = new CONSTANT_Package_info(this, cr); - break; - - case CONSTANT_String: - pool[i] = new CONSTANT_String_info(this, cr); - break; - - case CONSTANT_Utf8: - pool[i] = new CONSTANT_Utf8_info(cr); - break; - - default: - throw new InvalidEntry(i, tag); - } - } - } - - public ConstantPool(CPInfo[] pool) { - this.pool = pool; - } - - public int size() { - return pool.length; - } - - public int byteLength() { - int length = 2; - for (int i = 1; i < size(); ) { - CPInfo cpInfo = pool[i]; - length += cpInfo.byteLength(); - i += cpInfo.size(); - } - return length; - } - - public CPInfo get(int index) throws InvalidIndex { - if (index <= 0 || index >= pool.length) - throw new InvalidIndex(index); - CPInfo info = pool[index]; - if (info == null) { - // this occurs for indices referencing the "second half" of an - // 8 byte constant, such as CONSTANT_Double or CONSTANT_Long - throw new InvalidIndex(index); - } - return pool[index]; - } - - private CPInfo get(int index, int expected_type) throws InvalidIndex, UnexpectedEntry { - CPInfo info = get(index); - if (info.getTag() != expected_type) - throw new UnexpectedEntry(index, expected_type, info.getTag()); - return info; - } - - public CONSTANT_Utf8_info getUTF8Info(int index) throws InvalidIndex, UnexpectedEntry { - return ((CONSTANT_Utf8_info) get(index, CONSTANT_Utf8)); - } - - public CONSTANT_Class_info getClassInfo(int index) throws InvalidIndex, UnexpectedEntry { - return ((CONSTANT_Class_info) get(index, CONSTANT_Class)); - } - - public CONSTANT_Module_info getModuleInfo(int index) throws InvalidIndex, UnexpectedEntry { - return ((CONSTANT_Module_info) get(index, CONSTANT_Module)); - } - - public CONSTANT_NameAndType_info getNameAndTypeInfo(int index) throws InvalidIndex, UnexpectedEntry { - return ((CONSTANT_NameAndType_info) get(index, CONSTANT_NameAndType)); - } - - public CONSTANT_Package_info getPackageInfo(int index) throws InvalidIndex, UnexpectedEntry { - return ((CONSTANT_Package_info) get(index, CONSTANT_Package)); - } - - public String getUTF8Value(int index) throws InvalidIndex, UnexpectedEntry { - return getUTF8Info(index).value; - } - - public int getUTF8Index(String value) throws EntryNotFound { - for (int i = 1; i < pool.length; i++) { - CPInfo info = pool[i]; - if (info instanceof CONSTANT_Utf8_info && - ((CONSTANT_Utf8_info) info).value.equals(value)) - return i; - } - throw new EntryNotFound(value); - } - - public Iterable entries() { - return () -> new Iterator() { - - public boolean hasNext() { - return next < pool.length; - } - - public CPInfo next() { - current = pool[next]; - switch (current.getTag()) { - case CONSTANT_Double: - case CONSTANT_Long: - next += 2; - break; - default: - next += 1; - } - return current; - } - - public void remove() { - throw new UnsupportedOperationException(); - } - - private CPInfo current; - private int next = 1; - - }; - } - - private CPInfo[] pool; - - public interface Visitor { - R visitClass(CONSTANT_Class_info info, P p); - R visitDouble(CONSTANT_Double_info info, P p); - R visitFieldref(CONSTANT_Fieldref_info info, P p); - R visitFloat(CONSTANT_Float_info info, P p); - R visitInteger(CONSTANT_Integer_info info, P p); - R visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, P p); - R visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, P p); - R visitDynamicConstant(CONSTANT_Dynamic_info info, P p); - R visitLong(CONSTANT_Long_info info, P p); - R visitMethodref(CONSTANT_Methodref_info info, P p); - R visitMethodHandle(CONSTANT_MethodHandle_info info, P p); - R visitMethodType(CONSTANT_MethodType_info info, P p); - R visitModule(CONSTANT_Module_info info, P p); - R visitNameAndType(CONSTANT_NameAndType_info info, P p); - R visitPackage(CONSTANT_Package_info info, P p); - R visitString(CONSTANT_String_info info, P p); - R visitUtf8(CONSTANT_Utf8_info info, P p); - } - - public abstract static class CPInfo { - CPInfo() { - this.cp = null; - } - - CPInfo(ConstantPool cp) { - this.cp = cp; - } - - public abstract int getTag(); - - /** The number of slots in the constant pool used by this entry. - * 2 for CONSTANT_Double and CONSTANT_Long; 1 for everything else. */ - public int size() { - return 1; - } - - public abstract int byteLength(); - - public abstract R accept(Visitor visitor, D data); - - protected final ConstantPool cp; - } - - public abstract static class CPRefInfo extends CPInfo { - protected CPRefInfo(ConstantPool cp, ClassReader cr, int tag) throws IOException { - super(cp); - this.tag = tag; - class_index = cr.readUnsignedShort(); - name_and_type_index = cr.readUnsignedShort(); - } - - protected CPRefInfo(ConstantPool cp, int tag, int class_index, int name_and_type_index) { - super(cp); - this.tag = tag; - this.class_index = class_index; - this.name_and_type_index = name_and_type_index; - } - - public int getTag() { - return tag; - } - - public int byteLength() { - return 5; - } - - public CONSTANT_Class_info getClassInfo() throws ConstantPoolException { - return cp.getClassInfo(class_index); - } - - public String getClassName() throws ConstantPoolException { - return cp.getClassInfo(class_index).getName(); - } - - public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException { - return cp.getNameAndTypeInfo(name_and_type_index); - } - - public final int tag; - public final int class_index; - public final int name_and_type_index; - } - - public static class CONSTANT_Class_info extends CPInfo { - CONSTANT_Class_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp); - name_index = cr.readUnsignedShort(); - } - - public CONSTANT_Class_info(ConstantPool cp, int name_index) { - super(cp); - this.name_index = name_index; - } - - public int getTag() { - return CONSTANT_Class; - } - - public int byteLength() { - return 3; - } - - /** - * Get the raw value of the class referenced by this constant pool entry. - * This will either be the name of the class, in internal form, or a - * descriptor for an array class. - * @return the raw value of the class - */ - public String getName() throws ConstantPoolException { - return cp.getUTF8Value(name_index); - } - - /** - * If this constant pool entry identifies either a class or interface type, - * or a possibly multi-dimensional array of a class of interface type, - * return the name of the class or interface in internal form. Otherwise, - * (i.e. if this is a possibly multi-dimensional array of a primitive type), - * return null. - * @return the base class or interface name - */ - public String getBaseName() throws ConstantPoolException { - String name = getName(); - if (name.startsWith("[")) { - int index = name.indexOf("[L"); - if (index == -1) - return null; - return name.substring(index + 2, name.length() - 1); - } else - return name; - } - - public int getDimensionCount() throws ConstantPoolException { - String name = getName(); - int count = 0; - while (name.charAt(count) == '[') - count++; - return count; - } - - @Override - public String toString() { - return "CONSTANT_Class_info[name_index: " + name_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitClass(this, data); - } - - public final int name_index; - } - - public static class CONSTANT_Double_info extends CPInfo { - CONSTANT_Double_info(ClassReader cr) throws IOException { - value = cr.readDouble(); - } - - public CONSTANT_Double_info(double value) { - this.value = value; - } - - public int getTag() { - return CONSTANT_Double; - } - - public int byteLength() { - return 9; - } - - @Override - public int size() { - return 2; - } - - @Override - public String toString() { - return "CONSTANT_Double_info[value: " + value + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitDouble(this, data); - } - - public final double value; - } - - public static class CONSTANT_Fieldref_info extends CPRefInfo { - CONSTANT_Fieldref_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp, cr, CONSTANT_Fieldref); - } - - public CONSTANT_Fieldref_info(ConstantPool cp, int class_index, int name_and_type_index) { - super(cp, CONSTANT_Fieldref, class_index, name_and_type_index); - } - - @Override - public String toString() { - return "CONSTANT_Fieldref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitFieldref(this, data); - } - } - - public static class CONSTANT_Float_info extends CPInfo { - CONSTANT_Float_info(ClassReader cr) throws IOException { - value = cr.readFloat(); - } - - public CONSTANT_Float_info(float value) { - this.value = value; - } - - public int getTag() { - return CONSTANT_Float; - } - - public int byteLength() { - return 5; - } - - @Override - public String toString() { - return "CONSTANT_Float_info[value: " + value + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitFloat(this, data); - } - - public final float value; - } - - public static class CONSTANT_Integer_info extends CPInfo { - CONSTANT_Integer_info(ClassReader cr) throws IOException { - value = cr.readInt(); - } - - public CONSTANT_Integer_info(int value) { - this.value = value; - } - - public int getTag() { - return CONSTANT_Integer; - } - - public int byteLength() { - return 5; - } - - @Override - public String toString() { - return "CONSTANT_Integer_info[value: " + value + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitInteger(this, data); - } - - public final int value; - } - - public static class CONSTANT_InterfaceMethodref_info extends CPRefInfo { - CONSTANT_InterfaceMethodref_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp, cr, CONSTANT_InterfaceMethodref); - } - - public CONSTANT_InterfaceMethodref_info(ConstantPool cp, int class_index, int name_and_type_index) { - super(cp, CONSTANT_InterfaceMethodref, class_index, name_and_type_index); - } - - @Override - public String toString() { - return "CONSTANT_InterfaceMethodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitInterfaceMethodref(this, data); - } - } - - public static class CONSTANT_InvokeDynamic_info extends CPInfo { - CONSTANT_InvokeDynamic_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp); - bootstrap_method_attr_index = cr.readUnsignedShort(); - name_and_type_index = cr.readUnsignedShort(); - } - - public CONSTANT_InvokeDynamic_info(ConstantPool cp, int bootstrap_method_index, int name_and_type_index) { - super(cp); - this.bootstrap_method_attr_index = bootstrap_method_index; - this.name_and_type_index = name_and_type_index; - } - - public int getTag() { - return CONSTANT_InvokeDynamic; - } - - public int byteLength() { - return 5; - } - - @Override - public String toString() { - return "CONSTANT_InvokeDynamic_info[bootstrap_method_index: " + bootstrap_method_attr_index + ", name_and_type_index: " + name_and_type_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitInvokeDynamic(this, data); - } - - public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException { - return cp.getNameAndTypeInfo(name_and_type_index); - } - - public final int bootstrap_method_attr_index; - public final int name_and_type_index; - } - - public static class CONSTANT_Long_info extends CPInfo { - CONSTANT_Long_info(ClassReader cr) throws IOException { - value = cr.readLong(); - } - - public CONSTANT_Long_info(long value) { - this.value = value; - } - - public int getTag() { - return CONSTANT_Long; - } - - @Override - public int size() { - return 2; - } - - public int byteLength() { - return 9; - } - - @Override - public String toString() { - return "CONSTANT_Long_info[value: " + value + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitLong(this, data); - } - - public final long value; - } - - public static class CONSTANT_MethodHandle_info extends CPInfo { - CONSTANT_MethodHandle_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp); - reference_kind = RefKind.getRefkind(cr.readUnsignedByte()); - reference_index = cr.readUnsignedShort(); - } - - public CONSTANT_MethodHandle_info(ConstantPool cp, RefKind ref_kind, int member_index) { - super(cp); - this.reference_kind = ref_kind; - this.reference_index = member_index; - } - - public int getTag() { - return CONSTANT_MethodHandle; - } - - public int byteLength() { - return 4; - } - - @Override - public String toString() { - return "CONSTANT_MethodHandle_info[ref_kind: " + reference_kind + ", member_index: " + reference_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitMethodHandle(this, data); - } - - public CPRefInfo getCPRefInfo() throws ConstantPoolException { - int expected = CONSTANT_Methodref; - int actual = cp.get(reference_index).getTag(); - // allow these tag types also: - switch (actual) { - case CONSTANT_Fieldref: - case CONSTANT_InterfaceMethodref: - expected = actual; - } - return (CPRefInfo) cp.get(reference_index, expected); - } - - public final RefKind reference_kind; - public final int reference_index; - } - - public static class CONSTANT_MethodType_info extends CPInfo { - CONSTANT_MethodType_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp); - descriptor_index = cr.readUnsignedShort(); - } - - public CONSTANT_MethodType_info(ConstantPool cp, int signature_index) { - super(cp); - this.descriptor_index = signature_index; - } - - public int getTag() { - return CONSTANT_MethodType; - } - - public int byteLength() { - return 3; - } - - @Override - public String toString() { - return "CONSTANT_MethodType_info[signature_index: " + descriptor_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitMethodType(this, data); - } - - public String getType() throws ConstantPoolException { - return cp.getUTF8Value(descriptor_index); - } - - public final int descriptor_index; - } - - public static class CONSTANT_Methodref_info extends CPRefInfo { - CONSTANT_Methodref_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp, cr, CONSTANT_Methodref); - } - - public CONSTANT_Methodref_info(ConstantPool cp, int class_index, int name_and_type_index) { - super(cp, CONSTANT_Methodref, class_index, name_and_type_index); - } - - @Override - public String toString() { - return "CONSTANT_Methodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitMethodref(this, data); - } - } - - public static class CONSTANT_Module_info extends CPInfo { - CONSTANT_Module_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp); - name_index = cr.readUnsignedShort(); - } - - public CONSTANT_Module_info(ConstantPool cp, int name_index) { - super(cp); - this.name_index = name_index; - } - - public int getTag() { - return CONSTANT_Module; - } - - public int byteLength() { - return 3; - } - - /** - * Get the raw value of the module name referenced by this constant pool entry. - * This will be the name of the module. - * @return the raw value of the module name - */ - public String getName() throws ConstantPoolException { - return cp.getUTF8Value(name_index); - } - - @Override - public String toString() { - return "CONSTANT_Module_info[name_index: " + name_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitModule(this, data); - } - - public final int name_index; - } - - public static class CONSTANT_NameAndType_info extends CPInfo { - CONSTANT_NameAndType_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp); - name_index = cr.readUnsignedShort(); - type_index = cr.readUnsignedShort(); - } - - public CONSTANT_NameAndType_info(ConstantPool cp, int name_index, int type_index) { - super(cp); - this.name_index = name_index; - this.type_index = type_index; - } - - public int getTag() { - return CONSTANT_NameAndType; - } - - public int byteLength() { - return 5; - } - - public String getName() throws ConstantPoolException { - return cp.getUTF8Value(name_index); - } - - public String getType() throws ConstantPoolException { - return cp.getUTF8Value(type_index); - } - - public R accept(Visitor visitor, D data) { - return visitor.visitNameAndType(this, data); - } - - @Override - public String toString() { - return "CONSTANT_NameAndType_info[name_index: " + name_index + ", type_index: " + type_index + "]"; - } - - public final int name_index; - public final int type_index; - } - - public static class CONSTANT_Dynamic_info extends CPInfo { - CONSTANT_Dynamic_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp); - bootstrap_method_attr_index = cr.readUnsignedShort(); - name_and_type_index = cr.readUnsignedShort(); - } - - public CONSTANT_Dynamic_info(ConstantPool cp, int bootstrap_method_index, int name_and_type_index) { - super(cp); - this.bootstrap_method_attr_index = bootstrap_method_index; - this.name_and_type_index = name_and_type_index; - } - - public int getTag() { - return CONSTANT_Dynamic; - } - - public int byteLength() { - return 5; - } - - @Override - public String toString() { - return "CONSTANT_Dynamic_info[bootstrap_method_index: " + bootstrap_method_attr_index + ", name_and_type_index: " + name_and_type_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitDynamicConstant(this, data); - } - - public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException { - return cp.getNameAndTypeInfo(name_and_type_index); - } - - public final int bootstrap_method_attr_index; - public final int name_and_type_index; - } - - public static class CONSTANT_Package_info extends CPInfo { - CONSTANT_Package_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp); - name_index = cr.readUnsignedShort(); - } - - public CONSTANT_Package_info(ConstantPool cp, int name_index) { - super(cp); - this.name_index = name_index; - } - - public int getTag() { - return CONSTANT_Package; - } - - public int byteLength() { - return 3; - } - - /** - * Get the raw value of the package name referenced by this constant pool entry. - * This will be the name of the package, in internal form. - * @return the raw value of the module name - */ - public String getName() throws ConstantPoolException { - return cp.getUTF8Value(name_index); - } - - @Override - public String toString() { - return "CONSTANT_Package_info[name_index: " + name_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitPackage(this, data); - } - - public final int name_index; - } - - public static class CONSTANT_String_info extends CPInfo { - CONSTANT_String_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp); - string_index = cr.readUnsignedShort(); - } - - public CONSTANT_String_info(ConstantPool cp, int string_index) { - super(cp); - this.string_index = string_index; - } - - public int getTag() { - return CONSTANT_String; - } - - public int byteLength() { - return 3; - } - - public String getString() throws ConstantPoolException { - return cp.getUTF8Value(string_index); - } - - public R accept(Visitor visitor, D data) { - return visitor.visitString(this, data); - } - - @Override - public String toString() { - return "CONSTANT_String_info[class_index: " + string_index + "]"; - } - - public final int string_index; - } - - public static class CONSTANT_Utf8_info extends CPInfo { - CONSTANT_Utf8_info(ClassReader cr) throws IOException { - value = cr.readUTF(); - } - - public CONSTANT_Utf8_info(String value) { - this.value = value; - } - - public int getTag() { - return CONSTANT_Utf8; - } - - public int byteLength() { - class SizeOutputStream extends OutputStream { - @Override - public void write(int b) { - size++; - } - int size; - } - SizeOutputStream sizeOut = new SizeOutputStream(); - DataOutputStream out = new DataOutputStream(sizeOut); - try { out.writeUTF(value); } catch (IOException ignore) { } - return 1 + sizeOut.size; - } - - @Override - public String toString() { - if (value.length() < 32 && isPrintableAscii(value)) - return "CONSTANT_Utf8_info[value: \"" + value + "\"]"; - else - return "CONSTANT_Utf8_info[value: (" + value.length() + " chars)]"; - } - - static boolean isPrintableAscii(String s) { - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - if (c < 32 || c >= 127) - return false; - } - return true; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitUtf8(this, data); - } - - public final String value; - } - -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ConstantPoolException.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ConstantPoolException.java deleted file mode 100644 index 50a9e9b8d88a9..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ConstantPoolException.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -/* - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class ConstantPoolException extends Exception { - private static final long serialVersionUID = -2324397349644754565L; - ConstantPoolException(int index) { - this.index = index; - } - - public final int index; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ConstantValue_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ConstantValue_attribute.java deleted file mode 100644 index df40defa4f734..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ConstantValue_attribute.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.2. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class ConstantValue_attribute extends Attribute { - ConstantValue_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - constantvalue_index = cr.readUnsignedShort(); - } - - public ConstantValue_attribute(ConstantPool constant_pool, int constantvalue_index) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.ConstantValue), constantvalue_index); - } - - public ConstantValue_attribute(int name_index, int constantvalue_index) { - super(name_index, 2); - this.constantvalue_index = constantvalue_index; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitConstantValue(this, data); - } - - public final int constantvalue_index; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/DefaultAttribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/DefaultAttribute.java deleted file mode 100644 index 16fdeb9824d9a..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/DefaultAttribute.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -/* - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class DefaultAttribute extends Attribute { - DefaultAttribute(ClassReader cr, int name_index, byte[] data) { - this(cr, name_index, data, null); - } - - DefaultAttribute(ClassReader cr, int name_index, byte[] data, String reason) { - super(name_index, data.length); - info = data; - this.reason = reason; - } - - public DefaultAttribute(ConstantPool constant_pool, int name_index, byte[] info) { - this(constant_pool, name_index, info, null); - } - - public DefaultAttribute(ConstantPool constant_pool, int name_index, - byte[] info, String reason) { - super(name_index, info.length); - this.info = info; - this.reason = reason; - } - - public R accept(Visitor visitor, P p) { - return visitor.visitDefault(this, p); - } - - public final byte[] info; - /** Why did we need to generate a DefaultAttribute - */ - public final String reason; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Deprecated_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Deprecated_attribute.java deleted file mode 100644 index dbf6442f2023f..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Deprecated_attribute.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.15. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Deprecated_attribute extends Attribute { - Deprecated_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - } - - public Deprecated_attribute(ConstantPool constant_pool) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.Deprecated)); - } - - public Deprecated_attribute(int name_index) { - super(name_index, 0); - } - - public R accept(Visitor visitor, D data) { - return visitor.visitDeprecated(this, data); - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Descriptor.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Descriptor.java deleted file mode 100644 index fed0f3010a98d..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Descriptor.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.4. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Descriptor { - public static class InvalidDescriptor extends DescriptorException { - private static final long serialVersionUID = 1L; - InvalidDescriptor(String desc) { - this.desc = desc; - this.index = -1; - } - - InvalidDescriptor(String desc, int index) { - this.desc = desc; - this.index = index; - } - - @Override - public String getMessage() { - // i18n - if (index == -1) - return "invalid descriptor \"" + desc + "\""; - else - return "descriptor is invalid at offset " + index + " in \"" + desc + "\""; - } - - public final String desc; - public final int index; - - } - - public Descriptor(ClassReader cr) throws IOException { - this(cr.readUnsignedShort()); - } - - public Descriptor(int index) { - this.index = index; - - } - - public String getValue(ConstantPool constant_pool) throws ConstantPoolException { - return constant_pool.getUTF8Value(index); - } - - public int getParameterCount(ConstantPool constant_pool) - throws ConstantPoolException, InvalidDescriptor { - String desc = getValue(constant_pool); - int end = desc.indexOf(")"); - if (end == -1) - throw new InvalidDescriptor(desc); - parse(desc, 0, end + 1); - return count; - - } - - public String getParameterTypes(ConstantPool constant_pool) - throws ConstantPoolException, InvalidDescriptor { - String desc = getValue(constant_pool); - int end = desc.indexOf(")"); - if (end == -1) - throw new InvalidDescriptor(desc); - return parse(desc, 0, end + 1); - } - - public String getReturnType(ConstantPool constant_pool) - throws ConstantPoolException, InvalidDescriptor { - String desc = getValue(constant_pool); - int end = desc.indexOf(")"); - if (end == -1) - throw new InvalidDescriptor(desc); - return parse(desc, end + 1, desc.length()); - } - - public String getFieldType(ConstantPool constant_pool) - throws ConstantPoolException, InvalidDescriptor { - String desc = getValue(constant_pool); - return parse(desc, 0, desc.length()); - } - - private String parse(String desc, int start, int end) - throws InvalidDescriptor { - int p = start; - StringBuilder sb = new StringBuilder(); - int dims = 0; - count = 0; - - while (p < end) { - String type; - char ch; - switch (ch = desc.charAt(p++)) { - case '(': - sb.append('('); - continue; - - case ')': - sb.append(')'); - continue; - - case '[': - dims++; - continue; - - case 'B': - type = "byte"; - break; - - case 'C': - type = "char"; - break; - - case 'D': - type = "double"; - break; - - case 'F': - type = "float"; - break; - - case 'I': - type = "int"; - break; - - case 'J': - type = "long"; - break; - - case 'L': - int sep = desc.indexOf(';', p); - if (sep == -1) - throw new InvalidDescriptor(desc, p - 1); - type = desc.substring(p, sep).replace('/', '.'); - p = sep + 1; - break; - - case 'S': - type = "short"; - break; - - case 'Z': - type = "boolean"; - break; - - case 'V': - type = "void"; - break; - - default: - throw new InvalidDescriptor(desc, p - 1); - } - - if (sb.length() > 1 && sb.charAt(0) == '(') - sb.append(", "); - sb.append(type); - for ( ; dims > 0; dims-- ) - sb.append("[]"); - - count++; - } - - return sb.toString(); - } - - public final int index; - private int count; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/DescriptorException.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/DescriptorException.java deleted file mode 100644 index 0a91e36a9143d..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/DescriptorException.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -/* - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class DescriptorException extends Exception { - private static final long serialVersionUID = 2411890273788901032L; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/EnclosingMethod_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/EnclosingMethod_attribute.java deleted file mode 100644 index 4cbf1eba9120f..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/EnclosingMethod_attribute.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.7. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class EnclosingMethod_attribute extends Attribute { - EnclosingMethod_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - class_index = cr.readUnsignedShort(); - method_index = cr.readUnsignedShort(); - } - - public EnclosingMethod_attribute(ConstantPool constant_pool, int class_index, int method_index) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.EnclosingMethod), class_index, method_index); - } - - public EnclosingMethod_attribute(int name_index, int class_index, int method_index) { - super(name_index, 4); - this.class_index = class_index; - this.method_index = method_index; - } - - public String getClassName(ConstantPool constant_pool) throws ConstantPoolException { - return constant_pool.getClassInfo(class_index).getName(); - } - - public String getMethodName(ConstantPool constant_pool) throws ConstantPoolException { - if (method_index == 0) - return ""; - return constant_pool.getNameAndTypeInfo(method_index).getName(); - } - - public R accept(Visitor visitor, D data) { - return visitor.visitEnclosingMethod(this, data); - } - - public final int class_index; - public final int method_index; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Exceptions_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Exceptions_attribute.java deleted file mode 100644 index a56db00b371dd..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Exceptions_attribute.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.5. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Exceptions_attribute extends Attribute { - Exceptions_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - number_of_exceptions = cr.readUnsignedShort(); - exception_index_table = new int[number_of_exceptions]; - for (int i = 0; i < number_of_exceptions; i++) - exception_index_table[i] = cr.readUnsignedShort(); - } - - public Exceptions_attribute(ConstantPool constant_pool, int[] exception_index_table) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.Exceptions), exception_index_table); - } - - public Exceptions_attribute(int name_index, int[] exception_index_table) { - super(name_index, 2 + 2 * exception_index_table.length); - this.number_of_exceptions = exception_index_table.length; - this.exception_index_table = exception_index_table; - } - - public String getException(int index, ConstantPool constant_pool) throws ConstantPoolException { - int exception_index = exception_index_table[index]; - return constant_pool.getClassInfo(exception_index).getName(); - } - - public R accept(Visitor visitor, D data) { - return visitor.visitExceptions(this, data); - } - - public final int number_of_exceptions; - public final int[] exception_index_table; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/FatalError.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/FatalError.java deleted file mode 100644 index 1f7ad56ef9d6c..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/FatalError.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -/** - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class FatalError extends Error { - private static final long serialVersionUID = 8114054446416187030L; - - FatalError(String message) { - super(message); - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Field.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Field.java deleted file mode 100644 index 89e313f6fc890..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Field.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/* - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Field { - Field(ClassReader cr) throws IOException { - access_flags = new AccessFlags(cr); - name_index = cr.readUnsignedShort(); - descriptor = new Descriptor(cr); - attributes = new Attributes(cr); - } - - public Field(AccessFlags access_flags, - int name_index, Descriptor descriptor, - Attributes attributes) { - this.access_flags = access_flags; - this.name_index = name_index; - this.descriptor = descriptor; - this.attributes = attributes; - } - - public int byteLength() { - return 6 + attributes.byteLength(); - } - - public String getName(ConstantPool constant_pool) throws ConstantPoolException { - return constant_pool.getUTF8Value(name_index); - } - - public final AccessFlags access_flags; - public final int name_index; - public final Descriptor descriptor; - public final Attributes attributes; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/InnerClasses_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/InnerClasses_attribute.java deleted file mode 100644 index b7ae9ab5d5154..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/InnerClasses_attribute.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -import com.sun.tools.classfile.ConstantPool.*; - -/** - * See JVMS, section 4.8.6. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class InnerClasses_attribute extends Attribute { - InnerClasses_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - number_of_classes = cr.readUnsignedShort(); - classes = new Info[number_of_classes]; - for (int i = 0; i < number_of_classes; i++) - classes[i] = new Info(cr); - } - - public InnerClasses_attribute(ConstantPool constant_pool, Info[] classes) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.InnerClasses), classes); - } - - public InnerClasses_attribute(int name_index, Info[] classes) { - super(name_index, 2 + Info.length() * classes.length); - this.number_of_classes = classes.length; - this.classes = classes; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitInnerClasses(this, data); - } - - public final int number_of_classes; - public final Info[] classes; - - public static class Info { - Info(ClassReader cr) throws IOException { - inner_class_info_index = cr.readUnsignedShort(); - outer_class_info_index = cr.readUnsignedShort(); - inner_name_index = cr.readUnsignedShort(); - inner_class_access_flags = new AccessFlags(cr.readUnsignedShort()); - } - - public Info(int inner_class_info_index, int outer_class_info_index, int inner_name_index, AccessFlags inner_class_access_flags) { - this.inner_class_info_index = inner_class_info_index; - this.outer_class_info_index = outer_class_info_index; - this.inner_name_index = inner_name_index; - this.inner_class_access_flags = inner_class_access_flags; - } - - public CONSTANT_Class_info getInnerClassInfo(ConstantPool constant_pool) throws ConstantPoolException { - if (inner_class_info_index == 0) - return null; - return constant_pool.getClassInfo(inner_class_info_index); - } - - public CONSTANT_Class_info getOuterClassInfo(ConstantPool constant_pool) throws ConstantPoolException { - if (outer_class_info_index == 0) - return null; - return constant_pool.getClassInfo(outer_class_info_index); - } - - public String getInnerName(ConstantPool constant_pool) throws ConstantPoolException { - if (inner_name_index == 0) - return null; - return constant_pool.getUTF8Value(inner_name_index); - } - - public static int length() { - return 8; - } - - public final int inner_class_info_index; - public final int outer_class_info_index; - public final int inner_name_index; - public final AccessFlags inner_class_access_flags; - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Instruction.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Instruction.java deleted file mode 100644 index 0f5f15eed399b..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Instruction.java +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.util.Locale; - -/** - * See JVMS, chapter 6. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - * - * @see Code_attribute#getInstructions - */ -public class Instruction { - /** The kind of an instruction, as determined by the position, size and - * types of its operands. */ - public static enum Kind { - /** Opcode is not followed by any operands. */ - NO_OPERANDS(1), - /** Opcode is followed by a byte indicating a type. */ - ATYPE(2), - /** Opcode is followed by a 2-byte branch offset. */ - BRANCH(3), - /** Opcode is followed by a 4-byte branch offset. */ - BRANCH_W(5), - /** Opcode is followed by a signed byte value. */ - BYTE(2), - /** Opcode is followed by a 1-byte index into the constant pool. */ - CPREF(2), - /** Opcode is followed by a 2-byte index into the constant pool. */ - CPREF_W(3), - /** Opcode is followed by a 2-byte index into the constant pool, - * an unsigned byte value. */ - CPREF_W_UBYTE(4), - /** Opcode is followed by a 2-byte index into the constant pool., - * an unsigned byte value, and a zero byte. */ - CPREF_W_UBYTE_ZERO(5), - /** Opcode is followed by variable number of operands, depending - * on the instruction.*/ - DYNAMIC(-1), - /** Opcode is followed by a 1-byte reference to a local variable. */ - LOCAL(2), - /** Opcode is followed by a 1-byte reference to a local variable, - * and a signed byte value. */ - LOCAL_BYTE(3), - /** Opcode is followed by a signed short value. */ - SHORT(3), - /** Wide opcode is not followed by any operands. */ - WIDE_NO_OPERANDS(2), - /** Wide opcode is followed by a 2-byte index into the local variables array. */ - WIDE_LOCAL(4), - /** Wide opcode is followed by a 2-byte index into the constant pool. */ - WIDE_CPREF_W(4), - /** Wide opcode is followed by a 2-byte index into the constant pool, - * and a signed short value. */ - WIDE_CPREF_W_SHORT(6), - /** Wide opcode is followed by a 2-byte reference to a local variable, - * and a signed short value. */ - WIDE_LOCAL_SHORT(6), - /** Opcode was not recognized. */ - UNKNOWN(1); - - Kind(int length) { - this.length = length; - } - - /** The length, in bytes, of this kind of instruction, or -1 is the - * length depends on the specific instruction. */ - public final int length; - } - - /** A utility visitor to help decode the operands of an instruction. - * @see Instruction#accept */ - public interface KindVisitor { - /** See {@link Kind#NO_OPERANDS}, {@link Kind#WIDE_NO_OPERANDS}. */ - R visitNoOperands(Instruction instr, P p); - /** See {@link Kind#ATYPE}. */ - R visitArrayType(Instruction instr, TypeKind kind, P p); - /** See {@link Kind#BRANCH}, {@link Kind#BRANCH_W}. */ - R visitBranch(Instruction instr, int offset, P p); - /** See {@link Kind#CPREF}, {@link Kind#CPREF_W}, {@link Kind#WIDE_CPREF_W}. */ - R visitConstantPoolRef(Instruction instr, int index, P p); - /** See {@link Kind#CPREF_W_UBYTE}, {@link Kind#CPREF_W_UBYTE_ZERO}, {@link Kind#WIDE_CPREF_W_SHORT}. */ - R visitConstantPoolRefAndValue(Instruction instr, int index, int value, P p); - /** See {@link Kind#LOCAL}, {@link Kind#WIDE_LOCAL}. */ - R visitLocal(Instruction instr, int index, P p); - /** See {@link Kind#LOCAL_BYTE}. */ - R visitLocalAndValue(Instruction instr, int index, int value, P p); - /** See {@link Kind#DYNAMIC}. */ - R visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, P p); - /** See {@link Kind#DYNAMIC}. */ - R visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, P p); - /** See {@link Kind#BYTE}, {@link Kind#SHORT}. */ - R visitValue(Instruction instr, int value, P p); - /** Instruction is unrecognized. */ - R visitUnknown(Instruction instr, P p); - - } - - /** The kind of primitive array type to create. - * See JVMS chapter 6, newarray. */ - public static enum TypeKind { - T_BOOLEAN(4, "boolean"), - T_CHAR(5, "char"), - T_FLOAT(6, "float"), - T_DOUBLE(7, "double"), - T_BYTE(8, "byte"), - T_SHORT(9, "short"), - T_INT (10, "int"), - T_LONG (11, "long"); - TypeKind(int value, String name) { - this.value = value; - this.name = name; - } - - public static TypeKind get(int value) { - switch (value) { - case 4: return T_BOOLEAN; - case 5: return T_CHAR; - case 6: return T_FLOAT; - case 7: return T_DOUBLE; - case 8: return T_BYTE; - case 9: return T_SHORT; - case 10: return T_INT; - case 11: return T_LONG; - default: return null; - } - } - - public final int value; - public final String name; - } - - /** An instruction is defined by its position in a bytecode array. */ - public Instruction(byte[] bytes, int pc) { - this.bytes = bytes; - this.pc = pc; - } - - /** Get the position of the instruction within the bytecode array. */ - public int getPC() { - return pc; - } - - /** Get a byte value, relative to the start of this instruction. */ - public int getByte(int offset) { - return bytes[pc + offset]; - } - - /** Get an unsigned byte value, relative to the start of this instruction. */ - public int getUnsignedByte(int offset) { - return getByte(offset) & 0xff; - } - - /** Get a 2-byte value, relative to the start of this instruction. */ - public int getShort(int offset) { - return (getByte(offset) << 8) | getUnsignedByte(offset + 1); - } - - /** Get a unsigned 2-byte value, relative to the start of this instruction. */ - public int getUnsignedShort(int offset) { - return getShort(offset) & 0xFFFF; - } - - /** Get a 4-byte value, relative to the start of this instruction. */ - public int getInt(int offset) { - return (getShort(offset) << 16) | (getUnsignedShort(offset + 2)); - } - - /** Get the Opcode for this instruction, or null if the instruction is - * unrecognized. */ - public Opcode getOpcode() { - int b = getUnsignedByte(0); - switch (b) { - case Opcode.NONPRIV: - case Opcode.PRIV: - case Opcode.WIDE: - return Opcode.get(b, getUnsignedByte(1)); - } - return Opcode.get(b); - } - - /** Get the mnemonic for this instruction, or a default string if the - * instruction is unrecognized. */ - public String getMnemonic() { - Opcode opcode = getOpcode(); - if (opcode == null) - return "bytecode " + getUnsignedByte(0); - else - return opcode.toString().toLowerCase(Locale.US); - } - - /** Get the length, in bytes, of this instruction, including the opcode - * and all its operands. */ - public int length() { - Opcode opcode = getOpcode(); - if (opcode == null) - return 1; - - switch (opcode) { - case TABLESWITCH: { - int pad = align(pc + 1) - pc; - int low = getInt(pad + 4); - int high = getInt(pad + 8); - return pad + 12 + 4 * (high - low + 1); - } - case LOOKUPSWITCH: { - int pad = align(pc + 1) - pc; - int npairs = getInt(pad + 4); - return pad + 8 + 8 * npairs; - - } - default: - return opcode.kind.length; - } - } - - /** Get the {@link Kind} of this instruction. */ - public Kind getKind() { - Opcode opcode = getOpcode(); - return (opcode != null ? opcode.kind : Kind.UNKNOWN); - } - - /** Invoke a method on the visitor according to the kind of this - * instruction, passing in the decoded operands for the instruction. */ - public R accept(KindVisitor visitor, P p) { - switch (getKind()) { - case NO_OPERANDS: - return visitor.visitNoOperands(this, p); - - case ATYPE: - return visitor.visitArrayType( - this, TypeKind.get(getUnsignedByte(1)), p); - - case BRANCH: - return visitor.visitBranch(this, getShort(1), p); - - case BRANCH_W: - return visitor.visitBranch(this, getInt(1), p); - - case BYTE: - return visitor.visitValue(this, getByte(1), p); - - case CPREF: - return visitor.visitConstantPoolRef(this, getUnsignedByte(1), p); - - case CPREF_W: - return visitor.visitConstantPoolRef(this, getUnsignedShort(1), p); - - case CPREF_W_UBYTE: - case CPREF_W_UBYTE_ZERO: - return visitor.visitConstantPoolRefAndValue( - this, getUnsignedShort(1), getUnsignedByte(3), p); - - case DYNAMIC: { - switch (getOpcode()) { - case TABLESWITCH: { - int pad = align(pc + 1) - pc; - int default_ = getInt(pad); - int low = getInt(pad + 4); - int high = getInt(pad + 8); - if (low > high) - throw new IllegalStateException(); - int[] values = new int[high - low + 1]; - for (int i = 0; i < values.length; i++) - values[i] = getInt(pad + 12 + 4 * i); - return visitor.visitTableSwitch( - this, default_, low, high, values, p); - } - case LOOKUPSWITCH: { - int pad = align(pc + 1) - pc; - int default_ = getInt(pad); - int npairs = getInt(pad + 4); - if (npairs < 0) - throw new IllegalStateException(); - int[] matches = new int[npairs]; - int[] offsets = new int[npairs]; - for (int i = 0; i < npairs; i++) { - matches[i] = getInt(pad + 8 + i * 8); - offsets[i] = getInt(pad + 12 + i * 8); - } - return visitor.visitLookupSwitch( - this, default_, npairs, matches, offsets, p); - } - default: - throw new IllegalStateException(); - } - } - - case LOCAL: - return visitor.visitLocal(this, getUnsignedByte(1), p); - - case LOCAL_BYTE: - return visitor.visitLocalAndValue( - this, getUnsignedByte(1), getByte(2), p); - - case SHORT: - return visitor.visitValue(this, getShort(1), p); - - case WIDE_NO_OPERANDS: - return visitor.visitNoOperands(this, p); - - case WIDE_LOCAL: - return visitor.visitLocal(this, getUnsignedShort(2), p); - - case WIDE_CPREF_W: - return visitor.visitConstantPoolRef(this, getUnsignedShort(2), p); - - case WIDE_CPREF_W_SHORT: - return visitor.visitConstantPoolRefAndValue( - this, getUnsignedShort(2), getUnsignedByte(4), p); - - case WIDE_LOCAL_SHORT: - return visitor.visitLocalAndValue( - this, getUnsignedShort(2), getShort(4), p); - - case UNKNOWN: - return visitor.visitUnknown(this, p); - - default: - throw new IllegalStateException(); - } - } - - private static int align(int n) { - return (n + 3) & ~3; - } - - private byte[] bytes; - private int pc; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/LineNumberTable_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/LineNumberTable_attribute.java deleted file mode 100644 index 58595b7d0583e..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/LineNumberTable_attribute.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.12. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class LineNumberTable_attribute extends Attribute { - LineNumberTable_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - line_number_table_length = cr.readUnsignedShort(); - line_number_table = new Entry[line_number_table_length]; - for (int i = 0; i < line_number_table_length; i++) - line_number_table[i] = new Entry(cr); - } - - public LineNumberTable_attribute(ConstantPool constant_pool, Entry[] line_number_table) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.LineNumberTable), line_number_table); - } - - public LineNumberTable_attribute(int name_index, Entry[] line_number_table) { - super(name_index, 2 + line_number_table.length * Entry.length()); - this.line_number_table_length = line_number_table.length; - this.line_number_table = line_number_table; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitLineNumberTable(this, data); - } - - public final int line_number_table_length; - public final Entry[] line_number_table; - - public static class Entry { - Entry(ClassReader cr) throws IOException { - start_pc = cr.readUnsignedShort(); - line_number = cr.readUnsignedShort(); - } - - public static int length() { - return 4; - } - - public final int start_pc; - public final int line_number; - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/LocalVariableTable_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/LocalVariableTable_attribute.java deleted file mode 100644 index 1e4465f2f7ce2..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/LocalVariableTable_attribute.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.13. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class LocalVariableTable_attribute extends Attribute { - LocalVariableTable_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - local_variable_table_length = cr.readUnsignedShort(); - local_variable_table = new Entry[local_variable_table_length]; - for (int i = 0; i < local_variable_table_length; i++) - local_variable_table[i] = new Entry(cr); - } - - public LocalVariableTable_attribute(ConstantPool constant_pool, Entry[] local_variable_table) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.LocalVariableTable), local_variable_table); - } - - public LocalVariableTable_attribute(int name_index, Entry[] local_variable_table) { - super(name_index, 2 + local_variable_table.length * Entry.length()); - this.local_variable_table_length = local_variable_table.length; - this.local_variable_table = local_variable_table; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitLocalVariableTable(this, data); - } - - public final int local_variable_table_length; - public final Entry[] local_variable_table; - - public static class Entry { - Entry(ClassReader cr) throws IOException { - start_pc = cr.readUnsignedShort(); - length = cr.readUnsignedShort(); - name_index = cr.readUnsignedShort(); - descriptor_index = cr.readUnsignedShort(); - index = cr.readUnsignedShort(); - } - - public static int length() { - return 10; - } - - public final int start_pc; - public final int length; - public final int name_index; - public final int descriptor_index; - public final int index; - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/LocalVariableTypeTable_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/LocalVariableTypeTable_attribute.java deleted file mode 100644 index 8332cbec577da..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/LocalVariableTypeTable_attribute.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.14. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class LocalVariableTypeTable_attribute extends Attribute { - LocalVariableTypeTable_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - local_variable_table_length = cr.readUnsignedShort(); - local_variable_table = new Entry[local_variable_table_length]; - for (int i = 0; i < local_variable_table_length; i++) - local_variable_table[i] = new Entry(cr); - } - - public LocalVariableTypeTable_attribute(ConstantPool constant_pool, Entry[] local_variable_table) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.LocalVariableTypeTable), local_variable_table); - } - - public LocalVariableTypeTable_attribute(int name_index, Entry[] local_variable_table) { - super(name_index, 2 + local_variable_table.length * Entry.length()); - this.local_variable_table_length = local_variable_table.length; - this.local_variable_table = local_variable_table; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitLocalVariableTypeTable(this, data); - } - - public final int local_variable_table_length; - public final Entry[] local_variable_table; - - public static class Entry { - Entry(ClassReader cr) throws IOException { - start_pc = cr.readUnsignedShort(); - length = cr.readUnsignedShort(); - name_index = cr.readUnsignedShort(); - signature_index = cr.readUnsignedShort(); - index = cr.readUnsignedShort(); - } - - public static int length() { - return 10; - } - - public final int start_pc; - public final int length; - public final int name_index; - public final int signature_index; - public final int index; - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Method.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Method.java deleted file mode 100644 index 5345d54ccdfe1..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Method.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/* - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Method { - Method(ClassReader cr) throws IOException { - access_flags = new AccessFlags(cr); - name_index = cr.readUnsignedShort(); - descriptor = new Descriptor(cr); - attributes = new Attributes(cr); - } - - public Method(AccessFlags access_flags, - int name_index, Descriptor descriptor, - Attributes attributes) { - this.access_flags = access_flags; - this.name_index = name_index; - this.descriptor = descriptor; - this.attributes = attributes; - } - - public int byteLength() { - return 6 + attributes.byteLength(); - } - - public String getName(ConstantPool constant_pool) throws ConstantPoolException { - return constant_pool.getUTF8Value(name_index); - } - - public final AccessFlags access_flags; - public final int name_index; - public final Descriptor descriptor; - public final Attributes attributes; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/MethodParameters_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/MethodParameters_attribute.java deleted file mode 100644 index 942f8f00c049b..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/MethodParameters_attribute.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.13. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class MethodParameters_attribute extends Attribute { - - public final int method_parameter_table_length; - public final Entry[] method_parameter_table; - - MethodParameters_attribute(ClassReader cr, - int name_index, - int length) - throws IOException { - super(name_index, length); - - method_parameter_table_length = cr.readUnsignedByte(); - method_parameter_table = new Entry[method_parameter_table_length]; - for (int i = 0; i < method_parameter_table_length; i++) - method_parameter_table[i] = new Entry(cr); - } - - public MethodParameters_attribute(ConstantPool constant_pool, - Entry[] method_parameter_table) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.MethodParameters), - method_parameter_table); - } - - public MethodParameters_attribute(int name_index, - Entry[] method_parameter_table) { - super(name_index, 1 + method_parameter_table.length * Entry.length()); - this.method_parameter_table_length = method_parameter_table.length; - this.method_parameter_table = method_parameter_table; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitMethodParameters(this, data); - } - - public static class Entry { - Entry(ClassReader cr) throws IOException { - name_index = cr.readUnsignedShort(); - flags = cr.readUnsignedShort(); - } - - public Entry(int name_index, int flags) { - this.name_index = name_index; - this.flags = flags; - } - - public static int length() { - return 6; - } - - public final int name_index; - public final int flags; - } - -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModuleHashes_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModuleHashes_attribute.java deleted file mode 100644 index c227f3df8b726..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModuleHashes_attribute.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.15. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class ModuleHashes_attribute extends Attribute { - ModuleHashes_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - algorithm_index = cr.readUnsignedShort(); - hashes_table_length = cr.readUnsignedShort(); - hashes_table = new Entry[hashes_table_length]; - for (int i = 0; i < hashes_table_length; i++) - hashes_table[i] = new Entry(cr); - } - - public ModuleHashes_attribute(ConstantPool constant_pool, int algorithm_index, Entry[] hashes_table) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.ModuleHashes), algorithm_index, hashes_table); - } - - public ModuleHashes_attribute(int name_index, int algorithm_index, Entry[] hashes_table) { - super(name_index, 2 + 2 + length(hashes_table)); - this.algorithm_index = algorithm_index; - this.hashes_table_length = hashes_table.length; - this.hashes_table = hashes_table; - } - - @Override - public R accept(Visitor visitor, D data) { - return visitor.visitModuleHashes(this, data); - } - - private static int length(Entry[] hashes_table) { - int len = 0; - for (Entry e: hashes_table) { - len += e.length(); - } - return len; - } - - public final int algorithm_index; - public final int hashes_table_length; - public final Entry[] hashes_table; - - public static class Entry { - Entry(ClassReader cr) throws IOException { - module_name_index = cr.readUnsignedShort(); - int hash_length = cr.readUnsignedShort(); - hash = new byte[hash_length]; - for (int i=0; iThis is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class ModuleMainClass_attribute extends Attribute { - ModuleMainClass_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - main_class_index = cr.readUnsignedShort(); - } - - public ModuleMainClass_attribute(ConstantPool constant_pool, int mainClass_index) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.ModuleMainClass), mainClass_index); - } - - public ModuleMainClass_attribute(int name_index, int mainClass_index) { - super(name_index, 2); - this.main_class_index = mainClass_index; - } - - public String getMainClassName(ConstantPool constant_pool) throws ConstantPoolException { - return constant_pool.getClassInfo(main_class_index).getName(); - } - - @Override - public R accept(Visitor visitor, D data) { - return visitor.visitModuleMainClass(this, data); - } - - public final int main_class_index; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModulePackages_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModulePackages_attribute.java deleted file mode 100644 index 9b3cd433bd8bb..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModulePackages_attribute.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -import com.sun.tools.classfile.ConstantPool.CONSTANT_Package_info; - -/** - * See JVMS, section 4.8.15. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class ModulePackages_attribute extends Attribute { - ModulePackages_attribute(ClassReader cr, int name_index, int length) - throws IOException { - super(name_index, length); - packages_count = cr.readUnsignedShort(); - packages_index = new int[packages_count]; - for (int i = 0; i < packages_count; i++) - packages_index[i] = cr.readUnsignedShort(); - } - - public ModulePackages_attribute(ConstantPool constant_pool, - int[] packages_index) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.ModulePackages), - packages_index); - } - - public ModulePackages_attribute(int name_index, - int[] packages_index) { - super(name_index, 2 + packages_index.length * 2); - this.packages_count = packages_index.length; - this.packages_index = packages_index; - } - - public String getPackage(int index, ConstantPool constant_pool) throws ConstantPoolException { - int package_index = packages_index[index]; - CONSTANT_Package_info info = constant_pool.getPackageInfo(package_index); - return info.getName(); - } - - @Override - public R accept(Visitor visitor, D data) { - return visitor.visitModulePackages(this, data); - } - - public final int packages_count; - public final int[] packages_index; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModuleResolution_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModuleResolution_attribute.java deleted file mode 100644 index e1ba78a337629..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModuleResolution_attribute.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.15. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class ModuleResolution_attribute extends Attribute { - public static final int DO_NOT_RESOLVE_BY_DEFAULT = 0x0001; - public static final int WARN_DEPRECATED = 0x0002; - public static final int WARN_DEPRECATED_FOR_REMOVAL = 0x0004; - public static final int WARN_INCUBATING = 0x0008; - - ModuleResolution_attribute(ClassReader cr, int name_index, int length) - throws IOException { - super(name_index, length); - resolution_flags = cr.readUnsignedShort(); - } - - public ModuleResolution_attribute(ConstantPool constant_pool, - int resolution_flags) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.ModuleResolution), - resolution_flags); - } - - public ModuleResolution_attribute(int name_index, - int resolution_flags) { - super(name_index, 2); - this.resolution_flags = resolution_flags; - } - - @Override - public R accept(Visitor visitor, D data) { - return visitor.visitModuleResolution(this, data); - } - - public final int resolution_flags; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModuleTarget_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModuleTarget_attribute.java deleted file mode 100644 index b7d7ecc77e396..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ModuleTarget_attribute.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.15. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class ModuleTarget_attribute extends Attribute { - ModuleTarget_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - target_platform_index = cr.readUnsignedShort(); - } - - public ModuleTarget_attribute(int name_index, int target_platform_index) { - super(name_index, 2); - this.target_platform_index = target_platform_index; - } - - @Override - public R accept(Visitor visitor, D data) { - return visitor.visitModuleTarget(this, data); - } - - public final int target_platform_index; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Module_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Module_attribute.java deleted file mode 100644 index 6b0b525b50c10..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Module_attribute.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -import com.sun.tools.classfile.ConstantPool.CONSTANT_Module_info; - -/** - * See Jigsaw. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Module_attribute extends Attribute { - public static final int ACC_TRANSITIVE = 0x20; - public static final int ACC_STATIC_PHASE = 0x40; - public static final int ACC_OPEN = 0x20; - public static final int ACC_SYNTHETIC = 0x1000; - public static final int ACC_MANDATED = 0x8000; - - Module_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - - module_name = cr.readUnsignedShort(); - module_flags = cr.readUnsignedShort(); - - module_version_index = cr.readUnsignedShort(); - - requires_count = cr.readUnsignedShort(); - requires = new RequiresEntry[requires_count]; - for (int i = 0; i < requires_count; i++) - requires[i] = new RequiresEntry(cr); - - exports_count = cr.readUnsignedShort(); - exports = new ExportsEntry[exports_count]; - for (int i = 0; i < exports_count; i++) - exports[i] = new ExportsEntry(cr); - - opens_count = cr.readUnsignedShort(); - opens = new OpensEntry[opens_count]; - for (int i = 0; i < opens_count; i++) - opens[i] = new OpensEntry(cr); - - uses_count = cr.readUnsignedShort(); - uses_index = new int[uses_count]; - for (int i = 0; i < uses_count; i++) - uses_index[i] = cr.readUnsignedShort(); - - provides_count = cr.readUnsignedShort(); - provides = new ProvidesEntry[provides_count]; - for (int i = 0; i < provides_count; i++) - provides[i] = new ProvidesEntry(cr); - } - - public Module_attribute(int name_index, - int module_name, - int module_flags, - int module_version_index, - RequiresEntry[] requires, - ExportsEntry[] exports, - OpensEntry[] opens, - int[] uses, - ProvidesEntry[] provides) { - super(name_index, 2); - this.module_name = module_name; - this.module_flags = module_flags; - this.module_version_index = module_version_index; - requires_count = requires.length; - this.requires = requires; - exports_count = exports.length; - this.exports = exports; - opens_count = opens.length; - this.opens = opens; - uses_count = uses.length; - this.uses_index = uses; - provides_count = provides.length; - this.provides = provides; - } - - public String getUses(int index, ConstantPool constant_pool) throws ConstantPoolException { - int i = uses_index[index]; - return constant_pool.getClassInfo(i).getName(); - } - - @Override - public R accept(Visitor visitor, D data) { - return visitor.visitModule(this, data); - } - - public final int module_name; - public final int module_flags; - public final int module_version_index; - public final int requires_count; - public final RequiresEntry[] requires; - public final int exports_count; - public final ExportsEntry[] exports; - public final int opens_count; - public final OpensEntry[] opens; - public final int uses_count; - public final int[] uses_index; - public final int provides_count; - public final ProvidesEntry[] provides; - - public static class RequiresEntry { - RequiresEntry(ClassReader cr) throws IOException { - requires_index = cr.readUnsignedShort(); - requires_flags = cr.readUnsignedShort(); - requires_version_index = cr.readUnsignedShort(); - } - - public RequiresEntry(int index, int flags, int version_index) { - this.requires_index = index; - this.requires_flags = flags; - this.requires_version_index = version_index; - } - - public String getRequires(ConstantPool constant_pool) throws ConstantPoolException { - CONSTANT_Module_info info = constant_pool.getModuleInfo(requires_index); - return info.getName(); - } - - public static final int length = 4; - - public final int requires_index; - public final int requires_flags; - public final int requires_version_index; - } - - public static class ExportsEntry { - ExportsEntry(ClassReader cr) throws IOException { - exports_index = cr.readUnsignedShort(); - exports_flags = cr.readUnsignedShort(); - exports_to_count = cr.readUnsignedShort(); - exports_to_index = new int[exports_to_count]; - for (int i = 0; i < exports_to_count; i++) - exports_to_index[i] = cr.readUnsignedShort(); - } - - public ExportsEntry(int index, int flags, int[] to) { - this.exports_index = index; - this.exports_flags = flags; - this.exports_to_count = to.length; - this.exports_to_index = to; - } - - public int length() { - return 4 + 2 * exports_to_index.length; - } - - public final int exports_index; - public final int exports_flags; - public final int exports_to_count; - public final int[] exports_to_index; - } - - public static class OpensEntry { - OpensEntry(ClassReader cr) throws IOException { - opens_index = cr.readUnsignedShort(); - opens_flags = cr.readUnsignedShort(); - opens_to_count = cr.readUnsignedShort(); - opens_to_index = new int[opens_to_count]; - for (int i = 0; i < opens_to_count; i++) - opens_to_index[i] = cr.readUnsignedShort(); - } - - public OpensEntry(int index, int flags, int[] to) { - this.opens_index = index; - this.opens_flags = flags; - this.opens_to_count = to.length; - this.opens_to_index = to; - } - - public int length() { - return 4 + 2 * opens_to_index.length; - } - - public final int opens_index; - public final int opens_flags; - public final int opens_to_count; - public final int[] opens_to_index; - } - - public static class ProvidesEntry { - ProvidesEntry(ClassReader cr) throws IOException { - provides_index = cr.readUnsignedShort(); - with_count = cr.readUnsignedShort(); - with_index = new int[with_count]; - for (int i = 0; i < with_count; i++) - with_index[i] = cr.readUnsignedShort(); - } - - public ProvidesEntry(int provides, int[] with) { - this.provides_index = provides; - this.with_count = with.length; - this.with_index = with; - } - - public static final int length = 4; - - public final int provides_index; - public final int with_count; - public final int[] with_index; - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/NestHost_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/NestHost_attribute.java deleted file mode 100644 index 0473fbf56feb5..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/NestHost_attribute.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info; - -import java.io.IOException; - -/** - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class NestHost_attribute extends Attribute { - NestHost_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - top_index = cr.readUnsignedShort(); - } - - public NestHost_attribute(ConstantPool constant_pool, int signature_index) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.Signature), signature_index); - } - - public NestHost_attribute(int name_index, int top_index) { - super(name_index, 2); - this.top_index = top_index; - } - - public CONSTANT_Class_info getNestTop(ConstantPool constant_pool) throws ConstantPoolException { - return constant_pool.getClassInfo(top_index); - } - - public R accept(Visitor visitor, D data) { - return visitor.visitNestHost(this, data); - } - - public final int top_index; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/NestMembers_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/NestMembers_attribute.java deleted file mode 100644 index bf57a12a1a625..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/NestMembers_attribute.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info; - -import java.io.IOException; -import java.util.stream.IntStream; - -/** - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class NestMembers_attribute extends Attribute { - NestMembers_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - int len = cr.readUnsignedShort(); - members_indexes = new int[len]; - for (int i = 0 ; i < len ; i++) { - members_indexes[i] = cr.readUnsignedShort(); - } - } - - public NestMembers_attribute(int name_index, int[] members_indexes) { - super(name_index, 2); - this.members_indexes = members_indexes; - } - - public CONSTANT_Class_info[] getChildren(ConstantPool constant_pool) throws ConstantPoolException { - return IntStream.of(members_indexes) - .mapToObj(i -> { - try { - return constant_pool.getClassInfo(i); - } catch (ConstantPoolException ex) { - throw new AssertionError(ex); - } - }).toArray(CONSTANT_Class_info[]::new); - } - - public R accept(Visitor visitor, D data) { - return visitor.visitNestMembers(this, data); - } - - public final int[] members_indexes; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Opcode.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Opcode.java deleted file mode 100644 index 0f3ff0434165b..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Opcode.java +++ /dev/null @@ -1,472 +0,0 @@ -/* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import static com.sun.tools.classfile.Instruction.Kind.*; -import static com.sun.tools.classfile.Opcode.Set.*; - -/** - * See JVMS, chapter 6. - * - *

In addition to providing all the standard opcodes defined in JVMS, - * this class also provides legacy support for the PicoJava extensions. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public enum Opcode { - NOP(0x0), - ACONST_NULL(0x1), - ICONST_M1(0x2), - ICONST_0(0x3), - ICONST_1(0x4), - ICONST_2(0x5), - ICONST_3(0x6), - ICONST_4(0x7), - ICONST_5(0x8), - LCONST_0(0x9), - LCONST_1(0xa), - FCONST_0(0xb), - FCONST_1(0xc), - FCONST_2(0xd), - DCONST_0(0xe), - DCONST_1(0xf), - BIPUSH(0x10, BYTE), - SIPUSH(0x11, SHORT), - LDC(0x12, CPREF), - LDC_W(0x13, CPREF_W), - LDC2_W(0x14, CPREF_W), - ILOAD(0x15, LOCAL), - LLOAD(0x16, LOCAL), - FLOAD(0x17, LOCAL), - DLOAD(0x18, LOCAL), - ALOAD(0x19, LOCAL), - ILOAD_0(0x1a), - ILOAD_1(0x1b), - ILOAD_2(0x1c), - ILOAD_3(0x1d), - LLOAD_0(0x1e), - LLOAD_1(0x1f), - LLOAD_2(0x20), - LLOAD_3(0x21), - FLOAD_0(0x22), - FLOAD_1(0x23), - FLOAD_2(0x24), - FLOAD_3(0x25), - DLOAD_0(0x26), - DLOAD_1(0x27), - DLOAD_2(0x28), - DLOAD_3(0x29), - ALOAD_0(0x2a), - ALOAD_1(0x2b), - ALOAD_2(0x2c), - ALOAD_3(0x2d), - IALOAD(0x2e), - LALOAD(0x2f), - FALOAD(0x30), - DALOAD(0x31), - AALOAD(0x32), - BALOAD(0x33), - CALOAD(0x34), - SALOAD(0x35), - ISTORE(0x36, LOCAL), - LSTORE(0x37, LOCAL), - FSTORE(0x38, LOCAL), - DSTORE(0x39, LOCAL), - ASTORE(0x3a, LOCAL), - ISTORE_0(0x3b), - ISTORE_1(0x3c), - ISTORE_2(0x3d), - ISTORE_3(0x3e), - LSTORE_0(0x3f), - LSTORE_1(0x40), - LSTORE_2(0x41), - LSTORE_3(0x42), - FSTORE_0(0x43), - FSTORE_1(0x44), - FSTORE_2(0x45), - FSTORE_3(0x46), - DSTORE_0(0x47), - DSTORE_1(0x48), - DSTORE_2(0x49), - DSTORE_3(0x4a), - ASTORE_0(0x4b), - ASTORE_1(0x4c), - ASTORE_2(0x4d), - ASTORE_3(0x4e), - IASTORE(0x4f), - LASTORE(0x50), - FASTORE(0x51), - DASTORE(0x52), - AASTORE(0x53), - BASTORE(0x54), - CASTORE(0x55), - SASTORE(0x56), - POP(0x57), - POP2(0x58), - DUP(0x59), - DUP_X1(0x5a), - DUP_X2(0x5b), - DUP2(0x5c), - DUP2_X1(0x5d), - DUP2_X2(0x5e), - SWAP(0x5f), - IADD(0x60), - LADD(0x61), - FADD(0x62), - DADD(0x63), - ISUB(0x64), - LSUB(0x65), - FSUB(0x66), - DSUB(0x67), - IMUL(0x68), - LMUL(0x69), - FMUL(0x6a), - DMUL(0x6b), - IDIV(0x6c), - LDIV(0x6d), - FDIV(0x6e), - DDIV(0x6f), - IREM(0x70), - LREM(0x71), - FREM(0x72), - DREM(0x73), - INEG(0x74), - LNEG(0x75), - FNEG(0x76), - DNEG(0x77), - ISHL(0x78), - LSHL(0x79), - ISHR(0x7a), - LSHR(0x7b), - IUSHR(0x7c), - LUSHR(0x7d), - IAND(0x7e), - LAND(0x7f), - IOR(0x80), - LOR(0x81), - IXOR(0x82), - LXOR(0x83), - IINC(0x84, LOCAL_BYTE), - I2L(0x85), - I2F(0x86), - I2D(0x87), - L2I(0x88), - L2F(0x89), - L2D(0x8a), - F2I(0x8b), - F2L(0x8c), - F2D(0x8d), - D2I(0x8e), - D2L(0x8f), - D2F(0x90), - I2B(0x91), - I2C(0x92), - I2S(0x93), - LCMP(0x94), - FCMPL(0x95), - FCMPG(0x96), - DCMPL(0x97), - DCMPG(0x98), - IFEQ(0x99, BRANCH), - IFNE(0x9a, BRANCH), - IFLT(0x9b, BRANCH), - IFGE(0x9c, BRANCH), - IFGT(0x9d, BRANCH), - IFLE(0x9e, BRANCH), - IF_ICMPEQ(0x9f, BRANCH), - IF_ICMPNE(0xa0, BRANCH), - IF_ICMPLT(0xa1, BRANCH), - IF_ICMPGE(0xa2, BRANCH), - IF_ICMPGT(0xa3, BRANCH), - IF_ICMPLE(0xa4, BRANCH), - IF_ACMPEQ(0xa5, BRANCH), - IF_ACMPNE(0xa6, BRANCH), - GOTO(0xa7, BRANCH), - JSR(0xa8, BRANCH), - RET(0xa9, LOCAL), - TABLESWITCH(0xaa, DYNAMIC), - LOOKUPSWITCH(0xab, DYNAMIC), - IRETURN(0xac), - LRETURN(0xad), - FRETURN(0xae), - DRETURN(0xaf), - ARETURN(0xb0), - RETURN(0xb1), - GETSTATIC(0xb2, CPREF_W), - PUTSTATIC(0xb3, CPREF_W), - GETFIELD(0xb4, CPREF_W), - PUTFIELD(0xb5, CPREF_W), - INVOKEVIRTUAL(0xb6, CPREF_W), - INVOKESPECIAL(0xb7, CPREF_W), - INVOKESTATIC(0xb8, CPREF_W), - INVOKEINTERFACE(0xb9, CPREF_W_UBYTE_ZERO), - INVOKEDYNAMIC(0xba, CPREF_W_UBYTE_ZERO), - NEW(0xbb, CPREF_W), - NEWARRAY(0xbc, ATYPE), - ANEWARRAY(0xbd, CPREF_W), - ARRAYLENGTH(0xbe), - ATHROW(0xbf), - CHECKCAST(0xc0, CPREF_W), - INSTANCEOF(0xc1, CPREF_W), - MONITORENTER(0xc2), - MONITOREXIT(0xc3), - // wide 0xc4 - MULTIANEWARRAY(0xc5, CPREF_W_UBYTE), - IFNULL(0xc6, BRANCH), - IFNONNULL(0xc7, BRANCH), - GOTO_W(0xc8, BRANCH_W), - JSR_W(0xc9, BRANCH_W), - // impdep 0xfe: PicoJava nonpriv - // impdep 0xff: Picojava priv - - // wide opcodes - ILOAD_W(0xc415, WIDE_LOCAL), - LLOAD_W(0xc416, WIDE_LOCAL), - FLOAD_W(0xc417, WIDE_LOCAL), - DLOAD_W(0xc418, WIDE_LOCAL), - ALOAD_W(0xc419, WIDE_LOCAL), - ISTORE_W(0xc436, WIDE_LOCAL), - LSTORE_W(0xc437, WIDE_LOCAL), - FSTORE_W(0xc438, WIDE_LOCAL), - DSTORE_W(0xc439, WIDE_LOCAL), - ASTORE_W(0xc43a, WIDE_LOCAL), - IINC_W(0xc484, WIDE_LOCAL_SHORT), - RET_W(0xc4a9, WIDE_LOCAL), - - // PicoJava nonpriv instructions - LOAD_UBYTE(PICOJAVA, 0xfe00), - LOAD_BYTE(PICOJAVA, 0xfe01), - LOAD_CHAR(PICOJAVA, 0xfe02), - LOAD_SHORT(PICOJAVA, 0xfe03), - LOAD_WORD(PICOJAVA, 0xfe04), - RET_FROM_SUB(PICOJAVA, 0xfe05), - LOAD_CHAR_OE(PICOJAVA, 0xfe0a), - LOAD_SHORT_OE(PICOJAVA, 0xfe0b), - LOAD_WORD_OE(PICOJAVA, 0xfe0c), - NCLOAD_UBYTE(PICOJAVA, 0xfe10), - NCLOAD_BYTE(PICOJAVA, 0xfe11), - NCLOAD_CHAR(PICOJAVA, 0xfe12), - NCLOAD_SHORT(PICOJAVA, 0xfe13), - NCLOAD_WORD(PICOJAVA, 0xfe14), - NCLOAD_CHAR_OE(PICOJAVA, 0xfe1a), - NCLOAD_SHORT_OE(PICOJAVA, 0xfe1b), - NCLOAD_WORD_OE(PICOJAVA, 0xfe1c), - CACHE_FLUSH(PICOJAVA, 0xfe1e), - STORE_BYTE(PICOJAVA, 0xfe20), - STORE_SHORT(PICOJAVA, 0xfe22), - STORE_WORD(PICOJAVA, 0xfe24), - STORE_SHORT_OE(PICOJAVA, 0xfe2a), - STORE_WORD_OE(PICOJAVA, 0xfe2c), - NCSTORE_BYTE(PICOJAVA, 0xfe30), - NCSTORE_SHORT(PICOJAVA, 0xfe32), - NCSTORE_WORD(PICOJAVA, 0xfe34), - NCSTORE_SHORT_OE(PICOJAVA, 0xfe3a), - NCSTORE_WORD_OE(PICOJAVA, 0xfe3c), - ZERO_LINE(PICOJAVA, 0xfe3e), - ENTER_SYNC_METHOD(PICOJAVA, 0xfe3f), - - // PicoJava priv instructions - PRIV_LOAD_UBYTE(PICOJAVA, 0xff00), - PRIV_LOAD_BYTE(PICOJAVA, 0xff01), - PRIV_LOAD_CHAR(PICOJAVA, 0xff02), - PRIV_LOAD_SHORT(PICOJAVA, 0xff03), - PRIV_LOAD_WORD(PICOJAVA, 0xff04), - PRIV_RET_FROM_TRAP(PICOJAVA, 0xff05), - PRIV_READ_DCACHE_TAG(PICOJAVA, 0xff06), - PRIV_READ_DCACHE_DATA(PICOJAVA, 0xff07), - PRIV_LOAD_CHAR_OE(PICOJAVA, 0xff0a), - PRIV_LOAD_SHORT_OE(PICOJAVA, 0xff0b), - PRIV_LOAD_WORD_OE(PICOJAVA, 0xff0c), - PRIV_READ_ICACHE_TAG(PICOJAVA, 0xff0e), - PRIV_READ_ICACHE_DATA(PICOJAVA, 0xff0f), - PRIV_NCLOAD_UBYTE(PICOJAVA, 0xff10), - PRIV_NCLOAD_BYTE(PICOJAVA, 0xff11), - PRIV_NCLOAD_CHAR(PICOJAVA, 0xff12), - PRIV_NCLOAD_SHORT(PICOJAVA, 0xff13), - PRIV_NCLOAD_WORD(PICOJAVA, 0xff14), - PRIV_POWERDOWN(PICOJAVA, 0xff16), - PRIV_READ_SCACHE_DATA(PICOJAVA, 0xff17), - PRIV_NCLOAD_CHAR_OE(PICOJAVA, 0xff1a), - PRIV_NCLOAD_SHORT_OE(PICOJAVA, 0xff1b), - PRIV_NCLOAD_WORD_OE(PICOJAVA, 0xff1c), - PRIV_CACHE_FLUSH(PICOJAVA, 0xff1e), - PRIV_CACHE_INDEX_FLUSH(PICOJAVA, 0xff1f), - PRIV_STORE_BYTE(PICOJAVA, 0xff20), - PRIV_STORE_SHORT(PICOJAVA, 0xff22), - PRIV_STORE_WORD(PICOJAVA, 0xff24), - PRIV_WRITE_DCACHE_TAG(PICOJAVA, 0xff26), - PRIV_WRITE_DCACHE_DATA(PICOJAVA, 0xff27), - PRIV_STORE_SHORT_OE(PICOJAVA, 0xff2a), - PRIV_STORE_WORD_OE(PICOJAVA, 0xff2c), - PRIV_WRITE_ICACHE_TAG(PICOJAVA, 0xff2e), - PRIV_WRITE_ICACHE_DATA(PICOJAVA, 0xff2f), - PRIV_NCSTORE_BYTE(PICOJAVA, 0xff30), - PRIV_NCSTORE_SHORT(PICOJAVA, 0xff32), - PRIV_NCSTORE_WORD(PICOJAVA, 0xff34), - PRIV_RESET(PICOJAVA, 0xff36), - PRIV_WRITE_SCACHE_DATA(PICOJAVA, 0xff37), - PRIV_NCSTORE_SHORT_OE(PICOJAVA, 0xff3a), - PRIV_NCSTORE_WORD_OE(PICOJAVA, 0xff3c), - PRIV_ZERO_LINE(PICOJAVA, 0xff3e), - PRIV_READ_REG_0(PICOJAVA, 0xff40), - PRIV_READ_REG_1(PICOJAVA, 0xff41), - PRIV_READ_REG_2(PICOJAVA, 0xff42), - PRIV_READ_REG_3(PICOJAVA, 0xff43), - PRIV_READ_REG_4(PICOJAVA, 0xff44), - PRIV_READ_REG_5(PICOJAVA, 0xff45), - PRIV_READ_REG_6(PICOJAVA, 0xff46), - PRIV_READ_REG_7(PICOJAVA, 0xff47), - PRIV_READ_REG_8(PICOJAVA, 0xff48), - PRIV_READ_REG_9(PICOJAVA, 0xff49), - PRIV_READ_REG_10(PICOJAVA, 0xff4a), - PRIV_READ_REG_11(PICOJAVA, 0xff4b), - PRIV_READ_REG_12(PICOJAVA, 0xff4c), - PRIV_READ_REG_13(PICOJAVA, 0xff4d), - PRIV_READ_REG_14(PICOJAVA, 0xff4e), - PRIV_READ_REG_15(PICOJAVA, 0xff4f), - PRIV_READ_REG_16(PICOJAVA, 0xff50), - PRIV_READ_REG_17(PICOJAVA, 0xff51), - PRIV_READ_REG_18(PICOJAVA, 0xff52), - PRIV_READ_REG_19(PICOJAVA, 0xff53), - PRIV_READ_REG_20(PICOJAVA, 0xff54), - PRIV_READ_REG_21(PICOJAVA, 0xff55), - PRIV_READ_REG_22(PICOJAVA, 0xff56), - PRIV_READ_REG_23(PICOJAVA, 0xff57), - PRIV_READ_REG_24(PICOJAVA, 0xff58), - PRIV_READ_REG_25(PICOJAVA, 0xff59), - PRIV_READ_REG_26(PICOJAVA, 0xff5a), - PRIV_READ_REG_27(PICOJAVA, 0xff5b), - PRIV_READ_REG_28(PICOJAVA, 0xff5c), - PRIV_READ_REG_29(PICOJAVA, 0xff5d), - PRIV_READ_REG_30(PICOJAVA, 0xff5e), - PRIV_READ_REG_31(PICOJAVA, 0xff5f), - PRIV_WRITE_REG_0(PICOJAVA, 0xff60), - PRIV_WRITE_REG_1(PICOJAVA, 0xff61), - PRIV_WRITE_REG_2(PICOJAVA, 0xff62), - PRIV_WRITE_REG_3(PICOJAVA, 0xff63), - PRIV_WRITE_REG_4(PICOJAVA, 0xff64), - PRIV_WRITE_REG_5(PICOJAVA, 0xff65), - PRIV_WRITE_REG_6(PICOJAVA, 0xff66), - PRIV_WRITE_REG_7(PICOJAVA, 0xff67), - PRIV_WRITE_REG_8(PICOJAVA, 0xff68), - PRIV_WRITE_REG_9(PICOJAVA, 0xff69), - PRIV_WRITE_REG_10(PICOJAVA, 0xff6a), - PRIV_WRITE_REG_11(PICOJAVA, 0xff6b), - PRIV_WRITE_REG_12(PICOJAVA, 0xff6c), - PRIV_WRITE_REG_13(PICOJAVA, 0xff6d), - PRIV_WRITE_REG_14(PICOJAVA, 0xff6e), - PRIV_WRITE_REG_15(PICOJAVA, 0xff6f), - PRIV_WRITE_REG_16(PICOJAVA, 0xff70), - PRIV_WRITE_REG_17(PICOJAVA, 0xff71), - PRIV_WRITE_REG_18(PICOJAVA, 0xff72), - PRIV_WRITE_REG_19(PICOJAVA, 0xff73), - PRIV_WRITE_REG_20(PICOJAVA, 0xff74), - PRIV_WRITE_REG_21(PICOJAVA, 0xff75), - PRIV_WRITE_REG_22(PICOJAVA, 0xff76), - PRIV_WRITE_REG_23(PICOJAVA, 0xff77), - PRIV_WRITE_REG_24(PICOJAVA, 0xff78), - PRIV_WRITE_REG_25(PICOJAVA, 0xff79), - PRIV_WRITE_REG_26(PICOJAVA, 0xff7a), - PRIV_WRITE_REG_27(PICOJAVA, 0xff7b), - PRIV_WRITE_REG_28(PICOJAVA, 0xff7c), - PRIV_WRITE_REG_29(PICOJAVA, 0xff7d), - PRIV_WRITE_REG_30(PICOJAVA, 0xff7e), - PRIV_WRITE_REG_31(PICOJAVA, 0xff7f); - - Opcode(int opcode) { - this(STANDARD, opcode, NO_OPERANDS); - } - - Opcode(int opcode, Instruction.Kind kind) { - this(STANDARD, opcode, kind); - } - - Opcode(Set set, int opcode) { - this(set, opcode, (set == STANDARD ? NO_OPERANDS : WIDE_NO_OPERANDS)); - } - - Opcode(Set set, int opcode, Instruction.Kind kind) { - this.set = set; - this.opcode = opcode; - this.kind = kind; - } - - public final Set set; - public final int opcode; - public final Instruction.Kind kind; - - /** Get the Opcode for a simple standard 1-byte opcode. */ - public static Opcode get(int opcode) { - return stdOpcodes[opcode]; - } - - /** Get the Opcode for 1- or 2-byte opcode. */ - public static Opcode get(int opcodePrefix, int opcode) { - Opcode[] block = getOpcodeBlock(opcodePrefix); - return (block == null ? null : block[opcode]); - } - - private static Opcode[] getOpcodeBlock(int opcodePrefix) { - switch (opcodePrefix) { - case 0: - return stdOpcodes; - case WIDE: - return wideOpcodes; - case NONPRIV: - return nonPrivOpcodes; - case PRIV: - return privOpcodes; - default: - return null; - } - - } - - private static final Opcode[] stdOpcodes = new Opcode[256]; - private static final Opcode[] wideOpcodes = new Opcode[256]; - private static final Opcode[] nonPrivOpcodes = new Opcode[256]; - private static final Opcode[] privOpcodes = new Opcode[256]; - static { - for (Opcode o: values()) - getOpcodeBlock(o.opcode >> 8)[o.opcode & 0xff] = o; - } - - /** The byte prefix for the wide instructions. */ - public static final int WIDE = 0xc4; - /** The byte prefix for the PicoJava nonpriv instructions. */ - public static final int NONPRIV = 0xfe; - /** The byte prefix for the PicoJava priv instructions. */ - public static final int PRIV = 0xff; - - public enum Set { - /** Standard opcodes. */ - STANDARD, - /** Legacy support for PicoJava opcodes. */ - PICOJAVA } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/PermittedSubclasses_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/PermittedSubclasses_attribute.java deleted file mode 100644 index fcd680fdda4aa..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/PermittedSubclasses_attribute.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; -import java.util.stream.IntStream; - -import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info; - -public class PermittedSubclasses_attribute extends Attribute { - - public int[] subtypes; - - PermittedSubclasses_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - int number_of_classes = cr.readUnsignedShort(); - subtypes = new int[number_of_classes]; - for (int i = 0; i < number_of_classes; i++) - subtypes[i] = cr.readUnsignedShort(); - } - - public PermittedSubclasses_attribute(int name_index, int[] subtypes) { - super(name_index, 2); - this.subtypes = subtypes; - } - - public CONSTANT_Class_info[] getSubtypes(ConstantPool constant_pool) throws ConstantPoolException { - return IntStream.of(subtypes) - .mapToObj(i -> { - try { - return constant_pool.getClassInfo(i); - } catch (ConstantPoolException ex) { - throw new AssertionError(ex); - } - }).toArray(CONSTANT_Class_info[]::new); - } - - @Override - public R accept(Visitor visitor, D data) { - return visitor.visitPermittedSubclasses(this, data); - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Record_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Record_attribute.java deleted file mode 100644 index 8d67e6c3016f9..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Record_attribute.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; -import com.sun.tools.classfile.Attribute.Visitor; - -/** - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Record_attribute extends Attribute { - Record_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - component_count = cr.readUnsignedShort(); - component_info_arr = new ComponentInfo[component_count]; - for (int i = 0; i < component_count; i++) { - component_info_arr[i] = new ComponentInfo(cr); - } - } - - public Record_attribute(int name_index, ComponentInfo[] component_info_arr) { - super(name_index, 2); - this.component_count = component_info_arr.length; - this.component_info_arr = component_info_arr; - } - - @Override - public R accept(Visitor visitor, D data) { - return visitor.visitRecord(this, data); - } - - public final int component_count; - public final ComponentInfo[] component_info_arr; - - public static class ComponentInfo { - ComponentInfo(ClassReader cr) throws IOException { - name_index = cr.readUnsignedShort(); - descriptor = new Descriptor(cr); - attributes = new Attributes(cr); - } - - public ComponentInfo(int name_index, Descriptor descriptor, Attributes attributes) { - this.name_index = name_index; - this.descriptor = descriptor; - this.attributes = attributes; - } - - public String getName(ConstantPool constant_pool) throws ConstantPoolException { - return constant_pool.getUTF8Value(name_index); - } - - public final int name_index; - public final Descriptor descriptor; - public final Attributes attributes; - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ReferenceFinder.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ReferenceFinder.java deleted file mode 100644 index a15cb40a71833..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ReferenceFinder.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import com.sun.tools.classfile.Instruction.TypeKind; -import static com.sun.tools.classfile.ConstantPool.*; - -/** - * A utility class to find where in a ClassFile references - * a {@link CONSTANT_Methodref_info method}, - * a {@link CONSTANT_InterfaceMethodref_info interface method}, - * or a {@link CONSTANT_Fieldref_info field}. - */ -public final class ReferenceFinder { - /** - * Filter for ReferenceFinder of what constant pool entries for reference lookup. - */ - public interface Filter { - /** - * Decides if the given CPRefInfo entry should be accepted or filtered. - * - * @param cpool ConstantPool of the ClassFile being parsed - * @param cpref constant pool entry representing a reference to - * a fields method, and interface method. - * @return {@code true} if accepted; otherwise {@code false} - */ - boolean accept(ConstantPool cpool, CPRefInfo cpref); - } - - /** - * Visitor of individual method of a ClassFile that references the - * accepted field, method, or interface method references. - */ - public interface Visitor { - /** - * Invoked for a method containing one or more accepted CPRefInfo entries - * - * @param cf ClassFile - * @param method Method that does the references the accepted references - * @param refs Accepted constant pool method/field reference - */ - void visit(ClassFile cf, Method method, List refConstantPool); - } - - private final Filter filter; - private final Visitor visitor; - - /** - * Constructor. - */ - public ReferenceFinder(Filter filter, Visitor visitor) { - this.filter = Objects.requireNonNull(filter); - this.visitor = Objects.requireNonNull(visitor); - } - - /** - * Parses a given ClassFile and invoke the visitor if there is any reference - * to the constant pool entries referencing field, method, or - * interface method that are accepted. This method will return - * {@code true} if there is one or more accepted constant pool entries - * to lookup; otherwise, it will return {@code false}. - * - * @param cf ClassFile - * @return {@code true} if the given class file is processed to lookup - * references - * @throws ConstantPoolException if an error of the constant pool - */ - public boolean parse(ClassFile cf) throws ConstantPoolException { - List cprefs = new ArrayList<>(); - int index = 1; - for (ConstantPool.CPInfo cpInfo : cf.constant_pool.entries()) { - if (cpInfo.accept(cpVisitor, cf.constant_pool)) { - cprefs.add(index); - } - index += cpInfo.size(); - } - - if (cprefs.isEmpty()) { - return false; - } - - for (Method m : cf.methods) { - Set ids = new HashSet<>(); - Code_attribute c_attr = (Code_attribute) m.attributes.get(Attribute.Code); - if (c_attr != null) { - for (Instruction instr : c_attr.getInstructions()) { - int idx = instr.accept(codeVisitor, cprefs); - if (idx > 0) { - ids.add(idx); - } - } - } - if (ids.size() > 0) { - List refInfos = new ArrayList<>(ids.size()); - for (int id : ids) { - refInfos.add(CPRefInfo.class.cast(cf.constant_pool.get(id))); - } - visitor.visit(cf, m, refInfos); - } - } - return true; - } - - private ConstantPool.Visitor cpVisitor = - new ConstantPool.Visitor() - { - public Boolean visitClass(CONSTANT_Class_info info, ConstantPool cpool) { - return false; - } - - public Boolean visitFieldref(CONSTANT_Fieldref_info info, ConstantPool cpool) { - return filter.accept(cpool, info); - } - - public Boolean visitDouble(CONSTANT_Double_info info, ConstantPool cpool) { - return false; - } - - public Boolean visitFloat(CONSTANT_Float_info info, ConstantPool cpool) { - return false; - } - - public Boolean visitInteger(CONSTANT_Integer_info info, ConstantPool cpool) { - return false; - } - - public Boolean visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, ConstantPool cpool) { - return filter.accept(cpool, info); - } - - public Boolean visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, ConstantPool cpool) { - return false; - } - - @Override - public Boolean visitDynamicConstant(CONSTANT_Dynamic_info info, ConstantPool constantPool) { - return false; - } - - public Boolean visitLong(CONSTANT_Long_info info, ConstantPool cpool) { - return false; - } - - public Boolean visitMethodHandle(CONSTANT_MethodHandle_info info, ConstantPool cpool) { - return false; - } - - public Boolean visitMethodref(CONSTANT_Methodref_info info, ConstantPool cpool) { - return filter.accept(cpool, info); - } - - public Boolean visitMethodType(CONSTANT_MethodType_info info, ConstantPool cpool) { - return false; - } - - public Boolean visitModule(CONSTANT_Module_info info, ConstantPool cpool) { - return false; - } - - public Boolean visitNameAndType(CONSTANT_NameAndType_info info, ConstantPool cpool) { - return false; - } - - public Boolean visitPackage(CONSTANT_Package_info info, ConstantPool cpool) { - return false; - } - - public Boolean visitString(CONSTANT_String_info info, ConstantPool cpool) { - return false; - } - - public Boolean visitUtf8(CONSTANT_Utf8_info info, ConstantPool cpool) { - return false; - } - }; - - private Instruction.KindVisitor> codeVisitor = - new Instruction.KindVisitor>() - { - public Integer visitNoOperands(Instruction instr, List p) { - return 0; - } - - public Integer visitArrayType(Instruction instr, TypeKind kind, List p) { - return 0; - } - - public Integer visitBranch(Instruction instr, int offset, List p) { - return 0; - } - - public Integer visitConstantPoolRef(Instruction instr, int index, List p) { - return p.contains(index) ? index : 0; - } - - public Integer visitConstantPoolRefAndValue(Instruction instr, int index, int value, List p) { - return p.contains(index) ? index : 0; - } - - public Integer visitLocal(Instruction instr, int index, List p) { - return 0; - } - - public Integer visitLocalAndValue(Instruction instr, int index, int value, List p) { - return 0; - } - - public Integer visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, List p) { - return 0; - } - - public Integer visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, List p) { - return 0; - } - - public Integer visitValue(Instruction instr, int value, List p) { - return 0; - } - - public Integer visitUnknown(Instruction instr, List p) { - return 0; - } - }; -} - diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeAnnotations_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeAnnotations_attribute.java deleted file mode 100644 index 859cec405da03..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeAnnotations_attribute.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.16 and 4.8.17. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public abstract class RuntimeAnnotations_attribute extends Attribute { - protected RuntimeAnnotations_attribute(ClassReader cr, int name_index, int length) - throws IOException, Annotation.InvalidAnnotation { - super(name_index, length); - int num_annotations = cr.readUnsignedShort(); - annotations = new Annotation[num_annotations]; - for (int i = 0; i < annotations.length; i++) - annotations[i] = new Annotation(cr); - } - - protected RuntimeAnnotations_attribute(int name_index, Annotation[] annotations) { - super(name_index, length(annotations)); - this.annotations = annotations; - } - - private static int length(Annotation[] annos) { - int n = 2; - for (Annotation anno: annos) - n += anno.length(); - return n; - } - - public final Annotation[] annotations; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeInvisibleAnnotations_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeInvisibleAnnotations_attribute.java deleted file mode 100644 index ed700823cd54e..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeInvisibleAnnotations_attribute.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.17. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class RuntimeInvisibleAnnotations_attribute extends RuntimeAnnotations_attribute { - RuntimeInvisibleAnnotations_attribute(ClassReader cr, int name_index, int length) - throws IOException, AttributeException { - super(cr, name_index, length); - } - - public RuntimeInvisibleAnnotations_attribute(ConstantPool cp, Annotation[] annotations) - throws ConstantPoolException { - this(cp.getUTF8Index(Attribute.RuntimeInvisibleAnnotations), annotations); - } - - public RuntimeInvisibleAnnotations_attribute(int name_index, Annotation[] annotations) { - super(name_index, annotations); - } - - public R accept(Visitor visitor, P p) { - return visitor.visitRuntimeInvisibleAnnotations(this, p); - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeInvisibleParameterAnnotations_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeInvisibleParameterAnnotations_attribute.java deleted file mode 100644 index 57de543a90321..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeInvisibleParameterAnnotations_attribute.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.18. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class RuntimeInvisibleParameterAnnotations_attribute extends RuntimeParameterAnnotations_attribute { - RuntimeInvisibleParameterAnnotations_attribute(ClassReader cr, int name_index, int length) - throws IOException, Annotation.InvalidAnnotation { - super(cr, name_index, length); - } - - public RuntimeInvisibleParameterAnnotations_attribute(ConstantPool cp, Annotation[][] parameter_annotations) - throws ConstantPoolException { - this(cp.getUTF8Index(Attribute.RuntimeInvisibleParameterAnnotations), parameter_annotations); - } - - public RuntimeInvisibleParameterAnnotations_attribute(int name_index, Annotation[][] parameter_annotations) { - super(name_index, parameter_annotations); - } - - public R accept(Visitor visitor, P p) { - return visitor.visitRuntimeInvisibleParameterAnnotations(this, p); - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeInvisibleTypeAnnotations_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeInvisibleTypeAnnotations_attribute.java deleted file mode 100644 index 672bb55420f90..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeInvisibleTypeAnnotations_attribute.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JSR 308 specification, Section 3. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class RuntimeInvisibleTypeAnnotations_attribute extends RuntimeTypeAnnotations_attribute { - RuntimeInvisibleTypeAnnotations_attribute(ClassReader cr, int name_index, int length) - throws IOException, Annotation.InvalidAnnotation { - super(cr, name_index, length); - } - - public RuntimeInvisibleTypeAnnotations_attribute(ConstantPool cp, TypeAnnotation[] annotations) - throws ConstantPoolException { - this(cp.getUTF8Index(Attribute.RuntimeInvisibleTypeAnnotations), annotations); - } - - public RuntimeInvisibleTypeAnnotations_attribute(int name_index, TypeAnnotation[] annotations) { - super(name_index, annotations); - } - - public R accept(Visitor visitor, P p) { - return visitor.visitRuntimeInvisibleTypeAnnotations(this, p); - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeParameterAnnotations_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeParameterAnnotations_attribute.java deleted file mode 100644 index 904010f649f43..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeParameterAnnotations_attribute.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.18 and 4.8.19. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public abstract class RuntimeParameterAnnotations_attribute extends Attribute { - RuntimeParameterAnnotations_attribute(ClassReader cr, int name_index, int length) - throws IOException, Annotation.InvalidAnnotation { - super(name_index, length); - int num_parameters = cr.readUnsignedByte(); - parameter_annotations = new Annotation[num_parameters][]; - for (int p = 0; p < parameter_annotations.length; p++) { - int num_annotations = cr.readUnsignedShort(); - Annotation[] annotations = new Annotation[num_annotations]; - for (int i = 0; i < num_annotations; i++) - annotations[i] = new Annotation(cr); - parameter_annotations[p] = annotations; - } - } - - protected RuntimeParameterAnnotations_attribute(int name_index, Annotation[][] parameter_annotations) { - super(name_index, length(parameter_annotations)); - this.parameter_annotations = parameter_annotations; - } - - private static int length(Annotation[][] anno_arrays) { - int n = 1; - for (Annotation[] anno_array: anno_arrays) { - n += 2; - for (Annotation anno: anno_array) - n += anno.length(); - } - return n; - } - - public final Annotation[][] parameter_annotations; -} - diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeTypeAnnotations_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeTypeAnnotations_attribute.java deleted file mode 100644 index 162e0765c7e93..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeTypeAnnotations_attribute.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JSR 308 specification, Section 3. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public abstract class RuntimeTypeAnnotations_attribute extends Attribute { - protected RuntimeTypeAnnotations_attribute(ClassReader cr, int name_index, int length) - throws IOException, Annotation.InvalidAnnotation { - super(name_index, length); - int num_annotations = cr.readUnsignedShort(); - annotations = new TypeAnnotation[num_annotations]; - for (int i = 0; i < annotations.length; i++) - annotations[i] = new TypeAnnotation(cr); - } - - protected RuntimeTypeAnnotations_attribute(int name_index, TypeAnnotation[] annotations) { - super(name_index, length(annotations)); - this.annotations = annotations; - } - - private static int length(TypeAnnotation[] annos) { - int n = 2; - for (TypeAnnotation anno: annos) - n += anno.length(); - return n; - } - - public final TypeAnnotation[] annotations; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeVisibleAnnotations_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeVisibleAnnotations_attribute.java deleted file mode 100644 index c7a443905c6b1..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeVisibleAnnotations_attribute.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.16. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class RuntimeVisibleAnnotations_attribute extends RuntimeAnnotations_attribute { - RuntimeVisibleAnnotations_attribute(ClassReader cr, int name_index, int length) - throws IOException, Annotation.InvalidAnnotation { - super(cr, name_index, length); - } - - public RuntimeVisibleAnnotations_attribute(ConstantPool cp, Annotation[] annotations) - throws ConstantPoolException { - this(cp.getUTF8Index(Attribute.RuntimeVisibleAnnotations), annotations); - } - - public RuntimeVisibleAnnotations_attribute(int name_index, Annotation[] annotations) { - super(name_index, annotations); - } - - public R accept(Visitor visitor, P p) { - return visitor.visitRuntimeVisibleAnnotations(this, p); - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeVisibleParameterAnnotations_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeVisibleParameterAnnotations_attribute.java deleted file mode 100644 index 24214e7e2a255..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeVisibleParameterAnnotations_attribute.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.18. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class RuntimeVisibleParameterAnnotations_attribute extends RuntimeParameterAnnotations_attribute { - RuntimeVisibleParameterAnnotations_attribute(ClassReader cr, int name_index, int length) - throws IOException, Annotation.InvalidAnnotation { - super(cr, name_index, length); - } - - public RuntimeVisibleParameterAnnotations_attribute(ConstantPool cp, Annotation[][] parameter_annotations) - throws ConstantPoolException { - this(cp.getUTF8Index(Attribute.RuntimeVisibleParameterAnnotations), parameter_annotations); - } - - public RuntimeVisibleParameterAnnotations_attribute(int name_index, Annotation[][] parameter_annotations) { - super(name_index, parameter_annotations); - } - - public R accept(Visitor visitor, P p) { - return visitor.visitRuntimeVisibleParameterAnnotations(this, p); - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeVisibleTypeAnnotations_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeVisibleTypeAnnotations_attribute.java deleted file mode 100644 index 851c1f7d90723..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/RuntimeVisibleTypeAnnotations_attribute.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JSR 308 specification, Section 3. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class RuntimeVisibleTypeAnnotations_attribute extends RuntimeTypeAnnotations_attribute { - RuntimeVisibleTypeAnnotations_attribute(ClassReader cr, int name_index, int length) - throws IOException, Annotation.InvalidAnnotation { - super(cr, name_index, length); - } - - public RuntimeVisibleTypeAnnotations_attribute(ConstantPool cp, TypeAnnotation[] annotations) - throws ConstantPoolException { - this(cp.getUTF8Index(Attribute.RuntimeVisibleTypeAnnotations), annotations); - } - - public RuntimeVisibleTypeAnnotations_attribute(int name_index, TypeAnnotation[] annotations) { - super(name_index, annotations); - } - - public R accept(Visitor visitor, P p) { - return visitor.visitRuntimeVisibleTypeAnnotations(this, p); - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Signature.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Signature.java deleted file mode 100644 index 384c7080d7107..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Signature.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.util.ArrayList; -import java.util.List; -import com.sun.tools.classfile.Type.*; - -/** - * See JVMS 4.4.4. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Signature extends Descriptor { - - public Signature(int index) { - super(index); - } - - public Type getType(ConstantPool constant_pool) throws ConstantPoolException { - if (type == null) - type = parse(getValue(constant_pool)); - return type; - } - - @Override - public int getParameterCount(ConstantPool constant_pool) throws ConstantPoolException { - MethodType m = (MethodType) getType(constant_pool); - return m.paramTypes.size(); - } - - @Override - public String getParameterTypes(ConstantPool constant_pool) throws ConstantPoolException { - MethodType m = (MethodType) getType(constant_pool); - StringBuilder sb = new StringBuilder(); - sb.append("("); - String sep = ""; - for (Type paramType: m.paramTypes) { - sb.append(sep); - sb.append(paramType); - sep = ", "; - } - sb.append(")"); - return sb.toString(); - } - - @Override - public String getReturnType(ConstantPool constant_pool) throws ConstantPoolException { - MethodType m = (MethodType) getType(constant_pool); - return m.returnType.toString(); - } - - @Override - public String getFieldType(ConstantPool constant_pool) throws ConstantPoolException { - return getType(constant_pool).toString(); - } - - private Type parse(String sig) { - this.sig = sig; - sigp = 0; - - List typeParamTypes = null; - if (sig.charAt(sigp) == '<') - typeParamTypes = parseTypeParamTypes(); - - if (sig.charAt(sigp) == '(') { - List paramTypes = parseTypeSignatures(')'); - Type returnType = parseTypeSignature(); - List throwsTypes = null; - while (sigp < sig.length() && sig.charAt(sigp) == '^') { - sigp++; - if (throwsTypes == null) - throwsTypes = new ArrayList<>(); - throwsTypes.add(parseTypeSignature()); - } - return new MethodType(typeParamTypes, paramTypes, returnType, throwsTypes); - } else { - Type t = parseTypeSignature(); - if (typeParamTypes == null && sigp == sig.length()) - return t; - Type superclass = t; - List superinterfaces = null; - while (sigp < sig.length()) { - if (superinterfaces == null) - superinterfaces = new ArrayList<>(); - superinterfaces.add(parseTypeSignature()); - } - return new ClassSigType(typeParamTypes, superclass, superinterfaces); - - } - } - - private Type parseTypeSignature() { - switch (sig.charAt(sigp)) { - case 'B': - sigp++; - return new SimpleType("byte"); - - case 'C': - sigp++; - return new SimpleType("char"); - - case 'D': - sigp++; - return new SimpleType("double"); - - case 'F': - sigp++; - return new SimpleType("float"); - - case 'I': - sigp++; - return new SimpleType("int"); - - case 'J': - sigp++; - return new SimpleType("long"); - - case 'L': - return parseClassTypeSignature(); - - case 'S': - sigp++; - return new SimpleType("short"); - - case 'T': - return parseTypeVariableSignature(); - - case 'V': - sigp++; - return new SimpleType("void"); - - case 'Z': - sigp++; - return new SimpleType("boolean"); - - case '[': - sigp++; - return new ArrayType(parseTypeSignature()); - - case '*': - sigp++; - return new WildcardType(); - - case '+': - sigp++; - return new WildcardType(WildcardType.Kind.EXTENDS, parseTypeSignature()); - - case '-': - sigp++; - return new WildcardType(WildcardType.Kind.SUPER, parseTypeSignature()); - - default: - throw new IllegalStateException(debugInfo()); - } - } - - private List parseTypeSignatures(char term) { - sigp++; - List types = new ArrayList<>(); - while (sig.charAt(sigp) != term) - types.add(parseTypeSignature()); - sigp++; - return types; - } - - private Type parseClassTypeSignature() { - assert sig.charAt(sigp) == 'L'; - sigp++; - return parseClassTypeSignatureRest(); - } - - private Type parseClassTypeSignatureRest() { - StringBuilder sb = new StringBuilder(); - List argTypes = null; - ClassType t = null; - char sigch ; - - do { - switch (sigch = sig.charAt(sigp)) { - case '<': - argTypes = parseTypeSignatures('>'); - break; - - case '.': - case ';': - sigp++; - t = new ClassType(t, sb.toString(), argTypes); - sb.setLength(0); - argTypes = null; - break; - - default: - sigp++; - sb.append(sigch); - break; - } - } while (sigch != ';'); - - return t; - } - - private List parseTypeParamTypes() { - assert sig.charAt(sigp) == '<'; - sigp++; - List types = new ArrayList<>(); - while (sig.charAt(sigp) != '>') - types.add(parseTypeParamType()); - sigp++; - return types; - } - - private TypeParamType parseTypeParamType() { - int sep = sig.indexOf(":", sigp); - String name = sig.substring(sigp, sep); - Type classBound = null; - List interfaceBounds = null; - sigp = sep + 1; - if (sig.charAt(sigp) != ':') - classBound = parseTypeSignature(); - while (sig.charAt(sigp) == ':') { - sigp++; - if (interfaceBounds == null) - interfaceBounds = new ArrayList<>(); - interfaceBounds.add(parseTypeSignature()); - } - return new TypeParamType(name, classBound, interfaceBounds); - } - - private Type parseTypeVariableSignature() { - sigp++; - int sep = sig.indexOf(';', sigp); - Type t = new SimpleType(sig.substring(sigp, sep)); - sigp = sep + 1; - return t; - } - - private String debugInfo() { - return sig.substring(0, sigp) + "!" + sig.charAt(sigp) + "!" + sig.substring(sigp+1); - } - - private String sig; - private int sigp; - - private Type type; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Signature_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Signature_attribute.java deleted file mode 100644 index acb9475c7981e..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Signature_attribute.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.9. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Signature_attribute extends Attribute { - Signature_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - signature_index = cr.readUnsignedShort(); - } - - public Signature_attribute(ConstantPool constant_pool, int signature_index) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.Signature), signature_index); - } - - public Signature_attribute(int name_index, int signature_index) { - super(name_index, 2); - this.signature_index = signature_index; - } - - public String getSignature(ConstantPool constant_pool) throws ConstantPoolException { - return constant_pool.getUTF8Value(signature_index); - } - - public Signature getParsedSignature() { - return new Signature(signature_index); - } - - public R accept(Visitor visitor, D data) { - return visitor.visitSignature(this, data); - } - - public final int signature_index; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/SourceDebugExtension_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/SourceDebugExtension_attribute.java deleted file mode 100644 index 22e87723d2ff6..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/SourceDebugExtension_attribute.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.IOException; - -import static java.nio.charset.StandardCharsets.UTF_8; - -/** - * See JVMS, section 4.8.15. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class SourceDebugExtension_attribute extends Attribute { - - SourceDebugExtension_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - debug_extension = new byte[attribute_length]; - cr.readFully(debug_extension); - } - - public SourceDebugExtension_attribute(ConstantPool constant_pool, byte[] debug_extension) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.SourceDebugExtension), debug_extension); - } - - public SourceDebugExtension_attribute(int name_index, byte[] debug_extension) { - super(name_index, debug_extension.length); - this.debug_extension = debug_extension; - } - - public String getValue() { - return new String(debug_extension, UTF_8); - } - - public R accept(Visitor visitor, D data) { - return visitor.visitSourceDebugExtension(this, data); - } - - public final byte[] debug_extension; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/SourceFile_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/SourceFile_attribute.java deleted file mode 100644 index c3b7509d165dd..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/SourceFile_attribute.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.10. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class SourceFile_attribute extends Attribute { - SourceFile_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - sourcefile_index = cr.readUnsignedShort(); - } - - public SourceFile_attribute(ConstantPool constant_pool, int sourcefile_index) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.SourceFile), sourcefile_index); - } - - public SourceFile_attribute(int name_index, int sourcefile_index) { - super(name_index, 2); - this.sourcefile_index = sourcefile_index; - } - - public String getSourceFile(ConstantPool constant_pool) throws ConstantPoolException { - return constant_pool.getUTF8Value(sourcefile_index); - } - - public R accept(Visitor visitor, P p) { - return visitor.visitSourceFile(this, p); - } - - public final int sourcefile_index; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/SourceID_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/SourceID_attribute.java deleted file mode 100644 index d8c1e523c9d5e..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/SourceID_attribute.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class SourceID_attribute extends Attribute { - - SourceID_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - sourceID_index = cr.readUnsignedShort(); - } - - public SourceID_attribute(ConstantPool constant_pool, int sourceID_index) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.SourceID), sourceID_index); - } - - public SourceID_attribute(int name_index, int sourceID_index) { - super(name_index, 2); - this.sourceID_index = sourceID_index; - } - - String getSourceID(ConstantPool constant_pool) throws ConstantPoolException { - return constant_pool.getUTF8Value(sourceID_index); - } - - public R accept(Visitor visitor, D data) { - return visitor.visitSourceID(this, data); - } - - public final int sourceID_index; -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/StackMapTable_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/StackMapTable_attribute.java deleted file mode 100644 index a0f94f1bbd5f0..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/StackMapTable_attribute.java +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.4. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class StackMapTable_attribute extends Attribute { - static class InvalidStackMap extends AttributeException { - private static final long serialVersionUID = -5659038410855089780L; - InvalidStackMap(String msg) { - super(msg); - } - } - - StackMapTable_attribute(ClassReader cr, int name_index, int length) - throws IOException, InvalidStackMap { - super(name_index, length); - number_of_entries = cr.readUnsignedShort(); - entries = new stack_map_frame[number_of_entries]; - for (int i = 0; i < number_of_entries; i++) - entries[i] = stack_map_frame.read(cr); - } - - public StackMapTable_attribute(ConstantPool constant_pool, stack_map_frame[] entries) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.StackMapTable), entries); - } - - public StackMapTable_attribute(int name_index, stack_map_frame[] entries) { - super(name_index, length(entries)); - this.number_of_entries = entries.length; - this.entries = entries; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitStackMapTable(this, data); - } - - static int length(stack_map_frame[] entries) { - int n = 2; - for (stack_map_frame entry: entries) - n += entry.length(); - return n; - } - - public final int number_of_entries; - public final stack_map_frame entries[]; - - public abstract static class stack_map_frame { - static stack_map_frame read(ClassReader cr) - throws IOException, InvalidStackMap { - int frame_type = cr.readUnsignedByte(); - if (frame_type <= 63) - return new same_frame(frame_type); - else if (frame_type <= 127) - return new same_locals_1_stack_item_frame(frame_type, cr); - else if (frame_type <= 246) - throw new Error("unknown frame_type " + frame_type); - else if (frame_type == 247) - return new same_locals_1_stack_item_frame_extended(frame_type, cr); - else if (frame_type <= 250) - return new chop_frame(frame_type, cr); - else if (frame_type == 251) - return new same_frame_extended(frame_type, cr); - else if (frame_type <= 254) - return new append_frame(frame_type, cr); - else - return new full_frame(frame_type, cr); - } - - protected stack_map_frame(int frame_type) { - this.frame_type = frame_type; - } - - public int length() { - return 1; - } - - public abstract int getOffsetDelta(); - - public abstract R accept(Visitor visitor, D data); - - public final int frame_type; - - public static interface Visitor { - R visit_same_frame(same_frame frame, P p); - R visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, P p); - R visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, P p); - R visit_chop_frame(chop_frame frame, P p); - R visit_same_frame_extended(same_frame_extended frame, P p); - R visit_append_frame(append_frame frame, P p); - R visit_full_frame(full_frame frame, P p); - } - } - - public static class same_frame extends stack_map_frame { - same_frame(int frame_type) { - super(frame_type); - } - - public R accept(Visitor visitor, D data) { - return visitor.visit_same_frame(this, data); - } - - public int getOffsetDelta() { - return frame_type; - } - } - - public static class same_locals_1_stack_item_frame extends stack_map_frame { - same_locals_1_stack_item_frame(int frame_type, ClassReader cr) - throws IOException, InvalidStackMap { - super(frame_type); - stack = new verification_type_info[1]; - stack[0] = verification_type_info.read(cr); - } - - @Override - public int length() { - return super.length() + stack[0].length(); - } - - public R accept(Visitor visitor, D data) { - return visitor.visit_same_locals_1_stack_item_frame(this, data); - } - - public int getOffsetDelta() { - return frame_type - 64; - } - - public final verification_type_info[] stack; - } - - public static class same_locals_1_stack_item_frame_extended extends stack_map_frame { - same_locals_1_stack_item_frame_extended(int frame_type, ClassReader cr) - throws IOException, InvalidStackMap { - super(frame_type); - offset_delta = cr.readUnsignedShort(); - stack = new verification_type_info[1]; - stack[0] = verification_type_info.read(cr); - } - - @Override - public int length() { - return super.length() + 2 + stack[0].length(); - } - - public R accept(Visitor visitor, D data) { - return visitor.visit_same_locals_1_stack_item_frame_extended(this, data); - } - - public int getOffsetDelta() { - return offset_delta; - } - - public final int offset_delta; - public final verification_type_info[] stack; - } - - public static class chop_frame extends stack_map_frame { - chop_frame(int frame_type, ClassReader cr) throws IOException { - super(frame_type); - offset_delta = cr.readUnsignedShort(); - } - - @Override - public int length() { - return super.length() + 2; - } - - public R accept(Visitor visitor, D data) { - return visitor.visit_chop_frame(this, data); - } - - public int getOffsetDelta() { - return offset_delta; - } - - public final int offset_delta; - } - - public static class same_frame_extended extends stack_map_frame { - same_frame_extended(int frame_type, ClassReader cr) throws IOException { - super(frame_type); - offset_delta = cr.readUnsignedShort(); - } - - @Override - public int length() { - return super.length() + 2; - } - - public R accept(Visitor visitor, D data) { - return visitor.visit_same_frame_extended(this, data); - } - - public int getOffsetDelta() { - return offset_delta; - } - - public final int offset_delta; - } - - public static class append_frame extends stack_map_frame { - append_frame(int frame_type, ClassReader cr) - throws IOException, InvalidStackMap { - super(frame_type); - offset_delta = cr.readUnsignedShort(); - locals = new verification_type_info[frame_type - 251]; - for (int i = 0; i < locals.length; i++) - locals[i] = verification_type_info.read(cr); - } - - @Override - public int length() { - int n = super.length() + 2; - for (verification_type_info local: locals) - n += local.length(); - return n; - } - - public R accept(Visitor visitor, D data) { - return visitor.visit_append_frame(this, data); - } - - public int getOffsetDelta() { - return offset_delta; - } - - public final int offset_delta; - public final verification_type_info[] locals; - } - - public static class full_frame extends stack_map_frame { - full_frame(int frame_type, ClassReader cr) - throws IOException, InvalidStackMap { - super(frame_type); - offset_delta = cr.readUnsignedShort(); - number_of_locals = cr.readUnsignedShort(); - locals = new verification_type_info[number_of_locals]; - for (int i = 0; i < locals.length; i++) - locals[i] = verification_type_info.read(cr); - number_of_stack_items = cr.readUnsignedShort(); - stack = new verification_type_info[number_of_stack_items]; - for (int i = 0; i < stack.length; i++) - stack[i] = verification_type_info.read(cr); - } - - @Override - public int length() { - int n = super.length() + 2; - for (verification_type_info local: locals) - n += local.length(); - n += 2; - for (verification_type_info item: stack) - n += item.length(); - return n; - } - - public R accept(Visitor visitor, D data) { - return visitor.visit_full_frame(this, data); - } - - public int getOffsetDelta() { - return offset_delta; - } - - public final int offset_delta; - public final int number_of_locals; - public final verification_type_info[] locals; - public final int number_of_stack_items; - public final verification_type_info[] stack; - } - - public static class verification_type_info { - public static final int ITEM_Top = 0; - public static final int ITEM_Integer = 1; - public static final int ITEM_Float = 2; - public static final int ITEM_Long = 4; - public static final int ITEM_Double = 3; - public static final int ITEM_Null = 5; - public static final int ITEM_UninitializedThis = 6; - public static final int ITEM_Object = 7; - public static final int ITEM_Uninitialized = 8; - - static verification_type_info read(ClassReader cr) - throws IOException, InvalidStackMap { - int tag = cr.readUnsignedByte(); - switch (tag) { - case ITEM_Top: - case ITEM_Integer: - case ITEM_Float: - case ITEM_Long: - case ITEM_Double: - case ITEM_Null: - case ITEM_UninitializedThis: - return new verification_type_info(tag); - - case ITEM_Object: - return new Object_variable_info(cr); - - case ITEM_Uninitialized: - return new Uninitialized_variable_info(cr); - - default: - throw new InvalidStackMap("unrecognized verification_type_info tag"); - } - } - - protected verification_type_info(int tag) { - this.tag = tag; - } - - public int length() { - return 1; - } - - public final int tag; - } - - public static class Object_variable_info extends verification_type_info { - Object_variable_info(ClassReader cr) throws IOException { - super(ITEM_Object); - cpool_index = cr.readUnsignedShort(); - } - - @Override - public int length() { - return super.length() + 2; - } - - public final int cpool_index; - } - - public static class Uninitialized_variable_info extends verification_type_info { - Uninitialized_variable_info(ClassReader cr) throws IOException { - super(ITEM_Uninitialized); - offset = cr.readUnsignedShort(); - } - - @Override - public int length() { - return super.length() + 2; - } - - public final int offset; - - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/StackMap_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/StackMap_attribute.java deleted file mode 100644 index e57a24bfa981e..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/StackMap_attribute.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class StackMap_attribute extends Attribute { - StackMap_attribute(ClassReader cr, int name_index, int length) - throws IOException, StackMapTable_attribute.InvalidStackMap { - super(name_index, length); - number_of_entries = cr.readUnsignedShort(); - entries = new stack_map_frame[number_of_entries]; - for (int i = 0; i < number_of_entries; i++) - entries[i] = new stack_map_frame(cr); - } - - public StackMap_attribute(ConstantPool constant_pool, stack_map_frame[] entries) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.StackMap), entries); - } - - public StackMap_attribute(int name_index, stack_map_frame[] entries) { - super(name_index, StackMapTable_attribute.length(entries)); - this.number_of_entries = entries.length; - this.entries = entries; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitStackMap(this, data); - } - - public final int number_of_entries; - public final stack_map_frame entries[]; - - public static class stack_map_frame extends StackMapTable_attribute.full_frame { - stack_map_frame(ClassReader cr) - throws IOException, StackMapTable_attribute.InvalidStackMap { - super(255, cr); - } - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Synthetic_attribute.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Synthetic_attribute.java deleted file mode 100644 index 0b7f933d78765..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Synthetic_attribute.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JVMS, section 4.8.8. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Synthetic_attribute extends Attribute { - Synthetic_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - } - - public Synthetic_attribute(ConstantPool constant_pool) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.Synthetic)); - } - - public Synthetic_attribute(int name_index) { - super(name_index, 0); - } - - public R accept(Visitor visitor, D data) { - return visitor.visitSynthetic(this, data); - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Type.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Type.java deleted file mode 100644 index 478d1607324a0..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Type.java +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/* - * Family of classes used to represent the parsed form of a {@link Descriptor} - * or {@link Signature}. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public abstract class Type { - protected Type() { } - - public boolean isObject() { - return false; - } - - public abstract R accept(Visitor visitor, D data); - - protected static void append(StringBuilder sb, String prefix, List types, String suffix) { - sb.append(prefix); - String sep = ""; - for (Type t: types) { - sb.append(sep); - sb.append(t); - sep = ", "; - } - sb.append(suffix); - } - - protected static void appendIfNotEmpty(StringBuilder sb, String prefix, List types, String suffix) { - if (types != null && types.size() > 0) - append(sb, prefix, types, suffix); - } - - public interface Visitor { - R visitSimpleType(SimpleType type, P p); - R visitArrayType(ArrayType type, P p); - R visitMethodType(MethodType type, P p); - R visitClassSigType(ClassSigType type, P p); - R visitClassType(ClassType type, P p); - R visitTypeParamType(TypeParamType type, P p); - R visitWildcardType(WildcardType type, P p); - } - - /** - * Represents a type signature with a simple name. The name may be that of a - * primitive type, such "{@code int}, {@code float}, etc - * or that of a type argument, such as {@code T}, {@code K}, {@code V}, etc. - * - * See: - * JVMS 4.3.2 - * BaseType: - * {@code B}, {@code C}, {@code D}, {@code F}, {@code I}, - * {@code J}, {@code S}, {@code Z}; - * VoidDescriptor: - * {@code V}; - * JVMS 4.3.4 - * TypeVariableSignature: - * {@code T} Identifier {@code ;} - */ - public static class SimpleType extends Type { - public SimpleType(String name) { - this.name = name; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitSimpleType(this, data); - } - - public boolean isPrimitiveType() { - return primitiveTypes.contains(name); - } - // where - private static final Set primitiveTypes = new HashSet<>(Arrays.asList( - "boolean", "byte", "char", "double", "float", "int", "long", "short", "void")); - - @Override - public String toString() { - return name; - } - - public final String name; - } - - /** - * Represents an array type signature. - * - * See: - * JVMS 4.3.4 - * ArrayTypeSignature: - * {@code [} TypeSignature {@code ]} - */ - public static class ArrayType extends Type { - public ArrayType(Type elemType) { - this.elemType = elemType; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitArrayType(this, data); - } - - @Override - public String toString() { - return elemType + "[]"; - } - - public final Type elemType; - } - - /** - * Represents a method type signature. - * - * See; - * JVMS 4.3.4 - * MethodTypeSignature: - * FormalTypeParameters_opt {@code (} TypeSignature* {@code)} ReturnType - * ThrowsSignature* - */ - public static class MethodType extends Type { - public MethodType(List paramTypes, Type resultType) { - this(null, paramTypes, resultType, null); - } - - public MethodType(List typeParamTypes, - List paramTypes, - Type returnType, - List throwsTypes) { - this.typeParamTypes = typeParamTypes; - this.paramTypes = paramTypes; - this.returnType = returnType; - this.throwsTypes = throwsTypes; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitMethodType(this, data); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - appendIfNotEmpty(sb, "<", typeParamTypes, "> "); - sb.append(returnType); - append(sb, " (", paramTypes, ")"); - appendIfNotEmpty(sb, " throws ", throwsTypes, ""); - return sb.toString(); - } - - public final List typeParamTypes; - public final List paramTypes; - public final Type returnType; - public final List throwsTypes; - } - - /** - * Represents a class signature. These describe the signature of - * a class that has type arguments. - * - * See: - * JVMS 4.3.4 - * ClassSignature: - * FormalTypeParameters_opt SuperclassSignature SuperinterfaceSignature* - */ - public static class ClassSigType extends Type { - public ClassSigType(List typeParamTypes, Type superclassType, - List superinterfaceTypes) { - this.typeParamTypes = typeParamTypes; - this.superclassType = superclassType; - this.superinterfaceTypes = superinterfaceTypes; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitClassSigType(this, data); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - appendIfNotEmpty(sb, "<", typeParamTypes, ">"); - if (superclassType != null) { - sb.append(" extends "); - sb.append(superclassType); - } - appendIfNotEmpty(sb, " implements ", superinterfaceTypes, ""); - return sb.toString(); - } - - public final List typeParamTypes; - public final Type superclassType; - public final List superinterfaceTypes; - } - - /** - * Represents a class type signature. This is used to represent a - * reference to a class, such as in a field, parameter, return type, etc. - * - * See: - * JVMS 4.3.4 - * ClassTypeSignature: - * {@code L} PackageSpecifier_opt SimpleClassTypeSignature - * ClassTypeSignatureSuffix* {@code ;} - * PackageSpecifier: - * Identifier {@code /} PackageSpecifier* - * SimpleClassTypeSignature: - * Identifier TypeArguments_opt } - * ClassTypeSignatureSuffix: - * {@code .} SimpleClassTypeSignature - */ - public static class ClassType extends Type { - public ClassType(ClassType outerType, String name, List typeArgs) { - this.outerType = outerType; - this.name = name; - this.typeArgs = typeArgs; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitClassType(this, data); - } - - public String getBinaryName() { - if (outerType == null) - return name; - else - return (outerType.getBinaryName() + "$" + name); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - if (outerType != null) { - sb.append(outerType); - sb.append("."); - } - sb.append(name); - appendIfNotEmpty(sb, "<", typeArgs, ">"); - return sb.toString(); - } - - @Override - public boolean isObject() { - return (outerType == null) - && name.equals("java/lang/Object") - && (typeArgs == null || typeArgs.isEmpty()); - } - - public final ClassType outerType; - public final String name; - public final List typeArgs; - } - - /** - * Represents a FormalTypeParameter. These are used to declare the type - * parameters for generic classes and methods. - * - * See: - * JVMS 4.3.4 - * FormalTypeParameters: - * {@code <} FormalTypeParameter+ {@code >} - * FormalTypeParameter: - * Identifier ClassBound InterfaceBound* - * ClassBound: - * {@code :} FieldTypeSignature_opt - * InterfaceBound: - * {@code :} FieldTypeSignature - */ - public static class TypeParamType extends Type { - public TypeParamType(String name, Type classBound, List interfaceBounds) { - this.name = name; - this.classBound = classBound; - this.interfaceBounds = interfaceBounds; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitTypeParamType(this, data); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(name); - String sep = " extends "; - if (classBound != null) { - sb.append(sep); - sb.append(classBound); - sep = " & "; - } - if (interfaceBounds != null) { - for (Type bound: interfaceBounds) { - sb.append(sep); - sb.append(bound); - sep = " & "; - } - } - return sb.toString(); - } - - public final String name; - public final Type classBound; - public final List interfaceBounds; - } - - /** - * Represents a wildcard type argument. A type argument that is not a - * wildcard type argument will be represented by a ClassType, ArrayType, etc. - * - * See: - * JVMS 4.3.4 - * TypeArgument: - * WildcardIndicator_opt FieldTypeSignature - * {@code *} - * WildcardIndicator: - * {@code +} - * {@code -} - */ - public static class WildcardType extends Type { - public enum Kind { UNBOUNDED, EXTENDS, SUPER } - - public WildcardType() { - this(Kind.UNBOUNDED, null); - } - public WildcardType(Kind kind, Type boundType) { - this.kind = kind; - this.boundType = boundType; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitWildcardType(this, data); - } - - @Override - public String toString() { - switch (kind) { - case UNBOUNDED: - return "?"; - case EXTENDS: - return "? extends " + boundType; - case SUPER: - return "? super " + boundType; - default: - throw new AssertionError(); - } - } - - public final Kind kind; - public final Type boundType; - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/TypeAnnotation.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/TypeAnnotation.java deleted file mode 100644 index 65876d02b8d3d..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/TypeAnnotation.java +++ /dev/null @@ -1,654 +0,0 @@ -/* - * Copyright (c) 2009, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import com.sun.tools.classfile.TypeAnnotation.Position.TypePathEntry; - -/** - * See JSR 308 specification, Section 3. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class TypeAnnotation { - TypeAnnotation(ClassReader cr) throws IOException, Annotation.InvalidAnnotation { - constant_pool = cr.getConstantPool(); - position = read_position(cr); - annotation = new Annotation(cr); - } - - public TypeAnnotation(ConstantPool constant_pool, - Annotation annotation, Position position) { - this.constant_pool = constant_pool; - this.position = position; - this.annotation = annotation; - } - - public int length() { - int n = annotation.length(); - n += position_length(position); - return n; - } - - @Override - public String toString() { - try { - return "@" + constant_pool.getUTF8Value(annotation.type_index).substring(1) + - " pos: " + position.toString(); - } catch (Exception e) { - e.printStackTrace(); - return e.toString(); - } - } - - public final ConstantPool constant_pool; - public final Position position; - public final Annotation annotation; - - private static Position read_position(ClassReader cr) throws IOException, Annotation.InvalidAnnotation { - // Copied from ClassReader - int tag = cr.readUnsignedByte(); // TargetType tag is a byte - if (!TargetType.isValidTargetTypeValue(tag)) - throw new Annotation.InvalidAnnotation("TypeAnnotation: Invalid type annotation target type value: " + String.format("0x%02X", tag)); - - TargetType type = TargetType.fromTargetTypeValue(tag); - - Position position = new Position(); - position.type = type; - - switch (type) { - // instanceof - case INSTANCEOF: - // new expression - case NEW: - // constructor/method reference receiver - case CONSTRUCTOR_REFERENCE: - case METHOD_REFERENCE: - position.offset = cr.readUnsignedShort(); - break; - // local variable - case LOCAL_VARIABLE: - // resource variable - case RESOURCE_VARIABLE: - int table_length = cr.readUnsignedShort(); - position.lvarOffset = new int[table_length]; - position.lvarLength = new int[table_length]; - position.lvarIndex = new int[table_length]; - for (int i = 0; i < table_length; ++i) { - position.lvarOffset[i] = cr.readUnsignedShort(); - position.lvarLength[i] = cr.readUnsignedShort(); - position.lvarIndex[i] = cr.readUnsignedShort(); - } - break; - // exception parameter - case EXCEPTION_PARAMETER: - position.exception_index = cr.readUnsignedShort(); - break; - // method receiver - case METHOD_RECEIVER: - // Do nothing - break; - // type parameter - case CLASS_TYPE_PARAMETER: - case METHOD_TYPE_PARAMETER: - position.parameter_index = cr.readUnsignedByte(); - break; - // type parameter bound - case CLASS_TYPE_PARAMETER_BOUND: - case METHOD_TYPE_PARAMETER_BOUND: - position.parameter_index = cr.readUnsignedByte(); - position.bound_index = cr.readUnsignedByte(); - break; - // class extends or implements clause - case CLASS_EXTENDS: - position.type_index = cr.readUnsignedShort(); - break; - // throws - case THROWS: - position.type_index = cr.readUnsignedShort(); - break; - // method parameter - case METHOD_FORMAL_PARAMETER: - position.parameter_index = cr.readUnsignedByte(); - break; - // type cast - case CAST: - // method/constructor/reference type argument - case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: - case METHOD_INVOCATION_TYPE_ARGUMENT: - case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: - case METHOD_REFERENCE_TYPE_ARGUMENT: - position.offset = cr.readUnsignedShort(); - position.type_index = cr.readUnsignedByte(); - break; - // We don't need to worry about these - case METHOD_RETURN: - case FIELD: - break; - case UNKNOWN: - throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!"); - default: - throw new AssertionError("TypeAnnotation: Unknown target type: " + type); - } - - { // Write type path - int len = cr.readUnsignedByte(); - List loc = new ArrayList<>(len); - for (int i = 0; i < len * TypePathEntry.bytesPerEntry; ++i) - loc.add(cr.readUnsignedByte()); - position.location = Position.getTypePathFromBinary(loc); - } - return position; - } - - private static int position_length(Position pos) { - int n = 0; - n += 1; // TargetType tag is a byte - switch (pos.type) { - // instanceof - case INSTANCEOF: - // new expression - case NEW: - // constructor/method reference receiver - case CONSTRUCTOR_REFERENCE: - case METHOD_REFERENCE: - n += 2; // offset - break; - // local variable - case LOCAL_VARIABLE: - // resource variable - case RESOURCE_VARIABLE: - n += 2; // table_length; - int table_length = pos.lvarOffset.length; - n += 2 * table_length; // offset - n += 2 * table_length; // length - n += 2 * table_length; // index - break; - // exception parameter - case EXCEPTION_PARAMETER: - n += 2; // exception_index - break; - // method receiver - case METHOD_RECEIVER: - // Do nothing - break; - // type parameter - case CLASS_TYPE_PARAMETER: - case METHOD_TYPE_PARAMETER: - n += 1; // parameter_index - break; - // type parameter bound - case CLASS_TYPE_PARAMETER_BOUND: - case METHOD_TYPE_PARAMETER_BOUND: - n += 1; // parameter_index - n += 1; // bound_index - break; - // class extends or implements clause - case CLASS_EXTENDS: - n += 2; // type_index - break; - // throws - case THROWS: - n += 2; // type_index - break; - // method parameter - case METHOD_FORMAL_PARAMETER: - n += 1; // parameter_index - break; - // type cast - case CAST: - // method/constructor/reference type argument - case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: - case METHOD_INVOCATION_TYPE_ARGUMENT: - case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: - case METHOD_REFERENCE_TYPE_ARGUMENT: - n += 2; // offset - n += 1; // type index - break; - // We don't need to worry about these - case METHOD_RETURN: - case FIELD: - break; - case UNKNOWN: - throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!"); - default: - throw new AssertionError("TypeAnnotation: Unknown target type: " + pos.type); - } - - { - n += 1; // length - n += TypePathEntry.bytesPerEntry * pos.location.size(); // bytes for actual array - } - - return n; - } - - // Code duplicated from com.sun.tools.javac.code.TypeAnnotationPosition - public static class Position { - public enum TypePathEntryKind { - ARRAY(0), - INNER_TYPE(1), - WILDCARD(2), - TYPE_ARGUMENT(3); - - public final int tag; - - private TypePathEntryKind(int tag) { - this.tag = tag; - } - } - - public static class TypePathEntry { - /** The fixed number of bytes per TypePathEntry. */ - public static final int bytesPerEntry = 2; - - public final TypePathEntryKind tag; - public final int arg; - - public static final TypePathEntry ARRAY = new TypePathEntry(TypePathEntryKind.ARRAY); - public static final TypePathEntry INNER_TYPE = new TypePathEntry(TypePathEntryKind.INNER_TYPE); - public static final TypePathEntry WILDCARD = new TypePathEntry(TypePathEntryKind.WILDCARD); - - private TypePathEntry(TypePathEntryKind tag) { - if (!(tag == TypePathEntryKind.ARRAY || - tag == TypePathEntryKind.INNER_TYPE || - tag == TypePathEntryKind.WILDCARD)) { - throw new AssertionError("Invalid TypePathEntryKind: " + tag); - } - this.tag = tag; - this.arg = 0; - } - - public TypePathEntry(TypePathEntryKind tag, int arg) { - if (tag != TypePathEntryKind.TYPE_ARGUMENT) { - throw new AssertionError("Invalid TypePathEntryKind: " + tag); - } - this.tag = tag; - this.arg = arg; - } - - public static TypePathEntry fromBinary(int tag, int arg) { - if (arg != 0 && tag != TypePathEntryKind.TYPE_ARGUMENT.tag) { - throw new AssertionError("Invalid TypePathEntry tag/arg: " + tag + "/" + arg); - } - switch (tag) { - case 0: - return ARRAY; - case 1: - return INNER_TYPE; - case 2: - return WILDCARD; - case 3: - return new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg); - default: - throw new AssertionError("Invalid TypePathEntryKind tag: " + tag); - } - } - - @Override - public String toString() { - return tag.toString() + - (tag == TypePathEntryKind.TYPE_ARGUMENT ? ("(" + arg + ")") : ""); - } - - @Override - public boolean equals(Object other) { - if (! (other instanceof TypePathEntry)) { - return false; - } - TypePathEntry tpe = (TypePathEntry) other; - return this.tag == tpe.tag && this.arg == tpe.arg; - } - - @Override - public int hashCode() { - return this.tag.hashCode() * 17 + this.arg; - } - } - - public TargetType type = TargetType.UNKNOWN; - - // For generic/array types. - // TODO: or should we use null? No one will use this object. - public List location = new ArrayList<>(0); - - // Tree position. - public int pos = -1; - - // For typecasts, type tests, new (and locals, as start_pc). - public boolean isValidOffset = false; - public int offset = -1; - - // For locals. arrays same length - public int[] lvarOffset = null; - public int[] lvarLength = null; - public int[] lvarIndex = null; - - // For type parameter bound - public int bound_index = Integer.MIN_VALUE; - - // For type parameter and method parameter - public int parameter_index = Integer.MIN_VALUE; - - // For class extends, implements, and throws clauses - public int type_index = Integer.MIN_VALUE; - - // For exception parameters, index into exception table - public int exception_index = Integer.MIN_VALUE; - - public Position() {} - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append('['); - sb.append(type); - - switch (type) { - // instanceof - case INSTANCEOF: - // new expression - case NEW: - // constructor/method reference receiver - case CONSTRUCTOR_REFERENCE: - case METHOD_REFERENCE: - sb.append(", offset = "); - sb.append(offset); - break; - // local variable - case LOCAL_VARIABLE: - // resource variable - case RESOURCE_VARIABLE: - if (lvarOffset == null) { - sb.append(", lvarOffset is null!"); - break; - } - sb.append(", {"); - for (int i = 0; i < lvarOffset.length; ++i) { - if (i != 0) sb.append("; "); - sb.append("start_pc = "); - sb.append(lvarOffset[i]); - sb.append(", length = "); - sb.append(lvarLength[i]); - sb.append(", index = "); - sb.append(lvarIndex[i]); - } - sb.append("}"); - break; - // method receiver - case METHOD_RECEIVER: - // Do nothing - break; - // type parameter - case CLASS_TYPE_PARAMETER: - case METHOD_TYPE_PARAMETER: - sb.append(", param_index = "); - sb.append(parameter_index); - break; - // type parameter bound - case CLASS_TYPE_PARAMETER_BOUND: - case METHOD_TYPE_PARAMETER_BOUND: - sb.append(", param_index = "); - sb.append(parameter_index); - sb.append(", bound_index = "); - sb.append(bound_index); - break; - // class extends or implements clause - case CLASS_EXTENDS: - sb.append(", type_index = "); - sb.append(type_index); - break; - // throws - case THROWS: - sb.append(", type_index = "); - sb.append(type_index); - break; - // exception parameter - case EXCEPTION_PARAMETER: - sb.append(", exception_index = "); - sb.append(exception_index); - break; - // method parameter - case METHOD_FORMAL_PARAMETER: - sb.append(", param_index = "); - sb.append(parameter_index); - break; - // type cast - case CAST: - // method/constructor/reference type argument - case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: - case METHOD_INVOCATION_TYPE_ARGUMENT: - case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: - case METHOD_REFERENCE_TYPE_ARGUMENT: - sb.append(", offset = "); - sb.append(offset); - sb.append(", type_index = "); - sb.append(type_index); - break; - // We don't need to worry about these - case METHOD_RETURN: - case FIELD: - break; - case UNKNOWN: - sb.append(", position UNKNOWN!"); - break; - default: - throw new AssertionError("Unknown target type: " + type); - } - - // Append location data for generics/arrays. - if (!location.isEmpty()) { - sb.append(", location = ("); - sb.append(location); - sb.append(")"); - } - - sb.append(", pos = "); - sb.append(pos); - - sb.append(']'); - return sb.toString(); - } - - /** - * Indicates whether the target tree of the annotation has been optimized - * away from classfile or not. - * @return true if the target has not been optimized away - */ - public boolean emitToClassfile() { - return !type.isLocal() || isValidOffset; - } - - /** - * Decode the binary representation for a type path and set - * the {@code location} field. - * - * @param list The bytecode representation of the type path. - */ - public static List getTypePathFromBinary(List list) { - List loc = new ArrayList<>(list.size() / TypePathEntry.bytesPerEntry); - int idx = 0; - while (idx < list.size()) { - if (idx + 1 == list.size()) { - throw new AssertionError("Could not decode type path: " + list); - } - loc.add(TypePathEntry.fromBinary(list.get(idx), list.get(idx + 1))); - idx += 2; - } - return loc; - } - - public static List getBinaryFromTypePath(List locs) { - List loc = new ArrayList<>(locs.size() * TypePathEntry.bytesPerEntry); - for (TypePathEntry tpe : locs) { - loc.add(tpe.tag.tag); - loc.add(tpe.arg); - } - return loc; - } - } - - // Code duplicated from com.sun.tools.javac.code.TargetType - // The IsLocal flag could be removed here. - public enum TargetType { - /** For annotations on a class type parameter declaration. */ - CLASS_TYPE_PARAMETER(0x00), - - /** For annotations on a method type parameter declaration. */ - METHOD_TYPE_PARAMETER(0x01), - - /** For annotations on the type of an "extends" or "implements" clause. */ - CLASS_EXTENDS(0x10), - - /** For annotations on a bound of a type parameter of a class. */ - CLASS_TYPE_PARAMETER_BOUND(0x11), - - /** For annotations on a bound of a type parameter of a method. */ - METHOD_TYPE_PARAMETER_BOUND(0x12), - - /** For annotations on a field. */ - FIELD(0x13), - - /** For annotations on a method return type. */ - METHOD_RETURN(0x14), - - /** For annotations on the method receiver. */ - METHOD_RECEIVER(0x15), - - /** For annotations on a method parameter. */ - METHOD_FORMAL_PARAMETER(0x16), - - /** For annotations on a throws clause in a method declaration. */ - THROWS(0x17), - - /** For annotations on a local variable. */ - LOCAL_VARIABLE(0x40, true), - - /** For annotations on a resource variable. */ - RESOURCE_VARIABLE(0x41, true), - - /** For annotations on an exception parameter. */ - EXCEPTION_PARAMETER(0x42, true), - - /** For annotations on a type test. */ - INSTANCEOF(0x43, true), - - /** For annotations on an object creation expression. */ - NEW(0x44, true), - - /** For annotations on a constructor reference receiver. */ - CONSTRUCTOR_REFERENCE(0x45, true), - - /** For annotations on a method reference receiver. */ - METHOD_REFERENCE(0x46, true), - - /** For annotations on a typecast. */ - CAST(0x47, true), - - /** For annotations on a type argument of an object creation expression. */ - CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(0x48, true), - - /** For annotations on a type argument of a method call. */ - METHOD_INVOCATION_TYPE_ARGUMENT(0x49, true), - - /** For annotations on a type argument of a constructor reference. */ - CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT(0x4A, true), - - /** For annotations on a type argument of a method reference. */ - METHOD_REFERENCE_TYPE_ARGUMENT(0x4B, true), - - /** For annotations with an unknown target. */ - UNKNOWN(0xFF); - - private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x4B; - - private final int targetTypeValue; - private final boolean isLocal; - - private TargetType(int targetTypeValue) { - this(targetTypeValue, false); - } - - private TargetType(int targetTypeValue, boolean isLocal) { - if (targetTypeValue < 0 - || targetTypeValue > 255) - throw new AssertionError("Attribute type value needs to be an unsigned byte: " + String.format("0x%02X", targetTypeValue)); - this.targetTypeValue = targetTypeValue; - this.isLocal = isLocal; - } - - /** - * Returns whether or not this TargetType represents an annotation whose - * target is exclusively a tree in a method body - * - * Note: wildcard bound targets could target a local tree and a class - * member declaration signature tree - */ - public boolean isLocal() { - return isLocal; - } - - public int targetTypeValue() { - return this.targetTypeValue; - } - - private static final TargetType[] targets; - - static { - targets = new TargetType[MAXIMUM_TARGET_TYPE_VALUE + 1]; - TargetType[] alltargets = values(); - for (TargetType target : alltargets) { - if (target.targetTypeValue != UNKNOWN.targetTypeValue) - targets[target.targetTypeValue] = target; - } - for (int i = 0; i <= MAXIMUM_TARGET_TYPE_VALUE; ++i) { - if (targets[i] == null) - targets[i] = UNKNOWN; - } - } - - public static boolean isValidTargetTypeValue(int tag) { - if (tag == UNKNOWN.targetTypeValue) - return true; - return (tag >= 0 && tag < targets.length); - } - - public static TargetType fromTargetTypeValue(int tag) { - if (tag == UNKNOWN.targetTypeValue) - return UNKNOWN; - - if (tag < 0 || tag >= targets.length) - throw new AssertionError("Unknown TargetType: " + tag); - return targets[tag]; - } - } -} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/package-info.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/package-info.java deleted file mode 100644 index 505c1a7e03d93..0000000000000 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/package-info.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - A minimalist library to read and write class files into objects closely - based on the corresponding definitions in - The Java Virtual Machine Specification (JVMS). - -

This is NOT part of any supported API. - If you write code that depends on this, you do so at your own risk. - This code and its internal interfaces are subject to change or - deletion without notice. -*/ -package com.sun.tools.classfile; diff --git a/src/jdk.jdeps/share/classes/module-info.java b/src/jdk.jdeps/share/classes/module-info.java index 3fdd3ca32d270..3c15c3330c7ac 100644 --- a/src/jdk.jdeps/share/classes/module-info.java +++ b/src/jdk.jdeps/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -70,8 +70,6 @@ uses com.sun.tools.javac.platform.PlatformProvider; - exports com.sun.tools.classfile to jdk.jlink; - provides java.util.spi.ToolProvider with com.sun.tools.javap.Main.JavapToolProvider, com.sun.tools.jdeps.Main.JDepsToolProvider, diff --git a/test/langtools/tools/javac/generics/wildcards/separate_compilation/WildcardBoundsNotReadFromClassFileTest.java b/test/langtools/tools/javac/generics/wildcards/separate_compilation/WildcardBoundsNotReadFromClassFileTest.java index 6d44f7ccf1e4e..ec28c274e7dbb 100644 --- a/test/langtools/tools/javac/generics/wildcards/separate_compilation/WildcardBoundsNotReadFromClassFileTest.java +++ b/test/langtools/tools/javac/generics/wildcards/separate_compilation/WildcardBoundsNotReadFromClassFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,6 @@ * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file * jdk.compiler/com.sun.tools.javac.main - * jdk.jdeps/com.sun.tools.classfile * @build toolbox.ToolBox toolbox.JavacTask * @run main WildcardBoundsNotReadFromClassFileTest */ @@ -42,7 +41,6 @@ import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.util.Assert; -import com.sun.tools.classfile.ClassFile; import toolbox.TestRunner; import toolbox.ToolBox; From 45b7c748737f38c33c4666d17101b051b2fbe2ae Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 10 Apr 2025 01:38:47 +0000 Subject: [PATCH 0507/1101] 8341641: Make %APPDATA% and %LOCALAPPDATA% env variables available in *.cfg files Reviewed-by: almatvee --- .../jpackage/internal/util/TokenReplace.java | 16 +- src/jdk.jpackage/share/man/jpackage.md | 23 ++ .../share/native/applauncher/AppLauncher.cpp | 8 +- .../share/native/applauncher/CfgFile.cpp | 89 +++++-- .../share/native/applauncher/CfgFile.h | 9 +- .../native/applauncher/StringProcessing.cpp | 182 +++++++++++++ .../native/applauncher/StringProcessing.h | 83 ++++++ .../jdk/jpackage/test/AdditionalLauncher.java | 22 +- .../jdk/jpackage/test/JPackageCommand.java | 26 ++ .../jpackage/share/AppLauncherSubstTest.java | 249 ++++++++++++++++++ 10 files changed, 659 insertions(+), 48 deletions(-) create mode 100644 src/jdk.jpackage/share/native/applauncher/StringProcessing.cpp create mode 100644 src/jdk.jpackage/share/native/applauncher/StringProcessing.h create mode 100644 test/jdk/tools/jpackage/share/AppLauncherSubstTest.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/TokenReplace.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/TokenReplace.java index 24c13db1aa772..7c213851b9bf7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/TokenReplace.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/TokenReplace.java @@ -42,6 +42,12 @@ import java.util.stream.IntStream; import java.util.stream.Stream; +/** + * Class to replace tokens in strings. + *

+ * Single instance holds a list of tokens. Tokens can be substrings of each other. + * The implementation performs greedy replacement: longer tokens are replaced first. + */ public final class TokenReplace { private record TokenCut(String[] main, String[] sub) { @@ -103,7 +109,7 @@ public TokenReplace(String... tokens) { this.tokens = tokens; regexps = new ArrayList<>(); - for(;;) { + for (;;) { final var tokenCut = TokenCut.createFromOrderedTokens(tokens); regexps.add(Pattern.compile(Stream.of(tokenCut.main()).map(Pattern::quote).collect(joining("|", "(", ")")))); @@ -153,12 +159,12 @@ public int hashCode() { @Override public boolean equals(Object obj) { // Auto generated code - if (this == obj) + if (this == obj) { return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) + } + if ((obj == null) || (getClass() != obj.getClass())) { return false; + } TokenReplace other = (TokenReplace) obj; return Arrays.equals(tokens, other.tokens); } diff --git a/src/jdk.jpackage/share/man/jpackage.md b/src/jdk.jpackage/share/man/jpackage.md index 61b671579da4d..c50370c9641b5 100644 --- a/src/jdk.jpackage/share/man/jpackage.md +++ b/src/jdk.jpackage/share/man/jpackage.md @@ -219,12 +219,35 @@ The `jpackage` tool will take as input a Java application and a Java run-time im This option can be used multiple times. + Value can contain substrings that will be expanded at runtime. + Two types of such substrings are supported: environment variables + and "APPDIR", "BINDIR", and "ROOTDIR" tokens. + + An expandable substring should be enclosed between the dollar + sign character ($) and the first following non-alphanumeric + character. Alternatively, it can be enclosed between "${" and "}" + substrings. + + Expandable substrings are case-sensitive on Unix and + case-insensitive on Windows. No string expansion occurs if the + referenced environment variable is undefined. + + Environment variables with names "APPDIR", "BINDIR", and "ROOTDIR" + will be ignored, and these expandable substrings will be + replaced by values calculated by the app launcher. + + Prefix the dollar sign character with the backslash character (\) + to prevent substring expansion. + `--java-options` *options* : Options to pass to the Java runtime This option can be used multiple times. + Value can contain substrings that will be substituted at runtime, + such as for the --arguments option. + `--main-class` *class-name* : Qualified name of the application main class to execute diff --git a/src/jdk.jpackage/share/native/applauncher/AppLauncher.cpp b/src/jdk.jpackage/share/native/applauncher/AppLauncher.cpp index 96e8885e6ab50..fd1d07e92e05a 100644 --- a/src/jdk.jpackage/share/native/applauncher/AppLauncher.cpp +++ b/src/jdk.jpackage/share/native/applauncher/AppLauncher.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -164,9 +164,9 @@ CfgFile* AppLauncher::createCfgFile() const { << cfgFilePath << "\""); CfgFile::Macros macros; - macros[_T("$APPDIR")] = appDirPath; - macros[_T("$BINDIR")] = FileUtils::dirname(launcherPath); - macros[_T("$ROOTDIR")] = imageRoot; + macros[_T("APPDIR")] = appDirPath; + macros[_T("BINDIR")] = FileUtils::dirname(launcherPath); + macros[_T("ROOTDIR")] = imageRoot; std::unique_ptr dummy(new CfgFile()); CfgFile::load(cfgFilePath).expandMacros(macros).swap(*dummy); return dummy.release(); diff --git a/src/jdk.jpackage/share/native/applauncher/CfgFile.cpp b/src/jdk.jpackage/share/native/applauncher/CfgFile.cpp index b5049334b6482..0e99d131e69ec 100644 --- a/src/jdk.jpackage/share/native/applauncher/CfgFile.cpp +++ b/src/jdk.jpackage/share/native/applauncher/CfgFile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,16 @@ #include "kludge_c++11.h" +#include #include #include #include "CfgFile.h" +#include "SysInfo.h" #include "Log.h" #include "Toolbox.h" #include "FileUtils.h" #include "ErrorHandling.h" +#include "StringProcessing.h" const CfgFile::Properties& CfgFile::getProperties( @@ -60,38 +63,82 @@ CfgFile& CfgFile::setPropertyValue(const SectionName& sectionName, namespace { -tstring expandMacros(const tstring& str, const CfgFile::Macros& macros) { - tstring reply = str; - CfgFile::Macros::const_iterator it = macros.begin(); - const CfgFile::Macros::const_iterator end = macros.end(); - for (; it != end; ++it) { - reply = tstrings::replace(reply, it->first, it->second); +template +void iterateProperties(CfgFileType& cfgFile, OpType& op) { + for (auto mapIt = cfgFile.begin(), mapEnd = cfgFile.end(); mapIt != mapEnd; ++mapIt) { + for (auto propertyIt = mapIt->second.begin(), propertyEnd = mapIt->second.end(); propertyIt != propertyEnd; ++propertyIt) { + for (auto strIt = propertyIt->second.begin(), strEnd = propertyIt->second.end(); strIt != strEnd; ++strIt) { + op(strIt); + } + } } - return reply; } +struct tokenize_strings { + void operator () (tstring_array::const_iterator& strIt) { + const auto tokens = StringProcessing::tokenize(*strIt); + values.push_back(tokens); + } + + std::set variableNames() const { + std::set allVariableNames; + for (auto it = values.begin(), end = values.end(); it != end; ++it) { + const auto variableNames = StringProcessing::extractVariableNames(*it); + allVariableNames.insert(variableNames.begin(), variableNames.end()); + } + + return allVariableNames; + } + + std::vector values; +}; + +class expand_macros { +public: + expand_macros(const CfgFile::Macros& m, + std::vector::iterator iter) : macros(m), curTokenizedString(iter) { + } + + void operator () (tstring_array::iterator& strIt) { + StringProcessing::expandVariables(*curTokenizedString, macros); + auto newStr = StringProcessing::stringify(*curTokenizedString); + ++curTokenizedString; + if (*strIt != newStr) { + LOG_TRACE(tstrings::any() << "Map [" << *strIt << "] into [" << newStr << "]"); + } + strIt->swap(newStr); + } + +private: + const CfgFile::Macros& macros; + std::vector::iterator curTokenizedString; +}; + } // namespace CfgFile CfgFile::expandMacros(const Macros& macros) const { CfgFile copyCfgFile = *this; - PropertyMap::iterator mapIt = copyCfgFile.data.begin(); - const PropertyMap::iterator mapEnd = copyCfgFile.data.end(); - for (; mapIt != mapEnd; ++mapIt) { - Properties::iterator propertyIt = mapIt->second.begin(); - const Properties::iterator propertyEnd = mapIt->second.end(); - for (; propertyIt != propertyEnd; ++propertyIt) { - tstring_array::iterator strIt = propertyIt->second.begin(); - const tstring_array::iterator strEnd = propertyIt->second.end(); - for (; strIt != strEnd; ++strIt) { - tstring newValue; - while ((newValue = ::expandMacros(*strIt, macros)) != *strIt) { - strIt->swap(newValue); - } + tokenize_strings tokenizedStrings; + iterateProperties(static_cast(copyCfgFile.data), tokenizedStrings); + + Macros allMacros(macros); + + const auto variableNames = tokenizedStrings.variableNames(); + for (auto it = variableNames.begin(), end = variableNames.end(); it != end; ++it) { + if (macros.find(*it) == macros.end()) { + // Not one of the reserved macro names. Assuming an environment variable. + const auto envVarName = *it; + if (SysInfo::isEnvVariableSet(envVarName)) { + const auto envVarValue = SysInfo::getEnvVariable(envVarName); + allMacros[envVarName] = envVarValue; } } } + expand_macros expandMacros(allMacros, tokenizedStrings.values.begin()); + iterateProperties(copyCfgFile.data, expandMacros); + return copyCfgFile; } diff --git a/src/jdk.jpackage/share/native/applauncher/CfgFile.h b/src/jdk.jpackage/share/native/applauncher/CfgFile.h index 03f70d94fde06..0ab4ccc06a122 100644 --- a/src/jdk.jpackage/share/native/applauncher/CfgFile.h +++ b/src/jdk.jpackage/share/native/applauncher/CfgFile.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,8 +27,7 @@ #ifndef CfgFile_h #define CfgFile_h -#include -#include "tstrings.h" +#include "StringProcessing.h" class CfgFile { @@ -90,10 +89,10 @@ class CfgFile { std::swap(empty, other.empty); } - typedef std::map Macros; + typedef StringProcessing::VariableValues Macros; /** - * Returns copy of this instance with the given macros expanded. + * Returns copy of this instance with the given macros and environment variables expanded. */ CfgFile expandMacros(const Macros& macros) const; diff --git a/src/jdk.jpackage/share/native/applauncher/StringProcessing.cpp b/src/jdk.jpackage/share/native/applauncher/StringProcessing.cpp new file mode 100644 index 0000000000000..207db25fd94ba --- /dev/null +++ b/src/jdk.jpackage/share/native/applauncher/StringProcessing.cpp @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "kludge_c++11.h" + +#include +#include "StringProcessing.h" + + +namespace StringProcessing { + +namespace { + +class TokenBuilder { +public: + TokenBuilder(const tstring& v): cur(v.c_str()) { + } + + void addNextToken(tstring::const_pointer end, TokenType type, TokenizedString& tokens) { + if (end != cur) { + const auto value = tstring(cur, end - cur); + cur = end; + tokens.push_back(Token(type, value)); + } + } + +private: + tstring::const_pointer cur; +}; + +bool isValidVariableFirstChar(tstring::value_type chr) { + if ('A' <= chr && chr <= 'Z') { + return true; + } else if ('a' <= chr && chr <= 'z') { + return true; + } else if ('_' == chr) { + return true; + } else { + return false; + } +} + +bool isValidVariableOtherChar(tstring::value_type chr) { + if (isValidVariableFirstChar(chr)) { + return true; + } else if ('0' <= chr && chr <= '9') { + return true; + } else { + return false; + } +} + +} // namespace + +TokenizedString tokenize(const tstring& str) { + TokenizedString tokens; + TokenBuilder tb(str); + tstring::const_pointer cur = str.c_str(); + const tstring::const_pointer end = cur + str.length(); + while (cur != end) { + if (*cur == '\\' && cur + 1 != end) { + const auto maybeNextToken = cur++; + if (*cur == '\\' || *cur == '$') { + tb.addNextToken(maybeNextToken, STRING, tokens); + tb.addNextToken(++cur, ESCAPED_CHAR, tokens); + continue; + } + } else if (*cur == '$' && cur + 1 != end) { + const auto maybeNextToken = cur++; + bool variableFound = false; + if (*cur == '{') { + do { + cur++; + } while (cur != end && *cur != '}'); + if (cur != end) { + variableFound = true; + cur++; + } + } else if (isValidVariableFirstChar(*cur)) { + variableFound = true; + do { + cur++; + } while (cur != end && isValidVariableOtherChar(*cur)); + } else { + continue; + } + if (variableFound) { + tb.addNextToken(maybeNextToken, STRING, tokens); + tb.addNextToken(cur, VARIABLE, tokens); + } + } else { + ++cur; + } + } + tb.addNextToken(cur, STRING, tokens); + return tokens; +} + + +tstring stringify(const TokenizedString& tokens) { + tstringstream ss; + TokenizedString::const_iterator it = tokens.begin(); + const TokenizedString::const_iterator end = tokens.end(); + for (; it != end; ++it) { + if (it->type() == ESCAPED_CHAR) { + ss << it->value().substr(1); + } else { + ss << it->value(); + } + } + return ss.str(); +} + + +namespace { + +tstring getVariableName(const tstring& str) { + if (tstrings::endsWith(str, _T("}"))) { + // ${VAR} + return str.substr(2, str.length() - 3); + } else { + // $VAR + return str.substr(1); + } +} + +} // namespace + +VariableNameList extractVariableNames(const TokenizedString& tokens) { + VariableNameList reply; + + TokenizedString::const_iterator it = tokens.begin(); + const TokenizedString::const_iterator end = tokens.end(); + for (; it != end; ++it) { + if (it->type() == VARIABLE) { + reply.push_back(getVariableName(it->value())); + } + } + + std::sort(reply.begin(), reply.end()); + reply.erase(std::unique(reply.begin(), reply.end()), reply.end()); + return reply; +} + + +void expandVariables(TokenizedString& tokens, const VariableValues& variableValues) { + TokenizedString::iterator it = tokens.begin(); + const TokenizedString::iterator end = tokens.end(); + for (; it != end; ++it) { + if (it->type() == VARIABLE) { + const auto entry = variableValues.find(getVariableName(it->value())); + if (entry != variableValues.end()) { + auto newToken = Token(STRING, entry->second); + std::swap(*it, newToken); + } + } + } +} + +} // namespace StringProcessing diff --git a/src/jdk.jpackage/share/native/applauncher/StringProcessing.h b/src/jdk.jpackage/share/native/applauncher/StringProcessing.h new file mode 100644 index 0000000000000..85b14ae55d481 --- /dev/null +++ b/src/jdk.jpackage/share/native/applauncher/StringProcessing.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +#ifndef StringProcessor_h +#define StringProcessor_h + +#include +#include "tstrings.h" + + +namespace StringProcessing { + +enum TokenType { + STRING, + VARIABLE, + ESCAPED_CHAR +}; + +class Token { +public: + Token(TokenType type, const tstring& str): theType(type), theStr(str) { + } + + TokenType type() const { + return theType; + } + + const tstring& value() const { + return theStr; + } + +private: + TokenType theType; + tstring theStr; +}; + +typedef std::vector TokenizedString; +typedef std::vector VariableNameList; +#ifdef _WIN32 +struct less_ignore_case { + bool operator() (const tstring& x, const tstring& y) const { + return std::less()(tstrings::toLower(x), tstrings::toLower(y)); + } +}; +typedef std::map VariableValues; +#else +typedef std::map VariableValues; +#endif + +TokenizedString tokenize(const tstring& str); + +tstring stringify(const TokenizedString& tokens); + +VariableNameList extractVariableNames(const TokenizedString& tokens); + +void expandVariables(TokenizedString& tokens, const VariableValues& variableValues); + +} // namespace StringProcessing + +#endif // StringProcessor_h diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java index 5089dc0c60204..f10939555e57a 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java @@ -22,6 +22,9 @@ */ package jdk.jpackage.test; +import static java.util.stream.Collectors.toMap; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -35,11 +38,8 @@ import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.stream.Stream; -import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; import jdk.jpackage.internal.util.function.ThrowingBiConsumer; -import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; public class AdditionalLauncher { @@ -393,11 +393,9 @@ public static final class PropertyFile { PropertyFile(Path path) throws IOException { data = Files.readAllLines(path).stream().map(str -> { return str.split("=", 2); - }).collect( - Collectors.toMap(tokens -> tokens[0], tokens -> tokens[1], - (oldValue, newValue) -> { - return newValue; - })); + }).collect(toMap(tokens -> tokens[0], tokens -> tokens[1], (oldValue, newValue) -> { + return newValue; + })); } public boolean isPropertySet(String name) { @@ -419,11 +417,9 @@ public Optional getPropertyBooleanValue(String name) { } private static String resolveVariables(JPackageCommand cmd, String str) { - var map = Map.of( - "$APPDIR", cmd.appLayout().appDirectory(), - "$ROOTDIR", - cmd.isImagePackageType() ? cmd.outputBundle() : cmd.appInstallationDirectory(), - "$BINDIR", cmd.appLayout().launchersDirectory()); + var map = Stream.of(JPackageCommand.Macro.values()).collect(toMap(x -> { + return String.format("$%s", x.name()); + }, cmd::macroValue)); for (var e : map.entrySet()) { str = str.replaceAll(Pattern.quote(e.getKey()), Matcher.quoteReplacement(e.getValue().toString())); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 77e3b772cfadf..b4d2d1872eb9f 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -859,6 +859,32 @@ public JPackageCommand assertImageCreated() { return this; } + public static enum Macro { + APPDIR(cmd -> { + return cmd.appLayout().appDirectory().toString(); + }), + BINDIR(cmd -> { + return cmd.appLayout().launchersDirectory().toString(); + }), + ROOTDIR(cmd -> { + return (cmd.isImagePackageType() ? cmd.outputBundle() : cmd.appInstallationDirectory()).toString(); + }); + + private Macro(Function getValue) { + this.getValue = Objects.requireNonNull(getValue); + } + + String value(JPackageCommand cmd) { + return getValue.apply(cmd); + } + + private final Function getValue; + } + + public String macroValue(Macro macro) { + return macro.value(this); + } + public static enum AppLayoutAssert { APP_IMAGE_FILE(JPackageCommand::assertAppImageFile), PACKAGE_FILE(JPackageCommand::assertPackageFile), diff --git a/test/jdk/tools/jpackage/share/AppLauncherSubstTest.java b/test/jdk/tools/jpackage/share/AppLauncherSubstTest.java new file mode 100644 index 0000000000000..abd1288e02448 --- /dev/null +++ b/test/jdk/tools/jpackage/share/AppLauncherSubstTest.java @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import static jdk.internal.util.OperatingSystem.WINDOWS; +import static jdk.jpackage.test.HelloApp.configureAndExecute; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; +import jdk.jpackage.internal.util.TokenReplace; +import jdk.jpackage.test.Annotations.ParameterSupplier; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.Executor; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageCommand.Macro; +import jdk.jpackage.test.TKit; + +/* + * @test + * @summary Tests environment variables substitution by jpackage launcher + * @bug 8341641 + * @library /test/jdk/tools/jpackage/helpers + * @build jdk.jpackage.test.* + * @build AppLauncherSubstTest + * @run main/othervm -Xmx512m jdk.jpackage.test.Main + * --jpt-run=AppLauncherSubstTest + */ +public class AppLauncherSubstTest { + + record TestSpec(String str, String expectedStr, Map env) { + + static class Builder { + + Builder str(String v) { + str = v; + return this; + } + + Builder expect(String v) { + expectedStr = v; + return this; + } + + Builder var(String name, String value) { + env.put(name, value); + return this; + } + + TestSpec create() { + return new TestSpec(str, Optional.ofNullable(expectedStr).orElse(str), env); + } + + private String str; + private String expectedStr; + private Map env = new LinkedHashMap<>(); + } + + public TestSpec { + Objects.requireNonNull(str); + Objects.requireNonNull(expectedStr); + Objects.requireNonNull(env); + env.entrySet().forEach(Objects::requireNonNull); + } + + public String resolveExpectedStr(JPackageCommand cmd) { + return MACROS.applyTo(expectedStr, token -> { + // @@APPDIR@@ -> APPDIR + final var macro = token.substring(2, token.length() - 2); + return Path.of(cmd.macroValue(Macro.valueOf(macro))).toAbsolutePath(); + }); + } + + @Override + public String toString() { + final var sb = new StringBuilder(); + sb.append("str=").append(str); + sb.append(", expect=").append(expectedStr); + if (!env.isEmpty()) { + sb.append(", env=").append(env); + } + return sb.toString(); + } + + private final static TokenReplace MACROS = new TokenReplace(Stream.of(Macro.values()).map(macro -> { + return String.format("@@%s@@", macro); + }).toArray(String[]::new)); + } + + @Test + @ParameterSupplier + @ParameterSupplier(value = "testCaseSensitive", ifNotOS = WINDOWS) + @ParameterSupplier(value = "testCaseInsensitive", ifOS = WINDOWS) + public static void test(TestSpec spec) throws IOException { + final var cmd = JPackageCommand.helloAppImage(TEST_APP_JAVA + "*Hello") + .ignoreFakeRuntime() + .setArgumentValue("--java-options", "-D" + TEST_PROP + "="); + + cmd.execute(); + + // Manually edit main launcher config file. Don't do it directly because + // jpackage doesn't pass the value of `--java-options` option as-is into the config file. + final var cfgFile = cmd.appLauncherCfgPath(null); + TKit.createTextFile(cfgFile, Files.readAllLines(cfgFile).stream().map(line -> { + return TEST_PROP_REGEXP.matcher(line).replaceFirst(Matcher.quoteReplacement(spec.str())); + })); + + final var launcherExec = new Executor() + .saveOutput() + .dumpOutput() + .setExecutable(cmd.appLauncherPath().toAbsolutePath()) + .addArguments("--print-sys-prop=" + TEST_PROP); + + spec.env().forEach(launcherExec::setEnvVar); + + final var resolvedExpectedStr = spec.resolveExpectedStr(cmd); + final var actualStr = configureAndExecute(0, launcherExec).getFirstLineOfOutput().substring((TEST_PROP + "=").length()); + + if (TKit.isWindows() && !resolvedExpectedStr.equals(spec.expectedStr())) { + TKit.assertEquals(resolvedExpectedStr.toLowerCase(), actualStr.toLowerCase(), "Check the property value is as expected [lowercase]"); + } else { + TKit.assertEquals(resolvedExpectedStr, actualStr, "Check the property value is as expected"); + } + } + + public static Collection test() { + return Stream.of( + testSpec(""), + testSpec("$ONE ${TWO} ${ONE} $TWO ONE TWO").expect("one two one two ONE TWO").var("ONE", "one").var("TWO", "two"), + testSpec("\\$FOO\\\\$FOO\\${FOO}\\\\${FOO}").expect("$FOO\\BAR${FOO}\\BAR").var("FOO", "BAR"), + testSpec("$FOO-$BAR").expect("$FOO-").var("BAR", ""), + testSpec("${BINDIR}${APPDIR}${ROOTDIR}").expect("@@BINDIR@@@@APPDIR@@@@ROOTDIR@@").var("BINDIR", "a").var("APPDIR", "b").var("ROOTDIR", "c"), + testSpec("$BINDIR$APPDIR$ROOTDIR").expect("@@BINDIR@@@@APPDIR@@@@ROOTDIR@@"), + testSpec("$BINDIR2$APPDIR2$ROOTDIR2").expect("$BINDIR2$APPDIR2$ROOTDIR2") + ).map(TestSpec.Builder::create).map(v -> { + return new Object[] {v}; + }).toList(); + } + + public static Collection testCaseSensitive() { + final List testCases = new ArrayList<>(); + for (final var macro : Macro.values()) { + testCases.addAll(createTestCases(macro, true)); + } + + testCases.addAll(Stream.of( + testSpec("$ALPHA $alpha").expect("A a").var("ALPHA", "A").var("alpha", "a"), + testSpec("$ALPHA $alpha").expect("$ALPHA a").var("alpha", "a"), + testSpec("$ALPHA $alpha").expect("A $alpha").var("ALPHA", "A") + ).map(TestSpec.Builder::create).toList()); + + return testCases.stream().map(v -> { + return new Object[] {v}; + }).toList(); + } + + public static Collection testCaseInsensitive() { + final List testCases = new ArrayList<>(); + for (final var macro : Macro.values()) { + testCases.addAll(createTestCases(macro, false)); + } + + testCases.addAll(Stream.of( + testSpec("$ALPHA $alpha").expect("A A").var("AlphA", "A"), + testSpec("$ALPHA $alpha").expect("a a").var("alpha", "a"), + testSpec("$ALPHA $alpha").expect("A A").var("ALPHA", "A") + ).map(TestSpec.Builder::create).toList()); + + return testCases.stream().map(v -> { + return new Object[] {v}; + }).toList(); + } + + private static List createTestCases(Macro macro, boolean caseSensitive) { + final var name = macro.name(); + final var name2 = name.transform(str -> { + final var chars = name.toCharArray(); + for (int i = 0; i < chars.length; i += 2) { + chars[i] = Character.toLowerCase(chars[i]); + } + return new String(chars); + }); + + if (name.equals(name2)) { + throw new UnsupportedOperationException(); + } + + final var testSpec = testSpec(String.format("${%s}${%s}", name, name2)).var(name, "A").var(name2, "[foo]"); + if (caseSensitive) { + testSpec.expect(String.format("@@%s@@[foo]", name, name2)); + } else { + testSpec.expect(String.format("@@%s@@@@%s@@", name, name)); + } + + final var testSpec2 = testSpec(String.format("${%s}${%s}", name, name2)).var(name, "A"); + if (caseSensitive) { + testSpec2.expect(String.format("@@%s@@${%s}", name, name2)); + } else { + testSpec2.expect(String.format("@@%s@@@@%s@@", name, name)); + } + + final var testSpec3 = testSpec(String.format("${%s}${%s}", name, name2)); + if (caseSensitive) { + testSpec3.expect(String.format("@@%s@@${%s}", name, name2)); + } else { + testSpec3.expect(String.format("@@%s@@@@%s@@", name, name)); + } + + return Stream.of(testSpec, testSpec2).map(TestSpec.Builder::create).toList(); + } + + private static TestSpec.Builder testSpec(String str) { + return new TestSpec.Builder().str(str); + } + + private static final Path TEST_APP_JAVA = TKit.TEST_SRC_ROOT.resolve("apps/PrintEnv.java"); + + private static final String TEST_PROP = "jdk.jpackage.test.Property"; + private static final Pattern TEST_PROP_REGEXP = Pattern.compile("(?<=" + Pattern.quote(TEST_PROP) + "=).*"); +} From bcac42aabce5b57525f776037d73b51d0afcbaf5 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Thu, 10 Apr 2025 07:04:15 +0000 Subject: [PATCH 0508/1101] 8349479: C2: when a Type node becomes dead, make CFG path that uses it unreachable Reviewed-by: chagedorn, vlivanov --- src/hotspot/cpu/aarch64/aarch64.ad | 3 +- src/hotspot/cpu/arm/arm.ad | 3 +- src/hotspot/cpu/ppc/ppc.ad | 3 +- src/hotspot/cpu/riscv/riscv.ad | 3 +- src/hotspot/cpu/s390/s390.ad | 3 +- src/hotspot/cpu/x86/x86.ad | 3 +- .../share/nmt/nativeCallStackPrinter.cpp | 5 +- src/hotspot/share/opto/c2_globals.hpp | 6 ++ src/hotspot/share/opto/castnode.cpp | 10 ++- src/hotspot/share/opto/connode.hpp | 4 + src/hotspot/share/opto/convertnode.cpp | 18 ++++- src/hotspot/share/opto/movenode.cpp | 4 + src/hotspot/share/opto/node.cpp | 75 +++++++++++++++++++ src/hotspot/share/opto/node.hpp | 6 ++ src/hotspot/share/opto/phaseX.cpp | 17 +++++ src/hotspot/share/opto/phaseX.hpp | 1 + src/hotspot/share/utilities/ostream.cpp | 7 ++ src/hotspot/share/utilities/ostream.hpp | 1 + .../c2/TestGuardOfCastIIDoesntFold.java | 73 ++++++++++++++++++ .../assertion/TestAssertionPredicates.java | 15 ++++ 20 files changed, 246 insertions(+), 14 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestGuardOfCastIIDoesntFold.java diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 5bfe697d12c0b..76e3c92ddc261 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -16297,7 +16297,8 @@ instruct ShouldNotReachHere() %{ ins_encode %{ if (is_reachable()) { - __ stop(_halt_reason); + const char* str = __ code_string(_halt_reason); + __ stop(str); } %} diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 486d51ac46353..f3b97d23ad306 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -8992,7 +8992,8 @@ instruct ShouldNotReachHere( ) format %{ "ShouldNotReachHere" %} ins_encode %{ if (is_reachable()) { - __ stop(_halt_reason); + const char* str = __ code_string(_halt_reason); + __ stop(str); } %} ins_pipe(tail_call); diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 022a70d52a2b0..07d681e89823e 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -14699,7 +14699,8 @@ instruct ShouldNotReachHere() %{ format %{ "ShouldNotReachHere" %} ins_encode %{ if (is_reachable()) { - __ stop(_halt_reason); + const char* str = __ code_string(_halt_reason); + __ stop(str); } %} ins_pipe(pipe_class_default); diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 4ebfdf9f16c42..aca2f4dd488ae 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -10893,7 +10893,8 @@ instruct ShouldNotReachHere() %{ ins_encode %{ if (is_reachable()) { - __ stop(_halt_reason); + const char* str = __ code_string(_halt_reason); + __ stop(str); } %} diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index ea1bdb9e231ea..c32064be86d87 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -10080,7 +10080,8 @@ instruct ShouldNotReachHere() %{ format %{ "ILLTRAP; ShouldNotReachHere" %} ins_encode %{ if (is_reachable()) { - __ stop(_halt_reason); + const char* str = __ code_string(_halt_reason); + __ stop(str); } %} ins_pipe(pipe_class_dummy); diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 2d7548c37a87e..7bde4ced2ba48 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -2874,7 +2874,8 @@ instruct ShouldNotReachHere() %{ format %{ "stop\t# ShouldNotReachHere" %} ins_encode %{ if (is_reachable()) { - __ stop(_halt_reason); + const char* str = __ code_string(_halt_reason); + __ stop(str); } %} ins_pipe(pipe_slow); diff --git a/src/hotspot/share/nmt/nativeCallStackPrinter.cpp b/src/hotspot/share/nmt/nativeCallStackPrinter.cpp index c2a54961abe76..59a5bf991420b 100644 --- a/src/hotspot/share/nmt/nativeCallStackPrinter.cpp +++ b/src/hotspot/share/nmt/nativeCallStackPrinter.cpp @@ -44,10 +44,7 @@ void NativeCallStackPrinter::print_stack(const NativeCallStack* stack) const { if (created) { stringStream ss(4 * K); stack->print_frame(&ss, pc); - const size_t len = ss.size(); - char* store = NEW_ARENA_ARRAY(&_text_storage, char, len + 1); - memcpy(store, ss.base(), len + 1); - (*cached_frame_text) = store; + (*cached_frame_text) = ss.as_string(&_text_storage); } _out->print_raw_cr(*cached_frame_text); } diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index ad88554fedd04..41b081610974a 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -820,6 +820,12 @@ product(bool, UseStoreStoreForCtor, true, DIAGNOSTIC, \ "Use StoreStore barrier instead of Release barrier at the end " \ "of constructors") \ + \ + develop(bool, KillPathsReachableByDeadTypeNode, true, \ + "When a Type node becomes top, make paths where the node is " \ + "used dead by replacing them with a Halt node. Turning this off " \ + "could corrupt the graph in rare cases and should be used with " \ + "care.") \ // end of C2_FLAGS diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index 68ba291986bcf..198634af71bba 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -96,8 +96,14 @@ const Type* ConstraintCastNode::Value(PhaseGVN* phase) const { //------------------------------Ideal------------------------------------------ // Return a node which is more "ideal" than the current node. Strip out // control copies -Node *ConstraintCastNode::Ideal(PhaseGVN *phase, bool can_reshape) { - return (in(0) && remove_dead_region(phase, can_reshape)) ? this : nullptr; +Node* ConstraintCastNode::Ideal(PhaseGVN* phase, bool can_reshape) { + if (in(0) != nullptr && remove_dead_region(phase, can_reshape)) { + return this; + } + if (in(1) != nullptr && phase->type(in(1)) != Type::TOP) { + return TypeNode::Ideal(phase, can_reshape); + } + return nullptr; } uint ConstraintCastNode::hash() const { diff --git a/src/hotspot/share/opto/connode.hpp b/src/hotspot/share/opto/connode.hpp index 3b7657320e2e4..4788858796015 100644 --- a/src/hotspot/share/opto/connode.hpp +++ b/src/hotspot/share/opto/connode.hpp @@ -46,6 +46,10 @@ class ConNode : public TypeNode { virtual const RegMask &out_RegMask() const { return RegMask::Empty; } virtual const RegMask &in_RegMask(uint) const { return RegMask::Empty; } + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape) { + return Node::Ideal(phase, can_reshape); + } + // Polymorphic factory method: static ConNode* make(const Type *t); }; diff --git a/src/hotspot/share/opto/convertnode.cpp b/src/hotspot/share/opto/convertnode.cpp index 3e99277d90330..5df79a36edb7d 100644 --- a/src/hotspot/share/opto/convertnode.cpp +++ b/src/hotspot/share/opto/convertnode.cpp @@ -689,7 +689,14 @@ bool Compile::push_thru_add(PhaseGVN* phase, Node* z, const TypeInteger* tz, con //------------------------------Ideal------------------------------------------ -Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { +Node* ConvI2LNode::Ideal(PhaseGVN* phase, bool can_reshape) { + if (in(1) != nullptr && phase->type(in(1)) != Type::TOP) { + Node* progress = TypeNode::Ideal(phase, can_reshape); + if (progress != nullptr) { + return progress; + } + } + const TypeLong* this_type = this->type()->is_long(); if (can_reshape && !phase->C->post_loop_opts_phase()) { // makes sure we run ::Value to potentially remove type assertion after loop opts @@ -791,7 +798,14 @@ const Type* ConvL2INode::Value(PhaseGVN* phase) const { //------------------------------Ideal------------------------------------------ // Return a node which is more "ideal" than the current node. // Blow off prior masking to int -Node *ConvL2INode::Ideal(PhaseGVN *phase, bool can_reshape) { +Node* ConvL2INode::Ideal(PhaseGVN* phase, bool can_reshape) { + if (in(1) != nullptr && phase->type(in(1)) != Type::TOP) { + Node* progress = TypeNode::Ideal(phase, can_reshape); + if (progress != nullptr) { + return progress; + } + } + Node *andl = in(1); uint andl_op = andl->Opcode(); if( andl_op == Op_AndL ) { diff --git a/src/hotspot/share/opto/movenode.cpp b/src/hotspot/share/opto/movenode.cpp index b0db9c1d350fd..66db1df339b06 100644 --- a/src/hotspot/share/opto/movenode.cpp +++ b/src/hotspot/share/opto/movenode.cpp @@ -90,6 +90,10 @@ Node *CMoveNode::Ideal(PhaseGVN *phase, bool can_reshape) { phase->type(in(IfTrue)) == Type::TOP) { return nullptr; } + Node* progress = TypeNode::Ideal(phase, can_reshape); + if (progress != nullptr) { + return progress; + } // Check for Min/Max patterns. This is called before constants are pushed to the right input, as that transform can // make BoolTests non-canonical. diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index 37f6e95d5020c..d00bd3d394371 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -3076,3 +3076,78 @@ const Type* TypeNode::Value(PhaseGVN* phase) const { return _type; } uint TypeNode::ideal_reg() const { return _type->ideal_reg(); } + +void TypeNode::make_path_dead(PhaseIterGVN* igvn, PhaseIdealLoop* loop, Node* ctrl_use, uint j, const char* phase_str) { + Node* c = ctrl_use->in(j); + if (igvn->type(c) != Type::TOP) { + igvn->replace_input_of(ctrl_use, j, igvn->C->top()); + create_halt_path(igvn, c, loop, phase_str); + } +} + +// This Type node is dead. It could be because the type that it captures and the type of the node computed from its +// inputs do not intersect anymore. That node has some uses along some control flow paths. Those control flow paths must +// be unreachable as using a dead value makes no sense. For the Type node to capture a narrowed down type, some control +// flow construct must guard the Type node (an If node usually). When the Type node becomes dead, the guard usually +// constant folds and the control flow that leads to the Type node becomes unreachable. There are cases where that +// doesn't happen, however. They are handled here by following uses of the Type node until a CFG or a Phi to find dead +// paths. The dead paths are then replaced by a Halt node. +void TypeNode::make_paths_from_here_dead(PhaseIterGVN* igvn, PhaseIdealLoop* loop, const char* phase_str) { + Unique_Node_List wq; + wq.push(this); + for (uint i = 0; i < wq.size(); ++i) { + Node* n = wq.at(i); + for (DUIterator_Fast kmax, k = n->fast_outs(kmax); k < kmax; k++) { + Node* u = n->fast_out(k); + if (u->is_CFG()) { + assert(!u->is_Region(), "Can't reach a Region without going through a Phi"); + make_path_dead(igvn, loop, u, 0, phase_str); + } else if (u->is_Phi()) { + Node* r = u->in(0); + assert(r->is_Region() || r->is_top(), "unexpected Phi's control"); + if (r->is_Region()) { + for (uint j = 1; j < u->req(); ++j) { + if (u->in(j) == n) { + make_path_dead(igvn, loop, r, j, phase_str); + } + } + } + } else { + wq.push(u); + } + } + } +} + +void TypeNode::create_halt_path(PhaseIterGVN* igvn, Node* c, PhaseIdealLoop* loop, const char* phase_str) const { + Node* frame = new ParmNode(igvn->C->start(), TypeFunc::FramePtr); + if (loop == nullptr) { + igvn->register_new_node_with_optimizer(frame); + } else { + loop->register_new_node(frame, igvn->C->start()); + } + + stringStream ss; + ss.print("dead path discovered by TypeNode during %s", phase_str); + + Node* halt = new HaltNode(c, frame, ss.as_string(igvn->C->comp_arena())); + if (loop == nullptr) { + igvn->register_new_node_with_optimizer(halt); + } else { + loop->register_control(halt, loop->ltree_root(), c); + } + igvn->add_input_to(igvn->C->root(), halt); +} + +Node* TypeNode::Ideal(PhaseGVN* phase, bool can_reshape) { + if (KillPathsReachableByDeadTypeNode && can_reshape && Value(phase) == Type::TOP) { + PhaseIterGVN* igvn = phase->is_IterGVN(); + Node* top = igvn->C->top(); + ResourceMark rm; + make_paths_from_here_dead(igvn, nullptr, "igvn"); + return top; + } + + return Node::Ideal(phase, can_reshape); +} + diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 562e090a41bdd..1cb9009ef276b 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -155,6 +155,7 @@ class ParsePredicateNode; class PCTableNode; class PhaseCCP; class PhaseGVN; +class PhaseIdealLoop; class PhaseIterGVN; class PhaseRegAlloc; class PhaseTransform; @@ -2044,12 +2045,17 @@ class TypeNode : public Node { init_class_id(Class_Type); } virtual const Type* Value(PhaseGVN* phase) const; + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); virtual const Type *bottom_type() const; virtual uint ideal_reg() const; + + void make_path_dead(PhaseIterGVN* igvn, PhaseIdealLoop* loop, Node* ctrl_use, uint j, const char* phase_str); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; virtual void dump_compact_spec(outputStream *st) const; #endif + void make_paths_from_here_dead(PhaseIterGVN* igvn, PhaseIdealLoop* loop, const char* phase_str); + void create_halt_path(PhaseIterGVN* igvn, Node* c, PhaseIdealLoop* loop, const char* phase_str) const; }; #include "opto/opcodes.hpp" diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index ae6e49e2c4e41..90bc923187354 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1835,6 +1835,11 @@ void PhaseCCP::analyze() { set_type(n, new_type); push_child_nodes_to_worklist(worklist, n); } + if (KillPathsReachableByDeadTypeNode && n->is_Type() && new_type == Type::TOP) { + // Keep track of Type nodes to kill CFG paths that use Type + // nodes that become dead. + _maybe_top_type_nodes.push(n); + } } DEBUG_ONLY(verify_analyze(worklist_verify);) } @@ -2065,6 +2070,18 @@ Node *PhaseCCP::transform( Node *n ) { // track all visited nodes, so that we can remove the complement Unique_Node_List useful; + if (KillPathsReachableByDeadTypeNode) { + for (uint i = 0; i < _maybe_top_type_nodes.size(); ++i) { + Node* type_node = _maybe_top_type_nodes.at(i); + if (type(type_node) == Type::TOP) { + ResourceMark rm; + type_node->as_Type()->make_paths_from_here_dead(this, nullptr, "ccp"); + } + } + } else { + assert(_maybe_top_type_nodes.size() == 0, "we don't need type nodes"); + } + // Initialize the traversal. // This CCP pass may prove that no exit test for a loop ever succeeds (i.e. the loop is infinite). In that case, // the logic below doesn't follow any path from Root to the loop body: there's at least one such path but it's proven diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp index 7843bd39aeaab..c2a0f0dbb77b6 100644 --- a/src/hotspot/share/opto/phaseX.hpp +++ b/src/hotspot/share/opto/phaseX.hpp @@ -608,6 +608,7 @@ class PhaseIterGVN : public PhaseGVN { // Should be replaced with combined CCP & GVN someday. class PhaseCCP : public PhaseIterGVN { Unique_Node_List _root_and_safepoints; + Unique_Node_List _maybe_top_type_nodes; // Non-recursive. Use analysis to transform single Node. virtual Node* transform_once(Node* n); diff --git a/src/hotspot/share/utilities/ostream.cpp b/src/hotspot/share/utilities/ostream.cpp index 66fc3103a534f..e95bc776ce5e7 100644 --- a/src/hotspot/share/utilities/ostream.cpp +++ b/src/hotspot/share/utilities/ostream.cpp @@ -437,6 +437,13 @@ char* stringStream::as_string(bool c_heap) const { return copy; } +char* stringStream::as_string(Arena* arena) const { + char* copy = NEW_ARENA_ARRAY(arena, char, _written + 1); + ::memcpy(copy, _buffer, _written); + copy[_written] = '\0'; // terminating null + return copy; +} + stringStream::~stringStream() { if (!_is_fixed && _buffer != _small_buffer) { FREE_C_HEAP_ARRAY(char, _buffer); diff --git a/src/hotspot/share/utilities/ostream.hpp b/src/hotspot/share/utilities/ostream.hpp index 9faaf32fb6bc1..46bd0b673c16a 100644 --- a/src/hotspot/share/utilities/ostream.hpp +++ b/src/hotspot/share/utilities/ostream.hpp @@ -270,6 +270,7 @@ class stringStream : public outputStream { bool is_empty() const { return _buffer[0] == '\0'; } // Copy to a resource, or C-heap, array as requested char* as_string(bool c_heap = false) const; + char* as_string(Arena* arena) const; }; class fileStream : public outputStream { diff --git a/test/hotspot/jtreg/compiler/c2/TestGuardOfCastIIDoesntFold.java b/test/hotspot/jtreg/compiler/c2/TestGuardOfCastIIDoesntFold.java new file mode 100644 index 0000000000000..1751b117034c5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestGuardOfCastIIDoesntFold.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8349479 + * @summary C2: when a Type node becomes dead, make CFG path that uses it unreachable + * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement + * -XX:CompileCommand=dontinline,TestGuardOfCastIIDoesntFold::notInlined + * TestGuardOfCastIIDoesntFold + * @run main TestGuardOfCastIIDoesntFold + */ + +public class TestGuardOfCastIIDoesntFold { + private static volatile int volatileField; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test1(1, 0, 0, false); + helper1(1, 0, 0, true); + helper2(0, 0); + } + } + + private static int test1(int i, int j, int k, boolean flag) { + int l; + for (l = 0; l < 10; l++) { + } + j = helper2(j, l); + return helper1(i, j, k, flag); + } + + private static int helper2(int j, int l) { + if (l == 10) { + j = Integer.MAX_VALUE-1; + } + return j; + } + + private static int helper1(int i, int j, int k, boolean flag) { + if (flag) { + k = Integer.max(k, -2); + int[] array = new int[i + k]; + notInlined(array); + return array[j]; + } + volatileField = 42; + return volatileField; + } + + private static void notInlined(int[] array) { + } +} diff --git a/test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicates.java b/test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicates.java index ea8c627187d33..f7f2f1f20f68c 100644 --- a/test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicates.java +++ b/test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicates.java @@ -33,6 +33,7 @@ * -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode * compiler.predicates.assertion.TestAssertionPredicates Xbatch */ @@ -43,6 +44,7 @@ * -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode * compiler.predicates.assertion.TestAssertionPredicates NoTieredCompilation */ @@ -54,6 +56,7 @@ * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=inline,compiler.predicates.assertion.TestAssertionPredicates::inline + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode * compiler.predicates.assertion.TestAssertionPredicates Xcomp */ @@ -65,6 +68,7 @@ * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=inline,compiler.predicates.assertion.TestAssertionPredicates::inline + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode * compiler.predicates.assertion.TestAssertionPredicates XcompNoTiered */ @@ -76,6 +80,7 @@ * -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode * compiler.predicates.assertion.TestAssertionPredicates LoopMaxUnroll0 */ @@ -87,6 +92,7 @@ * -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode * compiler.predicates.assertion.TestAssertionPredicates LoopMaxUnroll2 */ @@ -98,6 +104,7 @@ * -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode * compiler.predicates.assertion.TestAssertionPredicates LoopUnrollLimit40 */ @@ -109,6 +116,7 @@ * -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode * compiler.predicates.assertion.TestAssertionPredicates LoopUnrollLimit150 */ @@ -120,6 +128,7 @@ * -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode * compiler.predicates.assertion.TestAssertionPredicates NoProfiledLoopPredicate */ @@ -131,6 +140,7 @@ * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:+AbortVMOnCompilationFailure * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode * compiler.predicates.assertion.TestAssertionPredicates DataUpdate */ @@ -141,6 +151,7 @@ * @run main/othervm -Xcomp -XX:-BlockLayoutByFrequency -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode * compiler.predicates.assertion.TestAssertionPredicates CloneDown */ @@ -152,6 +163,7 @@ * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:+StressGCM -XX:+AbortVMOnCompilationFailure * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode * compiler.predicates.assertion.TestAssertionPredicates Stress */ @@ -163,6 +175,7 @@ * @run main/othervm -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:+StressGCM -XX:+AbortVMOnCompilationFailure * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode * compiler.predicates.assertion.TestAssertionPredicates Stress */ @@ -174,6 +187,7 @@ * -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode * compiler.predicates.assertion.TestAssertionPredicates NoLoopPredication */ @@ -185,6 +199,7 @@ * -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode * compiler.predicates.assertion.TestAssertionPredicates NoLoopPredication */ From 4f80437ee05e4a3f755a166140669c0fd631f56d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Thu, 10 Apr 2025 07:24:45 +0000 Subject: [PATCH 0509/1101] 8353842: C2: Add graph dumps before and after loop opts phase Reviewed-by: chagedorn, epeter --- src/hotspot/share/opto/compile.cpp | 7 +++++++ src/hotspot/share/opto/phasetype.hpp | 4 +++- .../jtreg/compiler/lib/ir_framework/CompilePhase.java | 4 +++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 8a059d0852f7f..c830d0c854b2a 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1857,6 +1857,9 @@ void Compile::process_for_post_loop_opts_igvn(PhaseIterGVN& igvn) { // at least to this point, even if no loop optimizations were done. PhaseIdealLoop::verify(igvn); + if (has_loops() || _loop_opts_cnt > 0) { + print_method(PHASE_AFTER_LOOP_OPTS, 2); + } C->set_post_loop_opts_phase(); // no more loop opts allowed assert(!C->major_progress(), "not cleared"); @@ -2377,6 +2380,10 @@ void Compile::Optimize() { if (failing()) return; + if (has_loops()) { + print_method(PHASE_BEFORE_LOOP_OPTS, 2); + } + // Perform escape analysis if (do_escape_analysis() && ConnectionGraph::has_candidates(this)) { if (has_loops()) { diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp index 318a01e3bd82e..b3076dd80911e 100644 --- a/src/hotspot/share/opto/phasetype.hpp +++ b/src/hotspot/share/opto/phasetype.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ flags(ELIMINATE_VBOX_ALLOC, "Eliminate VectorBoxAllocate") \ flags(ITER_GVN_BEFORE_EA, "Iter GVN before EA") \ flags(ITER_GVN_AFTER_VECTOR, "Iter GVN after vector box elimination") \ + flags(BEFORE_LOOP_OPTS, "Before Loop Optimizations") \ flags(BEFORE_BEAUTIFY_LOOPS, "Before beautify loops") \ flags(AFTER_BEAUTIFY_LOOPS, "After beautify loops") \ flags(BEFORE_LOOP_UNROLLING, "Before Loop Unrolling") \ @@ -88,6 +89,7 @@ flags(CCP1, "PhaseCCP 1") \ flags(ITER_GVN2, "Iter GVN 2") \ flags(PHASEIDEALLOOP_ITERATIONS, "PhaseIdealLoop iterations") \ + flags(AFTER_LOOP_OPTS, "After Loop Optimizations") \ flags(AFTER_MERGE_STORES, "After Merge Stores") \ flags(BEFORE_MACRO_EXPANSION , "Before Macro Expansion") \ flags(AFTER_MACRO_EXPANSION_STEP, "After Macro Expansion Step") \ diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java b/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java index 6f4410a0220f0..ad32f6a94b914 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,6 +58,7 @@ public enum CompilePhase { ELIMINATE_VBOX_ALLOC("Eliminate VectorBoxAllocate"), ITER_GVN_BEFORE_EA("Iter GVN before EA"), ITER_GVN_AFTER_VECTOR("Iter GVN after vector box elimination"), + BEFORE_LOOP_OPTS("Before Loop Optimizations"), BEFORE_BEAUTIFY_LOOPS("Before beautify loops"), AFTER_BEAUTIFY_LOOPS("After beautify loops"), BEFORE_LOOP_UNROLLING("Before Loop Unrolling"), @@ -95,6 +96,7 @@ public enum CompilePhase { CCP1("PhaseCCP 1"), ITER_GVN2("Iter GVN 2"), PHASEIDEALLOOP_ITERATIONS("PhaseIdealLoop iterations"), + AFTER_LOOP_OPTS("After Loop Optimizations"), AFTER_MERGE_STORES("After Merge Stores"), BEFORE_MACRO_EXPANSION("Before Macro Expansion"), AFTER_MACRO_EXPANSION_STEP("After Macro Expansion Step"), From c447a10225576bc59e1ba9477417367d2ac28511 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Thu, 10 Apr 2025 07:42:40 +0000 Subject: [PATCH 0510/1101] 8353856: Deprecate FlighRecorderPermission class for removal Reviewed-by: mgronlun --- .../share/classes/jdk/jfr/EventSettings.java | 117 ++++++++++++++++- .../jdk/jfr/FlightRecorderPermission.java | 123 +----------------- .../jdk/jfr/internal/PrivateAccess.java | 4 +- 3 files changed, 120 insertions(+), 124 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/EventSettings.java b/src/jdk.jfr/share/classes/jdk/jfr/EventSettings.java index 17ce98d166c33..6ed20f124d98e 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/EventSettings.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/EventSettings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,15 @@ package jdk.jfr; import java.time.Duration; +import java.util.List; import java.util.Map; import java.util.Objects; +import jdk.jfr.internal.PlatformEventType; +import jdk.jfr.internal.PlatformRecorder; +import jdk.jfr.internal.PlatformRecording; +import jdk.jfr.internal.PrivateAccess; +import jdk.jfr.internal.Type; import jdk.jfr.internal.management.EventSettingsModifier; /** @@ -46,6 +52,115 @@ */ public abstract class EventSettings { + // Purpose of InternalAccess is to give classes in jdk.jfr.internal + // access to package private methods in this package (jdk.jfr). + // + // The initialization could be done in any class in this package, + // but this one was chosen because it is lightweight. + static { + PrivateAccess.setPrivateAccess(new InternalAccess()); + } + + private static final class InternalAccess extends PrivateAccess { + + @Override + public Type getType(Object o) { + if (o instanceof AnnotationElement ae) { + return ae.getType(); + } + if (o instanceof EventType et) { + return et.getType(); + } + if (o instanceof ValueDescriptor vd) { + return vd.getType(); + } + if (o instanceof SettingDescriptor sd) { + return sd.getType(); + } + throw new Error("Unknown type " + o.getClass()); + } + + @Override + public Configuration newConfiguration(String name, String label, String description, String provider, Map settings, String contents) { + return new Configuration(name, label, description, provider, settings, contents); + } + + @Override + public EventType newEventType(PlatformEventType platformEventType) { + return new EventType(platformEventType); + } + + @Override + public AnnotationElement newAnnotation(Type annotationType, List values, boolean boot) { + return new AnnotationElement(annotationType, values, boot); + } + + @Override + public ValueDescriptor newValueDescriptor(String name, Type fieldType, List annos, int dimension, boolean constantPool, String fieldName) { + return new ValueDescriptor(fieldType, name, annos, dimension, constantPool, fieldName); + } + + @Override + public PlatformRecording getPlatformRecording(Recording r) { + return r.getInternal(); + } + + @Override + public PlatformEventType getPlatformEventType(EventType eventType) { + return eventType.getPlatformEventType(); + } + + @Override + public boolean isConstantPool(ValueDescriptor v) { + return v.isConstantPool(); + } + + @Override + public void setAnnotations(ValueDescriptor v, List a) { + v.setAnnotations(a); + } + + @Override + public void setAnnotations(SettingDescriptor s, List a) { + s.setAnnotations(a); + } + + @Override + public String getFieldName(ValueDescriptor v) { + return v.getJavaFieldName(); + } + + @Override + public ValueDescriptor newValueDescriptor(Class type, String name) { + return new ValueDescriptor(type, name, List.of(), true); + } + + @Override + public SettingDescriptor newSettingDescriptor(Type type, String name, String defaultValue, List annotations) { + return new SettingDescriptor(type, name, defaultValue, annotations); + } + + @Override + public boolean isUnsigned(ValueDescriptor v) { + return v.isUnsigned(); + } + + @Override + public PlatformRecorder getPlatformRecorder() { + return FlightRecorder.getFlightRecorder().getInternal(); + } + + @Override + public EventSettings newEventSettings(EventSettingsModifier esm) { + return new EventSettings.DelegatedEventSettings(esm); + } + + @Override + public boolean isVisible(EventType t) { + return t.isVisible(); + } + } + // Used to provide EventSettings for jdk.management.jfr module static class DelegatedEventSettings extends EventSettings { private final EventSettingsModifier delegate; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderPermission.java b/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderPermission.java index 67e844ac269a9..8b0d7f42279af 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderPermission.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderPermission.java @@ -25,21 +25,12 @@ package jdk.jfr; -import java.util.List; -import java.util.Map; import java.util.Objects; -import jdk.jfr.internal.PlatformEventType; -import jdk.jfr.internal.PlatformRecorder; -import jdk.jfr.internal.PlatformRecording; -import jdk.jfr.internal.PrivateAccess; -import jdk.jfr.internal.Type; -import jdk.jfr.internal.management.EventSettingsModifier; - /** * Permission for controlling access to Flight Recorder. * - * @apiNote + * @deprecated * This permission cannot be used for controlling access to resources * as the Security Manager is no longer supported. * @@ -53,118 +44,8 @@ * */ @SuppressWarnings("serial") +@Deprecated(since="25", forRemoval=true) public final class FlightRecorderPermission extends java.security.BasicPermission { - - // Purpose of InternalAccess is to give classes in jdk.jfr.internal - // access to package private methods in this package (jdk.jfr). - // - // The initialization could be done in any class in this package, - // but this one was chosen because it is light weight and - // lacks dependencies on other public classes. - static { - PrivateAccess.setPrivateAccess(new InternalAccess()); - } - - private static final class InternalAccess extends PrivateAccess { - - @Override - public Type getType(Object o) { - if (o instanceof AnnotationElement ae) { - return ae.getType(); - } - if (o instanceof EventType et) { - return et.getType(); - } - if (o instanceof ValueDescriptor vd) { - return vd.getType(); - } - if (o instanceof SettingDescriptor sd) { - return sd.getType(); - } - throw new Error("Unknown type " + o.getClass()); - } - - @Override - public Configuration newConfiguration(String name, String label, String description, String provider, Map settings, String contents) { - return new Configuration(name, label, description, provider, settings, contents); - } - - @Override - public EventType newEventType(PlatformEventType platformEventType) { - return new EventType(platformEventType); - } - - @Override - public AnnotationElement newAnnotation(Type annotationType, List values, boolean boot) { - return new AnnotationElement(annotationType, values, boot); - } - - @Override - public ValueDescriptor newValueDescriptor(String name, Type fieldType, List annos, int dimension, boolean constantPool, String fieldName) { - return new ValueDescriptor(fieldType, name, annos, dimension, constantPool, fieldName); - } - - @Override - public PlatformRecording getPlatformRecording(Recording r) { - return r.getInternal(); - } - - @Override - public PlatformEventType getPlatformEventType(EventType eventType) { - return eventType.getPlatformEventType(); - } - - @Override - public boolean isConstantPool(ValueDescriptor v) { - return v.isConstantPool(); - } - - @Override - public void setAnnotations(ValueDescriptor v, List a) { - v.setAnnotations(a); - } - - @Override - public void setAnnotations(SettingDescriptor s, List a) { - s.setAnnotations(a); - } - - @Override - public String getFieldName(ValueDescriptor v) { - return v.getJavaFieldName(); - } - - @Override - public ValueDescriptor newValueDescriptor(Class type, String name) { - return new ValueDescriptor(type, name, List.of(), true); - } - - @Override - public SettingDescriptor newSettingDescriptor(Type type, String name, String defaultValue, List annotations) { - return new SettingDescriptor(type, name, defaultValue, annotations); - } - - @Override - public boolean isUnsigned(ValueDescriptor v) { - return v.isUnsigned(); - } - - @Override - public PlatformRecorder getPlatformRecorder() { - return FlightRecorder.getFlightRecorder().getInternal(); - } - - @Override - public EventSettings newEventSettings(EventSettingsModifier esm) { - return new EventSettings.DelegatedEventSettings(esm); - } - - @Override - public boolean isVisible(EventType t) { - return t.isVisible(); - } - } - /** * Constructs a {@code FlightRecorderPermission} with the specified name. * diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java index e9945f71158c0..95dbd0986dc98 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java @@ -56,9 +56,9 @@ public static PrivateAccess getInstance() { // deadlock with FlightRecorderPermission. if (instance == null) { // Will trigger - // FlightRecorderPermission. + // EventSettings. // which will call PrivateAccess.setPrivateAccess - new FlightRecorderPermission("accessFlightRecorder"); + SecuritySupport.ensureClassIsInitialized(EventSettings.class); } return instance; } From 73c8c755ea638c09147d28080646ee8887ee8283 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 10 Apr 2025 07:54:00 +0000 Subject: [PATCH 0511/1101] 8351157: Clean up x86 GC barriers after 32-bit x86 removal Reviewed-by: kbarrett, wkemper, tschatzl --- src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp | 2 +- .../x86/gc/g1/g1BarrierSetAssembler_x86.cpp | 103 ++------ .../x86/gc/g1/g1BarrierSetAssembler_x86.hpp | 6 +- src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad | 4 +- .../x86/gc/shared/barrierSetAssembler_x86.cpp | 113 +-------- .../x86/gc/shared/barrierSetAssembler_x86.hpp | 8 +- .../x86/gc/shared/barrierSetNMethod_x86.cpp | 37 --- .../cardTableBarrierSetAssembler_x86.cpp | 12 - .../shared/modRefBarrierSetAssembler_x86.cpp | 16 +- .../c1/shenandoahBarrierSetC1_x86.cpp | 5 +- .../shenandoahBarrierSetAssembler_x86.cpp | 230 +++--------------- .../shenandoahBarrierSetAssembler_x86.hpp | 4 +- .../cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp | 5 +- .../cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp | 3 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 32 ++- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 9 +- src/hotspot/cpu/x86/methodHandles_x86.cpp | 12 +- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 2 +- .../x86/templateInterpreterGenerator_x86.cpp | 2 +- src/hotspot/cpu/x86/templateTable_x86.cpp | 54 ++-- 20 files changed, 117 insertions(+), 542 deletions(-) diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index dd8c075cb872c..66defb5970283 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -147,7 +147,7 @@ void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_ // Defines obj, preserves var_size_in_bytes void C1_MacroAssembler::try_allocate(Register obj, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Register t2, Label& slow_case) { if (UseTLAB) { - tlab_allocate(noreg, obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); + tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); } else { jmp(slow_case); } diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp index 4aa02c4d6278b..bc5d6a233d389 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp @@ -49,11 +49,7 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0; if (!dest_uninitialized) { - Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread); -#ifndef _LP64 - __ push(thread); - __ get_thread(thread); -#endif + Register thread = r15_thread; Label filtered; Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); @@ -65,12 +61,9 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm __ cmpb(in_progress, 0); } - NOT_LP64(__ pop(thread);) - __ jcc(Assembler::equal, filtered); __ push_call_clobbered_registers(false /* save_fpu */); -#ifdef _LP64 if (count == c_rarg0) { if (addr == c_rarg1) { // exactly backwards!! @@ -88,10 +81,6 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm } else { __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_oop_entry), 2); } -#else - __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_oop_entry), - addr, count); -#endif __ pop_call_clobbered_registers(false /* save_fpu */); __ bind(filtered); @@ -101,7 +90,6 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp) { __ push_call_clobbered_registers(false /* save_fpu */); -#ifdef _LP64 if (c_rarg0 == count) { // On win64 c_rarg0 == rcx assert_different_registers(c_rarg1, addr); __ mov(c_rarg1, count); @@ -112,53 +100,26 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas __ mov(c_rarg1, count); } __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 2); -#else - __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), - addr, count); -#endif __ pop_call_clobbered_registers(false /* save_fpu */); + } void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register dst, Address src, Register tmp1, Register tmp_thread) { + Register dst, Address src, Register tmp1) { bool on_oop = is_reference_type(type); bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0; bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0; bool on_reference = on_weak || on_phantom; - ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); + ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1); if (on_oop && on_reference) { - Register thread = NOT_LP64(tmp_thread) LP64_ONLY(r15_thread); - -#ifndef _LP64 - // Work around the x86_32 bug that only manifests with Loom for some reason. - // MacroAssembler::resolve_weak_handle calls this barrier with tmp_thread == noreg. - if (thread == noreg) { - if (dst != rcx && tmp1 != rcx) { - thread = rcx; - } else if (dst != rdx && tmp1 != rdx) { - thread = rdx; - } else if (dst != rdi && tmp1 != rdi) { - thread = rdi; - } - } - assert_different_registers(dst, tmp1, thread); - __ push(thread); - __ get_thread(thread); -#endif - // Generate the G1 pre-barrier code to log the value of // the referent field in an SATB buffer. g1_write_barrier_pre(masm /* masm */, noreg /* obj */, dst /* pre_val */, - thread /* thread */, tmp1 /* tmp */, true /* tosca_live */, true /* expand_call */); - -#ifndef _LP64 - __ pop(thread); -#endif } } @@ -199,7 +160,7 @@ static void generate_pre_barrier_slow_path(MacroAssembler* masm, Label& runtime) { // Do we need to load the previous value? if (obj != noreg) { - __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); + __ load_heap_oop(pre_val, Address(obj, 0), noreg, AS_RAW); } // Is the previous value null? __ cmpptr(pre_val, NULL_WORD); @@ -215,7 +176,6 @@ static void generate_pre_barrier_slow_path(MacroAssembler* masm, void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Register obj, Register pre_val, - Register thread, Register tmp, bool tosca_live, bool expand_call) { @@ -223,9 +183,7 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, // directly to skip generating the check by // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp. -#ifdef _LP64 - assert(thread == r15_thread, "must be"); -#endif // _LP64 + const Register thread = r15_thread; Label done; Label runtime; @@ -260,18 +218,13 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, // expand_call should be passed true. if (expand_call) { - LP64_ONLY( assert(pre_val != c_rarg1, "smashed arg"); ) -#ifdef _LP64 + assert(pre_val != c_rarg1, "smashed arg"); if (c_rarg1 != thread) { __ mov(c_rarg1, thread); } if (c_rarg0 != pre_val) { __ mov(c_rarg0, pre_val); } -#else - __ push(thread); - __ push(pre_val); -#endif __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), 2); } else { __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread); @@ -333,12 +286,9 @@ static void generate_post_barrier_slow_path(MacroAssembler* masm, void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, - Register thread, Register tmp, Register tmp2) { -#ifdef _LP64 - assert(thread == r15_thread, "must be"); -#endif // _LP64 + const Register thread = r15_thread; Label done; Label runtime; @@ -350,7 +300,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, __ bind(runtime); // save the live input values - RegSet saved = RegSet::of(store_addr NOT_LP64(COMMA thread)); + RegSet saved = RegSet::of(store_addr); __ push_set(saved); __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp, thread); __ pop_set(saved); @@ -361,7 +311,6 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, #if defined(COMPILER2) static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) { -#ifdef _LP64 SaveLiveRegisters save_registers(masm, stub); if (c_rarg0 != arg) { __ mov(c_rarg0, arg); @@ -373,20 +322,15 @@ static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStub // call. If it did not contain any live value, it is free to be used. In // either case, it is safe to use it here as a call scratch register. __ call(RuntimeAddress(runtime_path), rax); -#else - Unimplemented(); -#endif // _LP64 } void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, Register obj, Register pre_val, - Register thread, Register tmp, G1PreBarrierStubC2* stub) { -#ifdef _LP64 - assert(thread == r15_thread, "must be"); -#endif // _LP64 + const Register thread = r15_thread; + assert(pre_val != noreg, "check this code"); if (obj != noreg) { assert_different_registers(obj, pre_val, tmp); @@ -422,14 +366,10 @@ void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, Register store_addr, Register new_val, - Register thread, Register tmp, Register tmp2, G1PostBarrierStubC2* stub) { -#ifdef _LP64 - assert(thread == r15_thread, "must be"); -#endif // _LP64 - + const Register thread = r15_thread; stub->initialize_registers(thread, tmp, tmp2); bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0; @@ -467,7 +407,6 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco bool needs_pre_barrier = as_normal; bool needs_post_barrier = val != noreg && in_heap; - Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx); // flatten object address if needed // We do it regardless of precise because we need the registers if (dst.index() == noreg && dst.disp() == 0) { @@ -478,18 +417,10 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco __ lea(tmp1, dst); } -#ifndef _LP64 - InterpreterMacroAssembler *imasm = static_cast(masm); -#endif - - NOT_LP64(__ get_thread(rcx)); - NOT_LP64(imasm->save_bcp()); - if (needs_pre_barrier) { g1_write_barrier_pre(masm /*masm*/, tmp1 /* obj */, tmp2 /* pre_val */, - rthread /* thread */, tmp3 /* tmp */, val != noreg /* tosca_live */, false /* expand_call */); @@ -510,12 +441,10 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco g1_write_barrier_post(masm /*masm*/, tmp1 /* store_adr */, new_val /* new_val */, - rthread /* thread */, tmp3 /* tmp */, tmp2 /* tmp2 */); } } - NOT_LP64(imasm->restore_bcp()); } #ifdef COMPILER1 @@ -575,11 +504,9 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* __ push(rdx); const Register pre_val = rax; - const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread); + const Register thread = r15_thread; const Register tmp = rdx; - NOT_LP64(__ get_thread(thread);) - Address queue_active(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); @@ -641,7 +568,7 @@ void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* // At this point we know new_value is non-null and the new_value crosses regions. // Must check to see if card is already dirty - const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread); + const Register thread = r15_thread; Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); @@ -659,8 +586,6 @@ void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* __ movptr(cardtable, (intptr_t)ct->card_table()->byte_map_base()); __ addptr(card_addr, cardtable); - NOT_LP64(__ get_thread(thread);) - __ cmpb(Address(card_addr, 0), G1CardTable::g1_young_card_val()); __ jcc(Assembler::equal, done); diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp index 237786a84d243..774e87b916c65 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp @@ -44,7 +44,6 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { void g1_write_barrier_pre(MacroAssembler* masm, Register obj, Register pre_val, - Register thread, Register tmp, bool tosca_live, bool expand_call); @@ -52,7 +51,6 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { void g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, - Register thread, Register tmp, Register tmp2); @@ -67,13 +65,12 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register dst, Address src, Register tmp1, Register tmp_thread); + Register dst, Address src, Register tmp1); #ifdef COMPILER2 void g1_write_barrier_pre_c2(MacroAssembler* masm, Register obj, Register pre_val, - Register thread, Register tmp, G1PreBarrierStubC2* c2_stub); void generate_c2_pre_barrier_stub(MacroAssembler* masm, @@ -81,7 +78,6 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { void g1_write_barrier_post_c2(MacroAssembler* masm, Register store_addr, Register new_val, - Register thread, Register tmp, Register tmp2, G1PostBarrierStubC2* c2_stub); diff --git a/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad b/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad index 8c1559f90f46d..819cd97696c15 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad +++ b/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad @@ -52,7 +52,7 @@ static void write_barrier_pre(MacroAssembler* masm, for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) { stub->dont_preserve(*reg); } - g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, r15_thread, tmp, stub); + g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, tmp, stub); } static void write_barrier_post(MacroAssembler* masm, @@ -67,7 +67,7 @@ static void write_barrier_post(MacroAssembler* masm, Assembler::InlineSkippedInstructionsCounter skip_counter(masm); G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node); - g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, r15_thread, tmp1, tmp2, stub); + g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, tmp1, tmp2, stub); } %} diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp index 5962609d08ede..be25326d68262 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp @@ -40,7 +40,7 @@ #define __ masm-> void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register dst, Address src, Register tmp1, Register tmp_thread) { + Register dst, Address src, Register tmp1) { bool in_heap = (decorators & IN_HEAP) != 0; bool in_native = (decorators & IN_NATIVE) != 0; bool is_not_null = (decorators & IS_NOT_NULL) != 0; @@ -50,7 +50,6 @@ void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, case T_OBJECT: case T_ARRAY: { if (in_heap) { -#ifdef _LP64 if (UseCompressedOops) { __ movl(dst, src); if (is_not_null) { @@ -58,9 +57,7 @@ void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, } else { __ decode_heap_oop(dst); } - } else -#endif - { + } else { __ movptr(dst, src); } } else { @@ -85,20 +82,7 @@ void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, break; case T_LONG: assert(dst == noreg, "only to ltos"); -#ifdef _LP64 __ movq(rax, src); -#else - if (atomic) { - __ fild_d(src); // Must load atomically - __ subptr(rsp,2*wordSize); // Make space for store - __ fistp_d(Address(rsp,0)); - __ pop(rax); - __ pop(rdx); - } else { - __ movl(rax, src); - __ movl(rdx, src.plus_disp(wordSize)); - } -#endif break; default: Unimplemented(); } @@ -117,17 +101,12 @@ void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators if (in_heap) { if (val == noreg) { assert(!is_not_null, "inconsistent access"); -#ifdef _LP64 if (UseCompressedOops) { __ movl(dst, NULL_WORD); } else { __ movslq(dst, NULL_WORD); } -#else - __ movl(dst, NULL_WORD); -#endif } else { -#ifdef _LP64 if (UseCompressedOops) { assert(!dst.uses(val), "not enough registers"); if (is_not_null) { @@ -136,9 +115,7 @@ void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators __ encode_heap_oop(val); } __ movl(dst, val); - } else -#endif - { + } else { __ movptr(dst, val); } } @@ -167,20 +144,7 @@ void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators break; case T_LONG: assert(val == noreg, "only tos"); -#ifdef _LP64 __ movq(dst, rax); -#else - if (atomic) { - __ push(rdx); - __ push(rax); // Must update atomically with FIST - __ fild_d(Address(rsp,0)); // So load into FPU register - __ fistp_d(dst); // and put into memory atomically - __ addptr(rsp, 2*wordSize); - } else { - __ movptr(dst, rax); - __ movptr(dst.plus_disp(wordSize), rdx); - } -#endif break; case T_FLOAT: assert(val == noreg, "only tos"); @@ -216,20 +180,14 @@ void BarrierSetAssembler::copy_load_at(MacroAssembler* masm, __ movl(dst, src); break; case 8: -#ifdef _LP64 __ movq(dst, src); -#else - fatal("No support for 8 bytes copy"); -#endif break; default: fatal("Unexpected size"); } -#ifdef _LP64 if ((decorators & ARRAYCOPY_CHECKCAST) != 0 && UseCompressedOops) { __ decode_heap_oop(dst); } -#endif } void BarrierSetAssembler::copy_store_at(MacroAssembler* masm, @@ -239,11 +197,9 @@ void BarrierSetAssembler::copy_store_at(MacroAssembler* masm, Address dst, Register src, Register tmp) { -#ifdef _LP64 if ((decorators & ARRAYCOPY_CHECKCAST) != 0 && UseCompressedOops) { __ encode_heap_oop(src); } -#endif assert(bytes <= 8, "can only deal with non-vector registers"); switch (bytes) { case 1: @@ -256,11 +212,7 @@ void BarrierSetAssembler::copy_store_at(MacroAssembler* masm, __ movl(dst, src); break; case 8: -#ifdef _LP64 __ movq(dst, src); -#else - fatal("No support for 8 bytes copy"); -#endif break; default: fatal("Unexpected size"); @@ -311,7 +263,7 @@ void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Re } void BarrierSetAssembler::tlab_allocate(MacroAssembler* masm, - Register thread, Register obj, + Register obj, Register var_size_in_bytes, int con_size_in_bytes, Register t1, @@ -320,15 +272,8 @@ void BarrierSetAssembler::tlab_allocate(MacroAssembler* masm, assert_different_registers(obj, t1, t2); assert_different_registers(obj, var_size_in_bytes, t1); Register end = t2; - if (!thread->is_valid()) { -#ifdef _LP64 - thread = r15_thread; -#else - assert(t1->is_valid(), "need temp reg"); - thread = t1; - __ get_thread(thread); -#endif - } + + const Register thread = r15_thread; __ verify_tlab(); @@ -351,7 +296,6 @@ void BarrierSetAssembler::tlab_allocate(MacroAssembler* masm, __ verify_tlab(); } -#ifdef _LP64 void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slow_path, Label* continuation) { BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); Register thread = r15_thread; @@ -375,35 +319,14 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo __ bind(done); } } -#else -void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label*, Label*) { - BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); - Label continuation; - - Register tmp = rdi; - __ push(tmp); - __ movptr(tmp, (intptr_t)bs_nm->disarmed_guard_value_address()); - Address disarmed_addr(tmp, 0); - __ align(4); - __ cmpl_imm32(disarmed_addr, 0); - __ pop(tmp); - __ jcc(Assembler::equal, continuation); - __ call(RuntimeAddress(StubRoutines::method_entry_barrier())); - __ bind(continuation); -} -#endif void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) { Label bad_call; __ cmpptr(rbx, 0); // rbx contains the incoming method for c2i adapters. __ jcc(Assembler::equal, bad_call); - Register tmp1 = LP64_ONLY( rscratch1 ) NOT_LP64( rax ); - Register tmp2 = LP64_ONLY( rscratch2 ) NOT_LP64( rcx ); -#ifndef _LP64 - __ push(tmp1); - __ push(tmp2); -#endif // !_LP64 + Register tmp1 = rscratch1; + Register tmp2 = rscratch2; // Pointer chase to the method holder to find out if the method is concurrently unloading. Label method_live; @@ -419,19 +342,9 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) { __ cmpptr(tmp1, 0); __ jcc(Assembler::notEqual, method_live); -#ifndef _LP64 - __ pop(tmp2); - __ pop(tmp1); -#endif - __ bind(bad_call); __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); __ bind(method_live); - -#ifndef _LP64 - __ pop(tmp2); - __ pop(tmp1); -#endif } void BarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) { @@ -451,8 +364,6 @@ void BarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register #ifdef COMPILER2 -#ifdef _LP64 - OptoReg::Name BarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) { if (!OptoReg::is_reg(opto_reg)) { return OptoReg::Bad; @@ -728,12 +639,4 @@ SaveLiveRegisters::~SaveLiveRegisters() { } } -#else // !_LP64 - -OptoReg::Name BarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) { - Unimplemented(); // This must be implemented to support late barrier expansion. -} - -#endif // _LP64 - #endif // COMPILER2 diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp index 5dde1c7aeedbb..fd52379d2e2bc 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp @@ -44,7 +44,7 @@ class BarrierSetAssembler: public CHeapObj { Register src, Register dst, Register count) {} virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register dst, Address src, Register tmp1, Register tmp_thread); + Register dst, Address src, Register tmp1); virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); @@ -93,7 +93,7 @@ class BarrierSetAssembler: public CHeapObj { Register obj, Register tmp, Label& slowpath); virtual void tlab_allocate(MacroAssembler* masm, - Register thread, Register obj, + Register obj, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Register t2, @@ -114,8 +114,6 @@ class BarrierSetAssembler: public CHeapObj { #ifdef COMPILER2 -#ifdef _LP64 - // This class saves and restores the registers that need to be preserved across // the runtime call represented by a given C2 barrier stub. Use as follows: // { @@ -160,8 +158,6 @@ class SaveLiveRegisters { ~SaveLiveRegisters(); }; -#endif // _LP64 - #endif // COMPILER2 #endif // CPU_X86_GC_SHARED_BARRIERSETASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp index e99774cbc401a..c27af4a29cd1f 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp @@ -39,7 +39,6 @@ class NativeNMethodCmpBarrier: public NativeInstruction { public: -#ifdef _LP64 enum Intel_specific_constants { instruction_code = 0x81, instruction_size = 8, @@ -47,14 +46,6 @@ class NativeNMethodCmpBarrier: public NativeInstruction { instruction_rex_prefix = Assembler::REX | Assembler::REX_B, instruction_modrm = 0x7f // [r15 + offset] }; -#else - enum Intel_specific_constants { - instruction_code = 0x81, - instruction_size = 7, - imm_offset = 2, - instruction_modrm = 0x3f // [rdi] - }; -#endif address instruction_address() const { return addr_at(0); } address immediate_address() const { return addr_at(imm_offset); } @@ -70,7 +61,6 @@ class NativeNMethodCmpBarrier: public NativeInstruction { } }; -#ifdef _LP64 bool NativeNMethodCmpBarrier::check_barrier(err_msg& msg) const { // Only require 4 byte alignment if (((uintptr_t) instruction_address()) & 0x3) { @@ -97,29 +87,6 @@ bool NativeNMethodCmpBarrier::check_barrier(err_msg& msg) const { } return true; } -#else -bool NativeNMethodCmpBarrier::check_barrier(err_msg& msg) const { - if (((uintptr_t) instruction_address()) & 0x3) { - msg.print("Addr: " INTPTR_FORMAT " not properly aligned", p2i(instruction_address())); - return false; - } - - int inst = ubyte_at(0); - if (inst != instruction_code) { - msg.print("Addr: " INTPTR_FORMAT " Code: 0x%x", p2i(instruction_address()), - inst); - return false; - } - - int modrm = ubyte_at(1); - if (modrm != instruction_modrm) { - msg.print("Addr: " INTPTR_FORMAT " mod/rm: 0x%x", p2i(instruction_address()), - modrm); - return false; - } - return true; -} -#endif // _LP64 void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { /* @@ -169,15 +136,11 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { // not find the expected native instruction at this offset, which needs updating. // Note that this offset is invariant of PreserveFramePointer. static int entry_barrier_offset(nmethod* nm) { -#ifdef _LP64 if (nm->is_compiled_by_c2()) { return -14; } else { return -15; } -#else - return -18; -#endif } static NativeNMethodCmpBarrier* native_nmethod_barrier(nmethod* nm) { diff --git a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp index 81284323e395e..ba89b09e4dcdc 100644 --- a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp @@ -57,7 +57,6 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl __ jcc(Assembler::zero, L_done); // zero count - nothing to do -#ifdef _LP64 __ leaq(end, Address(addr, count, TIMES_OOP, 0)); // end == addr+count*oop_size __ subptr(end, BytesPerHeapOop); // end - 1 to make inclusive __ shrptr(addr, CardTable::card_shift()); @@ -70,17 +69,6 @@ __ BIND(L_loop); __ movb(Address(addr, count, Address::times_1), 0); __ decrement(count); __ jcc(Assembler::greaterEqual, L_loop); -#else - __ lea(end, Address(addr, count, Address::times_ptr, -wordSize)); - __ shrptr(addr, CardTable::card_shift()); - __ shrptr(end, CardTable::card_shift()); - __ subptr(end, addr); // end --> count -__ BIND(L_loop); - Address cardtable(addr, count, Address::times_1, disp); - __ movb(cardtable, 0); - __ decrement(count); - __ jcc(Assembler::greaterEqual, L_loop); -#endif __ BIND(L_done); } diff --git a/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp index 76066409a7caa..42109b069f2e0 100644 --- a/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp @@ -31,10 +31,9 @@ void ModRefBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Decorat Register src, Register dst, Register count) { bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0; bool disjoint = (decorators & ARRAYCOPY_DISJOINT) != 0; - bool obj_int = type == T_OBJECT LP64_ONLY(&& UseCompressedOops); + bool obj_int = (type == T_OBJECT) && UseCompressedOops; if (is_reference_type(type)) { -#ifdef _LP64 if (!checkcast) { if (!obj_int) { // Save count for barrier @@ -44,11 +43,6 @@ void ModRefBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Decorat __ movq(r11, dst); } } -#else - if (disjoint) { - __ mov(rdx, dst); // save 'to' - } -#endif gen_write_ref_array_pre_barrier(masm, decorators, dst, count); } } @@ -57,11 +51,10 @@ void ModRefBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Decorat Register src, Register dst, Register count) { bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0; bool disjoint = (decorators & ARRAYCOPY_DISJOINT) != 0; - bool obj_int = type == T_OBJECT LP64_ONLY(&& UseCompressedOops); + bool obj_int = (type == T_OBJECT) && UseCompressedOops; Register tmp = rax; if (is_reference_type(type)) { -#ifdef _LP64 if (!checkcast) { if (!obj_int) { // Save count for barrier @@ -73,11 +66,6 @@ void ModRefBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Decorat } else { tmp = rscratch1; } -#else - if (disjoint) { - __ mov(dst, rdx); // restore 'to' - } -#endif gen_write_ref_array_post_barrier(masm, decorators, dst, count, tmp); } } diff --git a/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp index 063f4c2cc5ddf..298e5640b27d1 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp @@ -33,7 +33,6 @@ #define __ masm->masm()-> void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler* masm) { - NOT_LP64(assert(_addr->is_single_cpu(), "must be single");) Register addr = _addr->is_single_cpu() ? _addr->as_register() : _addr->as_register_lo(); Register newval = _new_value->as_register(); Register cmpval = _cmp_value->as_register(); @@ -46,14 +45,12 @@ void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler* masm) { assert(cmpval != addr, "cmp and addr must be in different registers"); assert(newval != addr, "new value and addr must be in different registers"); -#ifdef _LP64 if (UseCompressedOops) { __ encode_heap_oop(cmpval); __ mov(rscratch1, newval); __ encode_heap_oop(rscratch1); newval = rscratch1; } -#endif ShenandoahBarrierSet::assembler()->cmpxchg_oop(masm->masm(), result, Address(addr, 0), cmpval, newval, false, tmp1, tmp2); } @@ -105,7 +102,7 @@ LIR_Opr ShenandoahBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRIt // Because we want a 2-arg form of xchg and xadd __ move(value_opr, result); - assert(type == T_INT || is_reference_type(type) LP64_ONLY( || type == T_LONG ), "unexpected type"); + assert(type == T_INT || is_reference_type(type) || type == T_LONG, "unexpected type"); __ xchg(access.resolved_addr(), result, result, LIR_OprFact::illegalOpr); if (access.is_oop()) { diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp index a33ec611f55cd..6e1596a0e4b1a 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp @@ -51,10 +51,10 @@ static void save_machine_state(MacroAssembler* masm, bool handle_gpr, bool handl if (handle_fp) { // Some paths can be reached from the c2i adapter with live fp arguments in registers. - LP64_ONLY(assert(Argument::n_float_register_parameters_j == 8, "8 fp registers to save at java call")); + assert(Argument::n_float_register_parameters_j == 8, "8 fp registers to save at java call"); if (UseSSE >= 2) { - const int xmm_size = wordSize * LP64_ONLY(2) NOT_LP64(4); + const int xmm_size = wordSize * 2; __ subptr(rsp, xmm_size * 8); __ movdbl(Address(rsp, xmm_size * 0), xmm0); __ movdbl(Address(rsp, xmm_size * 1), xmm1); @@ -65,7 +65,7 @@ static void save_machine_state(MacroAssembler* masm, bool handle_gpr, bool handl __ movdbl(Address(rsp, xmm_size * 6), xmm6); __ movdbl(Address(rsp, xmm_size * 7), xmm7); } else if (UseSSE >= 1) { - const int xmm_size = wordSize * LP64_ONLY(1) NOT_LP64(2); + const int xmm_size = wordSize * 1; __ subptr(rsp, xmm_size * 8); __ movflt(Address(rsp, xmm_size * 0), xmm0); __ movflt(Address(rsp, xmm_size * 1), xmm1); @@ -84,7 +84,7 @@ static void save_machine_state(MacroAssembler* masm, bool handle_gpr, bool handl static void restore_machine_state(MacroAssembler* masm, bool handle_gpr, bool handle_fp) { if (handle_fp) { if (UseSSE >= 2) { - const int xmm_size = wordSize * LP64_ONLY(2) NOT_LP64(4); + const int xmm_size = wordSize * 2; __ movdbl(xmm0, Address(rsp, xmm_size * 0)); __ movdbl(xmm1, Address(rsp, xmm_size * 1)); __ movdbl(xmm2, Address(rsp, xmm_size * 2)); @@ -95,7 +95,7 @@ static void restore_machine_state(MacroAssembler* masm, bool handle_gpr, bool ha __ movdbl(xmm7, Address(rsp, xmm_size * 7)); __ addptr(rsp, xmm_size * 8); } else if (UseSSE >= 1) { - const int xmm_size = wordSize * LP64_ONLY(1) NOT_LP64(2); + const int xmm_size = wordSize * 1; __ movflt(xmm0, Address(rsp, xmm_size * 0)); __ movflt(xmm1, Address(rsp, xmm_size * 1)); __ movflt(xmm2, Address(rsp, xmm_size * 2)); @@ -124,11 +124,10 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec if (ShenandoahCardBarrier) { bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0; bool disjoint = (decorators & ARRAYCOPY_DISJOINT) != 0; - bool obj_int = type == T_OBJECT LP64_ONLY(&& UseCompressedOops); + bool obj_int = (type == T_OBJECT) && UseCompressedOops; // We need to save the original element count because the array copy stub // will destroy the value and we need it for the card marking barrier. -#ifdef _LP64 if (!checkcast) { if (!obj_int) { // Save count for barrier @@ -138,30 +137,10 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec __ movq(r11, dst); } } -#else - if (disjoint) { - __ mov(rdx, dst); // save 'to' - } -#endif } if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahLoadRefBarrier) { -#ifdef _LP64 Register thread = r15_thread; -#else - Register thread = rax; - if (thread == src || thread == dst || thread == count) { - thread = rbx; - } - if (thread == src || thread == dst || thread == count) { - thread = rcx; - } - if (thread == src || thread == dst || thread == count) { - thread = rdx; - } - __ push(thread); - __ get_thread(thread); -#endif assert_different_registers(src, dst, count, thread); Label L_done; @@ -182,16 +161,13 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec save_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ false); -#ifdef _LP64 assert(src == rdi, "expected"); assert(dst == rsi, "expected"); assert(count == rdx, "expected"); if (UseCompressedOops) { __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop), src, dst, count); - } else -#endif - { + } else { __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop), src, dst, count); } @@ -199,7 +175,6 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec restore_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ false); __ bind(L_done); - NOT_LP64(__ pop(thread);) } } @@ -211,10 +186,9 @@ void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Dec if (ShenandoahCardBarrier && is_reference_type(type)) { bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0; bool disjoint = (decorators & ARRAYCOPY_DISJOINT) != 0; - bool obj_int = type == T_OBJECT LP64_ONLY(&& UseCompressedOops); + bool obj_int = (type == T_OBJECT) && UseCompressedOops; Register tmp = rax; -#ifdef _LP64 if (!checkcast) { if (!obj_int) { // Save count for barrier @@ -226,11 +200,6 @@ void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Dec } else { tmp = rscratch1; } -#else - if (disjoint) { - __ mov(dst, rdx); // restore 'to' - } -#endif gen_write_ref_array_post_barrier(masm, decorators, dst, count, tmp); } } @@ -238,20 +207,18 @@ void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Dec void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm, Register obj, Register pre_val, - Register thread, Register tmp, bool tosca_live, bool expand_call) { if (ShenandoahSATBBarrier) { - satb_write_barrier_pre(masm, obj, pre_val, thread, tmp, tosca_live, expand_call); + satb_write_barrier_pre(masm, obj, pre_val, tmp, tosca_live, expand_call); } } void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, Register obj, Register pre_val, - Register thread, Register tmp, bool tosca_live, bool expand_call) { @@ -259,9 +226,7 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, // directly to skip generating the check by // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp. -#ifdef _LP64 - assert(thread == r15_thread, "must be"); -#endif // _LP64 + const Register thread = r15_thread; Label done; Label runtime; @@ -282,7 +247,7 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, // Do we need to load the previous value? if (obj != noreg) { - __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); + __ load_heap_oop(pre_val, Address(obj, 0), noreg, AS_RAW); } // Is the previous value null? @@ -327,9 +292,6 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, // So when we do not have have a full interpreter frame on the stack // expand_call should be passed true. - NOT_LP64( __ push(thread); ) - -#ifdef _LP64 // We move pre_val into c_rarg0 early, in order to avoid smashing it, should // pre_val be c_rarg1 (where the call prologue would copy thread argument). // Note: this should not accidentally smash thread, because thread is always r15. @@ -337,26 +299,18 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, if (c_rarg0 != pre_val) { __ mov(c_rarg0, pre_val); } -#endif if (expand_call) { - LP64_ONLY( assert(pre_val != c_rarg1, "smashed arg"); ) -#ifdef _LP64 + assert(pre_val != c_rarg1, "smashed arg"); if (c_rarg1 != thread) { __ mov(c_rarg1, thread); } // Already moved pre_val into c_rarg0 above -#else - __ push(thread); - __ push(pre_val); -#endif __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), 2); } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), LP64_ONLY(c_rarg0) NOT_LP64(pre_val), thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), c_rarg0, thread); } - NOT_LP64( __ pop(thread); ) - // save the live input values if (pre_val != rax) __ pop(pre_val); @@ -383,16 +337,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, __ block_comment("load_reference_barrier { "); // Check if GC is active -#ifdef _LP64 Register thread = r15_thread; -#else - Register thread = rcx; - if (thread == dst) { - thread = rbx; - } - __ push(thread); - __ get_thread(thread); -#endif Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); int flags = ShenandoahHeap::HAS_FORWARDED; @@ -438,7 +383,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, // The rest is saved with the optimized path - uint num_saved_regs = 4 + (dst != rax ? 1 : 0) LP64_ONLY(+4); + uint num_saved_regs = 4 + (dst != rax ? 1 : 0) + 4; __ subptr(rsp, num_saved_regs * wordSize); uint slot = num_saved_regs; if (dst != rax) { @@ -448,21 +393,15 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, __ movptr(Address(rsp, (--slot) * wordSize), rdx); __ movptr(Address(rsp, (--slot) * wordSize), rdi); __ movptr(Address(rsp, (--slot) * wordSize), rsi); -#ifdef _LP64 __ movptr(Address(rsp, (--slot) * wordSize), r8); __ movptr(Address(rsp, (--slot) * wordSize), r9); __ movptr(Address(rsp, (--slot) * wordSize), r10); __ movptr(Address(rsp, (--slot) * wordSize), r11); // r12-r15 are callee saved in all calling conventions -#endif assert(slot == 0, "must use all slots"); // Shuffle registers such that dst is in c_rarg0 and addr in c_rarg1. -#ifdef _LP64 Register arg0 = c_rarg0, arg1 = c_rarg1; -#else - Register arg0 = rdi, arg1 = rsi; -#endif if (dst == arg1) { __ lea(arg0, src); __ xchgptr(arg1, arg0); @@ -489,12 +428,10 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom), arg0, arg1); } -#ifdef _LP64 __ movptr(r11, Address(rsp, (slot++) * wordSize)); __ movptr(r10, Address(rsp, (slot++) * wordSize)); __ movptr(r9, Address(rsp, (slot++) * wordSize)); __ movptr(r8, Address(rsp, (slot++) * wordSize)); -#endif __ movptr(rsi, Address(rsp, (slot++) * wordSize)); __ movptr(rdi, Address(rsp, (slot++) * wordSize)); __ movptr(rdx, Address(rsp, (slot++) * wordSize)); @@ -520,10 +457,6 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, __ bind(heap_stable); __ block_comment("} load_reference_barrier"); - -#ifndef _LP64 - __ pop(thread); -#endif } // @@ -540,10 +473,10 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, // tmp1 (if it is valid) // void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register dst, Address src, Register tmp1, Register tmp_thread) { + Register dst, Address src, Register tmp1) { // 1: non-reference load, no additional barrier is needed if (!is_reference_type(type)) { - BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); + BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1); return; } @@ -567,7 +500,7 @@ void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet d assert_different_registers(dst, src.base(), src.index()); } - BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); + BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1); load_reference_barrier(masm, dst, src, decorators); @@ -582,25 +515,19 @@ void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet d dst = result_dst; } } else { - BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); + BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1); } // 3: apply keep-alive barrier if needed if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) { save_machine_state(masm, /* handle_gpr = */ true, /* handle_fp = */ true); - Register thread = NOT_LP64(tmp_thread) LP64_ONLY(r15_thread); - assert_different_registers(dst, tmp1, tmp_thread); - if (!thread->is_valid()) { - thread = rdx; - } - NOT_LP64(__ get_thread(thread)); + assert_different_registers(dst, tmp1, r15_thread); // Generate the SATB pre-barrier code to log the value of // the referent field in an SATB buffer. shenandoah_write_barrier_pre(masm /* masm */, noreg /* obj */, dst /* pre_val */, - thread /* thread */, tmp1 /* tmp */, true /* tosca_live */, true /* expand_call */); @@ -618,23 +545,8 @@ void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register o // We'll use this register as the TLS base address and also later on // to hold the byte_map_base. - Register thread = LP64_ONLY(r15_thread) NOT_LP64(rcx); - Register tmp = LP64_ONLY(rscratch1) NOT_LP64(rdx); - -#ifndef _LP64 - // The next two ifs are just to get temporary registers to use for TLS and card table base. - if (thread == obj) { - thread = rdx; - tmp = rsi; - } - if (tmp == obj) { - tmp = rsi; - } - - __ push(thread); - __ push(tmp); - __ get_thread(thread); -#endif + Register thread = r15_thread; + Register tmp = rscratch1; Address curr_ct_holder_addr(thread, in_bytes(ShenandoahThreadLocalData::card_table_offset())); __ movptr(tmp, curr_ct_holder_addr); @@ -650,11 +562,6 @@ void ShenandoahBarrierSetAssembler::store_check(MacroAssembler* masm, Register o } else { __ movb(card_addr, dirty); } - -#ifndef _LP64 - __ pop(tmp); - __ pop(thread); -#endif } void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, @@ -666,7 +573,6 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet if (on_oop && in_heap) { bool needs_pre_barrier = as_normal; - Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx); // flatten object address if needed // We do it regardless of precise because we need the registers if (dst.index() == noreg && dst.disp() == 0) { @@ -677,19 +583,12 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet __ lea(tmp1, dst); } - assert_different_registers(val, tmp1, tmp2, tmp3, rthread); - -#ifndef _LP64 - __ get_thread(rthread); - InterpreterMacroAssembler *imasm = static_cast(masm); - imasm->save_bcp(); -#endif + assert_different_registers(val, tmp1, tmp2, tmp3, r15_thread); if (needs_pre_barrier) { shenandoah_write_barrier_pre(masm /*masm*/, tmp1 /* obj */, tmp2 /* pre_val */, - rthread /* thread */, tmp3 /* tmp */, val != noreg /* tosca_live */, false /* expand_call */); @@ -701,7 +600,6 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet store_check(masm, tmp1); } } - NOT_LP64(imasm->restore_bcp()); } else { BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); } @@ -736,12 +634,9 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, Label L_success, L_failure; // Remember oldval for retry logic below -#ifdef _LP64 if (UseCompressedOops) { __ movl(tmp1, oldval); - } else -#endif - { + } else { __ movptr(tmp1, oldval); } @@ -749,13 +644,10 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, // // Try to CAS with given arguments. If successful, then we are done. -#ifdef _LP64 if (UseCompressedOops) { __ lock(); __ cmpxchgl(newval, addr); - } else -#endif - { + } else { __ lock(); __ cmpxchgptr(newval, addr); } @@ -776,23 +668,15 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, __ jcc(Assembler::zero, L_failure); // Filter: when heap is stable, the failure is definitely legitimate -#ifdef _LP64 const Register thread = r15_thread; -#else - const Register thread = tmp2; - __ get_thread(thread); -#endif Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); __ testb(gc_state, ShenandoahHeap::HAS_FORWARDED); __ jcc(Assembler::zero, L_failure); -#ifdef _LP64 if (UseCompressedOops) { __ movl(tmp2, oldval); __ decode_heap_oop(tmp2); - } else -#endif - { + } else { __ movptr(tmp2, oldval); } @@ -807,11 +691,9 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, __ shrptr(tmp2, 2); __ shlptr(tmp2, 2); -#ifdef _LP64 if (UseCompressedOops) { __ decode_heap_oop(tmp1); // decode for comparison } -#endif // Now we have the forwarded offender in tmp2. // Compare and if they don't match, we have legitimate failure @@ -827,19 +709,14 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, // with to-space ptr store. We still have to do the retry, because the GC might // have updated the reference for us. -#ifdef _LP64 if (UseCompressedOops) { __ encode_heap_oop(tmp2); // previously decoded at step 2. } -#endif -#ifdef _LP64 if (UseCompressedOops) { __ lock(); __ cmpxchgl(tmp2, addr); - } else -#endif - { + } else { __ lock(); __ cmpxchgptr(tmp2, addr); } @@ -851,22 +728,16 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, // from-space ptr into memory anymore. Make sure oldval is restored, after being // garbled during retries. // -#ifdef _LP64 if (UseCompressedOops) { __ movl(oldval, tmp2); - } else -#endif - { + } else { __ movptr(oldval, tmp2); } -#ifdef _LP64 if (UseCompressedOops) { __ lock(); __ cmpxchgl(newval, addr); - } else -#endif - { + } else { __ lock(); __ cmpxchgptr(newval, addr); } @@ -918,7 +789,6 @@ void ShenandoahBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssemb __ testl(count, count); __ jccb(Assembler::zero, L_done); -#ifdef _LP64 const Register thread = r15_thread; Address curr_ct_holder_addr(thread, in_bytes(ShenandoahThreadLocalData::card_table_offset())); __ movptr(tmp, curr_ct_holder_addr); @@ -935,26 +805,6 @@ void ShenandoahBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssemb __ movb(Address(addr, count, Address::times_1), 0); __ decrement(count); __ jccb(Assembler::greaterEqual, L_loop); -#else - const Register thread = tmp; - __ get_thread(thread); - - Address curr_ct_holder_addr(thread, in_bytes(ShenandoahThreadLocalData::byte_map_base_offset())); - __ movptr(tmp, curr_ct_holder_addr); - - __ lea(end, Address(addr, count, Address::times_ptr, -wordSize)); - __ shrptr(addr, CardTable::card_shift()); - __ shrptr(end, CardTable::card_shift()); - __ subptr(end, addr); // end --> count - - __ addptr(addr, tmp); - - __ BIND(L_loop); - Address cardtable(addr, count, Address::times_1, 0); - __ movb(cardtable, 0); - __ decrement(count); - __ jccb(Assembler::greaterEqual, L_loop); -#endif __ BIND(L_done); } @@ -1019,15 +869,8 @@ void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assemble __ mov(tmp1, res); __ shrptr(tmp1, ShenandoahHeapRegion::region_size_bytes_shift_jint()); __ movptr(tmp2, (intptr_t) ShenandoahHeap::in_cset_fast_test_addr()); -#ifdef _LP64 __ movbool(tmp2, Address(tmp2, tmp1, Address::times_1)); __ testbool(tmp2); -#else - // On x86_32, C1 register allocator can give us the register without 8-bit support. - // Do the full-register access and test to avoid compilation failures. - __ movptr(tmp2, Address(tmp2, tmp1, Address::times_1)); - __ testptr(tmp2, 0xFF); -#endif __ jcc(Assembler::zero, *stub->continuation()); } @@ -1061,11 +904,9 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss __ push(rdx); const Register pre_val = rax; - const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread); + const Register thread = r15_thread; const Register tmp = rdx; - NOT_LP64(__ get_thread(thread);) - Address queue_index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset())); Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset())); @@ -1120,7 +961,6 @@ void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_s bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators); bool is_native = ShenandoahBarrierSet::is_native_access(decorators); -#ifdef _LP64 __ load_parameter(0, c_rarg0); __ load_parameter(1, c_rarg1); if (is_strong) { @@ -1145,18 +985,6 @@ void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_s assert(is_native, "phantom must only be called off-heap"); __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom), c_rarg0, c_rarg1); } -#else - __ load_parameter(0, rax); - __ load_parameter(1, rbx); - if (is_strong) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong), rax, rbx); - } else if (is_weak) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak), rax, rbx); - } else { - assert(is_phantom, "only remaining strength"); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom), rax, rbx); - } -#endif __ restore_live_registers_except_rax(true); diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp index ae0ad3533e146..b0185f2dbffbd 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp @@ -44,7 +44,6 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { void satb_write_barrier_pre(MacroAssembler* masm, Register obj, Register pre_val, - Register thread, Register tmp, bool tosca_live, bool expand_call); @@ -52,7 +51,6 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { void shenandoah_write_barrier_pre(MacroAssembler* masm, Register obj, Register pre_val, - Register thread, Register tmp, bool tosca_live, bool expand_call); @@ -81,7 +79,7 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register src, Register dst, Register count); virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register dst, Address src, Register tmp1, Register tmp_thread); + Register dst, Address src, Register tmp1); virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp index f7b1e25cf3b5d..9cdf0b229c0a4 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp @@ -220,11 +220,10 @@ void ZBarrierSetAssembler::load_at(MacroAssembler* masm, BasicType type, Register dst, Address src, - Register tmp1, - Register tmp_thread) { + Register tmp1) { if (!ZBarrierSet::barrier_needed(decorators, type)) { // Barrier not needed - BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); + BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1); return; } diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp index 91be2e3b94585..8bb653ec5fbaf 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp @@ -73,8 +73,7 @@ class ZBarrierSetAssembler : public ZBarrierSetAssemblerBase { BasicType type, Register dst, Address src, - Register tmp1, - Register tmp_thread); + Register tmp1); virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index a2173be609b62..0f7651b9de2e8 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -4064,7 +4064,7 @@ void MacroAssembler::resolve_jobject(Register value, jcc(Assembler::notZero, tagged); // Resolve local handle - access_load_at(T_OBJECT, IN_NATIVE | AS_RAW, value, Address(value, 0), tmp, thread); + access_load_at(T_OBJECT, IN_NATIVE | AS_RAW, value, Address(value, 0), tmp); verify_oop(value); jmp(done); @@ -4073,14 +4073,14 @@ void MacroAssembler::resolve_jobject(Register value, jcc(Assembler::notZero, weak_tagged); // Resolve global handle - access_load_at(T_OBJECT, IN_NATIVE, value, Address(value, -JNIHandles::TypeTag::global), tmp, thread); + access_load_at(T_OBJECT, IN_NATIVE, value, Address(value, -JNIHandles::TypeTag::global), tmp); verify_oop(value); jmp(done); bind(weak_tagged); // Resolve jweak. access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF, - value, Address(value, -JNIHandles::TypeTag::weak_global), tmp, thread); + value, Address(value, -JNIHandles::TypeTag::weak_global), tmp); verify_oop(value); bind(done); @@ -4106,7 +4106,7 @@ void MacroAssembler::resolve_global_jobject(Register value, #endif // Resolve global handle - access_load_at(T_OBJECT, IN_NATIVE, value, Address(value, -JNIHandles::TypeTag::global), tmp, thread); + access_load_at(T_OBJECT, IN_NATIVE, value, Address(value, -JNIHandles::TypeTag::global), tmp); verify_oop(value); bind(done); @@ -4144,14 +4144,14 @@ void MacroAssembler::testptr(Register dst, Register src) { } // Defines obj, preserves var_size_in_bytes, okay for t2 == var_size_in_bytes. -void MacroAssembler::tlab_allocate(Register thread, Register obj, +void MacroAssembler::tlab_allocate(Register obj, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Register t2, Label& slow_case) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); - bs->tlab_allocate(this, thread, obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); + bs->tlab_allocate(this, obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); } RegSet MacroAssembler::call_clobbered_gp_registers() { @@ -5979,7 +5979,7 @@ void MacroAssembler::resolve_oop_handle(Register result, Register tmp) { // Only IN_HEAP loads require a thread_tmp register // OopHandle::resolve is an indirection like jobject. access_load_at(T_OBJECT, IN_NATIVE, - result, Address(result, 0), tmp, /*tmp_thread*/noreg); + result, Address(result, 0), tmp); } // ((WeakHandle)result).resolve(); @@ -5995,7 +5995,7 @@ void MacroAssembler::resolve_weak_handle(Register rresult, Register rtmp) { // Only IN_HEAP loads require a thread_tmp register // WeakHandle::resolve is an indirection like jweak. access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF, - rresult, Address(rresult, 0), rtmp, /*tmp_thread*/noreg); + rresult, Address(rresult, 0), rtmp); bind(resolved); } @@ -6092,14 +6092,14 @@ void MacroAssembler::cmp_klasses_from_objects(Register obj1, Register obj2, Regi } void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators, Register dst, Address src, - Register tmp1, Register thread_tmp) { + Register tmp1) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); decorators = AccessInternal::decorator_fixup(decorators, type); bool as_raw = (decorators & AS_RAW) != 0; if (as_raw) { - bs->BarrierSetAssembler::load_at(this, decorators, type, dst, src, tmp1, thread_tmp); + bs->BarrierSetAssembler::load_at(this, decorators, type, dst, src, tmp1); } else { - bs->load_at(this, decorators, type, dst, src, tmp1, thread_tmp); + bs->load_at(this, decorators, type, dst, src, tmp1); } } @@ -6115,15 +6115,13 @@ void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators, Ad } } -void MacroAssembler::load_heap_oop(Register dst, Address src, Register tmp1, - Register thread_tmp, DecoratorSet decorators) { - access_load_at(T_OBJECT, IN_HEAP | decorators, dst, src, tmp1, thread_tmp); +void MacroAssembler::load_heap_oop(Register dst, Address src, Register tmp1, DecoratorSet decorators) { + access_load_at(T_OBJECT, IN_HEAP | decorators, dst, src, tmp1); } // Doesn't do verification, generates fixed size code -void MacroAssembler::load_heap_oop_not_null(Register dst, Address src, Register tmp1, - Register thread_tmp, DecoratorSet decorators) { - access_load_at(T_OBJECT, IN_HEAP | IS_NOT_NULL | decorators, dst, src, tmp1, thread_tmp); +void MacroAssembler::load_heap_oop_not_null(Register dst, Address src, Register tmp1, DecoratorSet decorators) { + access_load_at(T_OBJECT, IN_HEAP | IS_NOT_NULL | decorators, dst, src, tmp1); } void MacroAssembler::store_heap_oop(Address dst, Register val, Register tmp1, diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 79f99afded24d..27c90fb866e05 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -371,14 +371,12 @@ class MacroAssembler: public Assembler { void cmp_klasses_from_objects(Register obj1, Register obj2, Register tmp1, Register tmp2); void access_load_at(BasicType type, DecoratorSet decorators, Register dst, Address src, - Register tmp1, Register thread_tmp); + Register tmp1); void access_store_at(BasicType type, DecoratorSet decorators, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); - void load_heap_oop(Register dst, Address src, Register tmp1 = noreg, - Register thread_tmp = noreg, DecoratorSet decorators = 0); - void load_heap_oop_not_null(Register dst, Address src, Register tmp1 = noreg, - Register thread_tmp = noreg, DecoratorSet decorators = 0); + void load_heap_oop(Register dst, Address src, Register tmp1 = noreg, DecoratorSet decorators = 0); + void load_heap_oop_not_null(Register dst, Address src, Register tmp1 = noreg, DecoratorSet decorators = 0); void store_heap_oop(Address dst, Register val, Register tmp1 = noreg, Register tmp2 = noreg, Register tmp3 = noreg, DecoratorSet decorators = 0); @@ -588,7 +586,6 @@ class MacroAssembler: public Assembler { // allocation void tlab_allocate( - Register thread, // Current thread Register obj, // result: pointer to object after successful allocation Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise int con_size_in_bytes, // object size in bytes if known at compile time diff --git a/src/hotspot/cpu/x86/methodHandles_x86.cpp b/src/hotspot/cpu/x86/methodHandles_x86.cpp index 0d95af133fa81..ed19daff37ddf 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.cpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp @@ -182,7 +182,7 @@ void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, __ verify_oop(method_temp); __ access_load_at(T_ADDRESS, IN_HEAP, method_temp, Address(method_temp, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset())), - noreg, noreg); + noreg); if (VerifyMethodHandles && !for_compiler_entry) { // make sure recv is already on stack @@ -212,7 +212,7 @@ void MethodHandles::jump_to_native_invoker(MacroAssembler* _masm, Register nep_r __ verify_oop(nep_reg); __ access_load_at(T_ADDRESS, IN_HEAP, temp_target, Address(nep_reg, NONZERO(jdk_internal_foreign_abi_NativeEntryPoint::downcall_stub_address_offset_in_bytes())), - noreg, noreg); + noreg); __ jmp(temp_target); BLOCK_COMMENT("} jump_to_native_invoker"); @@ -420,7 +420,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp3); } __ load_heap_oop(rbx_method, member_vmtarget); - __ access_load_at(T_ADDRESS, IN_HEAP, rbx_method, vmtarget_method, noreg, noreg); + __ access_load_at(T_ADDRESS, IN_HEAP, rbx_method, vmtarget_method, noreg); break; case vmIntrinsics::_linkToStatic: @@ -428,7 +428,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp3); } __ load_heap_oop(rbx_method, member_vmtarget); - __ access_load_at(T_ADDRESS, IN_HEAP, rbx_method, vmtarget_method, noreg, noreg); + __ access_load_at(T_ADDRESS, IN_HEAP, rbx_method, vmtarget_method, noreg); break; case vmIntrinsics::_linkToVirtual: @@ -442,7 +442,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, // pick out the vtable index from the MemberName, and then we can discard it: Register temp2_index = temp2; - __ access_load_at(T_ADDRESS, IN_HEAP, temp2_index, member_vmindex, noreg, noreg); + __ access_load_at(T_ADDRESS, IN_HEAP, temp2_index, member_vmindex, noreg); if (VerifyMethodHandles) { Label L_index_ok; @@ -474,7 +474,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, __ verify_klass_ptr(temp3_intf); Register rbx_index = rbx_method; - __ access_load_at(T_ADDRESS, IN_HEAP, rbx_index, member_vmindex, noreg, noreg); + __ access_load_at(T_ADDRESS, IN_HEAP, rbx_index, member_vmindex, noreg); if (VerifyMethodHandles) { Label L; __ cmpl(rbx_index, 0); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index b480c78f79d53..b88a2bd1f8e6b 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -3981,7 +3981,7 @@ address StubGenerator::generate_upcall_stub_load_target() { __ load_heap_oop(rbx, Address(rbx, java_lang_invoke_MemberName::method_offset()), rscratch1); __ access_load_at(T_ADDRESS, IN_HEAP, rbx, Address(rbx, java_lang_invoke_ResolvedMethodName::vmtarget_offset()), - noreg, noreg); + noreg); __ movptr(Address(r15_thread, JavaThread::callee_target_offset()), rbx); // just in case callee is deoptimized __ ret(0); diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index fecc804a04424..bdc2ca908bd41 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -654,7 +654,7 @@ address TemplateInterpreterGenerator::generate_Reference_get_entry(void) { // Load the value of the referent field. const Address field_address(rax, referent_offset); - __ load_heap_oop(rax, field_address, /*tmp1*/ rbx, /*tmp_thread*/ rdx, ON_WEAK_OOP_REF); + __ load_heap_oop(rax, field_address, /*tmp1*/ rbx, ON_WEAK_OOP_REF); // _areturn __ pop(rdi); // get return address diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index 1641abac9235b..b9637e1d7c49c 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -151,7 +151,7 @@ static void do_oop_load(InterpreterMacroAssembler* _masm, Address src, Register dst, DecoratorSet decorators = 0) { - __ load_heap_oop(dst, src, rdx, rbx, decorators); + __ load_heap_oop(dst, src, rdx, decorators); } Address TemplateTable::at_bcp(int offset) { @@ -740,7 +740,7 @@ void TemplateTable::iaload() { __ access_load_at(T_INT, IN_HEAP | IS_ARRAY, rax, Address(rdx, rax, Address::times_4, arrayOopDesc::base_offset_in_bytes(T_INT)), - noreg, noreg); + noreg); } void TemplateTable::laload() { @@ -752,7 +752,7 @@ void TemplateTable::laload() { __ access_load_at(T_LONG, IN_HEAP | IS_ARRAY, noreg /* ltos */, Address(rdx, rbx, Address::times_8, arrayOopDesc::base_offset_in_bytes(T_LONG)), - noreg, noreg); + noreg); } @@ -766,7 +766,7 @@ void TemplateTable::faload() { Address(rdx, rax, Address::times_4, arrayOopDesc::base_offset_in_bytes(T_FLOAT)), - noreg, noreg); + noreg); } void TemplateTable::daload() { @@ -778,7 +778,7 @@ void TemplateTable::daload() { Address(rdx, rax, Address::times_8, arrayOopDesc::base_offset_in_bytes(T_DOUBLE)), - noreg, noreg); + noreg); } void TemplateTable::aaload() { @@ -801,7 +801,7 @@ void TemplateTable::baload() { index_check(rdx, rax); // kills rbx __ access_load_at(T_BYTE, IN_HEAP | IS_ARRAY, rax, Address(rdx, rax, Address::times_1, arrayOopDesc::base_offset_in_bytes(T_BYTE)), - noreg, noreg); + noreg); } void TemplateTable::caload() { @@ -811,7 +811,7 @@ void TemplateTable::caload() { index_check(rdx, rax); // kills rbx __ access_load_at(T_CHAR, IN_HEAP | IS_ARRAY, rax, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR)), - noreg, noreg); + noreg); } // iload followed by caload frequent pair @@ -826,7 +826,7 @@ void TemplateTable::fast_icaload() { index_check(rdx, rax); // kills rbx __ access_load_at(T_CHAR, IN_HEAP | IS_ARRAY, rax, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR)), - noreg, noreg); + noreg); } @@ -837,7 +837,7 @@ void TemplateTable::saload() { index_check(rdx, rax); // kills rbx __ access_load_at(T_SHORT, IN_HEAP | IS_ARRAY, rax, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_SHORT)), - noreg, noreg); + noreg); } void TemplateTable::iload(int n) { @@ -2566,7 +2566,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ jcc(Assembler::notZero, notByte); // btos - __ access_load_at(T_BYTE, IN_HEAP, rax, field, noreg, noreg); + __ access_load_at(T_BYTE, IN_HEAP, rax, field, noreg); __ push(btos); // Rewrite bytecode to be faster if (!is_static && rc == may_rewrite) { @@ -2579,7 +2579,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ jcc(Assembler::notEqual, notBool); // ztos (same code as btos) - __ access_load_at(T_BOOLEAN, IN_HEAP, rax, field, noreg, noreg); + __ access_load_at(T_BOOLEAN, IN_HEAP, rax, field, noreg); __ push(ztos); // Rewrite bytecode to be faster if (!is_static && rc == may_rewrite) { @@ -2603,7 +2603,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ cmpl(tos_state, itos); __ jcc(Assembler::notEqual, notInt); // itos - __ access_load_at(T_INT, IN_HEAP, rax, field, noreg, noreg); + __ access_load_at(T_INT, IN_HEAP, rax, field, noreg); __ push(itos); // Rewrite bytecode to be faster if (!is_static && rc == may_rewrite) { @@ -2615,7 +2615,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ cmpl(tos_state, ctos); __ jcc(Assembler::notEqual, notChar); // ctos - __ access_load_at(T_CHAR, IN_HEAP, rax, field, noreg, noreg); + __ access_load_at(T_CHAR, IN_HEAP, rax, field, noreg); __ push(ctos); // Rewrite bytecode to be faster if (!is_static && rc == may_rewrite) { @@ -2627,7 +2627,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ cmpl(tos_state, stos); __ jcc(Assembler::notEqual, notShort); // stos - __ access_load_at(T_SHORT, IN_HEAP, rax, field, noreg, noreg); + __ access_load_at(T_SHORT, IN_HEAP, rax, field, noreg); __ push(stos); // Rewrite bytecode to be faster if (!is_static && rc == may_rewrite) { @@ -2641,7 +2641,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr // ltos // Generate code as if volatile (x86_32). There just aren't enough registers to // save that information and this code is faster than the test. - __ access_load_at(T_LONG, IN_HEAP | MO_RELAXED, noreg /* ltos */, field, noreg, noreg); + __ access_load_at(T_LONG, IN_HEAP | MO_RELAXED, noreg /* ltos */, field, noreg); __ push(ltos); // Rewrite bytecode to be faster if (!is_static && rc == may_rewrite) patch_bytecode(Bytecodes::_fast_lgetfield, bc, rbx); @@ -2652,7 +2652,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ jcc(Assembler::notEqual, notFloat); // ftos - __ access_load_at(T_FLOAT, IN_HEAP, noreg /* ftos */, field, noreg, noreg); + __ access_load_at(T_FLOAT, IN_HEAP, noreg /* ftos */, field, noreg); __ push(ftos); // Rewrite bytecode to be faster if (!is_static && rc == may_rewrite) { @@ -2668,7 +2668,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr #endif // dtos // MO_RELAXED: for the case of volatile field, in fact it adds no extra work for the underlying implementation - __ access_load_at(T_DOUBLE, IN_HEAP | MO_RELAXED, noreg /* dtos */, field, noreg, noreg); + __ access_load_at(T_DOUBLE, IN_HEAP | MO_RELAXED, noreg /* dtos */, field, noreg); __ push(dtos); // Rewrite bytecode to be faster if (!is_static && rc == may_rewrite) { @@ -3131,25 +3131,25 @@ void TemplateTable::fast_accessfield(TosState state) { __ verify_oop(rax); break; case Bytecodes::_fast_lgetfield: - __ access_load_at(T_LONG, IN_HEAP, noreg /* ltos */, field, noreg, noreg); + __ access_load_at(T_LONG, IN_HEAP, noreg /* ltos */, field, noreg); break; case Bytecodes::_fast_igetfield: - __ access_load_at(T_INT, IN_HEAP, rax, field, noreg, noreg); + __ access_load_at(T_INT, IN_HEAP, rax, field, noreg); break; case Bytecodes::_fast_bgetfield: - __ access_load_at(T_BYTE, IN_HEAP, rax, field, noreg, noreg); + __ access_load_at(T_BYTE, IN_HEAP, rax, field, noreg); break; case Bytecodes::_fast_sgetfield: - __ access_load_at(T_SHORT, IN_HEAP, rax, field, noreg, noreg); + __ access_load_at(T_SHORT, IN_HEAP, rax, field, noreg); break; case Bytecodes::_fast_cgetfield: - __ access_load_at(T_CHAR, IN_HEAP, rax, field, noreg, noreg); + __ access_load_at(T_CHAR, IN_HEAP, rax, field, noreg); break; case Bytecodes::_fast_fgetfield: - __ access_load_at(T_FLOAT, IN_HEAP, noreg /* ftos */, field, noreg, noreg); + __ access_load_at(T_FLOAT, IN_HEAP, noreg /* ftos */, field, noreg); break; case Bytecodes::_fast_dgetfield: - __ access_load_at(T_DOUBLE, IN_HEAP, noreg /* dtos */, field, noreg, noreg); + __ access_load_at(T_DOUBLE, IN_HEAP, noreg /* dtos */, field, noreg); break; default: ShouldNotReachHere(); @@ -3178,14 +3178,14 @@ void TemplateTable::fast_xaccess(TosState state) { const Address field = Address(rax, rbx, Address::times_1, 0*wordSize); switch (state) { case itos: - __ access_load_at(T_INT, IN_HEAP, rax, field, noreg, noreg); + __ access_load_at(T_INT, IN_HEAP, rax, field, noreg); break; case atos: do_oop_load(_masm, field, rax); __ verify_oop(rax); break; case ftos: - __ access_load_at(T_FLOAT, IN_HEAP, noreg /* ftos */, field, noreg, noreg); + __ access_load_at(T_FLOAT, IN_HEAP, noreg /* ftos */, field, noreg); break; default: ShouldNotReachHere(); @@ -3588,7 +3588,7 @@ void TemplateTable::_new() { // Go to slow path. if (UseTLAB) { - __ tlab_allocate(r15_thread, rax, rdx, 0, rcx, rbx, slow_case); + __ tlab_allocate(rax, rdx, 0, rcx, rbx, slow_case); if (ZeroTLAB) { // the fields have been already cleared __ jmp(initialize_header); From 04e2a0621d80f23cf70b4649ec4c24dad28e8e2d Mon Sep 17 00:00:00 2001 From: Saranya Natarajan Date: Thu, 10 Apr 2025 07:59:09 +0000 Subject: [PATCH 0512/1101] 8351660: C2: SIGFPE in unsigned_mod_value Co-authored-by: Emanuel Peter Reviewed-by: chagedorn, dfenacci, epeter --- src/hotspot/share/opto/divnode.cpp | 5 ++ .../TestUnsignedModByZero.java | 58 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/integerArithmetic/TestUnsignedModByZero.java diff --git a/src/hotspot/share/opto/divnode.cpp b/src/hotspot/share/opto/divnode.cpp index 22188446c804d..a70194274a793 100644 --- a/src/hotspot/share/opto/divnode.cpp +++ b/src/hotspot/share/opto/divnode.cpp @@ -1319,6 +1319,11 @@ static const Type* unsigned_mod_value(PhaseGVN* phase, const Node* mod) { return TypeClass::ZERO; } + // Mod by zero? Throw an exception at runtime! + if (type_divisor->is_con() && type_divisor->get_con() == 0) { + return TypeClass::POS; + } + const TypeClass* type_dividend = t1->cast(); if (type_dividend->is_con() && type_divisor->is_con()) { Unsigned dividend = static_cast(type_dividend->get_con()); diff --git a/test/hotspot/jtreg/compiler/integerArithmetic/TestUnsignedModByZero.java b/test/hotspot/jtreg/compiler/integerArithmetic/TestUnsignedModByZero.java new file mode 100644 index 0000000000000..27252cd53c733 --- /dev/null +++ b/test/hotspot/jtreg/compiler/integerArithmetic/TestUnsignedModByZero.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8351660 + * @summary Test that modulo by zero throws an exception at runtime in case of unsigned values. + * @library /test/lib + * @run main/othervm -Xbatch + * -XX:CompileCommand=compileonly,compiler.integerArithmetic.TestUnsignedModByZero::testInt + * -XX:CompileCommand=compileonly,compiler.integerArithmetic.TestUnsignedModByZero::testLong + * compiler.integerArithmetic.TestUnsignedModByZero + */ + + package compiler.integerArithmetic; + + import jdk.test.lib.Asserts; + + + public class TestUnsignedModByZero { + + public static Object testInt() { + double x = 1.0; + return Integer.remainderUnsigned(1, (int)(x % x)); + } + + public static Object testLong() { + double x = 1.0; + return Long.remainderUnsigned(1, (long)(x % x)); + } + + public static void main(String[] args) { + for (int i = 0; i < 10_000; i++) { + Asserts.assertThrows(ArithmeticException.class, TestUnsignedModByZero::testInt); + Asserts.assertThrows(ArithmeticException.class, TestUnsignedModByZero::testLong); + } + } + } \ No newline at end of file From f94a4f7accd11161912ec2cdae6e290d0957666a Mon Sep 17 00:00:00 2001 From: Serhiy Sachkov Date: Thu, 10 Apr 2025 08:28:01 +0000 Subject: [PATCH 0513/1101] 8353847: Remove extra args to System.out.printf in open/test/jdk/java/net/httpclient tests Reviewed-by: dfuchs --- test/jdk/java/net/httpclient/AsyncShutdownNow.java | 6 +++--- test/jdk/java/net/httpclient/HttpClientShutdown.java | 8 ++++---- test/jdk/java/net/httpclient/ShutdownNow.java | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/test/jdk/java/net/httpclient/AsyncShutdownNow.java b/test/jdk/java/net/httpclient/AsyncShutdownNow.java index 458bd56fbd5a7..39c82735248f8 100644 --- a/test/jdk/java/net/httpclient/AsyncShutdownNow.java +++ b/test/jdk/java/net/httpclient/AsyncShutdownNow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -208,7 +208,7 @@ void testConcurrent(String uriString) throws Exception { Thread.sleep(sleep); } if (i == step) { - out.printf("%d: shutting down client now%n", i, sleep); + out.printf("%d: shutting down client now%n", i); client.shutdownNow(); } var cf = bodyCF.exceptionally((t) -> { @@ -304,7 +304,7 @@ void testSequential(String uriString) throws Exception { Thread.sleep(sleep); } if (i == step) { - out.printf("%d: shutting down client now%n", i, sleep); + out.printf("%d: shutting down client now%n", i); client.shutdownNow(); } bodyCF.handle((r, t) -> { diff --git a/test/jdk/java/net/httpclient/HttpClientShutdown.java b/test/jdk/java/net/httpclient/HttpClientShutdown.java index 133a3d08f2726..3c77881c8aa9a 100644 --- a/test/jdk/java/net/httpclient/HttpClientShutdown.java +++ b/test/jdk/java/net/httpclient/HttpClientShutdown.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -192,7 +192,7 @@ ExchangeResult assertResponseState() { out.println(now() + step + ": Got response: " + response); assertEquals(response.statusCode(), 200); } catch (AssertionError error) { - out.printf(now() + "%s: Closing body due to assertion - %s", error); + out.printf(now() + "%s: Closing body due to assertion - %s", step, error); ensureClosed(this); throw error; } @@ -276,7 +276,7 @@ void testConcurrent(String uriString) throws Exception { continue; } if (i == step) { - out.printf(now() + "%d: shutting down client%n", i, sleep); + out.printf(now() + "%d: shutting down client%n", i); client.shutdown(); } var cf = bodyCF.exceptionally((t) -> { @@ -375,7 +375,7 @@ void testSequential(String uriString) throws Exception { continue; } if (i == step) { - out.printf(now() + "%d: shutting down client%n", i, sleep); + out.printf(now() + "%d: shutting down client%n", i); client.shutdown(); } bodyCF.handle((r, t) -> { diff --git a/test/jdk/java/net/httpclient/ShutdownNow.java b/test/jdk/java/net/httpclient/ShutdownNow.java index d175840724df4..045876597a2d7 100644 --- a/test/jdk/java/net/httpclient/ShutdownNow.java +++ b/test/jdk/java/net/httpclient/ShutdownNow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -182,7 +182,7 @@ void testConcurrent(String uriString) throws Exception { Thread.sleep(sleep); } if (i == step) { - out.printf("%d: shutting down client now%n", i, sleep); + out.printf("%d: shutting down client now%n", i); client.shutdownNow(); } final int si = i; @@ -242,7 +242,7 @@ void testSequential(String uriString) throws Exception { Thread.sleep(sleep); } if (i == step) { - out.printf("%d: shutting down client now%n", i, sleep); + out.printf("%d: shutting down client now%n", i); client.shutdownNow(); } final int si = i; From 6545e0d9a39c772ead0cbdd525b624f21e252a6a Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 10 Apr 2025 08:42:47 +0000 Subject: [PATCH 0514/1101] 8353189: [ASAN] memory leak after 8352184 Co-authored-by: Jiangli Zhou Co-authored-by: David Holmes Reviewed-by: dholmes, jiangli --- .../share/runtime/abstract_vm_version.cpp | 56 ++++++++++--------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp index 763e441fe541e..e95c96b4e9c25 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.cpp +++ b/src/hotspot/share/runtime/abstract_vm_version.cpp @@ -137,42 +137,46 @@ const char* Abstract_VM_Version::vm_vendor() { } +// The VM info string should be a constant, but its value cannot be finalized until after VM arguments +// have been fully processed. And we want to avoid dynamic memory allocation which will cause ASAN +// report error, so we enumerate all the cases by static const string value. const char* Abstract_VM_Version::vm_info_string() { - const char* mode; switch (Arguments::mode()) { case Arguments::_int: - mode = "interpreted mode"; - break; + if (is_vm_statically_linked()) { + return CDSConfig::is_using_archive() ? "interpreted mode, static, sharing" : "interpreted mode, static"; + } else { + return CDSConfig::is_using_archive() ? "interpreted mode, sharing" : "interpreted mode"; + } case Arguments::_mixed: - if (CompilationModeFlag::quick_only()) { - mode = "mixed mode, emulated-client"; + if (is_vm_statically_linked()) { + if (CompilationModeFlag::quick_only()) { + return CDSConfig::is_using_archive() ? "mixed mode, emulated-client, static, sharing" : "mixed mode, emulated-client, static"; + } else { + return CDSConfig::is_using_archive() ? "mixed mode, static, sharing" : "mixed mode, static"; + } } else { - mode = "mixed mode"; + if (CompilationModeFlag::quick_only()) { + return CDSConfig::is_using_archive() ? "mixed mode, emulated-client, sharing" : "mixed mode, emulated-client"; + } else { + return CDSConfig::is_using_archive() ? "mixed mode, sharing" : "mixed mode"; + } } - break; case Arguments::_comp: - if (CompilationModeFlag::quick_only()) { - mode = "compiled mode, emulated-client"; + if (is_vm_statically_linked()) { + if (CompilationModeFlag::quick_only()) { + return CDSConfig::is_using_archive() ? "compiled mode, emulated-client, static, sharing" : "compiled mode, emulated-client, static"; + } + return CDSConfig::is_using_archive() ? "compiled mode, static, sharing" : "compiled mode, static"; } else { - mode = "compiled mode"; + if (CompilationModeFlag::quick_only()) { + return CDSConfig::is_using_archive() ? "compiled mode, emulated-client, sharing" : "compiled mode, emulated-client"; + } + return CDSConfig::is_using_archive() ? "compiled mode, sharing" : "compiled mode"; } - break; - default: - ShouldNotReachHere(); } - - const char* static_info = ", static"; - const char* sharing_info = ", sharing"; - size_t len = strlen(mode) + - (is_vm_statically_linked() ? strlen(static_info) : 0) + - (CDSConfig::is_using_archive() ? strlen(sharing_info) : 0) + - 1; - char* vm_info = NEW_C_HEAP_ARRAY(char, len, mtInternal); - // jio_snprintf places null character in the last character. - jio_snprintf(vm_info, len, "%s%s%s", mode, - is_vm_statically_linked() ? static_info : "", - CDSConfig::is_using_archive() ? sharing_info : ""); - return vm_info; + ShouldNotReachHere(); + return ""; } // NOTE: do *not* use stringStream. this function is called by From 9a3f9997b68a1f64e53b9711b878fb073c3c9b90 Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Thu, 10 Apr 2025 09:44:58 +0000 Subject: [PATCH 0515/1101] 8346236: Auto vectorization support for various Float16 operations Reviewed-by: epeter, sviswanathan --- src/hotspot/cpu/x86/assembler_x86.cpp | 212 +++++++++++- src/hotspot/cpu/x86/assembler_x86.hpp | 21 ++ src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 39 ++- src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp | 9 +- src/hotspot/cpu/x86/x86.ad | 131 ++++++- src/hotspot/share/adlc/formssel.cpp | 20 +- src/hotspot/share/opto/classes.hpp | 8 + src/hotspot/share/opto/matcher.cpp | 4 +- src/hotspot/share/opto/superword.cpp | 5 +- .../share/opto/superwordVTransformBuilder.cpp | 6 +- src/hotspot/share/opto/vectornode.cpp | 101 ++++-- src/hotspot/share/opto/vectornode.hpp | 67 ++++ src/hotspot/share/opto/vtransform.cpp | 9 +- .../generators/AnyBitsFloat16Generator.java | 43 +++ .../compiler/lib/generators/Generators.java | 69 +++- .../lib/generators/RandomnessSource.java | 2 + .../generators/RandomnessSourceAdapter.java | 7 + .../generators/UniformFloat16Generator.java | 51 +++ .../compiler/lib/ir_framework/IRNode.java | 40 +++ .../TestFloat16VectorOperations.java | 321 ++++++++++++++++++ .../tests/MockRandomnessSource.java | 12 + .../generators/tests/TestGenerators.java | 28 +- .../vector/Float16OperationsBenchmark.java | 35 +- 23 files changed, 1153 insertions(+), 87 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/lib/generators/AnyBitsFloat16Generator.java create mode 100644 test/hotspot/jtreg/compiler/lib/generators/UniformFloat16Generator.java create mode 100644 test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 29e4fcee2f63a..5ead6ec99cab2 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -13810,6 +13810,18 @@ void Assembler::vcmpps(XMMRegister dst, XMMRegister nds, XMMRegister src, int co emit_int24((unsigned char)0xC2, (0xC0 | encode), (unsigned char)comparison); } +void Assembler::evcmpph(KRegister kdst, KRegister mask, XMMRegister nds, XMMRegister src, + ComparisonPredicateFP comparison, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), ""); + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + attributes.reset_is_clear_context(); + int encode = vex_prefix_and_encode(kdst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3A, &attributes); + emit_int24((unsigned char)0xC2, (0xC0 | encode), comparison); +} + void Assembler::evcmpsh(KRegister kdst, KRegister mask, XMMRegister nds, XMMRegister src, ComparisonPredicateFP comparison) { assert(VM_Version::supports_avx512_fp16(), ""); InstructionAttr attributes(Assembler::AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); @@ -13822,7 +13834,7 @@ void Assembler::evcmpsh(KRegister kdst, KRegister mask, XMMRegister nds, XMMRegi void Assembler::evcmpps(KRegister kdst, KRegister mask, XMMRegister nds, XMMRegister src, ComparisonPredicateFP comparison, int vector_len) { - assert(VM_Version::supports_evex(), ""); + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); // Encoding: EVEX.NDS.XXX.0F.W0 C2 /r ib InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); @@ -13834,7 +13846,7 @@ void Assembler::evcmpps(KRegister kdst, KRegister mask, XMMRegister nds, XMMRegi void Assembler::evcmppd(KRegister kdst, KRegister mask, XMMRegister nds, XMMRegister src, ComparisonPredicateFP comparison, int vector_len) { - assert(VM_Version::supports_evex(), ""); + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); // Encoding: EVEX.NDS.XXX.66.0F.W1 C2 /r ib InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); @@ -14155,7 +14167,7 @@ void Assembler::vpblendvb(XMMRegister dst, XMMRegister nds, XMMRegister src, XMM } void Assembler::evblendmpd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { - assert(VM_Version::supports_evex(), ""); + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); // Encoding: EVEX.NDS.XXX.66.0F38.W1 65 /r InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); @@ -14168,7 +14180,7 @@ void Assembler::evblendmpd(XMMRegister dst, KRegister mask, XMMRegister nds, XMM } void Assembler::evblendmps(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { - assert(VM_Version::supports_evex(), ""); + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); // Encoding: EVEX.NDS.XXX.66.0F38.W0 65 /r InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); @@ -14180,9 +14192,9 @@ void Assembler::evblendmps(XMMRegister dst, KRegister mask, XMMRegister nds, XMM emit_int16(0x65, (0xC0 | encode)); } -void Assembler::evpblendmb (XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { - assert(VM_Version::supports_evex(), ""); +void Assembler::evpblendmb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_avx512bw(), ""); + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); // Encoding: EVEX.NDS.512.66.0F38.W0 66 /r InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); @@ -14194,9 +14206,9 @@ void Assembler::evpblendmb (XMMRegister dst, KRegister mask, XMMRegister nds, XM emit_int16(0x66, (0xC0 | encode)); } -void Assembler::evpblendmw (XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { - assert(VM_Version::supports_evex(), ""); +void Assembler::evpblendmw(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_avx512bw(), ""); + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); // Encoding: EVEX.NDS.512.66.0F38.W1 66 /r InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); @@ -14208,8 +14220,8 @@ void Assembler::evpblendmw (XMMRegister dst, KRegister mask, XMMRegister nds, XM emit_int16(0x66, (0xC0 | encode)); } -void Assembler::evpblendmd (XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { - assert(VM_Version::supports_evex(), ""); +void Assembler::evpblendmd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); //Encoding: EVEX.NDS.512.66.0F38.W0 64 /r InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); @@ -14221,8 +14233,8 @@ void Assembler::evpblendmd (XMMRegister dst, KRegister mask, XMMRegister nds, XM emit_int16(0x64, (0xC0 | encode)); } -void Assembler::evpblendmq (XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { - assert(VM_Version::supports_evex(), ""); +void Assembler::evpblendmq(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); //Encoding: EVEX.NDS.512.66.0F38.W1 64 /r InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); @@ -14420,6 +14432,7 @@ void Assembler::shrxq(Register dst, Address src1, Register src2) { void Assembler::evpmovq2m(KRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512vldq(), ""); + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); @@ -14428,6 +14441,7 @@ void Assembler::evpmovq2m(KRegister dst, XMMRegister src, int vector_len) { void Assembler::evpmovd2m(KRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512vldq(), ""); + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); @@ -14436,6 +14450,7 @@ void Assembler::evpmovd2m(KRegister dst, XMMRegister src, int vector_len) { void Assembler::evpmovw2m(KRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512vlbw(), ""); + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); @@ -14444,6 +14459,7 @@ void Assembler::evpmovw2m(KRegister dst, XMMRegister src, int vector_len) { void Assembler::evpmovb2m(KRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512vlbw(), ""); + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); @@ -14452,6 +14468,7 @@ void Assembler::evpmovb2m(KRegister dst, XMMRegister src, int vector_len) { void Assembler::evpmovm2q(XMMRegister dst, KRegister src, int vector_len) { assert(VM_Version::supports_avx512vldq(), ""); + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); @@ -14460,6 +14477,7 @@ void Assembler::evpmovm2q(XMMRegister dst, KRegister src, int vector_len) { void Assembler::evpmovm2d(XMMRegister dst, KRegister src, int vector_len) { assert(VM_Version::supports_avx512vldq(), ""); + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); @@ -14468,6 +14486,7 @@ void Assembler::evpmovm2d(XMMRegister dst, KRegister src, int vector_len) { void Assembler::evpmovm2w(XMMRegister dst, KRegister src, int vector_len) { assert(VM_Version::supports_avx512vlbw(), ""); + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); @@ -14476,6 +14495,7 @@ void Assembler::evpmovm2w(XMMRegister dst, KRegister src, int vector_len) { void Assembler::evpmovm2b(XMMRegister dst, KRegister src, int vector_len) { assert(VM_Version::supports_avx512vlbw(), ""); + assert(VM_Version::supports_avx512vl() || vector_len == Assembler::AVX_512bit, ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); @@ -17161,3 +17181,171 @@ void Assembler::evpermt2q(XMMRegister dst, XMMRegister nds, XMMRegister src, int emit_int16(0x7E, (0xC0 | encode)); } +void Assembler::evaddph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x58, (0xC0 | encode)); +} + +void Assembler::evaddph(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int8(0x58); + emit_operand(dst, src, 0); +} + +void Assembler::evsubph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x5C, (0xC0 | encode)); +} + +void Assembler::evsubph(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int8(0x5C); + emit_operand(dst, src, 0); +} + +void Assembler::evmulph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x59, (0xC0 | encode)); +} + +void Assembler::evmulph(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int8(0x59); + emit_operand(dst, src, 0); +} + +void Assembler::evminph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x5D, (0xC0 | encode)); +} + +void Assembler::evminph(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int8(0x5D); + emit_operand(dst, src, 0); +} + +void Assembler::evmaxph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x5F, (0xC0 | encode)); +} + +void Assembler::evmaxph(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int8(0x5F); + emit_operand(dst, src, 0); +} + +void Assembler::evdivph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x5E, (0xC0 | encode)); +} + +void Assembler::evdivph(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int8(0x5E); + emit_operand(dst, src, 0); +} + +void Assembler::evsqrtph(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), ""); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x51, (0xC0 | encode)); +} + +void Assembler::evsqrtph(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), ""); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int8(0x51); + emit_operand(dst, src, 0); +} + +void Assembler::evfmadd132ph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), ""); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP6, &attributes); + emit_int16(0x98, (0xC0 | encode)); +} + +void Assembler::evfmadd132ph(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(VM_Version::supports_avx512_fp16(), ""); + assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP6, &attributes); + emit_int8(0x98); + emit_operand(dst, src, 0); +} + diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 15ea45edb9159..3a4eba334ef73 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -2888,6 +2888,24 @@ class Assembler : public AbstractAssembler { void evplzcntd(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len); void evplzcntq(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len); + // Float16 Vector instructions. + void evaddph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evaddph(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void evsubph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evsubph(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void evdivph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evdivph(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void evmulph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evmulph(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void evminph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evminph(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void evmaxph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evmaxph(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void evfmadd132ph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evfmadd132ph(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void evsqrtph(XMMRegister dst, XMMRegister src1, int vector_len); + void evsqrtph(XMMRegister dst, Address src1, int vector_len); + // Sub packed integers void psubb(XMMRegister dst, XMMRegister src); void psubw(XMMRegister dst, XMMRegister src); @@ -3195,6 +3213,9 @@ class Assembler : public AbstractAssembler { void evcmpps(KRegister kdst, KRegister mask, XMMRegister nds, XMMRegister src, ComparisonPredicateFP comparison, int vector_len); + void evcmpph(KRegister kdst, KRegister mask, XMMRegister nds, XMMRegister src, + ComparisonPredicateFP comparison, int vector_len); + void evcmpsh(KRegister kdst, KRegister mask, XMMRegister nds, XMMRegister src, ComparisonPredicateFP comparison); diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 9ca463336681e..5da3b8c09f9a1 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -6987,9 +6987,34 @@ void C2_MacroAssembler::vector_saturating_op(int ideal_opc, BasicType elem_bt, X } } +void C2_MacroAssembler::evfp16ph(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, int vlen_enc) { + switch(opcode) { + case Op_AddVHF: evaddph(dst, src1, src2, vlen_enc); break; + case Op_SubVHF: evsubph(dst, src1, src2, vlen_enc); break; + case Op_MulVHF: evmulph(dst, src1, src2, vlen_enc); break; + case Op_DivVHF: evdivph(dst, src1, src2, vlen_enc); break; + default: assert(false, "%s", NodeClassNames[opcode]); break; + } +} + +void C2_MacroAssembler::evfp16ph(int opcode, XMMRegister dst, XMMRegister src1, Address src2, int vlen_enc) { + switch(opcode) { + case Op_AddVHF: evaddph(dst, src1, src2, vlen_enc); break; + case Op_SubVHF: evsubph(dst, src1, src2, vlen_enc); break; + case Op_MulVHF: evmulph(dst, src1, src2, vlen_enc); break; + case Op_DivVHF: evdivph(dst, src1, src2, vlen_enc); break; + default: assert(false, "%s", NodeClassNames[opcode]); break; + } +} + void C2_MacroAssembler::scalar_max_min_fp16(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, - KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc) { - if (opcode == Op_MaxHF) { + KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2) { + vector_max_min_fp16(opcode, dst, src1, src2, ktmp, xtmp1, xtmp2, Assembler::AVX_128bit); +} + +void C2_MacroAssembler::vector_max_min_fp16(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, + KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc) { + if (opcode == Op_MaxVHF || opcode == Op_MaxHF) { // Move sign bits of src2 to mask register. evpmovw2m(ktmp, src2, vlen_enc); // xtmp1 = src2 < 0 ? src2 : src1 @@ -7001,15 +7026,15 @@ void C2_MacroAssembler::scalar_max_min_fp16(int opcode, XMMRegister dst, XMMRegi // the second source operand is returned. If only one value is a NaN (SNaN or QNaN) for this instruction, // the second source operand, either a NaN or a valid floating-point value, is returned // dst = max(xtmp1, xtmp2) - vmaxsh(dst, xtmp1, xtmp2); + evmaxph(dst, xtmp1, xtmp2, vlen_enc); // isNaN = is_unordered_quiet(xtmp1) - evcmpsh(ktmp, k0, xtmp1, xtmp1, Assembler::UNORD_Q); + evcmpph(ktmp, k0, xtmp1, xtmp1, Assembler::UNORD_Q, vlen_enc); // Final result is same as first source if its a NaN value, // in case second operand holds a NaN value then as per above semantics // result is same as second operand. Assembler::evmovdquw(dst, ktmp, xtmp1, true, vlen_enc); } else { - assert(opcode == Op_MinHF, ""); + assert(opcode == Op_MinVHF || opcode == Op_MinHF, ""); // Move sign bits of src1 to mask register. evpmovw2m(ktmp, src1, vlen_enc); // xtmp1 = src1 < 0 ? src2 : src1 @@ -7022,9 +7047,9 @@ void C2_MacroAssembler::scalar_max_min_fp16(int opcode, XMMRegister dst, XMMRegi // If only one value is a NaN (SNaN or QNaN) for this instruction, the second source operand, either a NaN // or a valid floating-point value, is written to the result. // dst = min(xtmp1, xtmp2) - vminsh(dst, xtmp1, xtmp2); + evminph(dst, xtmp1, xtmp2, vlen_enc); // isNaN = is_unordered_quiet(xtmp1) - evcmpsh(ktmp, k0, xtmp1, xtmp1, Assembler::UNORD_Q); + evcmpph(ktmp, k0, xtmp1, xtmp1, Assembler::UNORD_Q, vlen_enc); // Final result is same as first source if its a NaN value, // in case second operand holds a NaN value then as per above semantics // result is same as second operand. diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index 2c5fb4b516afc..dd2880d88c381 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -565,6 +565,13 @@ void select_from_two_vectors_evex(BasicType elem_bt, XMMRegister dst, XMMRegister src1, XMMRegister src2, int vlen_enc); + void evfp16ph(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, int vlen_enc); + + void evfp16ph(int opcode, XMMRegister dst, XMMRegister src1, Address src2, int vlen_enc); + + void vector_max_min_fp16(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, + KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc); + void scalar_max_min_fp16(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, - KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc); + KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2); #endif // CPU_X86_C2_MACROASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 7bde4ced2ba48..e2880a22fa9bf 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -1631,6 +1631,24 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { // * 128bit vroundpd instruction is present only in AVX1 int size_in_bits = vlen * type2aelembytes(bt) * BitsPerByte; switch (opcode) { + case Op_MaxVHF: + case Op_MinVHF: + if (!VM_Version::supports_avx512bw()) { + return false; + } + case Op_AddVHF: + case Op_DivVHF: + case Op_FmaVHF: + case Op_MulVHF: + case Op_SubVHF: + case Op_SqrtVHF: + if (size_in_bits < 512 && !VM_Version::supports_avx512vl()) { + return false; + } + if (!VM_Version::supports_avx512_fp16()) { + return false; + } + break; case Op_AbsVF: case Op_NegVF: if ((vlen == 16) && (VM_Version::supports_avx512dq() == false)) { @@ -10644,6 +10662,16 @@ instruct reinterpretS2HF(regF dst, rRegI src) ins_pipe(pipe_slow); %} +instruct reinterpretHF2S(rRegI dst, regF src) +%{ + match(Set dst (ReinterpretHF2S src)); + format %{ "vmovw $dst, $src" %} + ins_encode %{ + __ vmovw($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + instruct convF2HFAndS2HF(regF dst, regF src) %{ match(Set dst (ReinterpretS2HF (ConvF2HF src))); @@ -10664,16 +10692,6 @@ instruct convHF2SAndHF2F(regF dst, regF src) ins_pipe(pipe_slow); %} -instruct reinterpretHF2S(rRegI dst, regF src) -%{ - match(Set dst (ReinterpretHF2S src)); - format %{ "vmovw $dst, $src" %} - ins_encode %{ - __ vmovw($dst$$Register, $src$$XMMRegister); - %} - ins_pipe(pipe_slow); -%} - instruct scalar_sqrt_HF_reg(regF dst, regF src) %{ match(Set dst (SqrtHF src)); @@ -10707,7 +10725,7 @@ instruct scalar_minmax_HF_reg(regF dst, regF src1, regF src2, kReg ktmp, regF xt ins_encode %{ int opcode = this->ideal_Opcode(); __ scalar_max_min_fp16(opcode, $dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, $ktmp$$KRegister, - $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, Assembler::AVX_128bit); + $xtmp1$$XMMRegister, $xtmp2$$XMMRegister); %} ins_pipe( pipe_slow ); %} @@ -10722,3 +10740,94 @@ instruct scalar_fma_HF_reg(regF dst, regF src1, regF src2) %} ins_pipe( pipe_slow ); %} + + +instruct vector_sqrt_HF_reg(vec dst, vec src) +%{ + match(Set dst (SqrtVHF src)); + format %{ "vector_sqrt_fp16 $dst, $src" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + __ evsqrtph($dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + %} + ins_pipe(pipe_slow); +%} + +instruct vector_sqrt_HF_mem(vec dst, memory src) +%{ + match(Set dst (SqrtVHF (VectorReinterpret (LoadVector src)))); + format %{ "vector_sqrt_fp16_mem $dst, $src" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + __ evsqrtph($dst$$XMMRegister, $src$$Address, vlen_enc); + %} + ins_pipe(pipe_slow); +%} + +instruct vector_binOps_HF_reg(vec dst, vec src1, vec src2) +%{ + match(Set dst (AddVHF src1 src2)); + match(Set dst (DivVHF src1 src2)); + match(Set dst (MulVHF src1 src2)); + match(Set dst (SubVHF src1 src2)); + format %{ "vector_binop_fp16 $dst, $src1, $src2" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + int opcode = this->ideal_Opcode(); + __ evfp16ph(opcode, $dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vlen_enc); + %} + ins_pipe(pipe_slow); +%} + + +instruct vector_binOps_HF_mem(vec dst, vec src1, memory src2) +%{ + match(Set dst (AddVHF src1 (VectorReinterpret (LoadVector src2)))); + match(Set dst (DivVHF src1 (VectorReinterpret (LoadVector src2)))); + match(Set dst (MulVHF src1 (VectorReinterpret (LoadVector src2)))); + match(Set dst (SubVHF src1 (VectorReinterpret (LoadVector src2)))); + format %{ "vector_binop_fp16_mem $dst, $src1, $src2" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + int opcode = this->ideal_Opcode(); + __ evfp16ph(opcode, $dst$$XMMRegister, $src1$$XMMRegister, $src2$$Address, vlen_enc); + %} + ins_pipe(pipe_slow); +%} + +instruct vector_fma_HF_reg(vec dst, vec src1, vec src2) +%{ + match(Set dst (FmaVHF src2 (Binary dst src1))); + format %{ "vector_fma_fp16 $dst, $src1, $src2\t# $dst = $dst * $src1 + $src2 fma packedH" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + __ evfmadd132ph($dst$$XMMRegister, $src2$$XMMRegister, $src1$$XMMRegister, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vector_fma_HF_mem(vec dst, memory src1, vec src2) +%{ + match(Set dst (FmaVHF src2 (Binary dst (VectorReinterpret (LoadVector src1))))); + format %{ "vector_fma_fp16_mem $dst, $src1, $src2\t# $dst = $dst * $src1 + $src2 fma packedH" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + __ evfmadd132ph($dst$$XMMRegister, $src2$$XMMRegister, $src1$$Address, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct vector_minmax_HF_reg(vec dst, vec src1, vec src2, kReg ktmp, vec xtmp1, vec xtmp2) +%{ + match(Set dst (MinVHF src1 src2)); + match(Set dst (MaxVHF src1 src2)); + effect(TEMP_DEF dst, TEMP ktmp, TEMP xtmp1, TEMP xtmp2); + format %{ "vector_min_max_fp16 $dst, $src1, $src2\t using $ktmp, $xtmp1 and $xtmp2 as TEMP" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + int opcode = this->ideal_Opcode(); + __ vector_max_min_fp16(opcode, $dst$$XMMRegister, $src2$$XMMRegister, $src1$$XMMRegister, $ktmp$$KRegister, + $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index 7239031c8986b..b938d5b75608d 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -3965,10 +3965,10 @@ void MatchNode::count_commutative_op(int& count) { }; static const char *commut_vector_op_list[] = { - "AddVB", "AddVS", "AddVI", "AddVL", "AddVF", "AddVD", - "MulVB", "MulVS", "MulVI", "MulVL", "MulVF", "MulVD", + "AddVB", "AddVS", "AddVI", "AddVL", "AddVHF", "AddVF", "AddVD", + "MulVB", "MulVS", "MulVI", "MulVL", "MulVHF", "MulVF", "MulVD", "AndV", "OrV", "XorV", - "MaxV", "MinV", "UMax","UMin" + "MaxVHF", "MinVHF", "MaxV", "MinV", "UMax","UMin" }; if (_lChild && _rChild && (_lChild->_lChild || _rChild->_lChild)) { @@ -4335,15 +4335,15 @@ Form::DataType MatchRule::is_ideal_load() const { bool MatchRule::is_vector() const { static const char *vector_list[] = { - "AddVB","AddVS","AddVI","AddVL","AddVF","AddVD", - "SubVB","SubVS","SubVI","SubVL","SubVF","SubVD", - "MulVB","MulVS","MulVI","MulVL","MulVF","MulVD", - "DivVF","DivVD", + "AddVB","AddVS","AddVI","AddVL","AddVHF","AddVF","AddVD", + "SubVB","SubVS","SubVI","SubVL","SubVHF","SubVF","SubVD", + "MulVB","MulVS","MulVI","MulVL","MulVHF","MulVF","MulVD", + "DivVHF","DivVF","DivVD", "AbsVB","AbsVS","AbsVI","AbsVL","AbsVF","AbsVD", "NegVF","NegVD","NegVI","NegVL", - "SqrtVD","SqrtVF", + "SqrtVD","SqrtVF","SqrtVHF", "AndV" ,"XorV" ,"OrV", - "MaxV", "MinV", "UMinV", "UMaxV", + "MaxV", "MinV", "MinVHF", "MaxVHF", "UMinV", "UMaxV", "CompressV", "ExpandV", "CompressM", "CompressBitsV", "ExpandBitsV", "AddReductionVI", "AddReductionVL", "AddReductionVF", "AddReductionVD", @@ -4365,7 +4365,7 @@ bool MatchRule::is_vector() const { "VectorCastL2X", "VectorCastF2X", "VectorCastD2X", "VectorCastF2HF", "VectorCastHF2F", "VectorUCastB2X", "VectorUCastS2X", "VectorUCastI2X", "VectorMaskWrapper","VectorMaskCmp","VectorReinterpret","LoadVectorMasked","StoreVectorMasked", - "FmaVD","FmaVF","PopCountVI","PopCountVL","PopulateIndex","VectorLongToMask", + "FmaVD", "FmaVF", "FmaVHF", "PopCountVI", "PopCountVL", "PopulateIndex", "VectorLongToMask", "CountLeadingZerosV", "CountTrailingZerosV", "SignumVF", "SignumVD", "SaturatingAddV", "SaturatingSubV", // Next are vector mask ops. "MaskAll", "AndVMask", "OrVMask", "XorVMask", "VectorMaskCast", diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index a8d1a29250aca..bc259eed2d101 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -389,6 +389,7 @@ macro(AddReductionVI) macro(AddVL) macro(AddReductionVL) macro(AddVF) +macro(AddVHF) macro(AddReductionVF) macro(AddVD) macro(AddReductionVD) @@ -397,6 +398,7 @@ macro(SubVS) macro(SubVI) macro(SubVL) macro(SubVF) +macro(SubVHF) macro(SubVD) macro(MulVB) macro(MulVS) @@ -408,9 +410,12 @@ macro(MulVF) macro(MulReductionVF) macro(MulVD) macro(MulReductionVD) +macro(MulVHF) macro(MulAddVS2VI) macro(FmaVD) macro(FmaVF) +macro(FmaVHF) +macro(DivVHF) macro(DivVF) macro(DivVD) macro(AbsVB) @@ -425,6 +430,7 @@ macro(NegVF) macro(NegVD) macro(SqrtVD) macro(SqrtVF) +macro(SqrtVHF) macro(LShiftCntV) macro(RShiftCntV) macro(LShiftVB) @@ -447,6 +453,8 @@ macro(XorV) macro(XorReductionV) macro(MinV) macro(MaxV) +macro(MinVHF) +macro(MaxVHF) macro(UMinV) macro(UMaxV) macro(MinReductionV) diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index fd89a6e54319e..e34a43cc1e2f6 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -2307,6 +2307,7 @@ bool Matcher::find_shared_visit(MStack& mstack, Node* n, uint opcode, bool& mem_ case Op_FmaHF: case Op_FmaVD: case Op_FmaVF: + case Op_FmaVHF: case Op_MacroLogicV: case Op_VectorCmpMasked: case Op_CompressV: @@ -2479,7 +2480,8 @@ void Matcher::find_shared_post_visit(Node* n, uint opcode) { case Op_FmaF: case Op_FmaHF: case Op_FmaVD: - case Op_FmaVF: { + case Op_FmaVF: + case Op_FmaVHF: { // Restructure into a binary tree for Matching. Node* pair = new BinaryNode(n->in(1), n->in(2)); n->set_req(2, pair); diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 092fa07e18455..0746715f065a3 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -2591,6 +2591,7 @@ void VLoopTypes::compute_vector_element_type() { // Smallest type containing range of values const Type* VLoopTypes::container_type(Node* n) const { + int opc = n->Opcode(); if (n->is_Mem()) { BasicType bt = n->as_Mem()->memory_type(); if (n->is_Store() && (bt == T_CHAR)) { @@ -2598,7 +2599,7 @@ const Type* VLoopTypes::container_type(Node* n) const { // preceding arithmetic operation extends values to signed Int. bt = T_SHORT; } - if (n->Opcode() == Op_LoadUB) { + if (opc == Op_LoadUB) { // Adjust type for unsigned byte loads, it is important for right shifts. // T_BOOLEAN is used because there is no basic type representing type // TypeInt::UBYTE. Use of T_BOOLEAN for vectors is fine because only @@ -2612,7 +2613,7 @@ const Type* VLoopTypes::container_type(Node* n) const { // Float to half float conversion may be succeeded by a conversion from // half float to float, in such a case back propagation of narrow type (SHORT) // may not be possible. - if (n->Opcode() == Op_ConvF2HF || n->Opcode() == Op_ReinterpretHF2S) { + if (opc == Op_ConvF2HF || opc == Op_ReinterpretHF2S) { return TypeInt::SHORT; } // A narrow type of arithmetic operations will be determined by diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp index aee6add2a98ef..d356fcd510970 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.cpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -161,9 +161,11 @@ VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(co p0->is_CMove() || VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(opc) || VectorNode::is_convert_opcode(opc) || + VectorNode::is_reinterpret_opcode(opc) || VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(opc) || - opc == Op_FmaD || - opc == Op_FmaF || + opc == Op_FmaD || + opc == Op_FmaF || + opc == Op_FmaHF || opc == Op_SignumF || opc == Op_SignumD, "pack type must be in this list"); diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index 622766ecfd53a..084b70a690653 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -46,6 +46,7 @@ int VectorNode::opcode(int sopc, BasicType bt) { default: return 0; } case Op_AddL: return (bt == T_LONG ? Op_AddVL : 0); + case Op_AddHF: return (bt == T_SHORT ? Op_AddVHF : 0); case Op_AddF: return (bt == T_FLOAT ? Op_AddVF : 0); case Op_AddD: return (bt == T_DOUBLE ? Op_AddVD : 0); @@ -59,6 +60,7 @@ int VectorNode::opcode(int sopc, BasicType bt) { default: return 0; } case Op_SubL: return (bt == T_LONG ? Op_SubVL : 0); + case Op_SubHF: return (bt == T_SHORT ? Op_SubVHF : 0); case Op_SubF: return (bt == T_FLOAT ? Op_SubVF : 0); case Op_SubD: return (bt == T_DOUBLE ? Op_SubVD : 0); @@ -72,6 +74,8 @@ int VectorNode::opcode(int sopc, BasicType bt) { default: return 0; } case Op_MulL: return (bt == T_LONG ? Op_MulVL : 0); + case Op_MulHF: + return (bt == T_SHORT ? Op_MulVHF : 0); case Op_MulF: return (bt == T_FLOAT ? Op_MulVF : 0); case Op_MulD: @@ -80,12 +84,16 @@ int VectorNode::opcode(int sopc, BasicType bt) { return (bt == T_DOUBLE ? Op_FmaVD : 0); case Op_FmaF: return (bt == T_FLOAT ? Op_FmaVF : 0); + case Op_FmaHF: + return (bt == T_SHORT ? Op_FmaVHF : 0); case Op_CMoveF: return (bt == T_FLOAT ? Op_VectorBlend : 0); case Op_CMoveD: return (bt == T_DOUBLE ? Op_VectorBlend : 0); case Op_Bool: return Op_VectorMaskCmp; + case Op_DivHF: + return (bt == T_SHORT ? Op_DivVHF : 0); case Op_DivF: return (bt == T_FLOAT ? Op_DivVF : 0); case Op_DivD: @@ -112,6 +120,8 @@ int VectorNode::opcode(int sopc, BasicType bt) { } case Op_MinL: return (bt == T_LONG ? Op_MinV : 0); + case Op_MinHF: + return (bt == T_SHORT ? Op_MinVHF : 0); case Op_MinF: return (bt == T_FLOAT ? Op_MinV : 0); case Op_MinD: @@ -127,6 +137,8 @@ int VectorNode::opcode(int sopc, BasicType bt) { } case Op_MaxL: return (bt == T_LONG ? Op_MaxV : 0); + case Op_MaxHF: + return (bt == T_SHORT ? Op_MaxVHF : 0); case Op_MaxF: return (bt == T_FLOAT ? Op_MaxV : 0); case Op_MaxD: @@ -154,6 +166,8 @@ int VectorNode::opcode(int sopc, BasicType bt) { return (is_integral_type(bt) ? Op_RotateLeftV : 0); case Op_RotateRight: return (is_integral_type(bt) ? Op_RotateRightV : 0); + case Op_SqrtHF: + return (bt == T_SHORT ? Op_SqrtVHF : 0); case Op_SqrtF: return (bt == T_FLOAT ? Op_SqrtVF : 0); case Op_SqrtD: @@ -266,6 +280,9 @@ int VectorNode::opcode(int sopc, BasicType bt) { return Op_SignumVF; case Op_SignumD: return Op_SignumVD; + case Op_ReinterpretS2HF: + case Op_ReinterpretHF2S: + return Op_VectorReinterpret; default: assert(!VectorNode::is_convert_opcode(sopc), @@ -378,6 +395,10 @@ int VectorNode::scalar_opcode(int sopc, BasicType bt) { assert(false, "basic type not handled"); return 0; } + case Op_MinVHF: + return Op_MinHF; + case Op_MaxVHF: + return Op_MaxHF; default: assert(false, "Vector node %s is not handled in VectorNode::scalar_opcode", @@ -618,10 +639,10 @@ void VectorNode::vector_operands(Node* n, uint* start, uint* end) { *start = 1; *end = (n->is_Con() && Matcher::supports_vector_constant_rotates(n->get_int())) ? 2 : 3; break; - case Op_AddI: case Op_AddL: case Op_AddF: case Op_AddD: - case Op_SubI: case Op_SubL: case Op_SubF: case Op_SubD: - case Op_MulI: case Op_MulL: case Op_MulF: case Op_MulD: - case Op_DivF: case Op_DivD: + case Op_AddI: case Op_AddL: case Op_AddHF: case Op_AddF: case Op_AddD: + case Op_SubI: case Op_SubL: case Op_SubHF: case Op_SubF: case Op_SubD: + case Op_MulI: case Op_MulL: case Op_MulHF: case Op_MulF: case Op_MulD: + case Op_DivHF: case Op_DivF: case Op_DivD: case Op_AndI: case Op_AndL: case Op_OrI: case Op_OrL: case Op_XorI: case Op_XorL: @@ -631,6 +652,7 @@ void VectorNode::vector_operands(Node* n, uint* start, uint* end) { break; case Op_FmaD: case Op_FmaF: + case Op_FmaHF: *start = 1; *end = 4; // 3 vector operands break; @@ -675,32 +697,38 @@ VectorNode* VectorNode::make(int vopc, Node* n1, Node* n2, const TypeVect* vt, b } switch (vopc) { - case Op_AddVB: return new AddVBNode(n1, n2, vt); - case Op_AddVS: return new AddVSNode(n1, n2, vt); - case Op_AddVI: return new AddVINode(n1, n2, vt); - case Op_AddVL: return new AddVLNode(n1, n2, vt); - case Op_AddVF: return new AddVFNode(n1, n2, vt); - case Op_AddVD: return new AddVDNode(n1, n2, vt); - - case Op_SubVB: return new SubVBNode(n1, n2, vt); - case Op_SubVS: return new SubVSNode(n1, n2, vt); - case Op_SubVI: return new SubVINode(n1, n2, vt); - case Op_SubVL: return new SubVLNode(n1, n2, vt); - case Op_SubVF: return new SubVFNode(n1, n2, vt); - case Op_SubVD: return new SubVDNode(n1, n2, vt); - - case Op_MulVB: return new MulVBNode(n1, n2, vt); - case Op_MulVS: return new MulVSNode(n1, n2, vt); - case Op_MulVI: return new MulVINode(n1, n2, vt); - case Op_MulVL: return new MulVLNode(n1, n2, vt); - case Op_MulVF: return new MulVFNode(n1, n2, vt); - case Op_MulVD: return new MulVDNode(n1, n2, vt); - - case Op_DivVF: return new DivVFNode(n1, n2, vt); - case Op_DivVD: return new DivVDNode(n1, n2, vt); + case Op_AddVB: return new AddVBNode(n1, n2, vt); + case Op_AddVHF: return new AddVHFNode(n1, n2, vt); + case Op_AddVS: return new AddVSNode(n1, n2, vt); + case Op_AddVI: return new AddVINode(n1, n2, vt); + case Op_AddVL: return new AddVLNode(n1, n2, vt); + case Op_AddVF: return new AddVFNode(n1, n2, vt); + case Op_AddVD: return new AddVDNode(n1, n2, vt); + + case Op_SubVB: return new SubVBNode(n1, n2, vt); + case Op_SubVS: return new SubVSNode(n1, n2, vt); + case Op_SubVI: return new SubVINode(n1, n2, vt); + case Op_SubVL: return new SubVLNode(n1, n2, vt); + case Op_SubVHF: return new SubVHFNode(n1, n2, vt); + case Op_SubVF: return new SubVFNode(n1, n2, vt); + case Op_SubVD: return new SubVDNode(n1, n2, vt); + + case Op_MulVB: return new MulVBNode(n1, n2, vt); + case Op_MulVS: return new MulVSNode(n1, n2, vt); + case Op_MulVI: return new MulVINode(n1, n2, vt); + case Op_MulVL: return new MulVLNode(n1, n2, vt); + case Op_MulVHF: return new MulVHFNode(n1, n2, vt); + case Op_MulVF: return new MulVFNode(n1, n2, vt); + case Op_MulVD: return new MulVDNode(n1, n2, vt); + + case Op_DivVHF: return new DivVHFNode(n1, n2, vt); + case Op_DivVF: return new DivVFNode(n1, n2, vt); + case Op_DivVD: return new DivVDNode(n1, n2, vt); case Op_MinV: return new MinVNode(n1, n2, vt); case Op_MaxV: return new MaxVNode(n1, n2, vt); + case Op_MinVHF: return new MinVHFNode(n1, n2, vt); + case Op_MaxVHF: return new MaxVHFNode(n1, n2, vt); case Op_AbsVF: return new AbsVFNode(n1, vt); case Op_AbsVD: return new AbsVDNode(n1, vt); @@ -717,8 +745,9 @@ VectorNode* VectorNode::make(int vopc, Node* n1, Node* n2, const TypeVect* vt, b case Op_ReverseV: return new ReverseVNode(n1, vt); case Op_ReverseBytesV: return new ReverseBytesVNode(n1, vt); - case Op_SqrtVF: return new SqrtVFNode(n1, vt); - case Op_SqrtVD: return new SqrtVDNode(n1, vt); + case Op_SqrtVHF : return new SqrtVHFNode(n1, vt); + case Op_SqrtVF : return new SqrtVFNode(n1, vt); + case Op_SqrtVD : return new SqrtVDNode(n1, vt); case Op_RoundVF: return new RoundVFNode(n1, vt); case Op_RoundVD: return new RoundVDNode(n1, vt); @@ -802,6 +831,7 @@ VectorNode* VectorNode::make(int vopc, Node* n1, Node* n2, Node* n3, const TypeV switch (vopc) { case Op_FmaVD: return new FmaVDNode(n1, n2, n3, vt); case Op_FmaVF: return new FmaVFNode(n1, n2, n3, vt); + case Op_FmaVHF: return new FmaVHFNode(n1, n2, n3, vt); case Op_SelectFromTwoVector: return new SelectFromTwoVectorNode(n1, n2, n3, vt); case Op_SignumVD: return new SignumVDNode(n1, n2, n3, vt); case Op_SignumVF: return new SignumVFNode(n1, n2, n3, vt); @@ -949,8 +979,20 @@ bool VectorNode::is_vector_bitwise_not_pattern(Node* n) { return false; } + +bool VectorNode::is_reinterpret_opcode(int opc) { + switch (opc) { + case Op_ReinterpretHF2S: + case Op_ReinterpretS2HF: + return true; + default: + return false; + } +} + bool VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(int opc) { switch (opc) { + case Op_SqrtHF: case Op_SqrtF: case Op_SqrtD: case Op_AbsF: @@ -976,6 +1018,7 @@ bool VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(int opc) { } } + // Java API for Long.bitCount/numberOfLeadingZeros/numberOfTrailingZeros // returns int type, but Vector API for them returns long type. To unify // the implementation in backend, AutoVectorization splits the vector diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index 50220c9362b7b..36706a7b7a14b 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -136,6 +136,8 @@ class VectorNode : public TypeNode { static bool is_scalar_unary_op_with_equal_input_and_output_types(int opc); static bool is_scalar_op_that_returns_int_but_vector_op_returns_long(int opc); + static bool is_reinterpret_opcode(int opc); + static void trace_new_vector(Node* n, const char* context) { #ifdef ASSERT @@ -207,6 +209,14 @@ class AddVLNode : public VectorNode { virtual int Opcode() const; }; +//------------------------------AddVHFNode-------------------------------------- +// Vector add float +class AddVHFNode : public VectorNode { +public: + AddVHFNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {} + virtual int Opcode() const; +}; + //------------------------------AddVFNode-------------------------------------- // Vector add float class AddVFNode : public VectorNode { @@ -401,6 +411,15 @@ class SaturatingSubVNode : public SaturatingVectorNode { virtual int Opcode() const; }; +//------------------------------SubVHFNode-------------------------------------- +// Vector subtract half float +class SubVHFNode : public VectorNode { +public: + SubVHFNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {} + virtual int Opcode() const; +}; + + //------------------------------SubVFNode-------------------------------------- // Vector subtract float class SubVFNode : public VectorNode { @@ -453,6 +472,14 @@ class MulVLNode : public VectorNode { bool has_uint_inputs() const; }; +//------------------------------MulVFNode-------------------------------------- +// Vector multiply half float +class MulVHFNode : public VectorNode { +public: + MulVHFNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {} + virtual int Opcode() const; +}; + //------------------------------MulVFNode-------------------------------------- // Vector multiply float class MulVFNode : public VectorNode { @@ -503,6 +530,14 @@ class FmaVFNode : public FmaVNode { virtual int Opcode() const; }; +//------------------------------FmaVHFNode------------------------------------- +// Vector fused-multiply-add half-precision float +class FmaVHFNode : public FmaVNode { +public: + FmaVHFNode(Node* in1, Node* in2, Node* in3, const TypeVect* vt) : FmaVNode(in1, in2, in3, vt) {} + virtual int Opcode() const; +}; + //------------------------------MulReductionVINode-------------------------------------- // Vector multiply byte, short and int as a reduction class MulReductionVINode : public ReductionNode { @@ -571,6 +606,14 @@ class MulReductionVDNode : public ReductionNode { virtual uint size_of() const { return sizeof(*this); } }; +//------------------------------DivVHFNode------------------------------------- +// Vector divide half float +class DivVHFNode : public VectorNode { +public: + DivVHFNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {} + virtual int Opcode() const; +}; + //------------------------------DivVFNode-------------------------------------- // Vector divide float class DivVFNode : public VectorNode { @@ -611,6 +654,22 @@ class MinVNode : public VectorNode { virtual int Opcode() const; }; +//------------------------------MinVHFNode------------------------------------ +// Vector Min for half floats +class MinVHFNode : public VectorNode { +public: + MinVHFNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {} + virtual int Opcode() const; +}; + +//------------------------------MaxVHFNode------------------------------------ +// Vector Max for half floats +class MaxVHFNode : public VectorNode { +public: + MaxVHFNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {} + virtual int Opcode() const; +}; + class UMinVNode : public VectorNode { public: UMinVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2 ,vt) { @@ -731,6 +790,14 @@ class PopCountVLNode : public VectorNode { virtual int Opcode() const; }; +//------------------------------SqrtVHFNode------------------------------------- +// Vector Sqrt half-precision float +class SqrtVHFNode : public VectorNode { +public: + SqrtVHFNode(Node* in, const TypeVect* vt) : VectorNode(in, vt) {} + virtual int Opcode() const; +}; + //------------------------------SqrtVFNode-------------------------------------- // Vector Sqrt float class SqrtVFNode : public VectorNode { diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index 18b5c09acb857..c620b4d8aa6f0 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -576,6 +576,10 @@ VTransformApplyResult VTransformElementWiseVectorNode::apply(const VLoopAnalyzer assert(first->req() == 2 && req() == 2, "only one input expected"); int vopc = VectorCastNode::opcode(opc, in1->bottom_type()->is_vect()->element_basic_type()); vn = VectorCastNode::make(vopc, in1, bt, vlen); + } else if (VectorNode::is_reinterpret_opcode(opc)) { + assert(first->req() == 2 && req() == 2, "only one input expected"); + const TypeVect* vt = TypeVect::make(bt, vlen); + vn = new VectorReinterpretNode(in1, vt, in1->bottom_type()->is_vect()); } else if (VectorNode::can_use_RShiftI_instead_of_URShiftI(first, bt)) { opc = Op_RShiftI; vn = VectorNode::make(opc, in1, in2, vlen, bt); @@ -592,8 +596,9 @@ VTransformApplyResult VTransformElementWiseVectorNode::apply(const VLoopAnalyzer vn = VectorNode::make(opc, in1, in2, vlen, bt); // unary and binary } else { assert(req() == 4, "three inputs expected"); - assert(opc == Op_FmaD || - opc == Op_FmaF || + assert(opc == Op_FmaD || + opc == Op_FmaF || + opc == Op_FmaHF || opc == Op_SignumF || opc == Op_SignumD, "element wise operation must be from this list"); diff --git a/test/hotspot/jtreg/compiler/lib/generators/AnyBitsFloat16Generator.java b/test/hotspot/jtreg/compiler/lib/generators/AnyBitsFloat16Generator.java new file mode 100644 index 0000000000000..f11e8353760ee --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/generators/AnyBitsFloat16Generator.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.lib.generators; + +/** + * Provides an any-bits float16 distribution random generator, i.e. the bits are uniformly sampled, + * thus creating any possible float16 value, including the multiple different NaN representations. + */ +final class AnyBitsFloat16Generator extends BoundGenerator { + + /** + * Creates a new {@link AnyBitsFloat16Generator}. + */ + public AnyBitsFloat16Generator(Generators g) { + super(g); + } + + @Override + public Short next() { + return (short)g.random.nextInt(); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/generators/Generators.java b/test/hotspot/jtreg/compiler/lib/generators/Generators.java index 231b9822990af..ac4062f19d5a1 100644 --- a/test/hotspot/jtreg/compiler/lib/generators/Generators.java +++ b/test/hotspot/jtreg/compiler/lib/generators/Generators.java @@ -26,6 +26,7 @@ import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; import java.util.*; +import static java.lang.Float.floatToFloat16; import jdk.test.lib.Utils; @@ -165,6 +166,20 @@ public Generator anyBitsDouble() { return new AnyBitsDoubleGenerator(this); } + /** + * Generates uniform float16s in the range of [lo, hi) (inclusive of lo, exclusive of hi). + */ + public RestrictableGenerator uniformFloat16s(short lo, short hi) { + return new UniformFloat16Generator(this, lo, hi); + } + + /** + * Generates uniform float16s in the range of [0, 1) (inclusive of 0, exclusive of 1). + */ + public RestrictableGenerator uniformFloat16s() { + return uniformFloat16s(floatToFloat16(0.0f), floatToFloat16(1.0f)); + } + /** * Generates uniform doubles in the range of [lo, hi) (inclusive of lo, exclusive of hi). */ @@ -172,6 +187,14 @@ public RestrictableGenerator uniformFloats(float lo, float hi) { return new UniformFloatGenerator(this, lo, hi); } + /** + * Provides an any-bits float16 distribution random generator, i.e. the bits are uniformly sampled, + * thus creating any possible float16 value, including the multiple different NaN representations. + */ + public Generator anyBitsFloat16s() { + return new AnyBitsFloat16Generator(this); + } + /** * Generates uniform floats in the range of [0, 1) (inclusive of 0, exclusive of 1). */ @@ -344,6 +367,25 @@ public RestrictableGenerator uniformLongsMixedWithPowerOfTwos(int weightUn return mixed(uniformLongs(), powerOfTwoLongs(rangeSpecial), weightUniform, weightSpecial); } + /** + * Randomly pick a float16 generator. + * + * @return Random float16 generator. + */ + public Generator float16s() { + switch(random.nextInt(0, 5)) { + case 0 -> { return uniformFloat16s(floatToFloat16(-1.0f), floatToFloat16(1.0f)); } + // Well-balanced, so that multiplication reduction never explodes or collapses to zero: + case 1 -> { return uniformFloat16s(floatToFloat16(0.999f), floatToFloat16(1.001f)); } + case 2 -> { return anyBitsFloat16s(); } + // A tame distribution, mixed in with the occasional special float value: + case 3 -> { return mixedWithSpecialFloat16s(uniformFloat16s(floatToFloat16(0.999f), floatToFloat16(1.001f)), 10, 1000); } + // Generating any bits, but special values are more frequent. + case 4 -> { return mixedWithSpecialFloat16s(anyBitsFloat16s(), 100, 200); } + default -> { throw new RuntimeException("impossible"); } + } + } + /** * Randomly pick a float generator. * @@ -388,6 +430,7 @@ public Generator doubles() { */ public final RestrictableGenerator SPECIAL_DOUBLES = orderedRandomElement(List.of( 0d, + -0d, 1d, -1d, Double.POSITIVE_INFINITY, @@ -415,11 +458,12 @@ public RestrictableGenerator mixedWithSpecialDoubles(RestrictableGenerat } /** - * Generates interesting double values, which often are corner cases such as, 0, 1, -1, NaN, +/- Infinity, Min, + * Generates interesting float values, which often are corner cases such as, 0, 1, -1, NaN, +/- Infinity, Min, * Max. */ public final RestrictableGenerator SPECIAL_FLOATS = orderedRandomElement(List.of( 0f, + -0f, 1f, -1f, Float.POSITIVE_INFINITY, @@ -430,6 +474,29 @@ public RestrictableGenerator mixedWithSpecialDoubles(RestrictableGenerat Float.MIN_VALUE )); + /** + * Generates interesting float16 values, which often are corner cases such as, +/- 0, NaN, +/- Infinity, Min, + * Max. + */ + public final RestrictableGenerator SPECIAL_FLOAT16S = orderedRandomElement(List.of( + floatToFloat16(0.0f), + floatToFloat16(-0.0f), + floatToFloat16(Float.POSITIVE_INFINITY), + floatToFloat16(Float.NEGATIVE_INFINITY), + floatToFloat16(Float.NaN), + floatToFloat16(0x1.ffcP+15f), // MAX_VALUE + floatToFloat16(0x1.0P-14f), // MIN_NORMAL + floatToFloat16(0x1.0P-24f) // MIN_VALUE + )); + + /** + * Returns a mixed generator that mixes the provided background generator and {@link #SPECIAL_FLOAT16S} with the provided + * weights. + */ + public Generator mixedWithSpecialFloat16s(Generator background, int weightNormal, int weightSpecial) { + return mixed(background, SPECIAL_FLOAT16S, weightNormal, weightSpecial); + } + /** * Returns a mixed generator that mixes the provided background generator and {@link #SPECIAL_FLOATS} with the provided * weights. diff --git a/test/hotspot/jtreg/compiler/lib/generators/RandomnessSource.java b/test/hotspot/jtreg/compiler/lib/generators/RandomnessSource.java index 2b09b92cf3d47..f2771458975b9 100644 --- a/test/hotspot/jtreg/compiler/lib/generators/RandomnessSource.java +++ b/test/hotspot/jtreg/compiler/lib/generators/RandomnessSource.java @@ -42,4 +42,6 @@ public interface RandomnessSource { double nextDouble(double lo, double hi); /** Samples the next float value in the half-open interval [lo, hi) uniformly at random. */ float nextFloat(float lo, float hi); + /** Samples the next float16 value in the half-open interval [lo, hi) uniformly at random. */ + short nextFloat16(short lo, short hi); } diff --git a/test/hotspot/jtreg/compiler/lib/generators/RandomnessSourceAdapter.java b/test/hotspot/jtreg/compiler/lib/generators/RandomnessSourceAdapter.java index a8e62031cf6a2..599091f3a1c0a 100644 --- a/test/hotspot/jtreg/compiler/lib/generators/RandomnessSourceAdapter.java +++ b/test/hotspot/jtreg/compiler/lib/generators/RandomnessSourceAdapter.java @@ -24,6 +24,8 @@ package compiler.lib.generators; import java.util.random.RandomGenerator; +import static java.lang.Float.floatToFloat16; +import static java.lang.Float.float16ToFloat; /** * An adapter for using a {@link RandomGenerator} as a {@link RandomnessSource}. @@ -65,4 +67,9 @@ public double nextDouble(double lo, double hi) { public float nextFloat(float lo, float hi) { return rand.nextFloat(lo, hi); } + + @Override + public short nextFloat16(short lo, short hi) { + return floatToFloat16(rand.nextFloat(float16ToFloat(lo), float16ToFloat(hi))); + } } diff --git a/test/hotspot/jtreg/compiler/lib/generators/UniformFloat16Generator.java b/test/hotspot/jtreg/compiler/lib/generators/UniformFloat16Generator.java new file mode 100644 index 0000000000000..b2ff252ef05f8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/generators/UniformFloat16Generator.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.lib.generators; + +import static java.lang.Float.*; + +/** + * Provides a uniform float16 distribution random generator, in the provided range [lo, hi). + */ +final class UniformFloat16Generator extends UniformIntersectionRestrictableGenerator { + /** + * Creates a new {@link UniformFloat16Generator}. + * + * @param lo Lower bound of the range (inclusive). + * @param hi Higher bound of the range (exclusive). + */ + public UniformFloat16Generator(Generators g, Short lo, Short hi) { + super(g, lo, hi); + } + + @Override + public Short next() { + return g.random.nextFloat16(lo(), hi()); + } + + @Override + protected RestrictableGenerator doRestrictionFromIntersection(Short lo, Short hi) { + return new UniformFloat16Generator(g, lo, hi); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 46bd48eefb2c9..57e4d413fea07 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -244,6 +244,11 @@ public class IRNode { vectorNode(ADD_VI, "AddVI", TYPE_INT); } + public static final String ADD_VHF = VECTOR_PREFIX + "ADD_VHF" + POSTFIX; + static { + vectorNode(ADD_VHF, "AddVHF", TYPE_SHORT); + } + public static final String ADD_VF = VECTOR_PREFIX + "ADD_VF" + POSTFIX; static { vectorNode(ADD_VF, "AddVF", TYPE_FLOAT); @@ -679,6 +684,11 @@ public class IRNode { beforeMatchingNameRegex(DIV_MOD_L, "DivModL"); } + public static final String DIV_VHF = VECTOR_PREFIX + "DIV_VHF" + POSTFIX; + static { + vectorNode(DIV_VHF, "DivVHF", TYPE_SHORT); + } + public static final String DIV_VF = VECTOR_PREFIX + "DIV_VF" + POSTFIX; static { vectorNode(DIV_VF, "DivVF", TYPE_FLOAT); @@ -716,6 +726,11 @@ public class IRNode { optoOnly(FIELD_ACCESS, regex); } + public static final String FMA_VHF = VECTOR_PREFIX + "FMA_VHF" + POSTFIX; + static { + vectorNode(FMA_VHF, "FmaVHF", TYPE_SHORT); + } + public static final String FMA_VF = VECTOR_PREFIX + "FMA_VF" + POSTFIX; static { vectorNode(FMA_VF, "FmaVF", TYPE_FLOAT); @@ -1148,6 +1163,11 @@ public class IRNode { vectorNode(MAX_VI, "MaxV", TYPE_INT); } + public static final String MAX_VHF = VECTOR_PREFIX + "MAX_VHF" + POSTFIX; + static { + vectorNode(MAX_VHF, "MaxVHF", TYPE_SHORT); + } + public static final String MAX_VF = VECTOR_PREFIX + "MAX_VF" + POSTFIX; static { vectorNode(MAX_VF, "MaxV", TYPE_FLOAT); @@ -1248,6 +1268,11 @@ public class IRNode { vectorNode(MIN_VI, "MinV", TYPE_INT); } + public static final String MIN_VHF = VECTOR_PREFIX + "MIN_VHF" + POSTFIX; + static { + vectorNode(MIN_VHF, "MinVHF", TYPE_SHORT); + } + public static final String MIN_VF = VECTOR_PREFIX + "MIN_VF" + POSTFIX; static { vectorNode(MIN_VF, "MinV", TYPE_FLOAT); @@ -1349,6 +1374,11 @@ public class IRNode { vectorNode(MUL_VI, "MulVI", TYPE_INT); } + public static final String MUL_VHF = VECTOR_PREFIX + "MUL_VHF" + POSTFIX; + static { + vectorNode(MUL_VHF, "MulVHF", TYPE_SHORT); + } + public static final String MUL_VF = VECTOR_PREFIX + "MUL_VF" + POSTFIX; static { vectorNode(MUL_VF, "MulVF", TYPE_FLOAT); @@ -1760,6 +1790,11 @@ public class IRNode { vectorNode(SIGNUM_VF, "SignumVF", TYPE_FLOAT); } + public static final String SQRT_VHF = VECTOR_PREFIX + "SQRT_VHF" + POSTFIX; + static { + vectorNode(SQRT_VHF, "SqrtVHF", TYPE_SHORT); + } + public static final String SQRT_HF = PREFIX + "SQRT_HF" + POSTFIX; static { beforeMatchingNameRegex(SQRT_HF, "SqrtHF"); @@ -1946,6 +1981,11 @@ public class IRNode { vectorNode(SUB_VL, "SubVL", TYPE_LONG); } + public static final String SUB_VHF = VECTOR_PREFIX + "SUB_VHF" + POSTFIX; + static { + vectorNode(SUB_VHF, "SubVHF", TYPE_SHORT); + } + public static final String SUB_VF = VECTOR_PREFIX + "SUB_VF" + POSTFIX; static { vectorNode(SUB_VF, "SubVF", TYPE_FLOAT); diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java new file mode 100644 index 0000000000000..d295c3618b9e0 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Arm Limited. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** +* @test +* @bug 8346236 +* @summary Auto-vectorization support for various Float16 operations +* @modules jdk.incubator.vector +* @library /test/lib / +* @compile TestFloat16VectorOperations.java +* @run driver compiler.vectorization.TestFloat16VectorOperations +*/ + +package compiler.vectorization; +import compiler.lib.ir_framework.*; +import jdk.incubator.vector.Float16; +import static jdk.incubator.vector.Float16.*; +import static java.lang.Float.*; +import jdk.test.lib.*; +import compiler.lib.generators.Generator; +import static compiler.lib.generators.Generators.G; + +public class TestFloat16VectorOperations { + private short[] input1; + private short[] input2; + private short[] input3; + private short[] output; + private static short SCALAR_FP16 = (short)0x7777; + private static final int LEN = 2048; + + public static void main(String args[]) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector"); + } + + public static boolean assertResults(short expected, short actual) { + Float16 expected_fp16 = shortBitsToFloat16(expected); + Float16 actual_fp16 = shortBitsToFloat16(actual); + return !expected_fp16.equals(actual_fp16); + } + + public TestFloat16VectorOperations() { + input1 = new short[LEN]; + input2 = new short[LEN]; + input3 = new short[LEN]; + output = new short[LEN]; + + short min_value = float16ToRawShortBits(Float16.MIN_VALUE); + short max_value = float16ToRawShortBits(Float16.MAX_VALUE); + Generator gen = G.float16s(); + for (int i = 0; i < LEN; ++i) { + input1[i] = gen.next(); + input2[i] = gen.next(); + input3[i] = gen.next(); + } + } + + @Test + @Warmup(10000) + @IR(counts = {IRNode.ADD_VHF, ">= 1"}, + applyIfCPUFeature = {"avx512_fp16", "true"}) + public void vectorAddFloat16() { + for (int i = 0; i < LEN; ++i) { + output[i] = float16ToRawShortBits(add(shortBitsToFloat16(input1[i]), shortBitsToFloat16(input2[i]))); + } + } + + @Check(test="vectorAddFloat16") + public void checkResultAdd() { + for (int i = 0; i < LEN; ++i) { + short expected = floatToFloat16(float16ToFloat(input1[i]) + float16ToFloat(input2[i])); + if (assertResults(expected, output[i])) { + throw new RuntimeException("Invalid result: [" + i + "] input1 = " + input1[i] + " input2 = " + input2[i] + + " output = " + output[i] + " expected = " + expected); + } + } + } + + @Test + @Warmup(10000) + @IR(counts = {IRNode.SUB_VHF, ">= 1"}, + applyIfCPUFeature = {"avx512_fp16", "true"}) + public void vectorSubFloat16() { + for (int i = 0; i < LEN; ++i) { + output[i] = float16ToRawShortBits(subtract(shortBitsToFloat16(input1[i]), shortBitsToFloat16(input2[i]))); + } + } + + @Check(test="vectorSubFloat16") + public void checkResultSub() { + for (int i = 0; i < LEN; ++i) { + short expected = floatToFloat16(float16ToFloat(input1[i]) - float16ToFloat(input2[i])); + if (assertResults(expected, output[i])) { + throw new RuntimeException("Invalid result: [" + i + "] input1 = " + input1[i] + " input2 = " + input2[i] + + " output = " + output[i] + " expected = " + expected); + } + } + } + + @Test + @Warmup(10000) + @IR(counts = {IRNode.MUL_VHF, ">= 1"}, + applyIfCPUFeature = {"avx512_fp16", "true"}) + public void vectorMulFloat16() { + for (int i = 0; i < LEN; ++i) { + output[i] = float16ToRawShortBits(multiply(shortBitsToFloat16(input1[i]), shortBitsToFloat16(input2[i]))); + } + } + + @Check(test="vectorMulFloat16") + public void checkResultMul() { + for (int i = 0; i < LEN; ++i) { + short expected = floatToFloat16(float16ToFloat(input1[i]) * float16ToFloat(input2[i])); + if (assertResults(expected, output[i])) { + throw new RuntimeException("Invalid result: [" + i + "] input1 = " + input1[i] + " input2 = " + input2[i] + + " output = " + output[i] + " expected = " + expected); + } + } + } + + @Test + @Warmup(10000) + @IR(counts = {IRNode.DIV_VHF, ">= 1"}, + applyIfCPUFeature = {"avx512_fp16", "true"}) + public void vectorDivFloat16() { + for (int i = 0; i < LEN; ++i) { + output[i] = float16ToRawShortBits(divide(shortBitsToFloat16(input1[i]), shortBitsToFloat16(input2[i]))); + } + } + + @Check(test="vectorDivFloat16") + public void checkResultDiv() { + for (int i = 0; i < LEN; ++i) { + short expected = floatToFloat16(float16ToFloat(input1[i]) / float16ToFloat(input2[i])); + if (assertResults(expected, output[i])) { + throw new RuntimeException("Invalid result: [" + i + "] input1 = " + input1[i] + " input2 = " + input2[i] + + " output = " + output[i] + " expected = " + expected); + } + } + } + + @Test + @Warmup(10000) + @IR(counts = {IRNode.MIN_VHF, ">= 1"}, + applyIfCPUFeature = {"avx512_fp16", "true"}) + public void vectorMinFloat16() { + for (int i = 0; i < LEN; ++i) { + output[i] = float16ToRawShortBits(min(shortBitsToFloat16(input1[i]), shortBitsToFloat16(input2[i]))); + } + } + + @Check(test="vectorMinFloat16") + public void checkResultMin() { + for (int i = 0; i < LEN; ++i) { + short expected = floatToFloat16(Math.min(float16ToFloat(input1[i]), float16ToFloat(input2[i]))); + if (assertResults(expected, output[i])) { + throw new RuntimeException("Invalid result: [" + i + "] input1 = " + input1[i] + " input2 = " + input2[i] + + " output = " + output[i] + " expected = " + expected); + } + } + } + + @Test + @Warmup(10000) + @IR(counts = {IRNode.MAX_VHF, ">= 1"}, + applyIfCPUFeature = {"avx512_fp16", "true"}) + public void vectorMaxFloat16() { + for (int i = 0; i < LEN; ++i) { + output[i] = float16ToRawShortBits(max(shortBitsToFloat16(input1[i]), shortBitsToFloat16(input2[i]))); + } + } + + @Check(test="vectorMaxFloat16") + public void checkResultMax() { + for (int i = 0; i < LEN; ++i) { + short expected = floatToFloat16(Math.max(float16ToFloat(input1[i]), float16ToFloat(input2[i]))); + if (assertResults(expected, output[i])) { + throw new RuntimeException("Invalid result: [" + i + "] input1 = " + input1[i] + " input2 = " + input2[i] + + " output = " + output[i] + " expected = " + expected); + } + } + } + + @Test + @Warmup(10000) + @IR(counts = {IRNode.SQRT_VHF, ">= 1"}, + applyIfCPUFeature = {"avx512_fp16", "true"}) + public void vectorSqrtFloat16() { + for (int i = 0; i < LEN; ++i) { + output[i] = float16ToRawShortBits(sqrt(shortBitsToFloat16(input1[i]))); + } + } + + @Check(test="vectorSqrtFloat16") + public void checkResultSqrt() { + for (int i = 0; i < LEN; ++i) { + short expected = float16ToRawShortBits(sqrt(shortBitsToFloat16(input1[i]))); + if (assertResults(expected, output[i])) { + throw new RuntimeException("Invalid result: [" + i + "] input = " + input1[i] + + " output = " + output[i] + " expected = " + expected); + } + } + } + + @Test + @Warmup(10000) + @IR(counts = {IRNode.FMA_VHF, ">= 1"}, + applyIfCPUFeature = {"avx512_fp16", "true"}) + public void vectorFmaFloat16() { + for (int i = 0; i < LEN; ++i) { + output[i] = float16ToRawShortBits(fma(shortBitsToFloat16(input1[i]), shortBitsToFloat16(input2[i]), + shortBitsToFloat16(input3[i]))); + } + } + + @Check(test="vectorFmaFloat16") + public void checkResultFma() { + for (int i = 0; i < LEN; ++i) { + short expected = float16ToRawShortBits(fma(shortBitsToFloat16(input1[i]), shortBitsToFloat16(input2[i]), + shortBitsToFloat16(input3[i]))); + if (assertResults(expected, output[i])) { + throw new RuntimeException("Invalid result: [" + i + "] input1 = " + input1[i] + " input2 = " + input2[i] + + "input3 = " + input3[i] + " output = " + output[i] + " expected = " + expected); + } + } + } + + @Test + @Warmup(10000) + @IR(counts = {IRNode.FMA_VHF, " >= 1"}, + applyIfCPUFeature = {"avx512_fp16", "true"}) + public void vectorFmaFloat16ScalarMixedConstants() { + for (int i = 0; i < LEN; ++i) { + output[i] = float16ToRawShortBits(fma(shortBitsToFloat16(input1[i]), shortBitsToFloat16(SCALAR_FP16), + shortBitsToFloat16(floatToFloat16(3.0f)))); + } + } + + @Check(test="vectorFmaFloat16ScalarMixedConstants") + public void checkResultFmaScalarMixedConstants() { + for (int i = 0; i < LEN; ++i) { + short expected = float16ToRawShortBits(fma(shortBitsToFloat16(input1[i]), shortBitsToFloat16(SCALAR_FP16), + shortBitsToFloat16(floatToFloat16(3.0f)))); + if (assertResults(expected, output[i])) { + throw new RuntimeException("Invalid result: [" + i + "] input1 = " + input1[i] + " input2 = " + SCALAR_FP16 + + "input3 = 3.0 " + "output = " + output[i] + " expected = " + expected); + } + } + } + + + @Test + @Warmup(10000) + @IR(counts = {IRNode.FMA_VHF, " >= 1"}, + applyIfCPUFeature = {"avx512_fp16", "true"}) + public void vectorFmaFloat16MixedConstants() { + short input3 = floatToFloat16(3.0f); + for (int i = 0; i < LEN; ++i) { + output[i] = float16ToRawShortBits(fma(shortBitsToFloat16(input1[i]), shortBitsToFloat16(input2[i]), shortBitsToFloat16(input3))); + } + } + + @Check(test="vectorFmaFloat16MixedConstants") + public void checkResultFmaMixedConstants() { + short input3 = floatToFloat16(3.0f); + for (int i = 0; i < LEN; ++i) { + short expected = float16ToRawShortBits(fma(shortBitsToFloat16(input1[i]), shortBitsToFloat16(input2[i]), shortBitsToFloat16(input3))); + if (assertResults(expected, output[i])) { + throw new RuntimeException("Invalid result: [" + i + "] input1 = " + input1[i] + " input2 = " + input2[i] + + "input3 = " + input3 + " output = " + output[i] + " expected = " + expected); + } + } + } + + @Test + @Warmup(10000) + @IR(counts = {IRNode.FMA_VHF, " 0 "}, + applyIfCPUFeature = {"avx512_fp16", "true"}) + public void vectorFmaFloat16AllConstants() { + short input1 = floatToFloat16(1.0f); + short input2 = floatToFloat16(2.0f); + short input3 = floatToFloat16(3.0f); + for (int i = 0; i < LEN; ++i) { + output[i] = float16ToRawShortBits(fma(shortBitsToFloat16(input1), shortBitsToFloat16(input2), shortBitsToFloat16(input3))); + } + } + + @Check(test="vectorFmaFloat16AllConstants") + public void checkResultFmaAllConstants() { + short input1 = floatToFloat16(1.0f); + short input2 = floatToFloat16(2.0f); + short input3 = floatToFloat16(3.0f); + for (int i = 0; i < LEN; ++i) { + short expected = float16ToRawShortBits(fma(shortBitsToFloat16(input1), shortBitsToFloat16(input2), shortBitsToFloat16(input3))); + if (assertResults(expected, output[i])) { + throw new RuntimeException("Invalid result: [" + i + "] input1 = " + input1 + " input2 = " + input2 + + "input3 = " + input3 + " output = " + output[i] + " expected = " + expected); + } + } + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/generators/tests/MockRandomnessSource.java b/test/hotspot/jtreg/testlibrary_tests/generators/tests/MockRandomnessSource.java index c8d5f3257066c..21c7a8d250cd4 100644 --- a/test/hotspot/jtreg/testlibrary_tests/generators/tests/MockRandomnessSource.java +++ b/test/hotspot/jtreg/testlibrary_tests/generators/tests/MockRandomnessSource.java @@ -48,6 +48,7 @@ private record Bounded(T lo, T hi, T value) {} private final Queue> boundedIntegerQueue = new ArrayDeque<>(); private final Queue> boundedDoubleQueue = new ArrayDeque<>(); private final Queue> boundedFloatQueue = new ArrayDeque<>(); + private final Queue> boundedFloat16Queue = new ArrayDeque<>(); private T dequeueBounded(Queue> queue, T lo, T hi) { Bounded bounded = queue.remove(); @@ -91,6 +92,11 @@ public MockRandomnessSource enqueueFloat(float lo, float hi, float value) { return this; } + public MockRandomnessSource enqueueFloat16(short lo, short hi, short value) { + boundedFloat16Queue.add(new Bounded<>(lo, hi, value)); + return this; + } + public MockRandomnessSource checkEmpty() { checkQueueEmpty(unboundedLongQueue, "unbounded longs"); checkQueueEmpty(unboundedIntegerQueue, "unbounded integers"); @@ -98,6 +104,7 @@ public MockRandomnessSource checkEmpty() { checkQueueEmpty(boundedIntegerQueue, "bounded integers"); checkQueueEmpty(boundedDoubleQueue, "bounded doubles"); checkQueueEmpty(boundedFloatQueue, "bounded floats"); + checkQueueEmpty(boundedFloat16Queue, "bounded float16s"); return this; } @@ -130,4 +137,9 @@ public double nextDouble(double lo, double hi) { public float nextFloat(float lo, float hi) { return dequeueBounded(boundedFloatQueue, lo, hi); } + + @Override + public short nextFloat16(short lo, short hi) { + return dequeueBounded(boundedFloat16Queue, lo, hi); + } } diff --git a/test/hotspot/jtreg/testlibrary_tests/generators/tests/TestGenerators.java b/test/hotspot/jtreg/testlibrary_tests/generators/tests/TestGenerators.java index 203256ad7b86c..8ad0c17ba98e6 100644 --- a/test/hotspot/jtreg/testlibrary_tests/generators/tests/TestGenerators.java +++ b/test/hotspot/jtreg/testlibrary_tests/generators/tests/TestGenerators.java @@ -57,6 +57,7 @@ public static void main(String[] args) { testUniformLongs(); testAnyBits(); testUniformFloat(); + testUniformFloat16(); testUniformDouble(); testSingle(); testMixed(); @@ -64,6 +65,7 @@ public static void main(String[] args) { specialInt(); specialLong(); testSpecialFloat(); + testSpecialFloat16(); testSpecialDouble(); testSafeRestrict(); testFill(); @@ -157,7 +159,7 @@ static void testSpecialDouble() { .enqueueInteger(0, 10, 3) .enqueueDouble(0, 1, 3.4d) .enqueueInteger(0, 10, 6) - .enqueueInteger(0, 9, 1); + .enqueueInteger(0, 10, 1); var g = mockGS.mixedWithSpecialDoubles(mockGS.uniformDoubles(), 5, 5); Asserts.assertEQ(g.next(), 3.4d); Asserts.assertEQ(g.next(), -1d); @@ -169,12 +171,34 @@ static void testSpecialFloat() { .enqueueInteger(0, 10, 3) .enqueueFloat(0, 1, 3.4f) .enqueueInteger(0, 10, 6) - .enqueueInteger(0, 9, 1); + .enqueueInteger(0, 10, 1); var g = mockGS.mixedWithSpecialFloats(mockGS.uniformFloats(), 5, 5); Asserts.assertEQ(g.next(), 3.4f); Asserts.assertEQ(g.next(), -1f); } + static void testSpecialFloat16() { + mockSource + .checkEmpty() + .enqueueInteger(0, 8, 2) + .enqueueFloat16((short)0, (short)15360, (short)17010) + .enqueueInteger(0, 8, 6) + .enqueueInteger(0, 8, 5) + .enqueueInteger(0, 8, 7) + .enqueueInteger(0, 8, 4); + var g = mockGS.mixedWithSpecialFloat16s(mockGS.uniformFloat16s(), 4, 4); + Asserts.assertEQ(g.next(), (short)17010); + Asserts.assertEQ(g.next(), (short)31743); + Asserts.assertEQ(g.next(), (short)1024); + } + + static void testUniformFloat16() { + mockSource.checkEmpty().enqueueFloat16((short)0, (short)10, (short)17664); + Asserts.assertEQ(mockGS.uniformFloat16s((short)0, (short)10).next(), (short)17664); + mockSource.checkEmpty().enqueueFloat16((short)0, (short)5, (short)31744); + Asserts.assertEQ(mockGS.uniformFloat16s((short)0, (short)5).next(), (short)31744); + } + static void testUniformFloat() { mockSource.checkEmpty().enqueueFloat(-1, 10, 3.14159f); Asserts.assertEQ(mockGS.uniformFloats(-1, 10).next(), 3.14159f); diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/Float16OperationsBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/Float16OperationsBenchmark.java index a0a462ad6b1e9..ebbfbb01cc615 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/Float16OperationsBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/Float16OperationsBenchmark.java @@ -41,6 +41,8 @@ public class Float16OperationsBenchmark { short [] vector1; short [] vector2; short [] vector3; + short [] vector4; + short [] vector5; boolean [] vectorPredicate; static final short f16_one = Float.floatToFloat16(1.0f); @@ -53,12 +55,19 @@ public void BmSetup() { vector1 = new short[vectorDim]; vector2 = new short[vectorDim]; vector3 = new short[vectorDim]; + vector4 = new short[vectorDim]; + vector5 = new short[vectorDim]; vectorPredicate = new boolean[vectorDim]; IntStream.range(0, vectorDim).forEach(i -> {vector1[i] = Float.floatToFloat16((float)i);}); IntStream.range(0, vectorDim).forEach(i -> {vector2[i] = Float.floatToFloat16((float)i);}); IntStream.range(0, vectorDim).forEach(i -> {vector3[i] = Float.floatToFloat16((float)i);}); - + IntStream.range(0, vectorDim).forEach(i -> {vector4[i] = ((i & 0x1) == 0) ? + float16ToRawShortBits(Float16.POSITIVE_INFINITY) : + Float.floatToFloat16((float)i);}); + IntStream.range(0, vectorDim).forEach(i -> {vector5[i] = ((i & 0x1) == 0) ? + float16ToRawShortBits(Float16.NaN) : + Float.floatToFloat16((float)i);}); // Special Values Float16 [] specialValues = {Float16.NaN, Float16.NEGATIVE_INFINITY, Float16.valueOf(0.0), Float16.valueOf(-0.0), Float16.POSITIVE_INFINITY}; IntStream.range(0, vectorDim).forEach( @@ -140,7 +149,7 @@ public boolean isNaNBenchmark() { @Benchmark public void isNaNStoreBenchmark() { for (int i = 0; i < vectorDim; i++) { - vectorPredicate[i] = Float16.isNaN(shortBitsToFloat16(vector1[i])); + vectorPredicate[i] = isNaN(shortBitsToFloat16(vector1[i])); } } @@ -148,7 +157,7 @@ public void isNaNStoreBenchmark() { @Benchmark public void isNaNCMovBenchmark() { for (int i = 0; i < vectorDim; i++) { - vectorRes[i] = Float16.isNaN(shortBitsToFloat16(vector1[i])) ? f16_one : f16_two; + vectorRes[i] = isNaN(shortBitsToFloat16(vector5[i])) ? vector1[i] : vector2[i]; } } @@ -156,7 +165,7 @@ public void isNaNCMovBenchmark() { @Benchmark public void isInfiniteStoreBenchmark() { for (int i = 0; i < vectorDim; i++) { - vectorPredicate[i] = Float16.isInfinite(shortBitsToFloat16(vector1[i])); + vectorPredicate[i] = isInfinite(shortBitsToFloat16(vector1[i])); } } @@ -164,7 +173,7 @@ public void isInfiniteStoreBenchmark() { @Benchmark public void isInfiniteCMovBenchmark() { for (int i = 0; i < vectorDim; i++) { - vectorRes[i] = Float16.isInfinite(shortBitsToFloat16(vector1[i])) ? f16_one : f16_two; + vectorRes[i] = isInfinite(shortBitsToFloat16(vector4[i])) ? vector1[i] : vector2[i]; } } @@ -172,7 +181,7 @@ public void isInfiniteCMovBenchmark() { @Benchmark public void isFiniteStoreBenchmark() { for (int i = 0; i < vectorDim; i++) { - vectorPredicate[i] = Float16.isFinite(shortBitsToFloat16(vector1[i])); + vectorPredicate[i] = isFinite(shortBitsToFloat16(vector1[i])); } } @@ -180,7 +189,7 @@ public void isFiniteStoreBenchmark() { @Benchmark public void isFiniteCMovBenchmark() { for (int i = 0; i < vectorDim; i++) { - vectorRes[i] = Float16.isFinite(shortBitsToFloat16(vector1[i])) ? f16_one : f16_two; + vectorRes[i] = isFinite(shortBitsToFloat16(vector4[i])) ? vector1[i] : vector2[i]; } } @@ -293,4 +302,16 @@ public short euclideanDistanceDequantizedFP16() { } return float16ToRawShortBits(sqrt(shortBitsToFloat16(floatToFloat16(distRes)))); } + + @Benchmark + public short dotProductFP16() { + short distRes = floatToFloat16(0.0f); + for (int i = 0; i < vectorDim; i++) { + vectorRes[i] = float16ToRawShortBits(multiply(shortBitsToFloat16(vector1[i]), shortBitsToFloat16(vector2[i]))); + } + for (int i = 0; i < vectorDim; i++) { + distRes = float16ToRawShortBits(add(shortBitsToFloat16(vectorRes[i]), shortBitsToFloat16(distRes))); + } + return distRes; + } } From 51b3d6bba29b256616cf00c0be7a7fe0f97621ab Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Thu, 10 Apr 2025 10:18:46 +0000 Subject: [PATCH 0516/1101] 8352431: java/net/httpclient/EmptyAuthenticate.java uses "localhost" Reviewed-by: dfuchs, jpai --- .../net/httpclient/EmptyAuthenticate.java | 145 +++++++++++++----- 1 file changed, 105 insertions(+), 40 deletions(-) diff --git a/test/jdk/java/net/httpclient/EmptyAuthenticate.java b/test/jdk/java/net/httpclient/EmptyAuthenticate.java index 2e80e1bdc8138..ca5c41594e804 100644 --- a/test/jdk/java/net/httpclient/EmptyAuthenticate.java +++ b/test/jdk/java/net/httpclient/EmptyAuthenticate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,55 +24,120 @@ /* * @test * @bug 8263899 - * @summary HttpClient throws NPE in AuthenticationFilter when parsing www-authenticate head - * - * @run main/othervm EmptyAuthenticate + * @summary Verifies that empty `WWW-Authenticate` header is correctly parsed + * @library /test/jdk/java/net/httpclient/lib + * /test/lib + * @build jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * @run junit EmptyAuthenticate */ -import com.sun.net.httpserver.HttpServer; + +import jdk.httpclient.test.lib.common.HttpServerAdapters; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestHandler; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer; +import jdk.test.lib.net.SimpleSSLContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import javax.net.ssl.SSLContext; import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; import java.net.URI; -import java.net.URISyntaxException; import java.net.http.HttpClient; +import java.net.http.HttpClient.Version; +import java.net.http.HttpHeaders; import java.net.http.HttpRequest; import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.stream.Stream; -public class EmptyAuthenticate { - - public static void main(String[] args) throws IOException, URISyntaxException, InterruptedException { - int port = 0; - - //start server: - HttpServer server = HttpServer.create(new InetSocketAddress(port), 0); - port = server.getAddress().getPort(); - server.createContext("/", exchange -> { - String response = "test body"; - //this empty header will make the HttpClient throw NPE - exchange.getResponseHeaders().add("www-authenticate", ""); - exchange.sendResponseHeaders(401, response.length()); - OutputStream os = exchange.getResponseBody(); - os.write(response.getBytes()); - os.close(); - }); - server.start(); +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static org.junit.jupiter.api.Assertions.assertEquals; - HttpResponse response = null; - //run client: +class EmptyAuthenticate { + + private static final SSLContext SSL_CONTEXT = createSslContext(); + + private static final String WWW_AUTH_HEADER_NAME = "WWW-Authenticate"; + + private static SSLContext createSslContext() { try { - HttpClient httpClient = HttpClient.newHttpClient(); - HttpRequest request = HttpRequest.newBuilder(new URI("http://localhost:" + port + "/")).GET().build(); - //this line will throw NPE (wrapped by IOException) when parsing empty www-authenticate response header in AuthenticationFilter: - response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - boolean ok = !response.headers().firstValue("WWW-Authenticate").isEmpty(); - if (!ok) { - throw new RuntimeException("WWW-Authenicate missing"); - } - } catch (IOException e) { - e.printStackTrace(); - throw new RuntimeException("Test failed"); + return new SimpleSSLContext().get(); + } catch (IOException exception) { + throw new RuntimeException(exception); + } + } + + @ParameterizedTest + @MethodSource("args") + void test(Version version, boolean secure) throws Exception { + String handlerPath = "/%s/%s/".formatted(EmptyAuthenticate.class.getSimpleName(), version); + String uriPath = handlerPath + (secure ? 's' : 'c'); + HttpTestServer server = createServer(version, secure, handlerPath); + try (HttpClient client = createClient(version, secure)) { + HttpRequest request = createRequest(server, secure, uriPath); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.discarding()); + HttpHeaders responseHeaders = response.headers(); + assertEquals( + "", + responseHeaders.firstValue(WWW_AUTH_HEADER_NAME).orElse(null), + () -> "was expecting empty `%s` header in: %s".formatted( + WWW_AUTH_HEADER_NAME, responseHeaders.map())); } finally { - server.stop(0); + server.stop(); } } + + static Stream args() { + return Stream + .of(Version.HTTP_1_1, Version.HTTP_2) + .flatMap(version -> Stream + .of(true, false) + .map(secure -> Arguments.of(version, secure))); + } + + private static HttpTestServer createServer(Version version, boolean secure, String uriPath) + throws IOException { + HttpTestServer server = secure + ? HttpTestServer.create(version, SSL_CONTEXT) + : HttpTestServer.create(version); + HttpTestHandler handler = new ServerHandlerRespondingWithEmptyWwwAuthHeader(); + server.addHandler(handler, uriPath); + server.start(); + return server; + } + + private static final class ServerHandlerRespondingWithEmptyWwwAuthHeader implements HttpTestHandler { + + private int responseIndex = 0; + + @Override + public synchronized void handle(HttpServerAdapters.HttpTestExchange exchange) throws IOException { + try (exchange) { + exchange.getResponseHeaders().addHeader(WWW_AUTH_HEADER_NAME, ""); + byte[] responseBodyBytes = "test body %d" + .formatted(responseIndex) + .getBytes(StandardCharsets.US_ASCII); + exchange.sendResponseHeaders(401, responseBodyBytes.length); + exchange.getResponseBody().write(responseBodyBytes); + } finally { + responseIndex++; + } + } + + } + + private static HttpClient createClient(Version version, boolean secure) { + HttpClient.Builder clientBuilder = HttpClient.newBuilder().version(version).proxy(NO_PROXY); + if (secure) { + clientBuilder.sslContext(SSL_CONTEXT); + } + return clientBuilder.build(); + } + + private static HttpRequest createRequest(HttpTestServer server, boolean secure, String uriPath) { + URI uri = URI.create("%s://%s%s".formatted(secure ? "https" : "http", server.serverAuthority(), uriPath)); + return HttpRequest.newBuilder(uri).version(server.getVersion()).GET().build(); + } + } From 6c2667018a49ac78c3a01dc4d52ff6cdf39b7647 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 10 Apr 2025 10:21:32 +0000 Subject: [PATCH 0517/1101] 8324686: Remove redefinition of NULL for MSVC Reviewed-by: shade, dholmes --- .../utilities/globalDefinitions_visCPP.hpp | 19 ------------------- test/hotspot/jtreg/sources/TestNoNULL.java | 3 +-- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp b/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp index 83d075572877a..4b4a0f4d8382c 100644 --- a/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp +++ b/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp @@ -54,25 +54,6 @@ #error unsupported platform #endif -// 4810578: varargs unsafe on 32-bit integer/64-bit pointer architectures -// When __cplusplus is defined, NULL is defined as 0 (32-bit constant) in -// system header files. On 32-bit architectures, there is no problem. -// On 64-bit architectures, defining NULL as a 32-bit constant can cause -// problems with varargs functions: C++ integral promotion rules say for -// varargs, we pass the argument 0 as an int. So, if NULL was passed to a -// varargs function it will remain 32-bits. Depending on the calling -// convention of the machine, if the argument is passed on the stack then -// only 32-bits of the "NULL" pointer may be initialized to zero. The -// other 32-bits will be garbage. If the varargs function is expecting a -// pointer when it extracts the argument, then we may have a problem. -// -// Solution: For 64-bit architectures, redefine NULL as 64-bit constant 0. -#undef NULL -// 64-bit Windows uses a P64 data model (not LP64, although we define _LP64) -// Since longs are 32-bit we cannot use 0L here. Use the Visual C++ specific -// 64-bit integer-suffix (LL) instead. -#define NULL 0LL - typedef int64_t ssize_t; // Non-standard stdlib-like stuff: diff --git a/test/hotspot/jtreg/sources/TestNoNULL.java b/test/hotspot/jtreg/sources/TestNoNULL.java index 73a415466fe15..12fe46a609e98 100644 --- a/test/hotspot/jtreg/sources/TestNoNULL.java +++ b/test/hotspot/jtreg/sources/TestNoNULL.java @@ -74,8 +74,7 @@ public static void main(String[] args) throws IOException { private static void initializeExcludedPaths(Path rootDir) { List sourceExclusions = List.of( "src/hotspot/share/prims/jvmti.xml", - "src/hotspot/share/prims/jvmti.xsl", - "src/hotspot/share/utilities/globalDefinitions_visCPP.hpp" + "src/hotspot/share/prims/jvmti.xsl" ); List testExclusions = List.of( From 7e69b98e0548803b85b04b518929c073f8ffaf8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Thu, 10 Apr 2025 11:37:20 +0000 Subject: [PATCH 0518/1101] 8350441: ZGC: Overhaul Page Allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Axel Boldt-Christmas Co-authored-by: Erik Österlund Co-authored-by: Stefan Karlsson Co-authored-by: Stefan Johansson Reviewed-by: stefank, aboldtch, eosterlund --- .../cpu/aarch64/gc/z/zAddress_aarch64.cpp | 2 +- src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp | 2 +- src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp | 2 +- src/hotspot/cpu/x86/gc/z/zAddress_x86.cpp | 2 +- src/hotspot/os/bsd/gc/z/zNUMA_bsd.cpp | 15 +- .../bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp | 17 +- .../bsd/gc/z/zPhysicalMemoryBacking_bsd.hpp | 10 +- src/hotspot/os/linux/gc/z/zNUMA_linux.cpp | 15 +- .../gc/z/zPhysicalMemoryBacking_linux.cpp | 75 +- .../gc/z/zPhysicalMemoryBacking_linux.hpp | 32 +- ...ix.cpp => zVirtualMemoryManager_posix.cpp} | 13 +- .../os/windows/gc/z/zInitialize_windows.cpp | 3 + src/hotspot/os/windows/gc/z/zNUMA_windows.cpp | 14 +- .../gc/z/zPhysicalMemoryBacking_windows.cpp | 52 +- .../gc/z/zPhysicalMemoryBacking_windows.hpp | 8 +- ....cpp => zVirtualMemoryManager_windows.cpp} | 59 +- src/hotspot/share/gc/z/vmStructs_z.hpp | 22 +- src/hotspot/share/gc/z/zAddress.cpp | 12 + src/hotspot/share/gc/z/zAddress.hpp | 29 +- src/hotspot/share/gc/z/zAddress.inline.hpp | 259 +- src/hotspot/share/gc/z/zAddressSpaceLimit.cpp | 12 + src/hotspot/share/gc/z/zAddressSpaceLimit.hpp | 4 +- src/hotspot/share/gc/z/zAllocationFlags.hpp | 31 +- src/hotspot/share/gc/z/zArguments.cpp | 2 +- src/hotspot/share/gc/z/zArray.hpp | 44 +- src/hotspot/share/gc/z/zArray.inline.hpp | 89 +- src/hotspot/share/gc/z/zCollectedHeap.cpp | 7 +- src/hotspot/share/gc/z/zGeneration.cpp | 34 +- src/hotspot/share/gc/z/zGranuleMap.hpp | 5 +- src/hotspot/share/gc/z/zGranuleMap.inline.hpp | 13 +- src/hotspot/share/gc/z/zHeap.cpp | 46 +- src/hotspot/share/gc/z/zHeap.hpp | 5 +- src/hotspot/share/gc/z/zInitialize.cpp | 2 +- src/hotspot/share/gc/z/zIntrusiveRBTree.hpp | 293 ++ .../share/gc/z/zIntrusiveRBTree.inline.hpp | 1351 +++++++++ src/hotspot/share/gc/z/zList.hpp | 14 +- src/hotspot/share/gc/z/zList.inline.hpp | 29 +- src/hotspot/share/gc/z/zLiveMap.cpp | 41 +- src/hotspot/share/gc/z/zLiveMap.hpp | 15 +- src/hotspot/share/gc/z/zLiveMap.inline.hpp | 8 +- src/hotspot/share/gc/z/zMappedCache.cpp | 629 ++++ src/hotspot/share/gc/z/zMappedCache.hpp | 112 + src/hotspot/share/gc/z/zMemory.cpp | 284 -- src/hotspot/share/gc/z/zMemory.hpp | 104 - src/hotspot/share/gc/z/zMemory.inline.hpp | 80 - src/hotspot/share/gc/z/zNMT.cpp | 7 +- src/hotspot/share/gc/z/zNMT.hpp | 11 +- src/hotspot/share/gc/z/zNUMA.cpp | 13 +- src/hotspot/share/gc/z/zNUMA.hpp | 9 + src/hotspot/share/gc/z/zNUMA.inline.hpp | 24 + src/hotspot/share/gc/z/zObjectAllocator.cpp | 8 +- src/hotspot/share/gc/z/zPage.cpp | 114 +- src/hotspot/share/gc/z/zPage.hpp | 64 +- src/hotspot/share/gc/z/zPage.inline.hpp | 38 +- src/hotspot/share/gc/z/zPageAllocator.cpp | 2649 +++++++++++++---- src/hotspot/share/gc/z/zPageAllocator.hpp | 275 +- src/hotspot/share/gc/z/zPageCache.cpp | 332 --- src/hotspot/share/gc/z/zPageCache.hpp | 66 - src/hotspot/share/gc/z/zPageTable.cpp | 4 - src/hotspot/share/gc/z/zPageTable.inline.hpp | 4 +- src/hotspot/share/gc/z/zPhysicalMemory.cpp | 386 --- src/hotspot/share/gc/z/zPhysicalMemory.hpp | 105 - .../share/gc/z/zPhysicalMemory.inline.hpp | 74 - .../share/gc/z/zPhysicalMemoryManager.cpp | 376 +++ .../share/gc/z/zPhysicalMemoryManager.hpp | 79 + src/hotspot/share/gc/z/zRange.hpp | 76 + src/hotspot/share/gc/z/zRange.inline.hpp | 144 + src/hotspot/share/gc/z/zRangeRegistry.hpp | 150 + .../share/gc/z/zRangeRegistry.inline.hpp | 469 +++ src/hotspot/share/gc/z/zRelocate.cpp | 20 +- src/hotspot/share/gc/z/zRemembered.cpp | 2 - src/hotspot/share/gc/z/zRememberedSet.cpp | 6 - src/hotspot/share/gc/z/zRememberedSet.hpp | 3 +- src/hotspot/share/gc/z/zUncommitter.cpp | 27 +- src/hotspot/share/gc/z/zUncommitter.hpp | 9 +- src/hotspot/share/gc/z/zUnmapper.cpp | 129 - src/hotspot/share/gc/z/zUtils.hpp | 12 +- src/hotspot/share/gc/z/zUtils.inline.hpp | 33 +- src/hotspot/share/gc/z/zValue.hpp | 19 +- src/hotspot/share/gc/z/zValue.inline.hpp | 35 +- src/hotspot/share/gc/z/zVirtualMemory.cpp | 257 -- src/hotspot/share/gc/z/zVirtualMemory.hpp | 63 +- .../share/gc/z/zVirtualMemory.inline.hpp | 51 +- .../share/gc/z/zVirtualMemoryManager.cpp | 357 +++ .../share/gc/z/zVirtualMemoryManager.hpp | 109 + .../gc/z/zVirtualMemoryManager.inline.hpp | 52 + src/hotspot/share/gc/z/z_globals.hpp | 14 +- src/hotspot/share/jfr/metadata/metadata.xml | 20 +- src/hotspot/share/utilities/vmError.cpp | 6 + src/hotspot/share/utilities/vmError.hpp | 10 +- .../classes/sun/jvm/hotspot/gc/z/ZNUMA.java} | 51 +- .../sun/jvm/hotspot/gc/z/ZPageAllocator.java | 28 +- .../sun/jvm/hotspot/gc/z/ZPartition.java | 63 + .../jvm/hotspot/gc/z/ZPerNUMAZPartition.java | 61 + src/jdk.jfr/share/conf/jfr/default.jfc | 5 - src/jdk.jfr/share/conf/jfr/profile.jfc | 5 - test/hotspot/gtest/gc/z/test_zArray.cpp | 117 +- test/hotspot/gtest/gc/z/test_zForwarding.cpp | 6 +- .../gtest/gc/z/test_zIntrusiveRBTree.cpp | 379 +++ .../gtest/gc/z/test_zMapper_windows.cpp | 49 +- test/hotspot/gtest/gc/z/test_zMemory.cpp | 86 - test/hotspot/gtest/gc/z/test_zNUMA.cpp | 115 + .../gtest/gc/z/test_zPhysicalMemory.cpp | 218 -- .../gtest/gc/z/test_zVirtualMemory.cpp | 128 +- .../gtest/gc/z/test_zVirtualMemoryManager.cpp | 173 +- test/hotspot/gtest/gc/z/zunittest.hpp | 23 +- test/hotspot/jtreg/ProblemList-zgc.txt | 6 +- .../jtreg/gc/z/TestMappedCacheHarvest.java | 97 + .../jtreg/gc/z/TestPageCacheFlush.java | 82 - test/hotspot/jtreg/gc/z/TestUncommit.java | 6 +- ...stZForceDiscontiguousHeapReservations.java | 4 +- test/hotspot/jtreg/gc/z/TestZNMT.java | 4 +- .../jtreg/serviceability/sa/TestUniverse.java | 5 +- .../event/gc/detailed/TestZUnmapEvent.java | 70 - test/lib/jdk/test/lib/jfr/EventNames.java | 3 +- 115 files changed, 8555 insertions(+), 3837 deletions(-) rename src/hotspot/os/posix/gc/z/{zVirtualMemory_posix.cpp => zVirtualMemoryManager_posix.cpp} (81%) rename src/hotspot/os/windows/gc/z/{zVirtualMemory_windows.cpp => zVirtualMemoryManager_windows.cpp} (81%) create mode 100644 src/hotspot/share/gc/z/zIntrusiveRBTree.hpp create mode 100644 src/hotspot/share/gc/z/zIntrusiveRBTree.inline.hpp create mode 100644 src/hotspot/share/gc/z/zMappedCache.cpp create mode 100644 src/hotspot/share/gc/z/zMappedCache.hpp delete mode 100644 src/hotspot/share/gc/z/zMemory.cpp delete mode 100644 src/hotspot/share/gc/z/zMemory.hpp delete mode 100644 src/hotspot/share/gc/z/zMemory.inline.hpp delete mode 100644 src/hotspot/share/gc/z/zPageCache.cpp delete mode 100644 src/hotspot/share/gc/z/zPageCache.hpp delete mode 100644 src/hotspot/share/gc/z/zPhysicalMemory.cpp delete mode 100644 src/hotspot/share/gc/z/zPhysicalMemory.hpp delete mode 100644 src/hotspot/share/gc/z/zPhysicalMemory.inline.hpp create mode 100644 src/hotspot/share/gc/z/zPhysicalMemoryManager.cpp create mode 100644 src/hotspot/share/gc/z/zPhysicalMemoryManager.hpp create mode 100644 src/hotspot/share/gc/z/zRange.hpp create mode 100644 src/hotspot/share/gc/z/zRange.inline.hpp create mode 100644 src/hotspot/share/gc/z/zRangeRegistry.hpp create mode 100644 src/hotspot/share/gc/z/zRangeRegistry.inline.hpp delete mode 100644 src/hotspot/share/gc/z/zUnmapper.cpp delete mode 100644 src/hotspot/share/gc/z/zVirtualMemory.cpp create mode 100644 src/hotspot/share/gc/z/zVirtualMemoryManager.cpp create mode 100644 src/hotspot/share/gc/z/zVirtualMemoryManager.hpp create mode 100644 src/hotspot/share/gc/z/zVirtualMemoryManager.inline.hpp rename src/{hotspot/share/gc/z/zUnmapper.hpp => jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZNUMA.java} (52%) create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPartition.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPerNUMAZPartition.java create mode 100644 test/hotspot/gtest/gc/z/test_zIntrusiveRBTree.cpp delete mode 100644 test/hotspot/gtest/gc/z/test_zMemory.cpp create mode 100644 test/hotspot/gtest/gc/z/test_zNUMA.cpp delete mode 100644 test/hotspot/gtest/gc/z/test_zPhysicalMemory.cpp create mode 100644 test/hotspot/jtreg/gc/z/TestMappedCacheHarvest.java delete mode 100644 test/hotspot/jtreg/gc/z/TestPageCacheFlush.java delete mode 100644 test/jdk/jdk/jfr/event/gc/detailed/TestZUnmapEvent.java diff --git a/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp index a58c91a6a41e1..20e37528c047c 100644 --- a/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp @@ -95,7 +95,7 @@ size_t ZPlatformAddressOffsetBits() { static const size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1; const size_t max_address_offset_bits = valid_max_address_offset_bits - 3; const size_t min_address_offset_bits = max_address_offset_bits - 2; - const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio); + const size_t address_offset = ZGlobalsPointers::min_address_offset_request(); const size_t address_offset_bits = log2i_exact(address_offset); return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits); } diff --git a/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp b/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp index 28a57b2dc293f..2e3eed8ec60d9 100644 --- a/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp @@ -92,7 +92,7 @@ size_t ZPlatformAddressOffsetBits() { static const size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1; const size_t max_address_offset_bits = valid_max_address_offset_bits - 3; const size_t min_address_offset_bits = max_address_offset_bits - 2; - const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio); + const size_t address_offset = ZGlobalsPointers::min_address_offset_request(); const size_t address_offset_bits = log2i_exact(address_offset); return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits); } diff --git a/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp b/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp index 683d892915f50..1f2f0146f04a2 100644 --- a/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp @@ -94,7 +94,7 @@ size_t ZPlatformAddressOffsetBits() { static const size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1; const size_t max_address_offset_bits = valid_max_address_offset_bits - 3; const size_t min_address_offset_bits = max_address_offset_bits - 2; - const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio); + const size_t address_offset = ZGlobalsPointers::min_address_offset_request(); const size_t address_offset_bits = log2i_exact(address_offset); return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits); } diff --git a/src/hotspot/cpu/x86/gc/z/zAddress_x86.cpp b/src/hotspot/cpu/x86/gc/z/zAddress_x86.cpp index 3667a52050c7a..6b5b64d30367f 100644 --- a/src/hotspot/cpu/x86/gc/z/zAddress_x86.cpp +++ b/src/hotspot/cpu/x86/gc/z/zAddress_x86.cpp @@ -32,7 +32,7 @@ size_t ZPointerLoadShift; size_t ZPlatformAddressOffsetBits() { const size_t min_address_offset_bits = 42; // 4TB const size_t max_address_offset_bits = 44; // 16TB - const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio); + const size_t address_offset = ZGlobalsPointers::min_address_offset_request(); const size_t address_offset_bits = log2i_exact(address_offset); return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits); } diff --git a/src/hotspot/os/bsd/gc/z/zNUMA_bsd.cpp b/src/hotspot/os/bsd/gc/z/zNUMA_bsd.cpp index ac723483637f0..d0c06e2ebf1bc 100644 --- a/src/hotspot/os/bsd/gc/z/zNUMA_bsd.cpp +++ b/src/hotspot/os/bsd/gc/z/zNUMA_bsd.cpp @@ -21,15 +21,24 @@ * questions. */ -#include "gc/z/zNUMA.hpp" -#include "utilities/globalDefinitions.hpp" +#include "gc/shared/gc_globals.hpp" +#include "gc/z/zCPU.inline.hpp" +#include "gc/z/zNUMA.inline.hpp" +#include "runtime/globals_extension.hpp" void ZNUMA::pd_initialize() { _enabled = false; - _count = 1; + _count = !FLAG_IS_DEFAULT(ZFakeNUMA) + ? ZFakeNUMA + : 1; } uint32_t ZNUMA::id() { + if (is_faked()) { + // ZFakeNUMA testing, ignores _enabled + return ZCPU::id() % ZFakeNUMA; + } + return 0; } diff --git a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp index 37c855c2e2be5..86549e878cb74 100644 --- a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp +++ b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp @@ -26,7 +26,6 @@ #include "gc/z/zGlobals.hpp" #include "gc/z/zInitialize.hpp" #include "gc/z/zLargePages.inline.hpp" -#include "gc/z/zPhysicalMemory.inline.hpp" #include "gc/z/zPhysicalMemoryBacking_bsd.hpp" #include "logging/log.hpp" #include "runtime/globals.hpp" @@ -97,12 +96,12 @@ void ZPhysicalMemoryBacking::warn_commit_limits(size_t max_capacity) const { // Does nothing } -bool ZPhysicalMemoryBacking::commit_inner(zoffset offset, size_t length) const { +bool ZPhysicalMemoryBacking::commit_inner(zbacking_offset offset, size_t length) const { assert(is_aligned(untype(offset), os::vm_page_size()), "Invalid offset"); assert(is_aligned(length, os::vm_page_size()), "Invalid length"); log_trace(gc, heap)("Committing memory: %zuM-%zuM (%zuM)", - untype(offset) / M, untype(to_zoffset_end(offset, length)) / M, length / M); + untype(offset) / M, untype(to_zbacking_offset_end(offset, length)) / M, length / M); const uintptr_t addr = _base + untype(offset); const void* const res = mmap((void*)addr, length, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); @@ -116,7 +115,7 @@ bool ZPhysicalMemoryBacking::commit_inner(zoffset offset, size_t length) const { return true; } -size_t ZPhysicalMemoryBacking::commit(zoffset offset, size_t length) const { +size_t ZPhysicalMemoryBacking::commit(zbacking_offset offset, size_t length, uint32_t /* numa_id - ignored */) const { // Try to commit the whole region if (commit_inner(offset, length)) { // Success @@ -124,8 +123,8 @@ size_t ZPhysicalMemoryBacking::commit(zoffset offset, size_t length) const { } // Failed, try to commit as much as possible - zoffset start = offset; - zoffset end = offset + length; + zbacking_offset start = offset; + zbacking_offset end = offset + length; for (;;) { length = align_down((end - start) / 2, ZGranuleSize); @@ -144,12 +143,12 @@ size_t ZPhysicalMemoryBacking::commit(zoffset offset, size_t length) const { } } -size_t ZPhysicalMemoryBacking::uncommit(zoffset offset, size_t length) const { +size_t ZPhysicalMemoryBacking::uncommit(zbacking_offset offset, size_t length) const { assert(is_aligned(untype(offset), os::vm_page_size()), "Invalid offset"); assert(is_aligned(length, os::vm_page_size()), "Invalid length"); log_trace(gc, heap)("Uncommitting memory: %zuM-%zuM (%zuM)", - untype(offset) / M, untype(to_zoffset_end(offset, length)) / M, length / M); + untype(offset) / M, untype(to_zbacking_offset_end(offset, length)) / M, length / M); const uintptr_t start = _base + untype(offset); const void* const res = mmap((void*)start, length, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0); @@ -162,7 +161,7 @@ size_t ZPhysicalMemoryBacking::uncommit(zoffset offset, size_t length) const { return length; } -void ZPhysicalMemoryBacking::map(zaddress_unsafe addr, size_t size, zoffset offset) const { +void ZPhysicalMemoryBacking::map(zaddress_unsafe addr, size_t size, zbacking_offset offset) const { const ZErrno err = mremap(_base + untype(offset), untype(addr), size); if (err) { fatal("Failed to remap memory (%s)", err.to_string()); diff --git a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.hpp b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.hpp index d74de5375eecc..9fa64fb51bd3b 100644 --- a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.hpp +++ b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ class ZPhysicalMemoryBacking { uintptr_t _base; bool _initialized; - bool commit_inner(zoffset offset, size_t length) const; + bool commit_inner(zbacking_offset offset, size_t length) const; public: ZPhysicalMemoryBacking(size_t max_capacity); @@ -40,10 +40,10 @@ class ZPhysicalMemoryBacking { void warn_commit_limits(size_t max_capacity) const; - size_t commit(zoffset offset, size_t length) const; - size_t uncommit(zoffset offset, size_t length) const; + size_t commit(zbacking_offset offset, size_t length, uint32_t numa_id) const; + size_t uncommit(zbacking_offset offset, size_t length) const; - void map(zaddress_unsafe addr, size_t size, zoffset offset) const; + void map(zaddress_unsafe addr, size_t size, zbacking_offset offset) const; void unmap(zaddress_unsafe addr, size_t size) const; }; diff --git a/src/hotspot/os/linux/gc/z/zNUMA_linux.cpp b/src/hotspot/os/linux/gc/z/zNUMA_linux.cpp index 5a5db42854839..74e696559401f 100644 --- a/src/hotspot/os/linux/gc/z/zNUMA_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zNUMA_linux.cpp @@ -21,23 +21,34 @@ * questions. */ +#include "gc/shared/gc_globals.hpp" #include "gc/z/zCPU.inline.hpp" #include "gc/z/zErrno.hpp" -#include "gc/z/zNUMA.hpp" +#include "gc/z/zNUMA.inline.hpp" #include "gc/z/zSyscall_linux.hpp" #include "os_linux.hpp" #include "runtime/globals.hpp" +#include "runtime/globals_extension.hpp" #include "runtime/os.hpp" #include "utilities/debug.hpp" void ZNUMA::pd_initialize() { _enabled = UseNUMA; + + // UseNUMA and is_faked() are mutually excluded in zArguments.cpp. _count = UseNUMA ? os::Linux::numa_max_node() + 1 - : 1; + : !FLAG_IS_DEFAULT(ZFakeNUMA) + ? ZFakeNUMA + : 1; // No NUMA nodes } uint32_t ZNUMA::id() { + if (is_faked()) { + // ZFakeNUMA testing, ignores _enabled + return ZCPU::id() % ZFakeNUMA; + } + if (!_enabled) { // NUMA support not enabled return 0; diff --git a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp index 1ae4e18fcf142..c33e49b57f976 100644 --- a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp @@ -388,7 +388,7 @@ bool ZPhysicalMemoryBacking::tmpfs_supports_transparent_huge_pages() const { return access(ZFILENAME_SHMEM_ENABLED, R_OK) == 0; } -ZErrno ZPhysicalMemoryBacking::fallocate_compat_mmap_hugetlbfs(zoffset offset, size_t length, bool touch) const { +ZErrno ZPhysicalMemoryBacking::fallocate_compat_mmap_hugetlbfs(zbacking_offset offset, size_t length, bool touch) const { // On hugetlbfs, mapping a file segment will fail immediately, without // the need to touch the mapped pages first, if there aren't enough huge // pages available to back the mapping. @@ -439,7 +439,7 @@ static bool safe_touch_mapping(void* addr, size_t length, size_t page_size) { return true; } -ZErrno ZPhysicalMemoryBacking::fallocate_compat_mmap_tmpfs(zoffset offset, size_t length) const { +ZErrno ZPhysicalMemoryBacking::fallocate_compat_mmap_tmpfs(zbacking_offset offset, size_t length) const { // On tmpfs, we need to touch the mapped pages to figure out // if there are enough pages available to back the mapping. void* const addr = mmap(nullptr, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, untype(offset)); @@ -468,11 +468,11 @@ ZErrno ZPhysicalMemoryBacking::fallocate_compat_mmap_tmpfs(zoffset offset, size_ return backed ? 0 : ENOMEM; } -ZErrno ZPhysicalMemoryBacking::fallocate_compat_pwrite(zoffset offset, size_t length) const { +ZErrno ZPhysicalMemoryBacking::fallocate_compat_pwrite(zbacking_offset offset, size_t length) const { uint8_t data = 0; // Allocate backing memory by writing to each block - for (zoffset pos = offset; pos < offset + length; pos += _block_size) { + for (zbacking_offset pos = offset; pos < offset + length; pos += _block_size) { if (pwrite(_fd, &data, sizeof(data), untype(pos)) == -1) { // Failed return errno; @@ -483,7 +483,7 @@ ZErrno ZPhysicalMemoryBacking::fallocate_compat_pwrite(zoffset offset, size_t le return 0; } -ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole_compat(zoffset offset, size_t length) const { +ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole_compat(zbacking_offset offset, size_t length) const { // fallocate(2) is only supported by tmpfs since Linux 3.5, and by hugetlbfs // since Linux 4.3. When fallocate(2) is not supported we emulate it using // mmap/munmap (for hugetlbfs and tmpfs with transparent huge pages) or pwrite @@ -497,7 +497,7 @@ ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole_compat(zoffset offset, size_t } } -ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole_syscall(zoffset offset, size_t length) const { +ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole_syscall(zbacking_offset offset, size_t length) const { const int mode = 0; // Allocate const int res = ZSyscall::fallocate(_fd, mode, untype(offset), length); if (res == -1) { @@ -509,7 +509,7 @@ ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole_syscall(zoffset offset, size_ return 0; } -ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole(zoffset offset, size_t length) const { +ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole(zbacking_offset offset, size_t length) const { // Using compat mode is more efficient when allocating space on hugetlbfs. // Note that allocating huge pages this way will only reserve them, and not // associate them with segments of the file. We must guarantee that we at @@ -536,7 +536,7 @@ ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole(zoffset offset, size_t length return fallocate_fill_hole_compat(offset, length); } -ZErrno ZPhysicalMemoryBacking::fallocate_punch_hole(zoffset offset, size_t length) const { +ZErrno ZPhysicalMemoryBacking::fallocate_punch_hole(zbacking_offset offset, size_t length) const { if (ZLargePages::is_explicit()) { // We can only punch hole in pages that have been touched. Non-touched // pages are only reserved, and not associated with any specific file @@ -559,9 +559,9 @@ ZErrno ZPhysicalMemoryBacking::fallocate_punch_hole(zoffset offset, size_t lengt return 0; } -ZErrno ZPhysicalMemoryBacking::split_and_fallocate(bool punch_hole, zoffset offset, size_t length) const { +ZErrno ZPhysicalMemoryBacking::split_and_fallocate(bool punch_hole, zbacking_offset offset, size_t length) const { // Try first half - const zoffset offset0 = offset; + const zbacking_offset offset0 = offset; const size_t length0 = align_up(length / 2, _block_size); const ZErrno err0 = fallocate(punch_hole, offset0, length0); if (err0) { @@ -569,7 +569,7 @@ ZErrno ZPhysicalMemoryBacking::split_and_fallocate(bool punch_hole, zoffset offs } // Try second half - const zoffset offset1 = offset0 + length0; + const zbacking_offset offset1 = offset0 + length0; const size_t length1 = length - length0; const ZErrno err1 = fallocate(punch_hole, offset1, length1); if (err1) { @@ -580,7 +580,7 @@ ZErrno ZPhysicalMemoryBacking::split_and_fallocate(bool punch_hole, zoffset offs return 0; } -ZErrno ZPhysicalMemoryBacking::fallocate(bool punch_hole, zoffset offset, size_t length) const { +ZErrno ZPhysicalMemoryBacking::fallocate(bool punch_hole, zbacking_offset offset, size_t length) const { assert(is_aligned(untype(offset), _block_size), "Invalid offset"); assert(is_aligned(length, _block_size), "Invalid length"); @@ -596,9 +596,9 @@ ZErrno ZPhysicalMemoryBacking::fallocate(bool punch_hole, zoffset offset, size_t return err; } -bool ZPhysicalMemoryBacking::commit_inner(zoffset offset, size_t length) const { +bool ZPhysicalMemoryBacking::commit_inner(zbacking_offset offset, size_t length) const { log_trace(gc, heap)("Committing memory: %zuM-%zuM (%zuM)", - untype(offset) / M, untype(to_zoffset_end(offset, length)) / M, length / M); + untype(offset) / M, untype(to_zbacking_offset_end(offset, length)) / M, length / M); retry: const ZErrno err = fallocate(false /* punch_hole */, offset, length); @@ -627,30 +627,11 @@ bool ZPhysicalMemoryBacking::commit_inner(zoffset offset, size_t length) const { return true; } -static int offset_to_node(zoffset offset) { - const GrowableArray* mapping = os::Linux::numa_nindex_to_node(); - const size_t nindex = (untype(offset) >> ZGranuleSizeShift) % mapping->length(); - return mapping->at((int)nindex); -} - -size_t ZPhysicalMemoryBacking::commit_numa_interleaved(zoffset offset, size_t length) const { - size_t committed = 0; - - // Commit one granule at a time, so that each granule - // can be allocated from a different preferred node. - while (committed < length) { - const zoffset granule_offset = offset + committed; - - // Setup NUMA policy to allocate memory from a preferred node - os::Linux::numa_set_preferred(offset_to_node(granule_offset)); +size_t ZPhysicalMemoryBacking::commit_numa_preferred(zbacking_offset offset, size_t length, uint32_t numa_id) const { + // Setup NUMA policy to allocate memory from a preferred node + os::Linux::numa_set_preferred((int)numa_id); - if (!commit_inner(granule_offset, ZGranuleSize)) { - // Failed - break; - } - - committed += ZGranuleSize; - } + const size_t committed = commit_default(offset, length); // Restore NUMA policy os::Linux::numa_set_preferred(-1); @@ -658,7 +639,7 @@ size_t ZPhysicalMemoryBacking::commit_numa_interleaved(zoffset offset, size_t le return committed; } -size_t ZPhysicalMemoryBacking::commit_default(zoffset offset, size_t length) const { +size_t ZPhysicalMemoryBacking::commit_default(zbacking_offset offset, size_t length) const { // Try to commit the whole region if (commit_inner(offset, length)) { // Success @@ -666,8 +647,8 @@ size_t ZPhysicalMemoryBacking::commit_default(zoffset offset, size_t length) con } // Failed, try to commit as much as possible - zoffset start = offset; - zoffset end = offset + length; + zbacking_offset start = offset; + zbacking_offset_end end = to_zbacking_offset_end(offset, length); for (;;) { length = align_down((end - start) / 2, ZGranuleSize); @@ -686,19 +667,19 @@ size_t ZPhysicalMemoryBacking::commit_default(zoffset offset, size_t length) con } } -size_t ZPhysicalMemoryBacking::commit(zoffset offset, size_t length) const { +size_t ZPhysicalMemoryBacking::commit(zbacking_offset offset, size_t length, uint32_t numa_id) const { if (ZNUMA::is_enabled() && !ZLargePages::is_explicit()) { - // To get granule-level NUMA interleaving when using non-large pages, - // we must explicitly interleave the memory at commit/fallocate time. - return commit_numa_interleaved(offset, length); + // The memory is required to be preferred at the time it is paged in. As a + // consequence we must prefer the memory when committing non-large pages. + return commit_numa_preferred(offset, length, numa_id); } return commit_default(offset, length); } -size_t ZPhysicalMemoryBacking::uncommit(zoffset offset, size_t length) const { +size_t ZPhysicalMemoryBacking::uncommit(zbacking_offset offset, size_t length) const { log_trace(gc, heap)("Uncommitting memory: %zuM-%zuM (%zuM)", - untype(offset) / M, untype(to_zoffset_end(offset, length)) / M, length / M); + untype(offset) / M, untype(to_zbacking_offset_end(offset, length)) / M, length / M); const ZErrno err = fallocate(true /* punch_hole */, offset, length); if (err) { @@ -709,7 +690,7 @@ size_t ZPhysicalMemoryBacking::uncommit(zoffset offset, size_t length) const { return length; } -void ZPhysicalMemoryBacking::map(zaddress_unsafe addr, size_t size, zoffset offset) const { +void ZPhysicalMemoryBacking::map(zaddress_unsafe addr, size_t size, zbacking_offset offset) const { const void* const res = mmap((void*)untype(addr), size, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, _fd, untype(offset)); if (res == MAP_FAILED) { ZErrno err; diff --git a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.hpp b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.hpp index 59c00ad01bf60..4b083d1c79c33 100644 --- a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.hpp +++ b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,19 +48,19 @@ class ZPhysicalMemoryBacking { bool is_hugetlbfs() const; bool tmpfs_supports_transparent_huge_pages() const; - ZErrno fallocate_compat_mmap_hugetlbfs(zoffset offset, size_t length, bool touch) const; - ZErrno fallocate_compat_mmap_tmpfs(zoffset offset, size_t length) const; - ZErrno fallocate_compat_pwrite(zoffset offset, size_t length) const; - ZErrno fallocate_fill_hole_compat(zoffset offset, size_t length) const; - ZErrno fallocate_fill_hole_syscall(zoffset offset, size_t length) const; - ZErrno fallocate_fill_hole(zoffset offset, size_t length) const; - ZErrno fallocate_punch_hole(zoffset offset, size_t length) const; - ZErrno split_and_fallocate(bool punch_hole, zoffset offset, size_t length) const; - ZErrno fallocate(bool punch_hole, zoffset offset, size_t length) const; + ZErrno fallocate_compat_mmap_hugetlbfs(zbacking_offset offset, size_t length, bool touch) const; + ZErrno fallocate_compat_mmap_tmpfs(zbacking_offset offset, size_t length) const; + ZErrno fallocate_compat_pwrite(zbacking_offset offset, size_t length) const; + ZErrno fallocate_fill_hole_compat(zbacking_offset offset, size_t length) const; + ZErrno fallocate_fill_hole_syscall(zbacking_offset offset, size_t length) const; + ZErrno fallocate_fill_hole(zbacking_offset offset, size_t length) const; + ZErrno fallocate_punch_hole(zbacking_offset offset, size_t length) const; + ZErrno split_and_fallocate(bool punch_hole, zbacking_offset offset, size_t length) const; + ZErrno fallocate(bool punch_hole, zbacking_offset offset, size_t length) const; - bool commit_inner(zoffset offset, size_t length) const; - size_t commit_numa_interleaved(zoffset offset, size_t length) const; - size_t commit_default(zoffset offset, size_t length) const; + bool commit_inner(zbacking_offset offset, size_t length) const; + size_t commit_numa_preferred(zbacking_offset offset, size_t length, uint32_t numa_id) const; + size_t commit_default(zbacking_offset offset, size_t length) const; public: ZPhysicalMemoryBacking(size_t max_capacity); @@ -69,10 +69,10 @@ class ZPhysicalMemoryBacking { void warn_commit_limits(size_t max_capacity) const; - size_t commit(zoffset offset, size_t length) const; - size_t uncommit(zoffset offset, size_t length) const; + size_t commit(zbacking_offset offset, size_t length, uint32_t numa_id) const; + size_t uncommit(zbacking_offset offset, size_t length) const; - void map(zaddress_unsafe addr, size_t size, zoffset offset) const; + void map(zaddress_unsafe addr, size_t size, zbacking_offset offset) const; void unmap(zaddress_unsafe addr, size_t size) const; }; diff --git a/src/hotspot/os/posix/gc/z/zVirtualMemory_posix.cpp b/src/hotspot/os/posix/gc/z/zVirtualMemoryManager_posix.cpp similarity index 81% rename from src/hotspot/os/posix/gc/z/zVirtualMemory_posix.cpp rename to src/hotspot/os/posix/gc/z/zVirtualMemoryManager_posix.cpp index a103f764c9891..4eea35c8a2e9d 100644 --- a/src/hotspot/os/posix/gc/z/zVirtualMemory_posix.cpp +++ b/src/hotspot/os/posix/gc/z/zVirtualMemoryManager_posix.cpp @@ -22,21 +22,16 @@ */ #include "gc/z/zAddress.inline.hpp" -#include "gc/z/zVirtualMemory.hpp" +#include "gc/z/zVirtualMemoryManager.hpp" #include "logging/log.hpp" #include -#include -void ZVirtualMemoryManager::pd_initialize_before_reserve() { +void ZVirtualMemoryReserver::pd_register_callbacks(ZVirtualMemoryRegistry* registry) { // Does nothing } -void ZVirtualMemoryManager::pd_register_callbacks(ZMemoryManager* manager) { - // Does nothing -} - -bool ZVirtualMemoryManager::pd_reserve(zaddress_unsafe addr, size_t size) { +bool ZVirtualMemoryReserver::pd_reserve(zaddress_unsafe addr, size_t size) { void* const res = mmap((void*)untype(addr), size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0); if (res == MAP_FAILED) { // Failed to reserve memory @@ -53,7 +48,7 @@ bool ZVirtualMemoryManager::pd_reserve(zaddress_unsafe addr, size_t size) { return true; } -void ZVirtualMemoryManager::pd_unreserve(zaddress_unsafe addr, size_t size) { +void ZVirtualMemoryReserver::pd_unreserve(zaddress_unsafe addr, size_t size) { const int res = munmap((void*)untype(addr), size); assert(res == 0, "Failed to unmap memory"); } diff --git a/src/hotspot/os/windows/gc/z/zInitialize_windows.cpp b/src/hotspot/os/windows/gc/z/zInitialize_windows.cpp index a4751617ce7bd..e0e0b3be82c0a 100644 --- a/src/hotspot/os/windows/gc/z/zInitialize_windows.cpp +++ b/src/hotspot/os/windows/gc/z/zInitialize_windows.cpp @@ -24,6 +24,9 @@ #include "gc/z/zInitialize.hpp" #include "gc/z/zSyscall_windows.hpp" +void ZVirtualMemoryReserverImpl_initialize(); + void ZInitialize::pd_initialize() { ZSyscall::initialize(); + ZVirtualMemoryReserverImpl_initialize(); } diff --git a/src/hotspot/os/windows/gc/z/zNUMA_windows.cpp b/src/hotspot/os/windows/gc/z/zNUMA_windows.cpp index afe8f18c3927c..dc7521dde563f 100644 --- a/src/hotspot/os/windows/gc/z/zNUMA_windows.cpp +++ b/src/hotspot/os/windows/gc/z/zNUMA_windows.cpp @@ -21,14 +21,24 @@ * questions. */ -#include "gc/z/zNUMA.hpp" +#include "gc/shared/gc_globals.hpp" +#include "gc/z/zCPU.inline.hpp" +#include "gc/z/zNUMA.inline.hpp" +#include "runtime/globals_extension.hpp" void ZNUMA::pd_initialize() { _enabled = false; - _count = 1; + _count = !FLAG_IS_DEFAULT(ZFakeNUMA) + ? ZFakeNUMA + : 1; } uint32_t ZNUMA::id() { + if (is_faked()) { + // ZFakeNUMA testing + return ZCPU::id() % ZFakeNUMA; + } + return 0; } diff --git a/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.cpp b/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.cpp index 2764f51c13b98..b18abd7e9792f 100644 --- a/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.cpp +++ b/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.cpp @@ -33,9 +33,9 @@ class ZPhysicalMemoryBackingImpl : public CHeapObj { public: - virtual size_t commit(zoffset offset, size_t size) = 0; - virtual size_t uncommit(zoffset offset, size_t size) = 0; - virtual void map(zaddress_unsafe addr, size_t size, zoffset offset) const = 0; + virtual size_t commit(zbacking_offset offset, size_t size) = 0; + virtual size_t uncommit(zbacking_offset offset, size_t size) = 0; + virtual void map(zaddress_unsafe addr, size_t size, zbacking_offset offset) const = 0; virtual void unmap(zaddress_unsafe addr, size_t size) const = 0; }; @@ -50,21 +50,29 @@ class ZPhysicalMemoryBackingSmallPages : public ZPhysicalMemoryBackingImpl { private: ZGranuleMap _handles; - HANDLE get_handle(zoffset offset) const { - HANDLE const handle = _handles.get(offset); + static zoffset to_zoffset(zbacking_offset offset) { + // A zbacking_offset is always a valid zoffset + return zoffset(untype(offset)); + } + + HANDLE get_handle(zbacking_offset offset) const { + const zoffset z_offset = to_zoffset(offset); + HANDLE const handle = _handles.get(z_offset); assert(handle != 0, "Should be set"); return handle; } - void put_handle(zoffset offset, HANDLE handle) { + void put_handle(zbacking_offset offset, HANDLE handle) { + const zoffset z_offset = to_zoffset(offset); assert(handle != INVALID_HANDLE_VALUE, "Invalid handle"); - assert(_handles.get(offset) == 0, "Should be cleared"); - _handles.put(offset, handle); + assert(_handles.get(z_offset) == 0, "Should be cleared"); + _handles.put(z_offset, handle); } - void clear_handle(zoffset offset) { - assert(_handles.get(offset) != 0, "Should be set"); - _handles.put(offset, 0); + void clear_handle(zbacking_offset offset) { + const zoffset z_offset = to_zoffset(offset); + assert(_handles.get(z_offset) != 0, "Should be set"); + _handles.put(z_offset, 0); } public: @@ -72,7 +80,7 @@ class ZPhysicalMemoryBackingSmallPages : public ZPhysicalMemoryBackingImpl { : ZPhysicalMemoryBackingImpl(), _handles(max_capacity) {} - size_t commit(zoffset offset, size_t size) { + size_t commit(zbacking_offset offset, size_t size) { for (size_t i = 0; i < size; i += ZGranuleSize) { HANDLE const handle = ZMapper::create_and_commit_paging_file_mapping(ZGranuleSize); if (handle == 0) { @@ -85,7 +93,7 @@ class ZPhysicalMemoryBackingSmallPages : public ZPhysicalMemoryBackingImpl { return size; } - size_t uncommit(zoffset offset, size_t size) { + size_t uncommit(zbacking_offset offset, size_t size) { for (size_t i = 0; i < size; i += ZGranuleSize) { HANDLE const handle = get_handle(offset + i); clear_handle(offset + i); @@ -95,7 +103,7 @@ class ZPhysicalMemoryBackingSmallPages : public ZPhysicalMemoryBackingImpl { return size; } - void map(zaddress_unsafe addr, size_t size, zoffset offset) const { + void map(zaddress_unsafe addr, size_t size, zbacking_offset offset) const { assert(is_aligned(untype(offset), ZGranuleSize), "Misaligned"); assert(is_aligned(untype(addr), ZGranuleSize), "Misaligned"); assert(is_aligned(size, ZGranuleSize), "Misaligned"); @@ -149,7 +157,7 @@ class ZPhysicalMemoryBackingLargePages : public ZPhysicalMemoryBackingImpl { : ZPhysicalMemoryBackingImpl(), _page_array(alloc_page_array(max_capacity)) {} - size_t commit(zoffset offset, size_t size) { + size_t commit(zbacking_offset offset, size_t size) { const size_t index = untype(offset) >> ZGranuleSizeShift; const size_t npages = size >> ZGranuleSizeShift; @@ -167,7 +175,7 @@ class ZPhysicalMemoryBackingLargePages : public ZPhysicalMemoryBackingImpl { return npages_res << ZGranuleSizeShift; } - size_t uncommit(zoffset offset, size_t size) { + size_t uncommit(zbacking_offset offset, size_t size) { const size_t index = untype(offset) >> ZGranuleSizeShift; const size_t npages = size >> ZGranuleSizeShift; @@ -181,7 +189,7 @@ class ZPhysicalMemoryBackingLargePages : public ZPhysicalMemoryBackingImpl { return npages_res << ZGranuleSizeShift; } - void map(zaddress_unsafe addr, size_t size, zoffset offset) const { + void map(zaddress_unsafe addr, size_t size, zbacking_offset offset) const { const size_t npages = size >> ZGranuleSizeShift; const size_t index = untype(offset) >> ZGranuleSizeShift; @@ -222,21 +230,21 @@ void ZPhysicalMemoryBacking::warn_commit_limits(size_t max_capacity) const { // Does nothing } -size_t ZPhysicalMemoryBacking::commit(zoffset offset, size_t length) { +size_t ZPhysicalMemoryBacking::commit(zbacking_offset offset, size_t length, uint32_t /* numa_id - ignored */) { log_trace(gc, heap)("Committing memory: %zuM-%zuM (%zuM)", - untype(offset) / M, untype(to_zoffset_end(offset, length)) / M, length / M); + untype(offset) / M, untype(to_zbacking_offset_end(offset, length)) / M, length / M); return _impl->commit(offset, length); } -size_t ZPhysicalMemoryBacking::uncommit(zoffset offset, size_t length) { +size_t ZPhysicalMemoryBacking::uncommit(zbacking_offset offset, size_t length) { log_trace(gc, heap)("Uncommitting memory: %zuM-%zuM (%zuM)", - untype(offset) / M, untype(to_zoffset_end(offset, length)) / M, length / M); + untype(offset) / M, untype(to_zbacking_offset_end(offset, length)) / M, length / M); return _impl->uncommit(offset, length); } -void ZPhysicalMemoryBacking::map(zaddress_unsafe addr, size_t size, zoffset offset) const { +void ZPhysicalMemoryBacking::map(zaddress_unsafe addr, size_t size, zbacking_offset offset) const { assert(is_aligned(untype(offset), ZGranuleSize), "Misaligned: " PTR_FORMAT, untype(offset)); assert(is_aligned(untype(addr), ZGranuleSize), "Misaligned: " PTR_FORMAT, addr); assert(is_aligned(size, ZGranuleSize), "Misaligned: " PTR_FORMAT, size); diff --git a/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.hpp b/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.hpp index b8b73519ab5a9..91d59f4960982 100644 --- a/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.hpp +++ b/src/hotspot/os/windows/gc/z/zPhysicalMemoryBacking_windows.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,10 +42,10 @@ class ZPhysicalMemoryBacking { void warn_commit_limits(size_t max_capacity) const; - size_t commit(zoffset offset, size_t length); - size_t uncommit(zoffset offset, size_t length); + size_t commit(zbacking_offset offset, size_t length, uint32_t numa_id); + size_t uncommit(zbacking_offset offset, size_t length); - void map(zaddress_unsafe addr, size_t size, zoffset offset) const; + void map(zaddress_unsafe addr, size_t size, zbacking_offset offset) const; void unmap(zaddress_unsafe addr, size_t size) const; }; diff --git a/src/hotspot/os/windows/gc/z/zVirtualMemory_windows.cpp b/src/hotspot/os/windows/gc/z/zVirtualMemoryManager_windows.cpp similarity index 81% rename from src/hotspot/os/windows/gc/z/zVirtualMemory_windows.cpp rename to src/hotspot/os/windows/gc/z/zVirtualMemoryManager_windows.cpp index ac5be56a0c0df..48a32157f5963 100644 --- a/src/hotspot/os/windows/gc/z/zVirtualMemory_windows.cpp +++ b/src/hotspot/os/windows/gc/z/zVirtualMemoryManager_windows.cpp @@ -26,25 +26,26 @@ #include "gc/z/zLargePages.inline.hpp" #include "gc/z/zMapper_windows.hpp" #include "gc/z/zSyscall_windows.hpp" +#include "gc/z/zValue.inline.hpp" #include "gc/z/zVirtualMemory.inline.hpp" +#include "gc/z/zVirtualMemoryManager.inline.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" -class ZVirtualMemoryManagerImpl : public CHeapObj { +class ZVirtualMemoryReserverImpl : public CHeapObj { public: - virtual void initialize_before_reserve() {} - virtual void register_callbacks(ZMemoryManager* manager) {} + virtual void register_callbacks(ZVirtualMemoryRegistry* registry) {} virtual bool reserve(zaddress_unsafe addr, size_t size) = 0; virtual void unreserve(zaddress_unsafe addr, size_t size) = 0; }; // Implements small pages (paged) support using placeholder reservation. // -// When a memory area is free (kept by the virtual memory manager) a +// When a memory area is available (kept by the virtual memory manager) a // single placeholder is covering that memory area. When memory is -// allocated from the manager the placeholder is split into granule +// removed from the registry the placeholder is split into granule // sized placeholders to allow mapping operations on that granularity. -class ZVirtualMemoryManagerSmallPages : public ZVirtualMemoryManagerImpl { +class ZVirtualMemoryReserverSmallPages : public ZVirtualMemoryReserverImpl { private: class PlaceholderCallbacks : public AllStatic { private: @@ -84,7 +85,7 @@ class ZVirtualMemoryManagerSmallPages : public ZVirtualMemoryManagerImpl { // Called when a memory area is going to be handed out to be used. // // Splits the memory area into granule-sized placeholders. - static void prepare_for_hand_out_callback(const ZMemory& area) { + static void prepare_for_hand_out_callback(const ZVirtualMemory& area) { assert(is_aligned(area.size(), ZGranuleSize), "Must be granule aligned"); split_into_granule_sized_placeholders(area.start(), area.size()); @@ -93,7 +94,7 @@ class ZVirtualMemoryManagerSmallPages : public ZVirtualMemoryManagerImpl { // Called when a memory area is handed back to the memory manager. // // Combines the granule-sized placeholders into one placeholder. - static void prepare_for_hand_back_callback(const ZMemory& area) { + static void prepare_for_hand_back_callback(const ZVirtualMemory& area) { assert(is_aligned(area.size(), ZGranuleSize), "Must be granule aligned"); coalesce_into_one_placeholder(area.start(), area.size()); @@ -103,7 +104,7 @@ class ZVirtualMemoryManagerSmallPages : public ZVirtualMemoryManagerImpl { // existing, adjacent memory area. // // Coalesces the underlying placeholders into one. - static void grow_callback(const ZMemory& from, const ZMemory& to) { + static void grow_callback(const ZVirtualMemory& from, const ZVirtualMemory& to) { assert(is_aligned(from.size(), ZGranuleSize), "Must be granule aligned"); assert(is_aligned(to.size(), ZGranuleSize), "Must be granule aligned"); assert(from != to, "Must have grown"); @@ -116,7 +117,7 @@ class ZVirtualMemoryManagerSmallPages : public ZVirtualMemoryManagerImpl { // memory area. // // Splits the memory into two placeholders. - static void shrink_callback(const ZMemory& from, const ZMemory& to) { + static void shrink_callback(const ZVirtualMemory& from, const ZVirtualMemory& to) { assert(is_aligned(from.size(), ZGranuleSize), "Must be granule aligned"); assert(is_aligned(to.size(), ZGranuleSize), "Must be granule aligned"); assert(from != to, "Must have shrunk"); @@ -129,7 +130,7 @@ class ZVirtualMemoryManagerSmallPages : public ZVirtualMemoryManagerImpl { } public: - static ZMemoryManager::Callbacks callbacks() { + static ZVirtualMemoryRegistry::Callbacks callbacks() { // Each reserved virtual memory address area registered in _manager is // exactly covered by a single placeholder. Callbacks are installed so // that whenever a memory area changes, the corresponding placeholder @@ -153,7 +154,7 @@ class ZVirtualMemoryManagerSmallPages : public ZVirtualMemoryManagerImpl { // See comment in zMapper_windows.cpp explaining why placeholders are // split into ZGranuleSize sized placeholders. - ZMemoryManager::Callbacks callbacks; + ZVirtualMemoryRegistry::Callbacks callbacks; callbacks._prepare_for_hand_out = &prepare_for_hand_out_callback; callbacks._prepare_for_hand_back = &prepare_for_hand_back_callback; @@ -164,8 +165,8 @@ class ZVirtualMemoryManagerSmallPages : public ZVirtualMemoryManagerImpl { } }; - virtual void register_callbacks(ZMemoryManager* manager) { - manager->register_callbacks(PlaceholderCallbacks::callbacks()); + virtual void register_callbacks(ZVirtualMemoryRegistry* registry) { + registry->register_callbacks(PlaceholderCallbacks::callbacks()); } virtual bool reserve(zaddress_unsafe addr, size_t size) { @@ -185,12 +186,8 @@ class ZVirtualMemoryManagerSmallPages : public ZVirtualMemoryManagerImpl { // ZPhysicalMemory layer needs access to the section HANDLE ZAWESection; -class ZVirtualMemoryManagerLargePages : public ZVirtualMemoryManagerImpl { +class ZVirtualMemoryReserverLargePages : public ZVirtualMemoryReserverImpl { private: - virtual void initialize_before_reserve() { - ZAWESection = ZMapper::create_shared_awe_section(); - } - virtual bool reserve(zaddress_unsafe addr, size_t size) { const zaddress_unsafe res = ZMapper::reserve_for_shared_awe(ZAWESection, addr, size); @@ -201,27 +198,33 @@ class ZVirtualMemoryManagerLargePages : public ZVirtualMemoryManagerImpl { virtual void unreserve(zaddress_unsafe addr, size_t size) { ZMapper::unreserve_for_shared_awe(addr, size); } + +public: + ZVirtualMemoryReserverLargePages() { + ZAWESection = ZMapper::create_shared_awe_section(); + } }; -static ZVirtualMemoryManagerImpl* _impl = nullptr; +static ZVirtualMemoryReserverImpl* _impl = nullptr; + +void ZVirtualMemoryReserverImpl_initialize() { + assert(_impl == nullptr, "Should only initialize once"); -void ZVirtualMemoryManager::pd_initialize_before_reserve() { if (ZLargePages::is_enabled()) { - _impl = new ZVirtualMemoryManagerLargePages(); + _impl = new ZVirtualMemoryReserverLargePages(); } else { - _impl = new ZVirtualMemoryManagerSmallPages(); + _impl = new ZVirtualMemoryReserverSmallPages(); } - _impl->initialize_before_reserve(); } -void ZVirtualMemoryManager::pd_register_callbacks(ZMemoryManager* manager) { - _impl->register_callbacks(manager); +void ZVirtualMemoryReserver::pd_register_callbacks(ZVirtualMemoryRegistry* registry) { + _impl->register_callbacks(registry); } -bool ZVirtualMemoryManager::pd_reserve(zaddress_unsafe addr, size_t size) { +bool ZVirtualMemoryReserver::pd_reserve(zaddress_unsafe addr, size_t size) { return _impl->reserve(addr, size); } -void ZVirtualMemoryManager::pd_unreserve(zaddress_unsafe addr, size_t size) { +void ZVirtualMemoryReserver::pd_unreserve(zaddress_unsafe addr, size_t size) { _impl->unreserve(addr, size); } diff --git a/src/hotspot/share/gc/z/vmStructs_z.hpp b/src/hotspot/share/gc/z/vmStructs_z.hpp index 47fa6ac3021e6..e1eb2a661f59a 100644 --- a/src/hotspot/share/gc/z/vmStructs_z.hpp +++ b/src/hotspot/share/gc/z/vmStructs_z.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,8 +29,11 @@ #include "gc/z/zForwarding.hpp" #include "gc/z/zGranuleMap.hpp" #include "gc/z/zHeap.hpp" +#include "gc/z/zNUMA.hpp" #include "gc/z/zPageAllocator.hpp" #include "gc/z/zPageType.hpp" +#include "gc/z/zValue.hpp" +#include "gc/z/zVirtualMemory.hpp" #include "utilities/macros.hpp" // Expose some ZGC globals to the SA agent. @@ -61,6 +64,7 @@ class ZGlobalsForVMStructs { typedef ZGranuleMap ZGranuleMapForPageTable; typedef ZGranuleMap ZGranuleMapForForwarding; typedef ZAttachedArray ZAttachedArrayForForwarding; +typedef ZValue ZPerNUMAZPartition; #define VM_STRUCTS_Z(nonstatic_field, volatile_nonstatic_field, static_field) \ static_field(ZGlobalsForVMStructs, _instance_p, ZGlobalsForVMStructs*) \ @@ -87,8 +91,13 @@ typedef ZAttachedArray ZAttachedArrayForForwardin volatile_nonstatic_field(ZPage, _top, zoffset_end) \ \ nonstatic_field(ZPageAllocator, _max_capacity, const size_t) \ - volatile_nonstatic_field(ZPageAllocator, _capacity, size_t) \ - volatile_nonstatic_field(ZPageAllocator, _used, size_t) \ + nonstatic_field(ZPageAllocator, _partitions, ZPerNUMAZPartition) \ + \ + static_field(ZNUMA, _count, uint32_t) \ + nonstatic_field(ZPerNUMAZPartition, _addr, const uintptr_t) \ + \ + volatile_nonstatic_field(ZPartition, _capacity, size_t) \ + nonstatic_field(ZPartition, _used, size_t) \ \ nonstatic_field(ZPageTable, _map, ZGranuleMapForPageTable) \ \ @@ -97,8 +106,8 @@ typedef ZAttachedArray ZAttachedArrayForForwardin \ nonstatic_field(ZForwardingTable, _map, ZGranuleMapForForwarding) \ \ - nonstatic_field(ZVirtualMemory, _start, const zoffset) \ - nonstatic_field(ZVirtualMemory, _end, const zoffset_end) \ + nonstatic_field(ZVirtualMemory, _start, const zoffset_end) \ + nonstatic_field(ZVirtualMemory, _size, const size_t) \ \ nonstatic_field(ZForwarding, _virtual, const ZVirtualMemory) \ nonstatic_field(ZForwarding, _object_alignment_shift, const size_t) \ @@ -134,6 +143,9 @@ typedef ZAttachedArray ZAttachedArrayForForwardin declare_toplevel_type(ZPageType) \ declare_toplevel_type(ZPageAllocator) \ declare_toplevel_type(ZPageTable) \ + declare_toplevel_type(ZPartition) \ + declare_toplevel_type(ZNUMA) \ + declare_toplevel_type(ZPerNUMAZPartition) \ declare_toplevel_type(ZAttachedArrayForForwarding) \ declare_toplevel_type(ZGranuleMapForPageTable) \ declare_toplevel_type(ZGranuleMapForForwarding) \ diff --git a/src/hotspot/share/gc/z/zAddress.cpp b/src/hotspot/share/gc/z/zAddress.cpp index 59489f62372c4..9877941921916 100644 --- a/src/hotspot/share/gc/z/zAddress.cpp +++ b/src/hotspot/share/gc/z/zAddress.cpp @@ -24,6 +24,7 @@ #include "gc/shared/barrierSet.hpp" #include "gc/shared/gc_globals.hpp" #include "gc/z/zAddress.inline.hpp" +#include "gc/z/zNUMA.inline.hpp" #include "gc/z/zVerify.hpp" #include "oops/oopsHierarchy.hpp" #include "runtime/java.hpp" @@ -36,6 +37,10 @@ size_t ZAddressOffsetBits; uintptr_t ZAddressOffsetMask; size_t ZAddressOffsetMax; +size_t ZBackingOffsetMax; + +uint32_t ZBackingIndexMax; + uintptr_t ZPointerRemapped; uintptr_t ZPointerRemappedYoungMask; uintptr_t ZPointerRemappedOldMask; @@ -145,3 +150,10 @@ void ZGlobalsPointers::flip_old_relocate_start() { ZPointerRemappedOldMask ^= ZPointerRemappedMask; set_good_masks(); } + +size_t ZGlobalsPointers::min_address_offset_request() { + // See ZVirtualMemoryReserver for logic around setting up the heap for NUMA + const size_t desired_for_heap = MaxHeapSize * ZVirtualToPhysicalRatio; + const size_t desired_for_numa_multiplier = ZNUMA::count() > 1 ? 2 : 1; + return round_up_power_of_2(desired_for_heap * desired_for_numa_multiplier); +} diff --git a/src/hotspot/share/gc/z/zAddress.hpp b/src/hotspot/share/gc/z/zAddress.hpp index 6b3c887062e50..de97c17d089e8 100644 --- a/src/hotspot/share/gc/z/zAddress.hpp +++ b/src/hotspot/share/gc/z/zAddress.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,12 @@ const size_t ZAddressOffsetShift = 0; extern uintptr_t ZAddressOffsetMask; extern size_t ZAddressOffsetMax; +// Describes the maximal offset inside the backing storage. +extern size_t ZBackingOffsetMax; + +// Describes the maximal granule index inside the backing storage. +extern uint32_t ZBackingIndexMax; + // Layout of metadata bits in colored pointer / zpointer. // // A zpointer is a combination of the address bits (heap base bit + offset) @@ -223,16 +229,25 @@ const int ZPointerStoreGoodMaskLowOrderBitsOffset = LITTLE_ENDIAN_ONLY(0 // Offsets // - Virtual address range offsets -// - Physical memory offsets -enum class zoffset : uintptr_t {}; +enum class zoffset : uintptr_t { invalid = UINTPTR_MAX }; +// Offsets including end of offset range +enum class zoffset_end : uintptr_t { invalid = UINTPTR_MAX }; + +// - Physical memory segment offsets +enum class zbacking_offset : uintptr_t {}; // Offsets including end of offset range -enum class zoffset_end : uintptr_t {}; +enum class zbacking_offset_end : uintptr_t {}; + +// - Physical memory segment indicies +enum class zbacking_index : uint32_t { zero = 0, invalid = UINT32_MAX }; +// Offsets including end of indicies range +enum class zbacking_index_end : uint32_t { zero = 0, invalid = UINT32_MAX }; // Colored oop -enum class zpointer : uintptr_t { null = 0 }; +enum class zpointer : uintptr_t { null = 0 }; // Uncolored oop - safe to dereference -enum class zaddress : uintptr_t { null = 0 }; +enum class zaddress : uintptr_t { null = 0 }; // Uncolored oop - not safe to dereference, could point uncommitted memory enum class zaddress_unsafe : uintptr_t { null = 0 }; @@ -307,6 +322,8 @@ class ZGlobalsPointers : public AllStatic { static void flip_young_relocate_start(); static void flip_old_mark_start(); static void flip_old_relocate_start(); + + static size_t min_address_offset_request(); }; #endif // SHARE_GC_Z_ZADDRESS_HPP diff --git a/src/hotspot/share/gc/z/zAddress.inline.hpp b/src/hotspot/share/gc/z/zAddress.inline.hpp index bbc92a7e2aaf3..98f6900cbf0bf 100644 --- a/src/hotspot/share/gc/z/zAddress.inline.hpp +++ b/src/hotspot/share/gc/z/zAddress.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,124 @@ #include "gc/z/zAddress.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/z/zGlobals.hpp" #include "oops/oop.hpp" #include "oops/oopsHierarchy.hpp" #include "runtime/atomic.hpp" +#include "utilities/align.hpp" +#include "utilities/checkedCast.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/powerOfTwo.hpp" #include CPU_HEADER_INLINE(gc/z/zAddress) +#include + +// Offset Operator Macro +// Creates operators for the offset, offset_end style types + +#define CREATE_ZOFFSET_OPERATORS(offset_type) \ + \ + /* Arithmetic operators for offset_type */ \ + \ +inline offset_type operator+(offset_type offset, size_t size) { \ + const auto size_value = checked_cast>(size); \ + return to_##offset_type(untype(offset) + size_value); \ +} \ + \ +inline offset_type& operator+=(offset_type& offset, size_t size) { \ + const auto size_value = checked_cast>(size); \ + offset = to_##offset_type(untype(offset) + size_value); \ + return offset; \ +} \ + \ +inline offset_type operator-(offset_type offset, size_t size) { \ + const auto size_value = checked_cast>(size); \ + return to_##offset_type(untype(offset) - size_value); \ +} \ + \ +inline size_t operator-(offset_type first, offset_type second) { \ + return untype(first - untype(second)); \ +} \ + \ +inline offset_type& operator-=(offset_type& offset, size_t size) { \ + const auto size_value = checked_cast>(size); \ + offset = to_##offset_type(untype(offset) - size_value); \ + return offset; \ +} \ + \ + /* Arithmetic operators for offset_type##_end */ \ + \ +inline offset_type##_end operator+(offset_type##_end offset, size_t size) { \ + const auto size_value = checked_cast>(size); \ + return to_##offset_type##_end(untype(offset) + size_value); \ +} \ + \ +inline offset_type##_end& operator+=(offset_type##_end& offset, size_t size) { \ + const auto size_value = checked_cast>(size); \ + offset = to_##offset_type##_end(untype(offset) + size_value); \ + return offset; \ +} \ + \ +inline offset_type##_end operator-(offset_type##_end first, size_t size) { \ + const auto size_value = checked_cast>(size); \ + return to_##offset_type##_end(untype(first) - size_value); \ +} \ + \ +inline size_t operator-(offset_type##_end first, offset_type##_end second) { \ + return untype(first - untype(second)); \ +} \ + \ +inline offset_type##_end& operator-=(offset_type##_end& offset, size_t size) { \ + const auto size_value = checked_cast>(size); \ + offset = to_##offset_type##_end(untype(offset) - size_value); \ + return offset; \ +} \ + \ + /* Arithmetic operators for offset_type cross offset_type##_end */ \ + \ +inline size_t operator-(offset_type##_end first, offset_type second) { \ + return untype(first - untype(second)); \ +} \ + \ + /* Logical operators for offset_type cross offset_type##_end */ \ + \ +inline bool operator!=(offset_type first, offset_type##_end second) { \ + return untype(first) != untype(second); \ +} \ + \ +inline bool operator!=(offset_type##_end first, offset_type second) { \ + return untype(first) != untype(second); \ +} \ + \ +inline bool operator==(offset_type first, offset_type##_end second) { \ + return untype(first) == untype(second); \ +} \ + \ +inline bool operator==(offset_type##_end first, offset_type second) { \ + return untype(first) == untype(second); \ +} \ + \ +inline bool operator<(offset_type##_end first, offset_type second) { \ + return untype(first) < untype(second); \ +} \ + \ +inline bool operator<(offset_type first, offset_type##_end second) { \ + return untype(first) < untype(second); \ +} \ + \ +inline bool operator<=(offset_type##_end first, offset_type second) { \ + return untype(first) <= untype(second); \ +} \ + \ +inline bool operator>(offset_type first, offset_type##_end second) { \ + return untype(first) > untype(second); \ +} \ + \ +inline bool operator>=(offset_type first, offset_type##_end second) { \ + return untype(first) >= untype(second); \ +} \ + // zoffset functions inline uintptr_t untype(zoffset offset) { @@ -59,31 +169,6 @@ inline zoffset to_zoffset(zoffset_end offset) { return to_zoffset(value); } -inline zoffset operator+(zoffset offset, size_t size) { - return to_zoffset(untype(offset) + size); -} - -inline zoffset& operator+=(zoffset& offset, size_t size) { - offset = to_zoffset(untype(offset) + size); - return offset; -} - -inline zoffset operator-(zoffset offset, size_t size) { - const uintptr_t value = untype(offset) - size; - return to_zoffset(value); -} - -inline size_t operator-(zoffset left, zoffset right) { - const size_t diff = untype(left) - untype(right); - assert(diff < ZAddressOffsetMax, "Underflow"); - return diff; -} - -inline zoffset& operator-=(zoffset& offset, size_t size) { - offset = to_zoffset(untype(offset) - size); - return offset; -} - inline bool to_zoffset_end(zoffset_end* result, zoffset_end start, size_t size) { const uintptr_t value = untype(start) + size; if (value <= ZAddressOffsetMax) { @@ -109,62 +194,124 @@ inline zoffset_end to_zoffset_end(zoffset offset) { return zoffset_end(untype(offset)); } -inline bool operator!=(zoffset first, zoffset_end second) { - return untype(first) != untype(second); +CREATE_ZOFFSET_OPERATORS(zoffset) + +// zbacking_offset functions + +inline uintptr_t untype(zbacking_offset offset) { + const uintptr_t value = static_cast(offset); + assert(value < ZBackingOffsetMax, "must have no other bits"); + return value; +} + +inline uintptr_t untype(zbacking_offset_end offset) { + const uintptr_t value = static_cast(offset); + assert(value <= ZBackingOffsetMax, "must have no other bits"); + return value; +} + +inline zbacking_offset to_zbacking_offset(uintptr_t value) { + assert(value < ZBackingOffsetMax, "must have no other bits"); + return zbacking_offset(value); } -inline bool operator!=(zoffset_end first, zoffset second) { - return untype(first) != untype(second); +inline zbacking_offset to_zbacking_offset(zbacking_offset_end offset) { + const uintptr_t value = untype(offset); + return to_zbacking_offset(value); } -inline bool operator==(zoffset first, zoffset_end second) { - return untype(first) == untype(second); +inline zbacking_offset_end to_zbacking_offset_end(zbacking_offset start, size_t size) { + const uintptr_t value = untype(start) + size; + assert(value <= ZBackingOffsetMax, "Overflow start: " PTR_FORMAT " size: " PTR_FORMAT " value: " PTR_FORMAT, + untype(start), size, value); + return zbacking_offset_end(value); } -inline bool operator==(zoffset_end first, zoffset second) { - return untype(first) == untype(second); +inline zbacking_offset_end to_zbacking_offset_end(uintptr_t value) { + assert(value <= ZBackingOffsetMax, "must have no other bits"); + return zbacking_offset_end(value); } -inline bool operator<(zoffset_end first, zoffset second) { - return untype(first) < untype(second); +inline zbacking_offset_end to_zbacking_offset_end(zbacking_offset offset) { + return zbacking_offset_end(untype(offset)); } -inline bool operator<(zoffset first, zoffset_end second) { - return untype(first) < untype(second); +CREATE_ZOFFSET_OPERATORS(zbacking_offset) + +// zbacking_index functions + +inline uint32_t untype(zbacking_index index) { + const uint32_t value = static_cast(index); + assert(value < ZBackingIndexMax, "must have no other bits"); + return value; } -inline bool operator<=(zoffset_end first, zoffset second) { - return untype(first) <= untype(second); +inline uint32_t untype(zbacking_index_end index) { + const uint32_t value = static_cast(index); + assert(value <= ZBackingIndexMax, "must have no other bits"); + return value; } -inline bool operator>(zoffset first, zoffset_end second) { - return untype(first) > untype(second); +inline zbacking_index to_zbacking_index(uint32_t value) { + assert(value < ZBackingIndexMax, "must have no other bits"); + return zbacking_index(value); } -inline bool operator>=(zoffset first, zoffset_end second) { - return untype(first) >= untype(second); +inline zbacking_index to_zbacking_index(zbacking_index_end index) { + const uint32_t value = untype(index); + return to_zbacking_index(value); } -inline size_t operator-(zoffset_end first, zoffset second) { - return untype(first) - untype(second); +inline zbacking_index_end to_zbacking_index_end(zbacking_index start, size_t size) { + const uint32_t start_value = untype(start); + const uint32_t value = start_value + checked_cast(size); + assert(value <= ZBackingIndexMax && start_value <= value, + "Overflow start: %x size: %zu value: %x", start_value, size, value); + return zbacking_index_end(value); } -inline zoffset_end operator-(zoffset_end first, size_t second) { - return to_zoffset_end(untype(first) - second); +inline zbacking_index_end to_zbacking_index_end(uint32_t value) { + assert(value <= ZBackingIndexMax, "must have no other bits"); + return zbacking_index_end(value); +} + +inline zbacking_index_end to_zbacking_index_end(zbacking_index index) { + return zbacking_index_end(untype(index)); +} + +CREATE_ZOFFSET_OPERATORS(zbacking_index) + +#undef CREATE_ZOFFSET_OPERATORS + +// zbacking_offset <-> zbacking_index conversion functions + +inline zbacking_index to_zbacking_index(zbacking_offset offset) { + const uintptr_t value = untype(offset); + assert(is_aligned(value, ZGranuleSize), "must be granule aligned"); + return to_zbacking_index((uint32_t)(value >> ZGranuleSizeShift)); +} + +inline zbacking_offset to_zbacking_offset(zbacking_index index) { + const uintptr_t value = untype(index); + return to_zbacking_offset(value << ZGranuleSizeShift); +} + +// ZRange helper functions + +inline zoffset to_start_type(zoffset_end offset) { + return to_zoffset(offset); } -inline size_t operator-(zoffset_end first, zoffset_end second) { - return untype(first) - untype(second); +inline zbacking_index to_start_type(zbacking_index_end offset) { + return to_zbacking_index(offset); } -inline zoffset_end& operator-=(zoffset_end& offset, size_t size) { - offset = to_zoffset_end(untype(offset) - size); - return offset; +inline zoffset_end to_end_type(zoffset start, size_t size) { + return to_zoffset_end(start, size); } -inline zoffset_end& operator+=(zoffset_end& offset, size_t size) { - offset = to_zoffset_end(untype(offset) + size); - return offset; +inline zbacking_index_end to_end_type(zbacking_index start, size_t size) { + return to_zbacking_index_end(start, size); } // zpointer functions diff --git a/src/hotspot/share/gc/z/zAddressSpaceLimit.cpp b/src/hotspot/share/gc/z/zAddressSpaceLimit.cpp index fc42d9f3db1fa..9a6fb12779a16 100644 --- a/src/hotspot/share/gc/z/zAddressSpaceLimit.cpp +++ b/src/hotspot/share/gc/z/zAddressSpaceLimit.cpp @@ -22,11 +22,13 @@ */ #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcLogPrecious.hpp" #include "gc/z/zAddressSpaceLimit.hpp" #include "gc/z/zGlobals.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" #include "utilities/align.hpp" +#include "utilities/ostream.hpp" static size_t address_space_limit() { size_t limit = 0; @@ -44,3 +46,13 @@ size_t ZAddressSpaceLimit::heap() { const size_t limit = address_space_limit() / MaxVirtMemFraction; return align_up(limit, ZGranuleSize); } + +void ZAddressSpaceLimit::print_limits() { + const size_t limit = address_space_limit(); + + if (limit == SIZE_MAX) { + log_info_p(gc, init)("Address Space Size: unlimited"); + } else { + log_info_p(gc, init)("Address Space Size: limited (" EXACTFMT ")", EXACTFMTARGS(limit)); + } +} diff --git a/src/hotspot/share/gc/z/zAddressSpaceLimit.hpp b/src/hotspot/share/gc/z/zAddressSpaceLimit.hpp index 66e01f0ebb08c..1c9c65c3255a0 100644 --- a/src/hotspot/share/gc/z/zAddressSpaceLimit.hpp +++ b/src/hotspot/share/gc/z/zAddressSpaceLimit.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,8 @@ class ZAddressSpaceLimit : public AllStatic { public: static size_t heap(); + + static void print_limits(); }; #endif // SHARE_GC_Z_ZADDRESSSPACELIMIT_HPP diff --git a/src/hotspot/share/gc/z/zAllocationFlags.hpp b/src/hotspot/share/gc/z/zAllocationFlags.hpp index c6998bac6c1ae..d94badae929b0 100644 --- a/src/hotspot/share/gc/z/zAllocationFlags.hpp +++ b/src/hotspot/share/gc/z/zAllocationFlags.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,25 +31,22 @@ // Allocation flags layout // ----------------------- // -// 7 2 1 0 -// +-----+-+-+-+ -// |00000|1|1|1| -// +-----+-+-+-+ -// | | | | -// | | | * 0-0 Non-Blocking Flag (1-bit) -// | | | -// | | * 1-1 GC Relocation Flag (1-bit) -// | | -// | * 2-2 Low Address Flag (1-bit) +// 7 1 0 +// +------+-+-+ +// |000000|1|1| +// +------+-+-+ +// | | | +// | | * 0-0 Non-Blocking Flag (1-bit) +// | | +// | * 1-1 GC Relocation Flag (1-bit) // | -// * 7-3 Unused (5-bits) +// * 7-2 Unused (6-bits) // class ZAllocationFlags { private: typedef ZBitField field_non_blocking; typedef ZBitField field_gc_relocation; - typedef ZBitField field_low_address; uint8_t _flags; @@ -65,10 +62,6 @@ class ZAllocationFlags { _flags |= field_gc_relocation::encode(true); } - void set_low_address() { - _flags |= field_low_address::encode(true); - } - bool non_blocking() const { return field_non_blocking::decode(_flags); } @@ -76,10 +69,6 @@ class ZAllocationFlags { bool gc_relocation() const { return field_gc_relocation::decode(_flags); } - - bool low_address() const { - return field_low_address::decode(_flags); - } }; #endif // SHARE_GC_Z_ZALLOCATIONFLAGS_HPP diff --git a/src/hotspot/share/gc/z/zArguments.cpp b/src/hotspot/share/gc/z/zArguments.cpp index f972e0718b4cd..67b9f6f0bb918 100644 --- a/src/hotspot/share/gc/z/zArguments.cpp +++ b/src/hotspot/share/gc/z/zArguments.cpp @@ -122,7 +122,7 @@ void ZArguments::initialize() { GCArguments::initialize(); // Enable NUMA by default - if (FLAG_IS_DEFAULT(UseNUMA)) { + if (FLAG_IS_DEFAULT(UseNUMA) && FLAG_IS_DEFAULT(ZFakeNUMA)) { FLAG_SET_DEFAULT(UseNUMA, true); } diff --git a/src/hotspot/share/gc/z/zArray.hpp b/src/hotspot/share/gc/z/zArray.hpp index 7bcd4f59eebe2..1b7e99b3ace30 100644 --- a/src/hotspot/share/gc/z/zArray.hpp +++ b/src/hotspot/share/gc/z/zArray.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,9 +32,49 @@ #include +template class ZArray; class ZLock; -template using ZArray = GrowableArrayCHeap; +template +class ZArraySlice : public GrowableArrayView { + friend class ZArray; + friend class ZArray>; + friend class ZArraySlice>; + friend class ZArraySlice; + +private: + ZArraySlice(T* data, int len); + +public: + ZArraySlice slice_front(int end); + ZArraySlice slice_front(int end) const; + + ZArraySlice slice_back(int start); + ZArraySlice slice_back(int start) const; + + ZArraySlice slice(int start, int end); + ZArraySlice slice(int start, int end) const; + + operator ZArraySlice() const; +}; + +template +class ZArray : public GrowableArrayCHeap { +public: + using GrowableArrayCHeap::GrowableArrayCHeap; + + ZArraySlice slice_front(int end); + ZArraySlice slice_front(int end) const; + + ZArraySlice slice_back(int start); + ZArraySlice slice_back(int start) const; + + ZArraySlice slice(int start, int end); + ZArraySlice slice(int start, int end) const; + + operator ZArraySlice(); + operator ZArraySlice() const; +}; template class ZArrayIteratorImpl : public StackObj { diff --git a/src/hotspot/share/gc/z/zArray.inline.hpp b/src/hotspot/share/gc/z/zArray.inline.hpp index ec7feda8d6398..547a73ffc0dce 100644 --- a/src/hotspot/share/gc/z/zArray.inline.hpp +++ b/src/hotspot/share/gc/z/zArray.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,93 @@ #include "gc/z/zLock.inline.hpp" #include "runtime/atomic.hpp" +template +ZArraySlice::ZArraySlice(T* data, int len) + : GrowableArrayView(data, len, len) {} + +template +ZArraySlice ZArraySlice::slice_front(int end) { + return slice(0, end); +} + +template +ZArraySlice ZArraySlice::slice_front(int end) const { + return slice(0, end); +} + +template +ZArraySlice ZArraySlice::slice_back(int start) { + return slice(start, this->_len); +} + +template +ZArraySlice ZArraySlice::slice_back(int start) const { + return slice(start, this->_len); +} + +template +ZArraySlice ZArraySlice::slice(int start, int end) { + assert(0 <= start && start <= end && end <= this->_len, + "slice called with invalid range (%d, %d) for length %d", start, end, this->_len); + return ZArraySlice(this->_data + start, end - start); +} + +template +ZArraySlice ZArraySlice::slice(int start, int end) const { + assert(0 <= start && start <= end && end <= this->_len, + "slice called with invalid range (%d, %d) for length %d", start, end, this->_len); + return ZArraySlice(this->_data + start, end - start); +} + +template +ZArraySlice::operator ZArraySlice() const { + return slice(0, this->_len); +} + +template +ZArraySlice ZArray::slice_front(int end) { + return slice(0, end); +} + +template +ZArraySlice ZArray::slice_front(int end) const { + return slice(0, end); +} + +template +ZArraySlice ZArray::slice_back(int start) { + return slice(start, this->_len); +} + +template +ZArraySlice ZArray::slice_back(int start) const { + return slice(start, this->_len); +} + +template +ZArraySlice ZArray::slice(int start, int end) { + assert(0 <= start && start <= end && end <= this->_len, + "slice called with invalid range (%d, %d) for length %d", start, end, this->_len); + return ZArraySlice(this->_data + start, end - start); +} + +template +ZArraySlice ZArray::slice(int start, int end) const { + assert(0 <= start && start <= end && end <= this->_len, + "slice called with invalid range (%d, %d) for length %d", start, end, this->_len); + return ZArraySlice(this->_data + start, end - start); +} + +template +ZArray::operator ZArraySlice() { + return slice(0, this->_len); +} + +template +ZArray::operator ZArraySlice() const { + return slice(0, this->_len); +} + template inline bool ZArrayIteratorImpl::next_serial(size_t* index) { if (_next == _end) { diff --git a/src/hotspot/share/gc/z/zCollectedHeap.cpp b/src/hotspot/share/gc/z/zCollectedHeap.cpp index 828e3c9d033b2..642ad42a1d7bb 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.cpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp @@ -53,6 +53,7 @@ #include "runtime/stackWatermarkSet.hpp" #include "services/memoryUsage.hpp" #include "utilities/align.hpp" +#include "utilities/ostream.hpp" ZCollectedHeap* ZCollectedHeap::heap() { return named_heap(CollectedHeap::Z); @@ -245,7 +246,7 @@ size_t ZCollectedHeap::unsafe_max_tlab_alloc(Thread* ignored) const { } MemoryUsage ZCollectedHeap::memory_usage() { - const size_t initial_size = ZHeap::heap()->initial_capacity(); + const size_t initial_size = InitialHeapSize; const size_t committed = ZHeap::heap()->capacity(); const size_t used = MIN2(ZHeap::heap()->used(), committed); const size_t max_size = ZHeap::heap()->max_capacity(); @@ -355,10 +356,14 @@ void ZCollectedHeap::prepare_for_verify() { } void ZCollectedHeap::print_on(outputStream* st) const { + StreamAutoIndentor auto_indentor(st); + _heap.print_on(st); } void ZCollectedHeap::print_on_error(outputStream* st) const { + StreamAutoIndentor auto_indentor(st); + _heap.print_on_error(st); } diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index f847525673378..f3cd3393fc502 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -160,7 +160,7 @@ void ZGeneration::free_empty_pages(ZRelocationSetSelector* selector, int bulk) { // the page allocator lock, and trying to satisfy stalled allocations // too frequently. if (selector->should_free_empty_pages(bulk)) { - const size_t freed = ZHeap::heap()->free_empty_pages(selector->empty_pages()); + const size_t freed = ZHeap::heap()->free_empty_pages(_id, selector->empty_pages()); increase_freed(freed); selector->clear_empty_pages(); } @@ -190,17 +190,6 @@ void ZGeneration::select_relocation_set(bool promote_all) { for (ZPage* page; pt_iter.next(&page);) { if (!page->is_relocatable()) { // Not relocatable, don't register - // Note that the seqnum can change under our feet here as the page - // can be concurrently freed and recycled by a concurrent generation - // collection. However this property is stable across such transitions. - // If it was not relocatable before recycling, then it won't be - // relocatable after it gets recycled either, as the seqnum atomically - // becomes allocating for the given generation. The opposite property - // also holds: if the page is relocatable, then it can't have been - // concurrently freed; if it was re-allocated it would not be - // relocatable, and if it was not re-allocated we know that it was - // allocated earlier than mark start of the current generation - // collection. continue; } @@ -213,15 +202,14 @@ void ZGeneration::select_relocation_set(bool promote_all) { // Reclaim empty pages in bulk - // An active iterator blocks immediate recycle and delete of pages. - // The intent it to allow the code that iterates over the pages to - // safely read the properties of the pages without them being changed - // by another thread. However, this function both iterates over the - // pages AND frees/recycles them. We "yield" the iterator, so that we - // can perform immediate recycling (as long as no other thread is - // iterating over the pages). The contract is that the pages that are - // about to be freed are "owned" by this thread, and no other thread - // will change their states. + // An active iterator blocks immediate deletion of pages. The intent is + // to allow the code that iterates over pages to safely read properties + // of the pages without them being freed/deleted. However, this + // function both iterates over the pages AND frees them. We "yield" the + // iterator, so that we can perform immediate deletion (as long as no + // other thread is iterating over the pages). The contract is that the + // pages that are about to be freed are "owned" by this thread, and no + // other thread will change their states. pt_iter.yield([&]() { free_empty_pages(&selector, 64 /* bulk */); }); @@ -934,7 +922,7 @@ void ZGenerationYoung::flip_promote(ZPage* from_page, ZPage* to_page) { _page_table->replace(from_page, to_page); // Update statistics - _page_allocator->promote_used(from_page->size()); + _page_allocator->promote_used(from_page, to_page); increase_freed(from_page->size()); increase_promoted(from_page->live_bytes()); } @@ -943,7 +931,7 @@ void ZGenerationYoung::in_place_relocate_promote(ZPage* from_page, ZPage* to_pag _page_table->replace(from_page, to_page); // Update statistics - _page_allocator->promote_used(from_page->size()); + _page_allocator->promote_used(from_page, to_page); } void ZGenerationYoung::register_flip_promoted(const ZArray& pages) { diff --git a/src/hotspot/share/gc/z/zGranuleMap.hpp b/src/hotspot/share/gc/z/zGranuleMap.hpp index 58c95e331b65a..4cde26847be30 100644 --- a/src/hotspot/share/gc/z/zGranuleMap.hpp +++ b/src/hotspot/share/gc/z/zGranuleMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,9 @@ class ZGranuleMap { T get_acquire(zoffset offset) const; void release_put(zoffset offset, T value); void release_put(zoffset offset, size_t size, T value); + + const T* addr(zoffset offset) const; + T* addr(zoffset offset); }; template diff --git a/src/hotspot/share/gc/z/zGranuleMap.inline.hpp b/src/hotspot/share/gc/z/zGranuleMap.inline.hpp index 6cdc31f82700b..21be6a3d80a86 100644 --- a/src/hotspot/share/gc/z/zGranuleMap.inline.hpp +++ b/src/hotspot/share/gc/z/zGranuleMap.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,6 +101,17 @@ inline void ZGranuleMap::release_put(zoffset offset, size_t size, T value) { put(offset, size, value); } +template +inline const T* ZGranuleMap::addr(zoffset offset) const { + const size_t index = index_for_offset(offset); + return _map + index; +} + +template +inline T* ZGranuleMap::addr(zoffset offset) { + return const_cast(const_cast*>(this)->addr(offset)); +} + template inline ZGranuleMapIterator::ZGranuleMapIterator(const ZGranuleMap* granule_map) : ZArrayIteratorImpl(granule_map->_map, granule_map->_size) {} diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index e0f4cb6530370..90f8a86713532 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -59,7 +59,7 @@ ZHeap::ZHeap() _page_table(), _allocator_eden(), _allocator_relocation(), - _serviceability(initial_capacity(), min_capacity(), max_capacity()), + _serviceability(InitialHeapSize, min_capacity(), max_capacity()), _old(&_page_table, &_page_allocator), _young(&_page_table, _old.forwarding_table(), &_page_allocator), _initialized(false) { @@ -94,10 +94,6 @@ bool ZHeap::is_initialized() const { return _initialized; } -size_t ZHeap::initial_capacity() const { - return _page_allocator.initial_capacity(); -} - size_t ZHeap::min_capacity() const { return _page_allocator.min_capacity(); } @@ -240,18 +236,18 @@ void ZHeap::undo_alloc_page(ZPage* page) { log_trace(gc)("Undo page allocation, thread: " PTR_FORMAT " (%s), page: " PTR_FORMAT ", size: %zu", p2i(Thread::current()), ZUtils::thread_name(), p2i(page), page->size()); - free_page(page, false /* allow_defragment */); + free_page(page); } -void ZHeap::free_page(ZPage* page, bool allow_defragment) { +void ZHeap::free_page(ZPage* page) { // Remove page table entry _page_table.remove(page); // Free page - _page_allocator.free_page(page, allow_defragment); + _page_allocator.free_page(page); } -size_t ZHeap::free_empty_pages(const ZArray* pages) { +size_t ZHeap::free_empty_pages(ZGenerationId id, const ZArray* pages) { size_t freed = 0; // Remove page table entries ZArrayIterator iter(pages); @@ -261,7 +257,7 @@ size_t ZHeap::free_empty_pages(const ZArray* pages) { } // Free pages - _page_allocator.free_pages(pages); + _page_allocator.free_pages(id, pages); return freed; } @@ -319,21 +315,32 @@ ZServiceabilityCounters* ZHeap::serviceability_counters() { } void ZHeap::print_on(outputStream* st) const { - st->print_cr(" ZHeap used %zuM, capacity %zuM, max capacity %zuM", - used() / M, - capacity() / M, - max_capacity() / M); + streamIndentor indentor(st, 1); + _page_allocator.print_on(st); + + // Metaspace printing prepends spaces instead of using outputStream indentation + streamIndentor indentor_back(st, -1); MetaspaceUtils::print_on(st); } void ZHeap::print_on_error(outputStream* st) const { - print_on(st); + { + streamIndentor indentor(st, 1); + _page_allocator.print_on_error(st); + + // Metaspace printing prepends spaces instead of using outputStream indentation + streamIndentor indentor_back(st, -1); + MetaspaceUtils::print_on(st); + } st->cr(); print_globals_on(st); st->cr(); print_page_table_on(st); + st->cr(); + + _page_allocator.print_extended_on_error(st); } void ZHeap::print_globals_on(outputStream* st) const { @@ -366,9 +373,12 @@ void ZHeap::print_page_table_on(outputStream* st) const { // Print all pages st->print_cr("ZGC Page Table:"); - ZPageTableIterator iter(&_page_table); - for (ZPage* page; iter.next(&page);) { - page->print_on(st); + { + streamIndentor indentor(st, 1); + ZPageTableIterator iter(&_page_table); + for (ZPage* page; iter.next(&page);) { + page->print_on(st); + } } // Allow pages to be deleted diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index 25cd22090030e..823fc009b2ca0 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -67,7 +67,6 @@ class ZHeap { void out_of_memory(); // Heap metrics - size_t initial_capacity() const; size_t min_capacity() const; size_t max_capacity() const; size_t soft_max_capacity() const; @@ -104,8 +103,8 @@ class ZHeap { // Page allocation ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age); void undo_alloc_page(ZPage* page); - void free_page(ZPage* page, bool allow_defragment); - size_t free_empty_pages(const ZArray* pages); + void free_page(ZPage* page); + size_t free_empty_pages(ZGenerationId id, const ZArray* pages); // Object allocation bool is_alloc_stalling() const; diff --git a/src/hotspot/share/gc/z/zInitialize.cpp b/src/hotspot/share/gc/z/zInitialize.cpp index 125231355ac2e..b8efa8bcd69d4 100644 --- a/src/hotspot/share/gc/z/zInitialize.cpp +++ b/src/hotspot/share/gc/z/zInitialize.cpp @@ -57,8 +57,8 @@ void ZInitialize::initialize(ZBarrierSet* barrier_set) { // Early initialization ZNMT::initialize(); - ZGlobalsPointers::initialize(); ZNUMA::initialize(); + ZGlobalsPointers::initialize(); ZCPU::initialize(); ZStatValue::initialize(); ZThreadLocalAllocBuffer::initialize(); diff --git a/src/hotspot/share/gc/z/zIntrusiveRBTree.hpp b/src/hotspot/share/gc/z/zIntrusiveRBTree.hpp new file mode 100644 index 0000000000000..ff204d86462f6 --- /dev/null +++ b/src/hotspot/share/gc/z/zIntrusiveRBTree.hpp @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_Z_ZINTRUSIVERBTREE_HPP +#define SHARE_GC_Z_ZINTRUSIVERBTREE_HPP + +#include "metaprogramming/enableIf.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +enum class ZIntrusiveRBTreeDirection { LEFT, RIGHT }; + +class ZIntrusiveRBTreeNode { + template + friend class ZIntrusiveRBTree; + +public: + enum Color { RED = 0b0, BLACK = 0b1 }; + +private: + class ColoredNodePtr { + private: + static constexpr uintptr_t COLOR_MASK = 0b1; + static constexpr uintptr_t NODE_MASK = ~COLOR_MASK; + + uintptr_t _value; + + public: + ColoredNodePtr(ZIntrusiveRBTreeNode* node = nullptr, Color color = RED); + + constexpr Color color() const; + constexpr bool is_black() const; + constexpr bool is_red() const; + + ZIntrusiveRBTreeNode* node() const; + ZIntrusiveRBTreeNode* red_node() const; + ZIntrusiveRBTreeNode* black_node() const; + }; + +private: + ColoredNodePtr _colored_parent; + ZIntrusiveRBTreeNode* _left; + ZIntrusiveRBTreeNode* _right; + + template + const ZIntrusiveRBTreeNode* find_next_node() const; + + template + const ZIntrusiveRBTreeNode* child() const; + template + ZIntrusiveRBTreeNode* child(); + + template + ZIntrusiveRBTreeNode* const* child_addr() const; + + template + bool has_child() const; + + template + void update_child(ZIntrusiveRBTreeNode* new_child); + + void link_node(ZIntrusiveRBTreeNode* parent, ZIntrusiveRBTreeNode** insert_location); + + void copy_parent_and_color(ZIntrusiveRBTreeNode* other); + void update_parent_and_color(ZIntrusiveRBTreeNode* parent, Color color); + + void update_parent(ZIntrusiveRBTreeNode* parent); + void update_color(Color color); + + void update_left_child(ZIntrusiveRBTreeNode* new_child); + void update_right_child(ZIntrusiveRBTreeNode* new_child); + + const ZIntrusiveRBTreeNode* parent() const; + ZIntrusiveRBTreeNode* parent(); + const ZIntrusiveRBTreeNode* red_parent() const; + ZIntrusiveRBTreeNode* red_parent(); + const ZIntrusiveRBTreeNode* black_parent() const; + ZIntrusiveRBTreeNode* black_parent(); + + bool has_parent() const; + + Color color() const; + bool is_black() const; + bool is_red() const; + static bool is_black(ZIntrusiveRBTreeNode* node); + + ZIntrusiveRBTreeNode* const* left_child_addr() const; + ZIntrusiveRBTreeNode* const* right_child_addr() const; + + const ZIntrusiveRBTreeNode* left_child() const; + ZIntrusiveRBTreeNode* left_child(); + const ZIntrusiveRBTreeNode* right_child() const; + ZIntrusiveRBTreeNode* right_child(); + + bool has_left_child() const; + bool has_right_child() const; + +public: + ZIntrusiveRBTreeNode(); + + const ZIntrusiveRBTreeNode* prev() const; + ZIntrusiveRBTreeNode* prev(); + const ZIntrusiveRBTreeNode* next() const; + ZIntrusiveRBTreeNode* next(); +}; + +template +class ZIntrusiveRBTree { +public: + class FindCursor { + friend class ZIntrusiveRBTree; + + private: + ZIntrusiveRBTreeNode** _insert_location; + ZIntrusiveRBTreeNode* _parent; + bool _left_most; + bool _right_most; + DEBUG_ONLY(uintptr_t _sequence_number;) + + FindCursor(ZIntrusiveRBTreeNode** insert_location, ZIntrusiveRBTreeNode* parent, bool left_most, bool right_most DEBUG_ONLY(COMMA uintptr_t sequence_number)); + FindCursor(); + +#ifdef ASSERT + bool is_valid(uintptr_t sequence_number) const; +#endif + + public: + FindCursor(const FindCursor&) = default; + FindCursor& operator=(const FindCursor&) = default; + + bool is_valid() const; + bool found() const; + ZIntrusiveRBTreeNode* node() const; + bool is_left_most() const; + bool is_right_most() const; + ZIntrusiveRBTreeNode* parent() const; + ZIntrusiveRBTreeNode** insert_location() const; + }; + +private: + ZIntrusiveRBTreeNode* _root_node; + ZIntrusiveRBTreeNode* _left_most; + ZIntrusiveRBTreeNode* _right_most; + DEBUG_ONLY(uintptr_t _sequence_number;) + + NONCOPYABLE(ZIntrusiveRBTree); + +#ifdef ASSERT + template + bool verify_node(ZIntrusiveRBTreeNode* parent, ZIntrusiveRBTreeNode* left_child, ZIntrusiveRBTreeNode* right_child); + template + bool verify_node(ZIntrusiveRBTreeNode* parent); + template + bool verify_node(ZIntrusiveRBTreeNode* parent, ZIntrusiveRBTreeNode* left_child); + struct any_t {}; + template + bool verify_node(ZIntrusiveRBTreeNode* parent, any_t, ZIntrusiveRBTreeNode* right_child); +#endif // ASSERT + + ZIntrusiveRBTreeNode* const* root_node_addr() const; + + void update_child_or_root(ZIntrusiveRBTreeNode* old_node, ZIntrusiveRBTreeNode* new_node, ZIntrusiveRBTreeNode* parent); + void rotate_and_update_child_or_root(ZIntrusiveRBTreeNode* old_node, ZIntrusiveRBTreeNode* new_node, ZIntrusiveRBTreeNode::Color color); + + template + void rebalance_insert_with_sibling(ZIntrusiveRBTreeNode* node, ZIntrusiveRBTreeNode* parent, ZIntrusiveRBTreeNode* grand_parent); + template + bool rebalance_insert_with_parent_sibling(ZIntrusiveRBTreeNode** node_addr, ZIntrusiveRBTreeNode** parent_addr, ZIntrusiveRBTreeNode* grand_parent); + void rebalance_insert(ZIntrusiveRBTreeNode* new_node); + + template + bool rebalance_remove_with_sibling(ZIntrusiveRBTreeNode** node_addr, ZIntrusiveRBTreeNode** parent_addr); + void rebalance_remove(ZIntrusiveRBTreeNode* rebalance_from); + + FindCursor make_cursor(ZIntrusiveRBTreeNode* const* insert_location, ZIntrusiveRBTreeNode* parent, bool left_most, bool right_most) const; + template + FindCursor find_next(const FindCursor& cursor) const; + +public: + ZIntrusiveRBTree(); + + ZIntrusiveRBTreeNode* first() const; + ZIntrusiveRBTreeNode* last() const; + + FindCursor root_cursor() const; + FindCursor get_cursor(const ZIntrusiveRBTreeNode* node) const; + FindCursor prev_cursor(const ZIntrusiveRBTreeNode* node) const; + FindCursor next_cursor(const ZIntrusiveRBTreeNode* node) const; + FindCursor prev(const FindCursor& cursor) const; + FindCursor next(const FindCursor& cursor) const; + FindCursor find(const Key& key) const; + + void insert(ZIntrusiveRBTreeNode* new_node, const FindCursor& find_cursor); + void replace(ZIntrusiveRBTreeNode* new_node, const FindCursor& find_cursor); + void remove(const FindCursor& find_cursor); + + void verify_tree(); + +public: + template + class IteratorImplementation; + + using Iterator = IteratorImplementation; + using ConstIterator = IteratorImplementation; + using ReverseIterator = IteratorImplementation; + using ConstReverseIterator = IteratorImplementation; + + // remove and replace invalidate the iterators + // however the iterators provide a remove and replace + // function which does not invalidate that iterator nor + // any end iterator + Iterator begin(); + Iterator end(); + ConstIterator begin() const; + ConstIterator end() const; + ConstIterator cbegin() const; + ConstIterator cend() const; + ReverseIterator rbegin(); + ReverseIterator rend(); + ConstReverseIterator rbegin() const; + ConstReverseIterator rend() const; + ConstReverseIterator crbegin() const; + ConstReverseIterator crend() const; +}; + +template +template +class ZIntrusiveRBTree::IteratorImplementation { + friend IteratorImplementation; + +public: + using difference_type = std::ptrdiff_t; + using value_type = const ZIntrusiveRBTreeNode; + using pointer = value_type*; + using reference = value_type&; + +private: + ZIntrusiveRBTree* _tree; + const ZIntrusiveRBTreeNode* _node; + bool _removed; + + bool at_end() const; + +public: + IteratorImplementation(ZIntrusiveRBTree& tree, pointer node); + IteratorImplementation(const IteratorImplementation&) = default; + template + IteratorImplementation(const IteratorImplementation& other); + + reference operator*() const; + pointer operator->(); + IteratorImplementation& operator--(); + IteratorImplementation operator--(int); + IteratorImplementation& operator++(); + IteratorImplementation operator++(int); + + template + void replace(ZIntrusiveRBTreeNode * new_node); + template + void remove(); + + // Note: friend operator overloads defined inside class declaration because of problems with ADL + friend bool operator==(const IteratorImplementation& a, const IteratorImplementation& b) { + precond(a._tree == b._tree); + return a._node == b._node; + } + friend bool operator!=(const IteratorImplementation& a, const IteratorImplementation& b) { + precond(a._tree == b._tree); + return a._node != b._node; + } +}; + +#endif // SHARE_GC_Z_ZINTRUSIVERBTREE_HPP diff --git a/src/hotspot/share/gc/z/zIntrusiveRBTree.inline.hpp b/src/hotspot/share/gc/z/zIntrusiveRBTree.inline.hpp new file mode 100644 index 0000000000000..b62db5166ddba --- /dev/null +++ b/src/hotspot/share/gc/z/zIntrusiveRBTree.inline.hpp @@ -0,0 +1,1351 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_Z_ZINTRUSIVERBTREE_INLINE_HPP +#define SHARE_GC_Z_ZINTRUSIVERBTREE_INLINE_HPP + +#include "gc/z/zIntrusiveRBTree.hpp" + +#include "metaprogramming/enableIf.hpp" +#include "utilities/debug.hpp" + +static constexpr ZIntrusiveRBTreeDirection other(const ZIntrusiveRBTreeDirection& direction) { + return direction == ZIntrusiveRBTreeDirection::LEFT ? ZIntrusiveRBTreeDirection::RIGHT : ZIntrusiveRBTreeDirection::LEFT; +} + +inline ZIntrusiveRBTreeNode::ColoredNodePtr::ColoredNodePtr(ZIntrusiveRBTreeNode* node, Color color) + : _value(reinterpret_cast(node) | color) {} + +inline constexpr ZIntrusiveRBTreeNode::Color ZIntrusiveRBTreeNode::ColoredNodePtr::color() const { + return static_cast(_value & COLOR_MASK); +} + +inline constexpr bool ZIntrusiveRBTreeNode::ColoredNodePtr::is_black() const { + return color() == BLACK; +} + +inline constexpr bool ZIntrusiveRBTreeNode::ColoredNodePtr::is_red() const { + return color() == RED; +} + +inline ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::ColoredNodePtr::node() const { + return reinterpret_cast(_value & NODE_MASK); +} + +inline ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::ColoredNodePtr::red_node() const { + precond(is_red()); + return reinterpret_cast(_value); +} +inline ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::ColoredNodePtr::black_node() const { + precond(is_black()); + return reinterpret_cast(_value ^ BLACK); +} + +template +inline const ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::find_next_node() const { + constexpr ZIntrusiveRBTreeDirection OTHER_DIRECTION = other(DIRECTION); + const ZIntrusiveRBTreeNode* node = this; + + // Down the tree + if (node->has_child()) { + node = node->child(); + while (node->has_child()) { + node = node->child(); + } + return node; + } + + // Up the tree + const ZIntrusiveRBTreeNode* parent = node->parent(); + while (parent != nullptr && node == parent->child()) { + node = parent; + parent = node->parent(); + } + return parent; +} + +template +inline const ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::child() const { + if (DIRECTION == ZIntrusiveRBTreeDirection::LEFT) { + return _left; + } + assert(DIRECTION == ZIntrusiveRBTreeDirection::RIGHT, "must be"); + return _right; +} + +template +inline ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::child() { + return const_cast(const_cast(this)->template child()); +} + +template +inline ZIntrusiveRBTreeNode* const* ZIntrusiveRBTreeNode::child_addr() const { + if (DIRECTION == ZIntrusiveRBTreeDirection::LEFT) { + return &_left; + } + assert(DIRECTION == ZIntrusiveRBTreeDirection::RIGHT, "must be"); + return &_right; +} + +template +inline bool ZIntrusiveRBTreeNode::has_child() const { + if (DIRECTION == ZIntrusiveRBTreeDirection::LEFT) { + return _left != nullptr; + } + assert(DIRECTION == ZIntrusiveRBTreeDirection::RIGHT, "must be"); + return _right != nullptr; +} + +template +inline void ZIntrusiveRBTreeNode::update_child(ZIntrusiveRBTreeNode* new_child) { + if (DIRECTION == ZIntrusiveRBTreeDirection::LEFT) { + _left = new_child; + return; + } + assert(DIRECTION == ZIntrusiveRBTreeDirection::RIGHT, "must be"); + _right = new_child; +} + +inline void ZIntrusiveRBTreeNode::link_node(ZIntrusiveRBTreeNode* parent, ZIntrusiveRBTreeNode** insert_location) { + // Newly linked node is always red + _colored_parent = ColoredNodePtr(parent, RED); + _left = nullptr; + _right = nullptr; + + // Link into location + *insert_location = this; +} + +inline void ZIntrusiveRBTreeNode::copy_parent_and_color(ZIntrusiveRBTreeNode* other) { + _colored_parent = other->_colored_parent; +} + +inline void ZIntrusiveRBTreeNode::update_parent_and_color(ZIntrusiveRBTreeNode* parent, Color color) { + _colored_parent = ColoredNodePtr(parent, color); +} + +inline void ZIntrusiveRBTreeNode::update_parent(ZIntrusiveRBTreeNode* parent) { + _colored_parent = ColoredNodePtr(parent, color()); +} + +inline void ZIntrusiveRBTreeNode::update_color(Color color) { + _colored_parent = ColoredNodePtr(parent(), color); +} + +inline void ZIntrusiveRBTreeNode::update_left_child(ZIntrusiveRBTreeNode* new_child) { + update_child(new_child); +} + +inline void ZIntrusiveRBTreeNode::update_right_child(ZIntrusiveRBTreeNode* new_child) { + update_child(new_child); +} + +inline const ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::parent() const { + return _colored_parent.node(); +} + +inline ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::parent() { + return const_cast(const_cast(this)->parent()); +} + +inline const ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::red_parent() const { + return _colored_parent.red_node(); +} +inline ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::red_parent() { + return const_cast(const_cast(this)->red_parent()); +} + +inline const ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::black_parent() const { + return _colored_parent.black_node(); +} +inline ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::black_parent() { + return const_cast(const_cast(this)->black_parent()); +} + +inline bool ZIntrusiveRBTreeNode::has_parent() const { + return _colored_parent.node() != nullptr; +} + +inline ZIntrusiveRBTreeNode::Color ZIntrusiveRBTreeNode::color() const { + return _colored_parent.color(); +} + +inline bool ZIntrusiveRBTreeNode::is_black() const { + return _colored_parent.is_black(); +} + +inline bool ZIntrusiveRBTreeNode::is_red() const { + return _colored_parent.is_red(); +} + +inline bool ZIntrusiveRBTreeNode::is_black(ZIntrusiveRBTreeNode* node) { + return node == nullptr || node->is_black(); +} + +inline ZIntrusiveRBTreeNode* const* ZIntrusiveRBTreeNode::left_child_addr() const { + return child_addr(); +} + +inline ZIntrusiveRBTreeNode* const* ZIntrusiveRBTreeNode::right_child_addr() const { + return child_addr(); +} + +inline const ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::left_child() const { + return child(); +} + +inline ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::left_child() { + return const_cast(const_cast(this)->left_child()); +} + +inline const ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::right_child() const { + return child(); +} + +inline ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::right_child() { + return const_cast(const_cast(this)->right_child()); +} + +inline bool ZIntrusiveRBTreeNode::has_left_child() const { + return has_child(); +} + +inline bool ZIntrusiveRBTreeNode::has_right_child() const { + return has_child(); +} + +inline ZIntrusiveRBTreeNode::ZIntrusiveRBTreeNode() {} + +inline const ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::prev() const { + return find_next_node(); +} + +inline ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::prev() { + return const_cast(const_cast(this)->prev()); +} + +inline const ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::next() const { + return find_next_node(); +} + +inline ZIntrusiveRBTreeNode* ZIntrusiveRBTreeNode::next() { + return const_cast(const_cast(this)->next()); +} + +#ifdef ASSERT +template +template +inline bool ZIntrusiveRBTree::verify_node(ZIntrusiveRBTreeNode* parent, ZIntrusiveRBTreeNode* left_child, ZIntrusiveRBTreeNode* right_child) { + if (swap_left_right) { + ::swap(left_child, right_child); + } + assert(parent->left_child() == left_child, swap_left_right ? "Bad child Swapped" : "Bad child"); + assert(parent->right_child() == right_child, swap_left_right ? "Bad child Swapped" : "Bad child"); + if (left_child != nullptr) { + assert(left_child->parent() == parent, swap_left_right ? "Bad parent Swapped" : "Bad parent"); + } + if (right_child != nullptr) { + assert(right_child->parent() == parent, swap_left_right ? "Bad parent Swapped" : "Bad parent"); + } + return true; +} + +template +template +inline bool ZIntrusiveRBTree::verify_node(ZIntrusiveRBTreeNode* parent) { + if (parent == nullptr) { + return true; + } + if (swap_left_right) { + return verify_node(parent, parent->right_child()); + } + return verify_node(parent, parent->left_child()); +} + +template +template +inline bool ZIntrusiveRBTree::verify_node(ZIntrusiveRBTreeNode* parent, ZIntrusiveRBTreeNode* left_child) { + if (swap_left_right) { + return verify_node(parent, left_child, parent->left_child()); + } + return verify_node(parent, left_child, parent->right_child()); +} + +template +template +inline bool ZIntrusiveRBTree::verify_node(ZIntrusiveRBTreeNode* parent, any_t, ZIntrusiveRBTreeNode* right_child) { + if (swap_left_right) { + return verify_node(parent, parent->right_child(), right_child); + } + return verify_node(parent, parent->left_child(), right_child); +} +#endif // ASSERT + +template +inline ZIntrusiveRBTreeNode* const* ZIntrusiveRBTree::root_node_addr() const { + return &_root_node; +} + +template +void ZIntrusiveRBTree::update_child_or_root(ZIntrusiveRBTreeNode* old_node, ZIntrusiveRBTreeNode* new_node, ZIntrusiveRBTreeNode* parent) { + if (parent == nullptr) { + // Update root + _root_node = new_node; + return; + } + if (old_node == parent->left_child()) { + parent->update_left_child(new_node); + return; + } + assert(old_node == parent->right_child(), "must be"); + parent->update_right_child(new_node); +} + +template +inline void ZIntrusiveRBTree::rotate_and_update_child_or_root(ZIntrusiveRBTreeNode* old_node, ZIntrusiveRBTreeNode* new_node, ZIntrusiveRBTreeNode::Color color) { + ZIntrusiveRBTreeNode* const parent = old_node->parent(); + new_node->copy_parent_and_color(old_node); + old_node->update_parent_and_color(new_node, color); + update_child_or_root(old_node, new_node, parent); +} + +template +template +inline void ZIntrusiveRBTree::rebalance_insert_with_sibling(ZIntrusiveRBTreeNode* node, ZIntrusiveRBTreeNode* parent, ZIntrusiveRBTreeNode* grand_parent) { + DEBUG_ONLY(const bool swap_left_right = PARENT_SIBLING_DIRECTION == ZIntrusiveRBTreeDirection::LEFT;) + constexpr ZIntrusiveRBTreeDirection OTHER_DIRECTION = other(PARENT_SIBLING_DIRECTION); + ZIntrusiveRBTreeNode* sibling = parent->template child(); + DEBUG_ONLY(bool rotated_parent = false;) + if (node == sibling) { + DEBUG_ONLY(rotated_parent = true;) + // Rotate up node through parent + ZIntrusiveRBTreeNode* child = node->template child(); + + //// PRE + // + // G G + // / \ + // p or p + // \ / + // n n + // / \ + // (c) (c) + // + //// + precond(grand_parent->is_black()); + precond(parent->is_red()); + precond(node->is_red()); + precond(verify_node(grand_parent, parent)); + precond(verify_node(parent, any_t{}, node)); + precond(verify_node(node, child)); + precond(verify_node(child)); + + // Fix children + parent->template update_child(child); + node->template update_child(parent); + + // Fix parents and colors + if (child != nullptr) { + child->update_parent_and_color(parent, ZIntrusiveRBTreeNode::BLACK); + } + parent->update_parent_and_color(node, ZIntrusiveRBTreeNode::RED); + + //// POST + // + // G G + // / \ + // n or n + // / \ + // p p + // \ / + // (C) (C) + // + //// + postcond(grand_parent->is_black()); + postcond(parent->is_red()); + postcond(node->is_red()); + postcond(ZIntrusiveRBTreeNode::is_black(child)); + // The grand_parent is updated in the next rotation + // postcond(verify_node(grand_parent, node)); + postcond(verify_node(node, parent)); + postcond(verify_node(parent, any_t{}, child)); + postcond(verify_node(child)); + + parent = node; + sibling = parent->template child(); + DEBUG_ONLY(node = parent->template child();) + } + + //// PRE + // + // G G + // / \ + // p or p + // / \ / \ + // n (s) (s) n + // + //// + precond(grand_parent->is_black()); + precond(parent->is_red()); + precond(node->is_red()); + precond(rotated_parent || verify_node(grand_parent, parent)); + precond(verify_node(parent, node, sibling)); + precond(verify_node(node)); + precond(verify_node(sibling)); + + // Rotate up parent through grand-parent + + // Fix children + grand_parent->template update_child(sibling); + parent->template update_child(grand_parent); + + // Fix parents and colors + if (sibling != nullptr) { + sibling->update_parent_and_color(grand_parent, ZIntrusiveRBTreeNode::BLACK); + } + rotate_and_update_child_or_root(grand_parent, parent, ZIntrusiveRBTreeNode::RED); + + //// POST + // + // P P + // / \ / \ + // n g or g n + // / \ + // (S) (S) + // + //// + postcond(parent->is_black()); + postcond(grand_parent->is_red()); + postcond(node->is_red()); + postcond(ZIntrusiveRBTreeNode::is_black(sibling)); + postcond(verify_node(parent, node, grand_parent)); + postcond(verify_node(node)); + postcond(verify_node(grand_parent, sibling)); + postcond(verify_node(sibling)); +} + +template +template +inline bool ZIntrusiveRBTree::rebalance_insert_with_parent_sibling(ZIntrusiveRBTreeNode** node_addr, ZIntrusiveRBTreeNode** parent_addr, ZIntrusiveRBTreeNode* grand_parent) { + DEBUG_ONLY(const bool swap_left_right = PARENT_SIBLING_DIRECTION == ZIntrusiveRBTreeDirection::LEFT;) + constexpr ZIntrusiveRBTreeDirection OTHER_DIRECTION = other(PARENT_SIBLING_DIRECTION); + ZIntrusiveRBTreeNode* const parent_sibling = grand_parent->template child(); + ZIntrusiveRBTreeNode*& node = *node_addr; + ZIntrusiveRBTreeNode*& parent = *parent_addr; + if (parent_sibling != nullptr && parent_sibling->is_red()) { + //// PRE + // + // G G + // / \ / \ + // p u or u p + // / \ / \ + // n | n n | n + // + //// + precond(grand_parent->is_black()); + precond(parent_sibling->is_red()); + precond(parent->is_red()); + precond(node->is_red()); + precond(verify_node(grand_parent, parent, parent_sibling)); + precond(parent->left_child() == node || parent->right_child() == node); + precond(verify_node(parent)); + precond(verify_node(parent_sibling)); + precond(verify_node(node)); + + // Flip colors of parent, parent sibling and grand parent + parent_sibling->update_parent_and_color(grand_parent, ZIntrusiveRBTreeNode::BLACK); + parent->update_parent_and_color(grand_parent, ZIntrusiveRBTreeNode::BLACK); + ZIntrusiveRBTreeNode* grand_grand_parent = grand_parent->black_parent(); + grand_parent->update_parent_and_color(grand_grand_parent, ZIntrusiveRBTreeNode::RED); + + //// POST + // + // g g + // / \ / \ + // P U or U P + // / \ / \ + // n | n n | n + // + //// + postcond(grand_parent->is_red()); + postcond(parent_sibling->is_black()); + postcond(parent->is_black()); + postcond(node->is_red()); + postcond(verify_node(grand_parent, parent, parent_sibling)); + postcond(parent->left_child() == node || parent->right_child() == node); + postcond(verify_node(parent)); + postcond(verify_node(parent_sibling)); + postcond(verify_node(node)); + + // Recurse up the tree + node = grand_parent; + parent = grand_grand_parent; + return false; // Not finished + } + + rebalance_insert_with_sibling(node, parent, grand_parent); + return true; // Finished +} + +template +inline void ZIntrusiveRBTree::rebalance_insert(ZIntrusiveRBTreeNode* new_node) { + ZIntrusiveRBTreeNode* node = new_node; + ZIntrusiveRBTreeNode* parent = node->red_parent(); + for (;;) { + precond(node->is_red()); + if (parent == nullptr) { + // Recursive (or root) case + node->update_parent_and_color(parent, ZIntrusiveRBTreeNode::BLACK); + break; + } + if (parent->is_black()) { + // Tree is balanced + break; + } + ZIntrusiveRBTreeNode* grand_parent = parent->red_parent(); + if (parent == grand_parent->left_child() ? rebalance_insert_with_parent_sibling(&node, &parent, grand_parent) + : rebalance_insert_with_parent_sibling(&node, &parent, grand_parent)) { + break; + } + } +} + +template +template +inline bool ZIntrusiveRBTree::rebalance_remove_with_sibling(ZIntrusiveRBTreeNode** node_addr, ZIntrusiveRBTreeNode** parent_addr) { + DEBUG_ONLY(const bool swap_left_right = SIBLING_DIRECTION == ZIntrusiveRBTreeDirection::LEFT;) + constexpr ZIntrusiveRBTreeDirection OTHER_DIRECTION = other(SIBLING_DIRECTION); + ZIntrusiveRBTreeNode*& node = *node_addr; + ZIntrusiveRBTreeNode*& parent = *parent_addr; + ZIntrusiveRBTreeNode* sibling = parent->template child(); + if (sibling->is_red()) { + ZIntrusiveRBTreeNode* sibling_child = sibling->template child(); + //// PRE + // + // P P + // / \ / \ + // N s or s N + // / \ + // SC SC + // + //// + precond(parent->is_black()); + precond(ZIntrusiveRBTreeNode::is_black(node)); + precond(sibling->is_red()); + precond(ZIntrusiveRBTreeNode::is_black(sibling_child)); + precond(verify_node(parent, node, sibling)); + precond(verify_node(node)); + precond(verify_node(sibling, sibling_child)); + precond(verify_node(sibling_child)); + + // Rotate sibling up through parent + + // Fix children + parent->template update_child(sibling_child); + sibling->template update_child(parent); + + // Fix parents and colors + sibling_child->update_parent_and_color(parent, ZIntrusiveRBTreeNode::BLACK); + rotate_and_update_child_or_root(parent, sibling, ZIntrusiveRBTreeNode::RED); + + //// POST + // + // S S + // / \ + // p p + // / \ / \ + // N SC SC N + // + //// + postcond(sibling->is_black()); + postcond(parent->is_red()); + postcond(ZIntrusiveRBTreeNode::is_black(node)); + postcond(ZIntrusiveRBTreeNode::is_black(sibling_child)); + postcond(verify_node(sibling, parent)); + postcond(verify_node(parent, node, sibling_child)); + postcond(verify_node(node)); + postcond(verify_node(sibling_child)); + + // node has a new sibling + sibling = sibling_child; + } + + ZIntrusiveRBTreeNode* sibling_child = sibling->template child(); + DEBUG_ONLY(bool rotated_parent = false;) + if (ZIntrusiveRBTreeNode::is_black(sibling_child)) { + DEBUG_ONLY(rotated_parent = true;) + ZIntrusiveRBTreeNode* sibling_other_child = sibling->template child(); + if (ZIntrusiveRBTreeNode::is_black(sibling_other_child)) { + //// PRE + // + // (p) (p) + // / \ / \ + // N S or S N + // + //// + precond(ZIntrusiveRBTreeNode::is_black(node)); + precond(sibling->is_black()); + precond(verify_node(parent, node, sibling)); + + // Flip sibling color to RED + sibling->update_parent_and_color(parent, ZIntrusiveRBTreeNode::RED); + + //// POST + // + // (p) (p) + // / \ / \ + // N s or s N + // + //// + postcond(ZIntrusiveRBTreeNode::is_black(node)); + postcond(sibling->is_red()); + postcond(verify_node(parent, node, sibling)); + + if (parent->is_black()) { + // We did not introduce a RED-RED edge, if parent is + // the root we are done, else recurse up the tree + if (parent->parent() != nullptr) { + node = parent; + parent = node->parent(); + return false; + } + return true; + } + // Change RED-RED edge to BLACK-RED edge + parent->update_color(ZIntrusiveRBTreeNode::BLACK); + return true; + } + + ZIntrusiveRBTreeNode* sibling_grand_child = sibling_other_child->template child(); + //// PRE + // + // (p) (p) + // / \ / \ + // N S S N + // / or \ + // soc soc + // \ / + // (sgc) (sgc) + // + //// + precond(ZIntrusiveRBTreeNode::is_black(node)); + precond(sibling->is_black()); + precond(sibling_other_child->is_red()); + precond(verify_node(parent, node, sibling)); + precond(verify_node(node)); + precond(verify_node(sibling, sibling_other_child, sibling_child)); + precond(verify_node(sibling_other_child, any_t{}, sibling_grand_child)); + precond(verify_node(sibling_grand_child)); + + // Rotate sibling other child through the sibling + + // Fix children + sibling->template update_child(sibling_grand_child); + sibling_other_child->template update_child(sibling); + parent->template update_child(sibling_other_child); + + // Fix parents and colors + if (sibling_grand_child != nullptr) { + sibling_grand_child->update_parent_and_color(sibling, ZIntrusiveRBTreeNode::BLACK); + } + // Defer updating the sibling and sibling other child parents until + // after we rotate below. This will also fix the any potential RED-RED + // edge between parent and sibling_other_child + + //// POST + // + // (p) (p) + // / \ / \ + // N soc or soc N + // / \ / \ + // SGC S S SGC + // + //// + postcond(ZIntrusiveRBTreeNode::is_black(node)); + postcond(sibling->is_black()); + postcond(sibling_other_child->is_red()); + postcond(ZIntrusiveRBTreeNode::is_black(sibling_grand_child)); + // Deferred + // postcond(verify_node(parent, node, sibling_other_child)); + postcond(verify_node(node)); + // postcond(verify_node(sibling_other_child, sibling_grand_child, sibling)); + postcond(verify_node(sibling_grand_child)); + postcond(verify_node(sibling)); + + // node has a new sibling + sibling_child = sibling; + sibling = sibling_other_child; + } + + ZIntrusiveRBTreeNode* sibling_other_child = sibling->template child(); + //// PRE + // + // (p) (p) + // / \ / \ + // N S or S N + // / \ / \ + // (soc)(sc) (sc)(soc) + // + //// + DEBUG_ONLY(ZIntrusiveRBTreeNode::Color parent_color = parent->color();) + precond(ZIntrusiveRBTreeNode::is_black(node)); + precond(rotated_parent || sibling->is_black()); + DEBUG_ONLY(bool sibling_other_child_is_black = ZIntrusiveRBTreeNode::is_black(sibling_other_child);) + precond(rotated_parent || verify_node(parent, node, sibling)); + precond(verify_node(node)); + precond(rotated_parent || verify_node(sibling, sibling_other_child, sibling_child)); + postcond(verify_node(sibling_other_child)); + postcond(verify_node(sibling_child)); + + // Rotate sibling through parent and fix colors + + // Fix children + parent->template update_child(sibling_other_child); + sibling->template update_child(parent); + + // Fix parents and colors + sibling_child->update_parent_and_color(sibling, ZIntrusiveRBTreeNode::BLACK); + if (sibling_other_child != nullptr) { + sibling_other_child->update_parent(parent); + } + rotate_and_update_child_or_root(parent, sibling, ZIntrusiveRBTreeNode::BLACK); + + //// POST + // + // (s) (s) + // / \ / \ + // P SC or SC P + // / \ / \ + // N (soc) (soc) N + // + //// + postcond(sibling->color() == parent_color); + postcond(parent->is_black()); + postcond(sibling_child->is_black()); + postcond(ZIntrusiveRBTreeNode::is_black(node)); + postcond(sibling_other_child_is_black == ZIntrusiveRBTreeNode::is_black(sibling_other_child)); + postcond(verify_node(sibling, parent, sibling_child)); + postcond(verify_node(parent, node, sibling_other_child)); + postcond(verify_node(sibling_child)); + postcond(verify_node(node)); + postcond(verify_node(sibling_other_child)); + return true; +} + +template +inline void ZIntrusiveRBTree::rebalance_remove(ZIntrusiveRBTreeNode* rebalance_from) { + ZIntrusiveRBTreeNode* node = nullptr; + ZIntrusiveRBTreeNode* parent = rebalance_from; + + for (;;) { + precond(ZIntrusiveRBTreeNode::is_black(node)); + precond(parent != nullptr); + if (node == parent->left_child() ? rebalance_remove_with_sibling(&node, &parent) + : rebalance_remove_with_sibling(&node, &parent)) { + break; + } + } +} + +template +inline ZIntrusiveRBTree::FindCursor::FindCursor(ZIntrusiveRBTreeNode** insert_location, ZIntrusiveRBTreeNode* parent, bool left_most, bool right_most DEBUG_ONLY(COMMA uintptr_t sequence_number)) + : _insert_location(insert_location), + _parent(parent), + _left_most(left_most), + _right_most(right_most) + DEBUG_ONLY(COMMA _sequence_number(sequence_number)) {} + +template +inline ZIntrusiveRBTree::FindCursor::FindCursor() + : _insert_location(nullptr), + _parent(nullptr), + _left_most(), + _right_most() + DEBUG_ONLY(COMMA _sequence_number()) {} + +#ifdef ASSERT +template +inline bool ZIntrusiveRBTree::FindCursor::is_valid(uintptr_t sequence_number) const { + return is_valid() && _sequence_number == sequence_number; +} +#endif // ASSERT + +template +inline bool ZIntrusiveRBTree::FindCursor::is_valid() const { + return insert_location() != nullptr; +} + +template +inline bool ZIntrusiveRBTree::FindCursor::found() const { + return node() != nullptr; +} + +template +inline ZIntrusiveRBTreeNode* ZIntrusiveRBTree::FindCursor::node() const { + precond(is_valid()); + return *_insert_location == nullptr ? nullptr : *_insert_location; +} + +template +inline bool ZIntrusiveRBTree::FindCursor::is_left_most() const { + precond(is_valid()); + return _left_most; +} + +template +inline bool ZIntrusiveRBTree::FindCursor::is_right_most() const { + precond(is_valid()); + return _right_most; +} + +template +inline ZIntrusiveRBTreeNode* ZIntrusiveRBTree::FindCursor::parent() const { + precond(is_valid()); + return _parent; +} + +template +inline ZIntrusiveRBTreeNode** ZIntrusiveRBTree::FindCursor::insert_location() const { + return _insert_location; +} + +template +inline typename ZIntrusiveRBTree::FindCursor ZIntrusiveRBTree::make_cursor(ZIntrusiveRBTreeNode* const* insert_location, ZIntrusiveRBTreeNode* parent, bool left_most, bool right_most) const { + return FindCursor(const_cast(insert_location), parent, left_most, right_most DEBUG_ONLY(COMMA _sequence_number)); +} + +template +template +inline typename ZIntrusiveRBTree::FindCursor ZIntrusiveRBTree::find_next(const FindCursor& cursor) const { + constexpr ZIntrusiveRBTreeDirection OTHER_DIRECTION = other(DIRECTION); + if (cursor.found()) { + ZIntrusiveRBTreeNode* const node = cursor.node(); + const ZIntrusiveRBTreeNode* const next_node = node->template find_next_node(); + if (next_node != nullptr) { + return get_cursor(next_node); + } + const bool is_right_most = DIRECTION == ZIntrusiveRBTreeDirection::RIGHT && node == _right_most; + const bool is_left_most = DIRECTION == ZIntrusiveRBTreeDirection::LEFT && node == _left_most; + return make_cursor(node->template child_addr(), node, is_left_most, is_right_most); + } + ZIntrusiveRBTreeNode* const parent = cursor.parent(); + if (parent == nullptr) { + assert(&_root_node == cursor.insert_location(), "must be"); + // tree is empty + return FindCursor(); + } + if (parent->template child_addr() == cursor.insert_location()) { + // Cursor at leaf in other direction, parent is next in direction + return get_cursor(parent); + } + assert(parent->template child_addr() == cursor.insert_location(), "must be"); + // Cursor at leaf in direction, parent->next in direction is also cursors next in direction + return get_cursor(parent->template find_next_node()); +} + +template +inline ZIntrusiveRBTree::ZIntrusiveRBTree() + : _root_node(nullptr), + _left_most(nullptr), + _right_most(nullptr) + DEBUG_ONLY(COMMA _sequence_number()) {} + +template +inline ZIntrusiveRBTreeNode* ZIntrusiveRBTree::first() const { + return _left_most; +} + +template +inline ZIntrusiveRBTreeNode* ZIntrusiveRBTree::last() const { + return _right_most; +} + +template +inline typename ZIntrusiveRBTree::FindCursor ZIntrusiveRBTree::root_cursor() const { + const bool is_left_most = _root_node == _left_most; + const bool is_right_most = _root_node == _right_most; + return make_cursor(&_root_node, nullptr, is_left_most, is_right_most); +} + +template +inline typename ZIntrusiveRBTree::FindCursor ZIntrusiveRBTree::get_cursor(const ZIntrusiveRBTreeNode* node) const { + if (node == nullptr) { + // Return a invalid cursor + return FindCursor(); + } + const bool is_left_most = node == _left_most; + const bool is_right_most = node == _right_most; + if (node->has_parent()) { + const ZIntrusiveRBTreeNode* const parent = node->parent(); + if (parent->left_child() == node) { + return make_cursor(parent->left_child_addr(), nullptr, is_left_most, is_right_most); + } + assert(parent->right_child() == node, "must be"); + return make_cursor(parent->right_child_addr(), nullptr, is_left_most, is_right_most); + } + // No parent, root node + return make_cursor(&_root_node, nullptr, is_left_most, is_right_most); +} + +template +inline typename ZIntrusiveRBTree::FindCursor ZIntrusiveRBTree::prev_cursor(const ZIntrusiveRBTreeNode* node) const { + return prev(get_cursor(node)); +} + +template +inline typename ZIntrusiveRBTree::FindCursor ZIntrusiveRBTree::next_cursor(const ZIntrusiveRBTreeNode* node) const { + return next(get_cursor(node)); +} + +template +inline typename ZIntrusiveRBTree::FindCursor ZIntrusiveRBTree::prev(const FindCursor& cursor) const { + return find_next(cursor); +} + +template +inline typename ZIntrusiveRBTree::FindCursor ZIntrusiveRBTree::next(const FindCursor& cursor) const { + return find_next(cursor); +} + +template +inline typename ZIntrusiveRBTree::FindCursor ZIntrusiveRBTree::find(const Key& key) const { + Compare compare_fn; + ZIntrusiveRBTreeNode* const* insert_location = root_node_addr(); + ZIntrusiveRBTreeNode* parent = nullptr; + bool left_most = true; + bool right_most = true; + while (*insert_location != nullptr) { + int result = compare_fn(key, *insert_location); + if (result == 0) { + assert(*insert_location != _left_most || left_most, "must be"); + assert(*insert_location != _right_most || right_most, "must be"); + return make_cursor(insert_location, parent, *insert_location == _left_most, *insert_location == _right_most); + } + parent = *insert_location; + if (result < 0) { + insert_location = parent->left_child_addr(); + // We took one step to the left, cannot be right_most. + right_most = false; + } else { + insert_location = parent->right_child_addr(); + // We took one step to the right, cannot be left_most. + left_most = false; + } + } + return make_cursor(insert_location, parent, left_most, right_most); +} + +template +inline void ZIntrusiveRBTree::insert(ZIntrusiveRBTreeNode* new_node, const FindCursor& find_cursor) { + precond(find_cursor.is_valid(_sequence_number)); + precond(!find_cursor.found()); + DEBUG_ONLY(_sequence_number++;) + + // Link in the new node + new_node->link_node(find_cursor.parent(), find_cursor.insert_location()); + + // Keep track of first and last node(s) + if (find_cursor.is_left_most()) { + _left_most = new_node; + } + if (find_cursor.is_right_most()) { + _right_most = new_node; + } + + rebalance_insert(new_node); +} + +template +inline void ZIntrusiveRBTree::replace(ZIntrusiveRBTreeNode* new_node, const FindCursor& find_cursor) { + precond(find_cursor.is_valid(_sequence_number)); + precond(find_cursor.found()); + DEBUG_ONLY(_sequence_number++;) + + const ZIntrusiveRBTreeNode* const node = find_cursor.node(); + + if (new_node != node) { + // Node has changed + + // Copy the node to new location + *new_node = *node; + + // Update insert location + *find_cursor.insert_location() = new_node; + + // Update children's parent + if (new_node->has_left_child()) { + new_node->left_child()->update_parent(new_node); + } + if (new_node->has_right_child()) { + new_node->right_child()->update_parent(new_node); + } + + // Keep track of first and last node(s) + if (find_cursor.is_left_most()) { + assert(_left_most == node, "must be"); + _left_most = new_node; + } + if (find_cursor.is_right_most()) { + assert(_right_most == node, "must be"); + _right_most = new_node; + } + } +} + +template +inline void ZIntrusiveRBTree::remove(const FindCursor& find_cursor) { + precond(find_cursor.is_valid(_sequence_number)); + precond(find_cursor.found()); + DEBUG_ONLY(_sequence_number++;) + + ZIntrusiveRBTreeNode* const node = find_cursor.node(); + ZIntrusiveRBTreeNode* const parent = node->parent(); + + // Keep track of first and last node(s) + if (find_cursor.is_left_most()) { + assert(_left_most == node, "must be"); + _left_most = _left_most->next(); + } + if (find_cursor.is_right_most()) { + assert(_right_most == node, "must be"); + _right_most = _right_most->prev(); + } + + ZIntrusiveRBTreeNode* rebalance_from = nullptr; + + if (!node->has_left_child() && !node->has_right_child()) { + // No children + + // Remove node + update_child_or_root(node, nullptr, parent); + if (node->is_black()) { + // We unbalanced the tree + rebalance_from = parent; + } + } else if (!node->has_left_child() || !node->has_right_child()) { + assert(node->has_right_child() || node->has_left_child(), "must be"); + // Only one child + ZIntrusiveRBTreeNode* child = node->has_left_child() ? node->left_child() : node->right_child(); + + // Let child take nodes places + update_child_or_root(node, child, parent); + + // And update parent and color + child->copy_parent_and_color(node); + } else { + assert(node->has_left_child() && node->has_right_child(), "must be"); + // Find next node and let it take the nodes place + // This asymmetry always swap next instead of prev, + // I wonder how this behaves w.r.t. our mapped cache + // strategy of mostly removing from the left side of + // the tree + + // This will never walk up the tree, hope the compiler sees this. + ZIntrusiveRBTreeNode* next_node = node->next(); + + ZIntrusiveRBTreeNode* next_node_parent = next_node->parent(); + ZIntrusiveRBTreeNode* next_node_child = next_node->right_child(); + if (next_node_parent != node) { + // Not the direct descendant, adopt node's child + ZIntrusiveRBTreeNode* node_child = node->right_child(); + next_node->update_right_child(node_child); + node_child->update_parent(next_node); + + // And let parent adopt their grand child + next_node_parent->update_left_child(next_node_child); + } else { + next_node_parent = next_node; + } + // Adopt node's other child + ZIntrusiveRBTreeNode* node_child = node->left_child(); + next_node->update_left_child(node_child); + node_child->update_parent(next_node); + + update_child_or_root(node, next_node, parent); + + // Update parent(s) and colors + if (next_node_child != nullptr) { + next_node_child->update_parent_and_color(next_node_parent, ZIntrusiveRBTreeNode::BLACK); + } else if (next_node->is_black()) { + rebalance_from = next_node_parent; + } + next_node->copy_parent_and_color(node); + } + + if (rebalance_from == nullptr) { + // Removal did not unbalance the tree + return; + } + + rebalance_remove(rebalance_from); +} + +template +inline void ZIntrusiveRBTree::verify_tree() { + // Properties: + // (a) Node's are either BLACK or RED + // (b) All nullptr children are counted as BLACK + // (c) Compare::operator(Node*, Node*) <=> 0 is transitive + // Invariants: + // (1) Root node is BLACK + // (2) All RED nodes only have BLACK children + // (3) Every simple path from the root to a leaf + // contains the same amount of BLACK nodes + // (4) A node's children must have that node as + // its parent + // (5) Each node N in the sub-tree formed from a + // node A's child must: + // if left child: Compare::operator(A, N) < 0 + // if right child: Compare::operator(A, N) > 0 + // + // Note: 1-4 may not hold during a call to insert + // and remove. + + // Helpers + const auto is_leaf = [](ZIntrusiveRBTreeNode* node) { + return node == nullptr; + }; + const auto is_black = [&](ZIntrusiveRBTreeNode* node) { + return is_leaf(node) || node->is_black(); + }; + const auto is_red = [&](ZIntrusiveRBTreeNode* node) { + return !is_black(node); + }; + + // Verify (1) + ZIntrusiveRBTreeNode* const root_node = _root_node; + guarantee(is_black(root_node), "Invariant (1)"); + + // Verify (2) + const auto verify_2 = [&](ZIntrusiveRBTreeNode* node) { + guarantee(!is_red(node) || is_black(node->left_child()), "Invariant (2)"); + guarantee(!is_red(node) || is_black(node->right_child()), "Invariant (2)"); + }; + + // Verify (3) + size_t first_simple_path_black_nodes_traversed = 0; + const auto verify_3 = [&](ZIntrusiveRBTreeNode* node, size_t black_nodes_traversed) { + if (!is_leaf(node)) { return; } + if (first_simple_path_black_nodes_traversed == 0) { + first_simple_path_black_nodes_traversed = black_nodes_traversed; + } + guarantee(first_simple_path_black_nodes_traversed == black_nodes_traversed, "Invariant (3)"); + }; + + // Verify (4) + const auto verify_4 = [&](ZIntrusiveRBTreeNode* node) { + if (is_leaf(node)) { return; } + guarantee(!node->has_left_child() || node->left_child()->parent() == node, "Invariant (4)"); + guarantee(!node->has_right_child() || node->right_child()->parent() == node, "Invariant (4)"); + }; + guarantee(root_node == nullptr || root_node->parent() == nullptr, "Invariant (4)"); + + // Verify (5) + const auto verify_5 = [&](ZIntrusiveRBTreeNode* node) { + // Because of the transitive property of Compare (c) we simply check + // this that (5) hold for each parent child pair. + if (is_leaf(node)) { return; } + Compare compare_fn; + guarantee(!node->has_left_child() || compare_fn(node->left_child(), node) < 0, "Invariant (5)"); + guarantee(!node->has_right_child() || compare_fn(node->right_child(), node) > 0, "Invariant (5)"); + }; + + // Walk every simple path by recursively descending the tree from the root + const auto recursive_walk = [&](auto&& recurse, ZIntrusiveRBTreeNode* node, size_t black_nodes_traversed) { + if (is_black(node)) { black_nodes_traversed++; } + verify_2(node); + verify_3(node, black_nodes_traversed); + verify_4(node); + verify_5(node); + if (is_leaf(node)) { return; } + recurse(recurse, node->left_child(), black_nodes_traversed); + recurse(recurse, node->right_child(), black_nodes_traversed); + }; + recursive_walk(recursive_walk, root_node, 0); +} + +template +inline typename ZIntrusiveRBTree::Iterator ZIntrusiveRBTree::begin() { + return Iterator(*this, first()); +} + +template +inline typename ZIntrusiveRBTree::Iterator ZIntrusiveRBTree::end() { + return Iterator(*this, nullptr); +} + +template +inline typename ZIntrusiveRBTree::ConstIterator ZIntrusiveRBTree::begin() const { + return cbegin(); +} + +template +inline typename ZIntrusiveRBTree::ConstIterator ZIntrusiveRBTree::end() const { + return cend(); +} + +template +inline typename ZIntrusiveRBTree::ConstIterator ZIntrusiveRBTree::cbegin() const { + return const_cast*>(this)->begin(); +} + +template +inline typename ZIntrusiveRBTree::ConstIterator ZIntrusiveRBTree::cend() const { + return const_cast*>(this)->end(); +} + +template +inline typename ZIntrusiveRBTree::ReverseIterator ZIntrusiveRBTree::rbegin() { + return ReverseIterator(*this, last()); +} + +template +inline typename ZIntrusiveRBTree::ReverseIterator ZIntrusiveRBTree::rend() { + return ReverseIterator(*this, nullptr); +} + +template +inline typename ZIntrusiveRBTree::ConstReverseIterator ZIntrusiveRBTree::rbegin() const { + return crbegin(); +} + +template +inline typename ZIntrusiveRBTree::ConstReverseIterator ZIntrusiveRBTree::rend() const { + return crend(); +} + +template +inline typename ZIntrusiveRBTree::ConstReverseIterator ZIntrusiveRBTree::crbegin() const { + return const_cast*>(this)->rbegin(); +} + +template +inline typename ZIntrusiveRBTree::ConstReverseIterator ZIntrusiveRBTree::crend() const { + return const_cast*>(this)->rend(); +} + +template +template +inline bool ZIntrusiveRBTree::IteratorImplementation::at_end() const { + return _node == nullptr; +} + +template +template +inline ZIntrusiveRBTree::IteratorImplementation::IteratorImplementation(ZIntrusiveRBTree& tree, pointer node) +: _tree(&tree), + _node(node), + _removed(false) {} + +template +template +template +inline ZIntrusiveRBTree::IteratorImplementation::IteratorImplementation(const IteratorImplementation& other) +: _tree(other._tree), + _node(other._node), + _removed(false) {} + +template +template +inline typename ZIntrusiveRBTree::template IteratorImplementation::reference ZIntrusiveRBTree::IteratorImplementation::operator*() const { + precond(!_removed); + return *_node; +} + +template +template +inline typename ZIntrusiveRBTree::template IteratorImplementation::pointer ZIntrusiveRBTree::IteratorImplementation::operator->() { + precond(!_removed); + return _node; +} + +template +template +inline typename ZIntrusiveRBTree::template IteratorImplementation& ZIntrusiveRBTree::IteratorImplementation::operator--() { + if (_removed) { + _removed = false; + } else if (Reverse) { + precond(_node != _tree->last()); + _node = at_end() ? _tree->first() : _node->next(); + } else { + precond(_node != _tree->first()); + _node = at_end() ? _tree->last() : _node->prev(); + } + return *this; +} + +template +template +inline typename ZIntrusiveRBTree::template IteratorImplementation ZIntrusiveRBTree::IteratorImplementation::operator--(int) { + IteratorImplementation tmp = *this; + --(*this); + return tmp; +} + +template +template +inline typename ZIntrusiveRBTree::template IteratorImplementation& ZIntrusiveRBTree::IteratorImplementation::operator++() { + if (_removed) { + _removed = false; + } else if (Reverse) { + precond(!at_end()); + _node = _node->prev(); + } else { + precond(!at_end()); + _node = _node->next(); + } + return *this; +} + +template +template +inline typename ZIntrusiveRBTree::template IteratorImplementation ZIntrusiveRBTree::IteratorImplementation::operator++(int) { + IteratorImplementation tmp = *this; + ++(*this); + return tmp; +} + +template +template +template +void ZIntrusiveRBTree::IteratorImplementation::replace(ZIntrusiveRBTreeNode* new_node) { + precond(!_removed); + precond(!at_end()); + FindCursor cursor = _tree->get_cursor(_node); + _node = new_node; + _tree->replace(new_node, cursor); +} + +template +template +template +void ZIntrusiveRBTree::IteratorImplementation::remove() { + precond(!_removed); + precond(!at_end()); + FindCursor cursor = _tree->get_cursor(_node); + ++(*this); + _removed = true; + _tree->remove(cursor); +} + +#endif // SHARE_GC_Z_ZINTRUSIVERBTREE_INLINE_HPP diff --git a/src/hotspot/share/gc/z/zList.hpp b/src/hotspot/share/gc/z/zList.hpp index 0da2f8238649a..36cefbbeef7d1 100644 --- a/src/hotspot/share/gc/z/zList.hpp +++ b/src/hotspot/share/gc/z/zList.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #define SHARE_GC_Z_ZLIST_HPP #include "memory/allocation.hpp" +#include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" template class ZList; @@ -46,7 +47,12 @@ class ZListNode { public: ZListNode(); - ~ZListNode(); + ~ZListNode() { + // Implementation placed here to make it easier easier to embed ZListNode + // instances without having to include zListNode.inline.hpp. + assert(_next == this, "Should not be in a list"); + assert(_prev == this, "Should not be in a list"); + } }; // Doubly linked list @@ -59,6 +65,7 @@ class ZList { NONCOPYABLE(ZList); void verify_head() const; + void verify_head_error_reporter_safe() const; void insert(ZListNode* before, ZListNode* node); @@ -68,6 +75,9 @@ class ZList { public: ZList(); + size_t size_error_reporter_safe() const; + bool is_empty_error_reporter_safe() const; + size_t size() const; bool is_empty() const; diff --git a/src/hotspot/share/gc/z/zList.inline.hpp b/src/hotspot/share/gc/z/zList.inline.hpp index 9c4f2b8fbf2d8..20edfaa620b85 100644 --- a/src/hotspot/share/gc/z/zList.inline.hpp +++ b/src/hotspot/share/gc/z/zList.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,17 +27,13 @@ #include "gc/z/zList.hpp" #include "utilities/debug.hpp" +#include "utilities/vmError.hpp" template inline ZListNode::ZListNode() : _next(this), _prev(this) {} -template -inline ZListNode::~ZListNode() { - verify_links_unlinked(); -} - template inline void ZListNode::verify_links() const { assert(_next->_prev == this, "Corrupt list node"); @@ -62,6 +58,16 @@ inline void ZList::verify_head() const { _head.verify_links(); } +template +inline void ZList::verify_head_error_reporter_safe() const { + if (VMError::is_error_reported() && VMError::is_error_reported_in_current_thread()) { + // Do not verify if this thread is in the process of reporting an error. + return; + } + + verify_head(); +} + template inline void ZList::insert(ZListNode* before, ZListNode* node) { verify_head(); @@ -97,6 +103,17 @@ inline ZList::ZList() verify_head(); } +template +inline size_t ZList::size_error_reporter_safe() const { + verify_head_error_reporter_safe(); + return _size; +} + +template +inline bool ZList::is_empty_error_reporter_safe() const { + return size_error_reporter_safe() == 0; +} + template inline size_t ZList::size() const { verify_head(); diff --git a/src/hotspot/share/gc/z/zLiveMap.cpp b/src/hotspot/share/gc/z/zLiveMap.cpp index ef125af9c2e8f..5b9e0a932c353 100644 --- a/src/hotspot/share/gc/z/zLiveMap.cpp +++ b/src/hotspot/share/gc/z/zLiveMap.cpp @@ -34,24 +34,19 @@ static const ZStatCounter ZCounterMarkSeqNumResetContention("Contention", "Mark SeqNum Reset Contention", ZStatUnitOpsPerSecond); static const ZStatCounter ZCounterMarkSegmentResetContention("Contention", "Mark Segment Reset Contention", ZStatUnitOpsPerSecond); -static size_t bitmap_size(uint32_t size, size_t NumSegments) { - // We need at least one bit per segment - return MAX2(size, NumSegments) * 2; -} - -ZLiveMap::ZLiveMap(uint32_t size) - : _seqnum(0), +ZLiveMap::ZLiveMap(uint32_t object_max_count) + : _segment_size((object_max_count == 1 ? 1u : (object_max_count / NumSegments)) * BitsPerObject), + _segment_shift(log2i_exact(_segment_size)), + _seqnum(0), _live_objects(0), _live_bytes(0), _segment_live_bits(0), _segment_claim_bits(0), - _bitmap_size(bitmap_size(size, NumSegments)), - _bitmap(0), - _segment_shift(log2i_exact(segment_size())) {} + _bitmap(0) {} -void ZLiveMap::allocate_bitmap() { - if (_bitmap.size() != _bitmap_size) { - _bitmap.initialize(_bitmap_size, false /* clear */); +void ZLiveMap::initialize_bitmap() { + if (_bitmap.size() == 0) { + _bitmap.initialize(size_t(_segment_size) * size_t(NumSegments), false /* clear */); } } @@ -71,14 +66,14 @@ void ZLiveMap::reset(ZGenerationId id) { _live_bytes = 0; _live_objects = 0; - // We lazily initialize the bitmap the first time the page is - // marked, i.e. a bit is about to be set for the first time. - allocate_bitmap(); - // Clear segment claimed/live bits segment_live_bits().clear(); segment_claim_bits().clear(); + // We lazily initialize the bitmap the first time the page is marked, i.e. + // a bit is about to be set for the first time. + initialize_bitmap(); + assert(_seqnum == seqnum_initializing, "Invalid"); // Make sure the newly reset marking information is ordered @@ -125,7 +120,7 @@ void ZLiveMap::reset_segment(BitMap::idx_t segment) { // Segment claimed, clear it const BitMap::idx_t start_index = segment_start(segment); const BitMap::idx_t end_index = segment_end(segment); - if (segment_size() / BitsPerWord >= 32) { + if (_segment_size / BitsPerWord >= 32) { _bitmap.clear_large_range(start_index, end_index); } else { _bitmap.clear_range(start_index, end_index); @@ -135,13 +130,3 @@ void ZLiveMap::reset_segment(BitMap::idx_t segment) { const bool success = set_segment_live(segment); assert(success, "Should never fail"); } - -void ZLiveMap::resize(uint32_t size) { - const size_t new_bitmap_size = bitmap_size(size, NumSegments); - _bitmap_size = new_bitmap_size; - _segment_shift = log2i_exact(segment_size()); - - if (_bitmap.size() != 0 && _bitmap.size() != new_bitmap_size) { - _bitmap.reinitialize(new_bitmap_size, false /* clear */); - } -} diff --git a/src/hotspot/share/gc/z/zLiveMap.hpp b/src/hotspot/share/gc/z/zLiveMap.hpp index 9f6514b574f7a..71457d05a419c 100644 --- a/src/hotspot/share/gc/z/zLiveMap.hpp +++ b/src/hotspot/share/gc/z/zLiveMap.hpp @@ -35,16 +35,18 @@ class ZLiveMap { friend class ZLiveMapTest; private: - static const size_t NumSegments = 64; + static const uint32_t NumSegments = 64; + static const uint32_t BitsPerObject = 2; + + const uint32_t _segment_size; + const int _segment_shift; volatile uint32_t _seqnum; volatile uint32_t _live_objects; volatile size_t _live_bytes; BitMap::bm_word_t _segment_live_bits; BitMap::bm_word_t _segment_claim_bits; - size_t _bitmap_size; ZBitMap _bitmap; - int _segment_shift; const BitMapView segment_live_bits() const; const BitMapView segment_claim_bits() const; @@ -52,8 +54,6 @@ class ZLiveMap { BitMapView segment_live_bits(); BitMapView segment_claim_bits(); - BitMap::idx_t segment_size() const; - BitMap::idx_t segment_start(BitMap::idx_t segment) const; BitMap::idx_t segment_end(BitMap::idx_t segment) const; @@ -66,7 +66,7 @@ class ZLiveMap { bool claim_segment(BitMap::idx_t segment); - void allocate_bitmap(); + void initialize_bitmap(); void reset(ZGenerationId id); void reset_segment(BitMap::idx_t segment); @@ -77,11 +77,10 @@ class ZLiveMap { void iterate_segment(BitMap::idx_t segment, Function function); public: - ZLiveMap(uint32_t size); + ZLiveMap(uint32_t object_max_count); ZLiveMap(const ZLiveMap& other) = delete; void reset(); - void resize(uint32_t size); bool is_marked(ZGenerationId id) const; diff --git a/src/hotspot/share/gc/z/zLiveMap.inline.hpp b/src/hotspot/share/gc/z/zLiveMap.inline.hpp index fdbbdfaba0e08..a7f836a85596e 100644 --- a/src/hotspot/share/gc/z/zLiveMap.inline.hpp +++ b/src/hotspot/share/gc/z/zLiveMap.inline.hpp @@ -87,10 +87,6 @@ inline BitMap::idx_t ZLiveMap::next_live_segment(BitMap::idx_t segment) const { return segment_live_bits().find_first_set_bit(segment + 1, NumSegments); } -inline BitMap::idx_t ZLiveMap::segment_size() const { - return _bitmap_size / NumSegments; -} - inline BitMap::idx_t ZLiveMap::index_to_segment(BitMap::idx_t index) const { return index >> _segment_shift; } @@ -125,11 +121,11 @@ inline void ZLiveMap::inc_live(uint32_t objects, size_t bytes) { } inline BitMap::idx_t ZLiveMap::segment_start(BitMap::idx_t segment) const { - return segment_size() * segment; + return segment * _segment_size; } inline BitMap::idx_t ZLiveMap::segment_end(BitMap::idx_t segment) const { - return segment_start(segment) + segment_size(); + return segment_start(segment) + _segment_size; } inline size_t ZLiveMap::do_object(ObjectClosure* cl, zaddress addr) const { diff --git a/src/hotspot/share/gc/z/zMappedCache.cpp b/src/hotspot/share/gc/z/zMappedCache.cpp new file mode 100644 index 0000000000000..c1c6e9edee9ed --- /dev/null +++ b/src/hotspot/share/gc/z/zMappedCache.cpp @@ -0,0 +1,629 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "gc/z/zAddress.inline.hpp" +#include "gc/z/zGlobals.hpp" +#include "gc/z/zIntrusiveRBTree.inline.hpp" +#include "gc/z/zList.inline.hpp" +#include "gc/z/zMappedCache.hpp" +#include "gc/z/zVirtualMemory.inline.hpp" +#include "utilities/align.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/powerOfTwo.hpp" + +class ZMappedCacheEntry { +private: + ZVirtualMemory _vmem; + ZMappedCache::TreeNode _tree_node; + ZMappedCache::SizeClassListNode _size_class_list_node; + +public: + ZMappedCacheEntry(ZVirtualMemory vmem) + : _vmem(vmem), + _tree_node(), + _size_class_list_node() {} + + static ZMappedCacheEntry* cast_to_entry(ZMappedCache::TreeNode* tree_node); + static const ZMappedCacheEntry* cast_to_entry(const ZMappedCache::TreeNode* tree_node); + static ZMappedCacheEntry* cast_to_entry(ZMappedCache::SizeClassListNode* list_node); + + zoffset start() const { + return _vmem.start(); + } + + zoffset_end end() const { + return _vmem.end(); + } + + ZVirtualMemory vmem() const { + return _vmem; + } + + ZMappedCache::TreeNode* node_addr() { + return &_tree_node; + } + + void update_start(ZVirtualMemory vmem) { + precond(vmem.end() == end()); + + _vmem = vmem; + } + + ZMappedCache::ZSizeClassListNode* size_class_node() { + return &_size_class_list_node; + } +}; + +ZMappedCacheEntry* ZMappedCacheEntry::cast_to_entry(ZMappedCache::TreeNode* tree_node) { + return const_cast(ZMappedCacheEntry::cast_to_entry(const_cast(tree_node))); +} + +const ZMappedCacheEntry* ZMappedCacheEntry::cast_to_entry(const ZMappedCache::TreeNode* tree_node) { + return (const ZMappedCacheEntry*)((uintptr_t)tree_node - offset_of(ZMappedCacheEntry, _tree_node)); +} + +ZMappedCacheEntry* ZMappedCacheEntry::cast_to_entry(ZMappedCache::SizeClassListNode* list_node) { + const size_t offset = offset_of(ZMappedCacheEntry, _size_class_list_node); + return (ZMappedCacheEntry*)((uintptr_t)list_node - offset); +} + +static void* entry_address_for_zoffset_end(zoffset_end offset) { + STATIC_ASSERT(is_aligned(ZCacheLineSize, alignof(ZMappedCacheEntry)));; + + // This spreads out the location of the entries in an effort to combat hyper alignment. + // Verify if this is an efficient and worthwhile optimization. + + constexpr size_t aligned_entry_size = align_up(sizeof(ZMappedCacheEntry), ZCacheLineSize); + + // Do not use the last location + constexpr size_t number_of_locations = ZGranuleSize / aligned_entry_size - 1; + const size_t granule_index = untype(offset) >> ZGranuleSizeShift; + const size_t index = granule_index % number_of_locations; + const uintptr_t end_addr = untype(offset) + ZAddressHeapBase; + + return reinterpret_cast(end_addr - aligned_entry_size * (index + 1)); +} + +static ZMappedCacheEntry* create_entry(const ZVirtualMemory& vmem) { + precond(vmem.size() >= ZGranuleSize); + + void* placement_addr = entry_address_for_zoffset_end(vmem.end()); + ZMappedCacheEntry* entry = new (placement_addr) ZMappedCacheEntry(vmem); + + postcond(entry->start() == vmem.start()); + postcond(entry->end() == vmem.end()); + + return entry; +} + +int ZMappedCache::EntryCompare::operator()(ZMappedCache::TreeNode* a, ZMappedCache::TreeNode* b) { + const ZVirtualMemory vmem_a = ZMappedCacheEntry::cast_to_entry(a)->vmem(); + const ZVirtualMemory vmem_b = ZMappedCacheEntry::cast_to_entry(b)->vmem(); + + if (vmem_a.end() < vmem_b.start()) { return -1; } + if (vmem_b.end() < vmem_a.start()) { return 1; } + + return 0; // Overlapping +} + +int ZMappedCache::EntryCompare::operator()(zoffset key, ZMappedCache::TreeNode* node) { + const ZVirtualMemory vmem = ZMappedCacheEntry::cast_to_entry(node)->vmem(); + + if (key < vmem.start()) { return -1; } + if (key > vmem.end()) { return 1; } + + return 0; // Containing +} + +int ZMappedCache::size_class_index(size_t size) { + // Returns the size class index of for size, or -1 if smaller than the smallest size class. + const int size_class_power = log2i_graceful(size) - (int)ZGranuleSizeShift; + + if (size_class_power < MinSizeClassShift) { + // Allocation is smaller than the smallest size class minimum size. + return -1; + } + + return MIN2(size_class_power, MaxSizeClassShift) - MinSizeClassShift; +} + +int ZMappedCache::guaranteed_size_class_index(size_t size) { + // Returns the size class index of the smallest size class which can always + // accommodate a size allocation, or -1 otherwise. + const int size_class_power = log2i_ceil(size) - (int)ZGranuleSizeShift; + + if (size_class_power > MaxSizeClassShift) { + // Allocation is larger than the largest size class minimum size. + return -1; + } + + return MAX2(size_class_power, MinSizeClassShift) - MinSizeClassShift; +} + +void ZMappedCache::tree_insert(const Tree::FindCursor& cursor, const ZVirtualMemory& vmem) { + ZMappedCacheEntry* const entry = create_entry(vmem); + + // Insert creates a new entry + _entry_count += 1; + + // Insert in tree + _tree.insert(entry->node_addr(), cursor); + + // Insert in size-class lists + const size_t size = vmem.size(); + const int index = size_class_index(size); + if (index != -1) { + _size_class_lists[index].insert_first(entry->size_class_node()); + } +} + +void ZMappedCache::tree_remove(const Tree::FindCursor& cursor, const ZVirtualMemory& vmem) { + ZMappedCacheEntry* entry = ZMappedCacheEntry::cast_to_entry(cursor.node()); + + // Remove destroys an old entry + _entry_count -= 1; + + // Remove from tree + _tree.remove(cursor); + + // Insert in size-class lists + const size_t size = vmem.size(); + const int index = size_class_index(size); + if (index != -1) { + _size_class_lists[index].remove(entry->size_class_node()); + } + + // Destroy entry + entry->~ZMappedCacheEntry(); +} + +void ZMappedCache::tree_replace(const Tree::FindCursor& cursor, const ZVirtualMemory& vmem) { + ZMappedCacheEntry* const entry = create_entry(vmem); + + ZMappedCache::TreeNode* const node = cursor.node(); + ZMappedCacheEntry* const old_entry = ZMappedCacheEntry::cast_to_entry(node); + assert(old_entry->end() != vmem.end(), "should not replace, use update"); + + // Replace in tree + _tree.replace(entry->node_addr(), cursor); + + // Replace in size-class lists + + // Remove old + const size_t old_size = old_entry->vmem().size(); + const int old_index = size_class_index(old_size); + if (old_index != -1) { + _size_class_lists[old_index].remove(old_entry->size_class_node()); + } + + // Insert new + const size_t new_size = vmem.size(); + const int new_index = size_class_index(new_size); + if (new_index != -1) { + _size_class_lists[new_index].insert_first(entry->size_class_node()); + } + + // Destroy old entry + old_entry->~ZMappedCacheEntry(); +} + +void ZMappedCache::tree_update(ZMappedCacheEntry* entry, const ZVirtualMemory& vmem) { + assert(entry->end() == vmem.end(), "must be"); + + // Remove or add to size-class lists if required + + const size_t old_size = entry->vmem().size(); + const size_t new_size = vmem.size(); + const int old_index = size_class_index(old_size); + const int new_index = size_class_index(new_size); + + if (old_index != new_index) { + // Size class changed + + // Remove old + if (old_index != -1) { + _size_class_lists[old_index].remove(entry->size_class_node()); + } + + // Insert new + if (new_index != -1) { + _size_class_lists[new_index].insert_first(entry->size_class_node()); + } + } + + // And update entry + entry->update_start(vmem); +} + +template +ZVirtualMemory ZMappedCache::remove_vmem(ZMappedCacheEntry* const entry, size_t min_size, SelectFunction select) { + ZVirtualMemory vmem = entry->vmem(); + const size_t size = vmem.size(); + + if (size < min_size) { + // Do not select this, smaller than min_size + return ZVirtualMemory(); + } + + // Query how much to remove + const size_t to_remove = select(size); + assert(to_remove <= size, "must not remove more than size"); + + if (to_remove == 0) { + // Nothing to remove + return ZVirtualMemory(); + } + + if (to_remove != size) { + // Partial removal + if (strategy == RemovalStrategy::LowestAddress) { + const size_t unused_size = size - to_remove; + const ZVirtualMemory unused_vmem = vmem.shrink_from_back(unused_size); + tree_update(entry, unused_vmem); + + } else { + assert(strategy == RemovalStrategy::HighestAddress, "must be LowestAddress or HighestAddress"); + + const size_t unused_size = size - to_remove; + const ZVirtualMemory unused_vmem = vmem.shrink_from_front(unused_size); + + auto cursor = _tree.get_cursor(entry->node_addr()); + assert(cursor.is_valid(), "must be"); + tree_replace(cursor, unused_vmem); + } + + } else { + // Whole removal + auto cursor = _tree.get_cursor(entry->node_addr()); + assert(cursor.is_valid(), "must be"); + tree_remove(cursor, vmem); + } + + // Update statistics + _size -= to_remove; + _min = MIN2(_size, _min); + + postcond(to_remove == vmem.size()); + return vmem; +} + +template +bool ZMappedCache::try_remove_vmem_size_class(size_t min_size, SelectFunction select, ConsumeFunction consume) { +new_max_size: + // Query the max select size possible given the size of the cache + const size_t max_size = select(_size); + + if (max_size < min_size) { + // Never select less than min_size + return false; + } + + // Start scanning from max_size guaranteed size class to the largest size class + const int guaranteed_index = guaranteed_size_class_index(max_size); + for (int index = guaranteed_index; index != -1 && index < NumSizeClasses; ++index) { + ZList& list = _size_class_lists[index]; + if (!list.is_empty()) { + ZMappedCacheEntry* const entry = ZMappedCacheEntry::cast_to_entry(list.first()); + + // Because this is guaranteed, select should always succeed + const ZVirtualMemory vmem = remove_vmem(entry, min_size, select); + assert(!vmem.is_null(), "select must succeed"); + + if (consume(vmem)) { + // consume is satisfied + return true; + } + + // Continue with a new max_size + goto new_max_size; + } + } + + // Consume the rest starting at max_size's size class to min_size's size class + const int max_size_index = size_class_index(max_size); + const int min_size_index = size_class_index(min_size); + const int lowest_index = MAX2(min_size_index, 0); + + for (int index = max_size_index; index >= lowest_index; --index) { + ZListIterator iter(&_size_class_lists[index]); + for (ZSizeClassListNode* list_node; iter.next(&list_node);) { + ZMappedCacheEntry* const entry = ZMappedCacheEntry::cast_to_entry(list_node); + + // Try remove + const ZVirtualMemory vmem = remove_vmem(entry, min_size, select); + + if (!vmem.is_null() && consume(vmem)) { + // Found a vmem and consume is satisfied + return true; + } + } + } + + // consume was not satisfied + return false; +} + +template +void ZMappedCache::scan_remove_vmem(size_t min_size, SelectFunction select, ConsumeFunction consume) { + if (strategy == RemovalStrategy::SizeClasses) { + if (try_remove_vmem_size_class(min_size, select, consume)) { + // Satisfied using size classes + return; + } + + if (size_class_index(min_size) != -1) { + // There exists a size class for our min size. All possibilities must have + // been exhausted, do not scan the tree. + return; + } + + // Fallthrough to tree scan + } + + if (strategy == RemovalStrategy::HighestAddress) { + // Scan whole tree starting at the highest address + for (ZMappedCache::TreeNode* node = _tree.last(); node != nullptr; node = node->prev()) { + ZMappedCacheEntry* const entry = ZMappedCacheEntry::cast_to_entry(node); + + const ZVirtualMemory vmem = remove_vmem(entry, min_size, select); + + if (!vmem.is_null() && consume(vmem)) { + // Found a vmem and consume is satisfied. + return; + } + } + + } else { + assert(strategy == RemovalStrategy::SizeClasses || strategy == RemovalStrategy::LowestAddress, "unknown strategy"); + + // Scan whole tree starting at the lowest address + for (ZMappedCache::TreeNode* node = _tree.first(); node != nullptr; node = node->next()) { + ZMappedCacheEntry* const entry = ZMappedCacheEntry::cast_to_entry(node); + + const ZVirtualMemory vmem = remove_vmem(entry, min_size, select); + + if (!vmem.is_null() && consume(vmem)) { + // Found a vmem and consume is satisfied. + return; + } + } + } +} + +template +void ZMappedCache::scan_remove_vmem(SelectFunction select, ConsumeFunction consume) { + // Scan without a min_size + scan_remove_vmem(0, select, consume); +} + +template +size_t ZMappedCache::remove_discontiguous_with_strategy(size_t size, ZArray* out) { + precond(size > 0); + precond(is_aligned(size, ZGranuleSize)); + + size_t remaining = size; + + const auto select_size_fn = [&](size_t vmem_size) { + // Select at most remaining + return MIN2(remaining, vmem_size); + }; + + const auto consume_vmem_fn = [&](ZVirtualMemory vmem) { + const size_t vmem_size = vmem.size(); + out->append(vmem); + + assert(vmem_size <= remaining, "consumed to much"); + + // Track remaining, and stop when it reaches zero + remaining -= vmem_size; + + return remaining == 0; + }; + + scan_remove_vmem(select_size_fn, consume_vmem_fn); + + return size - remaining; +} + +ZMappedCache::ZMappedCache() + : _tree(), + _entry_count(0), + _size_class_lists{}, + _size(0), + _min(_size) {} + +void ZMappedCache::insert(const ZVirtualMemory& vmem) { + _size += vmem.size(); + + Tree::FindCursor current_cursor = _tree.find(vmem.start()); + Tree::FindCursor next_cursor = _tree.next(current_cursor); + + const bool extends_left = current_cursor.found(); + const bool extends_right = next_cursor.is_valid() && next_cursor.found() && + ZMappedCacheEntry::cast_to_entry(next_cursor.node())->start() == vmem.end(); + + if (extends_left && extends_right) { + ZMappedCacheEntry* next_entry = ZMappedCacheEntry::cast_to_entry(next_cursor.node()); + + const ZVirtualMemory left_vmem = ZMappedCacheEntry::cast_to_entry(current_cursor.node())->vmem(); + const ZVirtualMemory right_vmem = next_entry->vmem(); + assert(left_vmem.adjacent_to(vmem), "must be"); + assert(vmem.adjacent_to(right_vmem), "must be"); + + ZVirtualMemory new_vmem = left_vmem; + new_vmem.grow_from_back(vmem.size()); + new_vmem.grow_from_back(right_vmem.size()); + + // Remove current (left vmem) + tree_remove(current_cursor, left_vmem); + + // And update next's start + tree_update(next_entry, new_vmem); + + return; + } + + if (extends_left) { + const ZVirtualMemory left_vmem = ZMappedCacheEntry::cast_to_entry(current_cursor.node())->vmem(); + assert(left_vmem.adjacent_to(vmem), "must be"); + + ZVirtualMemory new_vmem = left_vmem; + new_vmem.grow_from_back(vmem.size()); + + tree_replace(current_cursor, new_vmem); + + return; + } + + if (extends_right) { + ZMappedCacheEntry* next_entry = ZMappedCacheEntry::cast_to_entry(next_cursor.node()); + + const ZVirtualMemory right_vmem = next_entry->vmem(); + assert(vmem.adjacent_to(right_vmem), "must be"); + + ZVirtualMemory new_vmem = vmem; + new_vmem.grow_from_back(right_vmem.size()); + + // Update next's start + tree_update(next_entry, new_vmem); + + return; + } + + tree_insert(current_cursor, vmem); +} + +ZVirtualMemory ZMappedCache::remove_contiguous(size_t size) { + precond(size > 0); + precond(is_aligned(size, ZGranuleSize)); + + ZVirtualMemory result; + + const auto select_size_fn = [&](size_t) { + // We always select the size + return size; + }; + + const auto consume_vmem_fn = [&](ZVirtualMemory vmem) { + assert(result.is_null(), "only consume once"); + assert(vmem.size() == size, "wrong size consumed"); + + result = vmem; + + // Only require one vmem + return true; + }; + + if (size == ZPageSizeSmall) { + // Small page allocations allocate at the lowest possible address + scan_remove_vmem(size, select_size_fn, consume_vmem_fn); + } else { + // Other sizes uses approximate best fit size classes first + scan_remove_vmem(size, select_size_fn, consume_vmem_fn); + } + + return result; +} + +size_t ZMappedCache::remove_discontiguous(size_t size, ZArray* out) { + return remove_discontiguous_with_strategy(size, out); +} + +size_t ZMappedCache::reset_min() { + const size_t old_min = _min; + + _min = _size; + + return old_min; +} + +size_t ZMappedCache::remove_from_min(size_t max_size, ZArray* out) { + const size_t size = MIN2(_min, max_size); + + if (size == 0) { + return 0; + } + + return remove_discontiguous_with_strategy(size, out); +} + +void ZMappedCache::print_on(outputStream* st) const { + // This may be called from error printing where we may not hold the lock, so + // values may be inconsistent. As such we read the _entry_count only once. And + // use is_empty_error_reporter_safe and size_error_reporter_safe on the size + // class lists. + const size_t entry_count = Atomic::load(&_entry_count); + + st->print("Cache"); + st->fill_to(17); + st->print_cr("%zuM (%zu)", _size / M, entry_count); + + if (entry_count == 0) { + // Empty cache, skip printing size classes + return; + } + + // Aggregate the number of size class entries + size_t size_class_entry_count = 0; + for (int index = 0; index < NumSizeClasses; ++index) { + size_class_entry_count += _size_class_lists[index].size_error_reporter_safe(); + } + + // Print information on size classes + streamIndentor indentor(st, 1); + + st->print("size classes"); + st->fill_to(17); + + // Print the number of entries smaller than the min size class's size + const size_t small_entry_size_count = entry_count - size_class_entry_count; + bool first = true; + if (small_entry_size_count != 0) { + st->print(EXACTFMT " (%zu)", EXACTFMTARGS(ZGranuleSize), small_entry_size_count); + first = false; + } + + for (int index = 0; index < NumSizeClasses; ++index) { + const ZList& list = _size_class_lists[index]; + if (!list.is_empty_error_reporter_safe()) { + const int shift = index + MinSizeClassShift + (int)ZGranuleSizeShift; + const size_t size = (size_t)1 << shift; + + st->print("%s" EXACTFMT " (%zu)", first ? "" : ", ", EXACTFMTARGS(size), list.size_error_reporter_safe()); + first = false; + } + } + + st->cr(); +} + +void ZMappedCache::print_extended_on(outputStream* st) const { + // Print the ranges and size of all nodes in the tree + for (ZMappedCache::TreeNode* node = _tree.first(); node != nullptr; node = node->next()) { + const ZVirtualMemory vmem = ZMappedCacheEntry::cast_to_entry(node)->vmem(); + + st->print_cr(PTR_FORMAT " " PTR_FORMAT " " EXACTFMT, + untype(vmem.start()), untype(vmem.end()), EXACTFMTARGS(vmem.size())); + } +} diff --git a/src/hotspot/share/gc/z/zMappedCache.hpp b/src/hotspot/share/gc/z/zMappedCache.hpp new file mode 100644 index 0000000000000..8d1c90fd00334 --- /dev/null +++ b/src/hotspot/share/gc/z/zMappedCache.hpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_Z_ZMAPPEDCACHE_HPP +#define SHARE_GC_Z_ZMAPPEDCACHE_HPP + +#include "gc/z/zAddress.hpp" +#include "gc/z/zArray.hpp" +#include "gc/z/zGlobals.hpp" +#include "gc/z/zIntrusiveRBTree.hpp" +#include "gc/z/zList.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/ostream.hpp" + +class ZMappedCacheEntry; +class ZVirtualMemory; + +class ZMappedCache { + friend class ZMappedCacheEntry; + +private: + struct EntryCompare { + int operator()(ZIntrusiveRBTreeNode* a, ZIntrusiveRBTreeNode* b); + int operator()(zoffset key, ZIntrusiveRBTreeNode* node); + }; + + struct ZSizeClassListNode { + ZListNode _node; + }; + + using Tree = ZIntrusiveRBTree; + using TreeNode = ZIntrusiveRBTreeNode; + using SizeClassList = ZList; + using SizeClassListNode = ZSizeClassListNode; + + // Maintain size class lists from 4MB to 16GB + static constexpr int MaxLongArraySizeClassShift = 3 /* 8 byte */ + 31 /* max length */; + static constexpr int MinSizeClassShift = 1; + static constexpr int MaxSizeClassShift = MaxLongArraySizeClassShift - ZGranuleSizeShift; + static constexpr int NumSizeClasses = MaxSizeClassShift - MinSizeClassShift + 1; + + Tree _tree; + size_t _entry_count; + SizeClassList _size_class_lists[NumSizeClasses]; + size_t _size; + size_t _min; + + static int size_class_index(size_t size); + static int guaranteed_size_class_index(size_t size); + + void tree_insert(const Tree::FindCursor& cursor, const ZVirtualMemory& vmem); + void tree_remove(const Tree::FindCursor& cursor, const ZVirtualMemory& vmem); + void tree_replace(const Tree::FindCursor& cursor, const ZVirtualMemory& vmem); + void tree_update(ZMappedCacheEntry* entry, const ZVirtualMemory& vmem); + + enum class RemovalStrategy { + LowestAddress, + HighestAddress, + SizeClasses, + }; + + template + ZVirtualMemory remove_vmem(ZMappedCacheEntry* const entry, size_t min_size, SelectFunction select); + + template + bool try_remove_vmem_size_class(size_t min_size, SelectFunction select, ConsumeFunction consume); + + template + void scan_remove_vmem(size_t min_size, SelectFunction select, ConsumeFunction consume); + + template + void scan_remove_vmem(SelectFunction select, ConsumeFunction consume); + + template + size_t remove_discontiguous_with_strategy(size_t size, ZArray* out); + +public: + ZMappedCache(); + + void insert(const ZVirtualMemory& vmem); + + ZVirtualMemory remove_contiguous(size_t size); + size_t remove_discontiguous(size_t size, ZArray* out); + + size_t reset_min(); + size_t remove_from_min(size_t max_size, ZArray* out); + + void print_on(outputStream* st) const; + void print_extended_on(outputStream* st) const; +}; + +#endif // SHARE_GC_Z_ZMAPPEDCACHE_HPP diff --git a/src/hotspot/share/gc/z/zMemory.cpp b/src/hotspot/share/gc/z/zMemory.cpp deleted file mode 100644 index 35e95888d4d67..0000000000000 --- a/src/hotspot/share/gc/z/zMemory.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "gc/z/zList.inline.hpp" -#include "gc/z/zLock.inline.hpp" -#include "gc/z/zMemory.inline.hpp" - -void ZMemoryManager::shrink_from_front(ZMemory* area, size_t size) { - if (_callbacks._shrink != nullptr) { - const ZMemory* from = area; - const ZMemory to(area->start() + size, area->size() - size); - _callbacks._shrink(*from, to); - } - area->shrink_from_front(size); -} - -void ZMemoryManager::shrink_from_back(ZMemory* area, size_t size) { - if (_callbacks._shrink != nullptr) { - const ZMemory* from = area; - const ZMemory to(area->start(), area->size() - size); - _callbacks._shrink(*from, to); - } - area->shrink_from_back(size); -} - -void ZMemoryManager::grow_from_front(ZMemory* area, size_t size) { - if (_callbacks._grow != nullptr) { - const ZMemory* from = area; - const ZMemory to(area->start() - size, area->size() + size); - _callbacks._grow(*from, to); - } - area->grow_from_front(size); -} - -void ZMemoryManager::grow_from_back(ZMemory* area, size_t size) { - if (_callbacks._grow != nullptr) { - const ZMemory* from = area; - const ZMemory to(area->start(), area->size() + size); - _callbacks._grow(*from, to); - } - area->grow_from_back(size); -} - -ZMemoryManager::Callbacks::Callbacks() - : _prepare_for_hand_out(nullptr), - _prepare_for_hand_back(nullptr), - _grow(nullptr), - _shrink(nullptr) {} - -ZMemoryManager::ZMemoryManager() - : _freelist(), - _callbacks() {} - -bool ZMemoryManager::free_is_contiguous() const { - return _freelist.size() == 1; -} - -void ZMemoryManager::register_callbacks(const Callbacks& callbacks) { - _callbacks = callbacks; -} - -zoffset ZMemoryManager::peek_low_address() const { - ZLocker locker(&_lock); - - const ZMemory* const area = _freelist.first(); - if (area != nullptr) { - return area->start(); - } - - // Out of memory - return zoffset(UINTPTR_MAX); -} - -zoffset_end ZMemoryManager::peak_high_address_end() const { - ZLocker locker(&_lock); - - const ZMemory* const area = _freelist.last(); - if (area != nullptr) { - return area->end(); - } - - // Out of memory - return zoffset_end(UINTPTR_MAX); -} - -zoffset ZMemoryManager::alloc_low_address(size_t size) { - ZLocker locker(&_lock); - - ZListIterator iter(&_freelist); - for (ZMemory* area; iter.next(&area);) { - if (area->size() >= size) { - zoffset start; - - if (area->size() == size) { - // Exact match, remove area - start = area->start(); - _freelist.remove(area); - delete area; - } else { - // Larger than requested, shrink area - start = area->start(); - shrink_from_front(area, size); - } - - if (_callbacks._prepare_for_hand_out != nullptr) { - _callbacks._prepare_for_hand_out(ZMemory(start, size)); - } - - return start; - } - } - - // Out of memory - return zoffset(UINTPTR_MAX); -} - -zoffset ZMemoryManager::alloc_low_address_at_most(size_t size, size_t* allocated) { - ZLocker locker(&_lock); - - ZMemory* const area = _freelist.first(); - if (area != nullptr) { - const zoffset start = area->start(); - - if (area->size() <= size) { - // Smaller than or equal to requested, remove area - _freelist.remove(area); - *allocated = area->size(); - delete area; - } else { - // Larger than requested, shrink area - shrink_from_front(area, size); - *allocated = size; - } - - if (_callbacks._prepare_for_hand_out != nullptr) { - _callbacks._prepare_for_hand_out(ZMemory(start, *allocated)); - } - - return start; - } - - // Out of memory - *allocated = 0; - return zoffset(UINTPTR_MAX); -} - -zoffset ZMemoryManager::alloc_high_address(size_t size) { - ZLocker locker(&_lock); - - ZListReverseIterator iter(&_freelist); - for (ZMemory* area; iter.next(&area);) { - if (area->size() >= size) { - zoffset start; - - if (area->size() == size) { - // Exact match, remove area - start = area->start(); - _freelist.remove(area); - delete area; - } else { - // Larger than requested, shrink area - shrink_from_back(area, size); - start = to_zoffset(area->end()); - } - - if (_callbacks._prepare_for_hand_out != nullptr) { - _callbacks._prepare_for_hand_out(ZMemory(start, size)); - } - - return start; - } - } - - // Out of memory - return zoffset(UINTPTR_MAX); -} - -void ZMemoryManager::move_into(zoffset start, size_t size) { - assert(start != zoffset(UINTPTR_MAX), "Invalid address"); - const zoffset_end end = to_zoffset_end(start, size); - - ZListIterator iter(&_freelist); - for (ZMemory* area; iter.next(&area);) { - if (start < area->start()) { - ZMemory* const prev = _freelist.prev(area); - if (prev != nullptr && start == prev->end()) { - if (end == area->start()) { - // Merge with prev and current area - grow_from_back(prev, size + area->size()); - _freelist.remove(area); - delete area; - } else { - // Merge with prev area - grow_from_back(prev, size); - } - } else if (end == area->start()) { - // Merge with current area - grow_from_front(area, size); - } else { - // Insert new area before current area - assert(end < area->start(), "Areas must not overlap"); - ZMemory* const new_area = new ZMemory(start, size); - _freelist.insert_before(area, new_area); - } - - // Done - return; - } - } - - // Insert last - ZMemory* const last = _freelist.last(); - if (last != nullptr && start == last->end()) { - // Merge with last area - grow_from_back(last, size); - } else { - // Insert new area last - ZMemory* const new_area = new ZMemory(start, size); - _freelist.insert_last(new_area); - } -} - -void ZMemoryManager::free(zoffset start, size_t size) { - ZLocker locker(&_lock); - - if (_callbacks._prepare_for_hand_back != nullptr) { - _callbacks._prepare_for_hand_back(ZMemory(start, size)); - } - - move_into(start, size); -} - -void ZMemoryManager::register_range(zoffset start, size_t size) { - // Note that there's no need to call the _prepare_for_hand_back when memory - // is added the first time. We don't have to undo the effects of a previous - // _prepare_for_hand_out callback. - - // No need to lock during initialization. - - move_into(start, size); -} - -bool ZMemoryManager::unregister_first(zoffset* start_out, size_t* size_out) { - // Note that this doesn't hand out memory to be used, so we don't call the - // _prepare_for_hand_out callback. - - ZLocker locker(&_lock); - - if (_freelist.is_empty()) { - return false; - } - - // Don't invoke the _prepare_for_hand_out callback - - ZMemory* const area = _freelist.remove_first(); - - // Return the range - *start_out = area->start(); - *size_out = area->size(); - - delete area; - - return true; -} diff --git a/src/hotspot/share/gc/z/zMemory.hpp b/src/hotspot/share/gc/z/zMemory.hpp deleted file mode 100644 index da37596c1c7b2..0000000000000 --- a/src/hotspot/share/gc/z/zMemory.hpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2015, 2023, 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_GC_Z_ZMEMORY_HPP -#define SHARE_GC_Z_ZMEMORY_HPP - -#include "gc/z/zAddress.hpp" -#include "gc/z/zList.hpp" -#include "gc/z/zLock.hpp" -#include "memory/allocation.hpp" - -class ZMemory : public CHeapObj { - friend class ZList; - -private: - zoffset _start; - zoffset_end _end; - ZListNode _node; - -public: - ZMemory(zoffset start, size_t size); - - zoffset start() const; - zoffset_end end() const; - size_t size() const; - - bool operator==(const ZMemory& other) const; - bool operator!=(const ZMemory& other) const; - - bool contains(const ZMemory& other) const; - - void shrink_from_front(size_t size); - void shrink_from_back(size_t size); - void grow_from_front(size_t size); - void grow_from_back(size_t size); -}; - -class ZMemoryManager { - friend class ZVirtualMemoryManagerTest; - -public: - typedef void (*CallbackPrepare)(const ZMemory& area); - typedef void (*CallbackResize)(const ZMemory& from, const ZMemory& to); - - struct Callbacks { - CallbackPrepare _prepare_for_hand_out; - CallbackPrepare _prepare_for_hand_back; - CallbackResize _grow; - CallbackResize _shrink; - - Callbacks(); - }; - -private: - mutable ZLock _lock; - ZList _freelist; - Callbacks _callbacks; - - void shrink_from_front(ZMemory* area, size_t size); - void shrink_from_back(ZMemory* area, size_t size); - void grow_from_front(ZMemory* area, size_t size); - void grow_from_back(ZMemory* area, size_t size); - - void move_into(zoffset start, size_t size); - -public: - ZMemoryManager(); - - bool free_is_contiguous() const; - - void register_callbacks(const Callbacks& callbacks); - - zoffset peek_low_address() const; - zoffset_end peak_high_address_end() const; - zoffset alloc_low_address(size_t size); - zoffset alloc_low_address_at_most(size_t size, size_t* allocated); - zoffset alloc_high_address(size_t size); - - void free(zoffset start, size_t size); - void register_range(zoffset start, size_t size); - bool unregister_first(zoffset* start_out, size_t* size_out); -}; - -#endif // SHARE_GC_Z_ZMEMORY_HPP diff --git a/src/hotspot/share/gc/z/zMemory.inline.hpp b/src/hotspot/share/gc/z/zMemory.inline.hpp deleted file mode 100644 index 39e5b26d85696..0000000000000 --- a/src/hotspot/share/gc/z/zMemory.inline.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2015, 2023, 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_GC_Z_ZMEMORY_INLINE_HPP -#define SHARE_GC_Z_ZMEMORY_INLINE_HPP - -#include "gc/z/zMemory.hpp" - -#include "gc/z/zAddress.inline.hpp" -#include "gc/z/zList.inline.hpp" -#include "utilities/debug.hpp" - -inline ZMemory::ZMemory(zoffset start, size_t size) - : _start(start), - _end(to_zoffset_end(start, size)) {} - -inline zoffset ZMemory::start() const { - return _start; -} - -inline zoffset_end ZMemory::end() const { - return _end; -} - -inline size_t ZMemory::size() const { - return end() - start(); -} - -inline bool ZMemory::operator==(const ZMemory& other) const { - return _start == other._start && _end == other._end; -} - -inline bool ZMemory::operator!=(const ZMemory& other) const { - return !operator==(other); -} - -inline bool ZMemory::contains(const ZMemory& other) const { - return _start <= other._start && other.end() <= end(); -} - -inline void ZMemory::shrink_from_front(size_t size) { - assert(this->size() > size, "Too small"); - _start += size; -} - -inline void ZMemory::shrink_from_back(size_t size) { - assert(this->size() > size, "Too small"); - _end -= size; -} - -inline void ZMemory::grow_from_front(size_t size) { - assert(size_t(start()) >= size, "Too big"); - _start -= size; -} - -inline void ZMemory::grow_from_back(size_t size) { - _end += size; -} - -#endif // SHARE_GC_Z_ZMEMORY_INLINE_HPP diff --git a/src/hotspot/share/gc/z/zNMT.cpp b/src/hotspot/share/gc/z/zNMT.cpp index 4e1efbf9cafe9..76e164308dd0c 100644 --- a/src/hotspot/share/gc/z/zNMT.cpp +++ b/src/hotspot/share/gc/z/zNMT.cpp @@ -24,7 +24,6 @@ #include "gc/z/zAddress.inline.hpp" #include "gc/z/zGlobals.hpp" #include "gc/z/zNMT.hpp" -#include "gc/z/zVirtualMemory.hpp" #include "nmt/memTag.hpp" #include "nmt/memTracker.hpp" #include "nmt/memoryFileTracker.hpp" @@ -60,15 +59,15 @@ void ZNMT::unreserve(zaddress_unsafe start, size_t size) { } } -void ZNMT::commit(zoffset offset, size_t size) { +void ZNMT::commit(zbacking_offset offset, size_t size) { MemTracker::allocate_memory_in(ZNMT::_device, untype(offset), size, CALLER_PC, mtJavaHeap); } -void ZNMT::uncommit(zoffset offset, size_t size) { +void ZNMT::uncommit(zbacking_offset offset, size_t size) { MemTracker::free_memory_in(ZNMT::_device, untype(offset), size); } -void ZNMT::map(zaddress_unsafe addr, size_t size, zoffset offset) { +void ZNMT::map(zaddress_unsafe addr, size_t size, zbacking_offset offset) { // NMT doesn't track mappings at the moment. } diff --git a/src/hotspot/share/gc/z/zNMT.hpp b/src/hotspot/share/gc/z/zNMT.hpp index bea6a6b62ac12..b5b1aa07870f3 100644 --- a/src/hotspot/share/gc/z/zNMT.hpp +++ b/src/hotspot/share/gc/z/zNMT.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,13 +26,10 @@ #include "gc/z/zAddress.hpp" #include "gc/z/zGlobals.hpp" -#include "gc/z/zMemory.hpp" -#include "gc/z/zVirtualMemory.hpp" #include "memory/allStatic.hpp" #include "nmt/memTracker.hpp" #include "nmt/memoryFileTracker.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/nativeCallStack.hpp" class ZNMT : public AllStatic { private: @@ -44,10 +41,10 @@ class ZNMT : public AllStatic { static void reserve(zaddress_unsafe start, size_t size); static void unreserve(zaddress_unsafe start, size_t size); - static void commit(zoffset offset, size_t size); - static void uncommit(zoffset offset, size_t size); + static void commit(zbacking_offset offset, size_t size); + static void uncommit(zbacking_offset offset, size_t size); - static void map(zaddress_unsafe addr, size_t size, zoffset offset); + static void map(zaddress_unsafe addr, size_t size, zbacking_offset offset); static void unmap(zaddress_unsafe addr, size_t size); }; diff --git a/src/hotspot/share/gc/z/zNUMA.cpp b/src/hotspot/share/gc/z/zNUMA.cpp index a302a1843bb41..cf2d88a90e5a9 100644 --- a/src/hotspot/share/gc/z/zNUMA.cpp +++ b/src/hotspot/share/gc/z/zNUMA.cpp @@ -21,8 +21,10 @@ * questions. */ +#include "gc/shared/gc_globals.hpp" #include "gc/shared/gcLogPrecious.hpp" -#include "gc/z/zNUMA.hpp" +#include "gc/z/zNUMA.inline.hpp" +#include "utilities/macros.hpp" bool ZNUMA::_enabled; uint32_t ZNUMA::_count; @@ -31,11 +33,20 @@ void ZNUMA::initialize() { pd_initialize(); log_info_p(gc, init)("NUMA Support: %s", to_string()); + if (_enabled) { + assert(!is_faked(), "Currently not supported"); log_info_p(gc, init)("NUMA Nodes: %u", _count); + + } else if (is_faked()) { + log_info_p(gc, init)("Fake NUMA Nodes: %u", count()); } } const char* ZNUMA::to_string() { + if (is_faked()) { + return "Faked"; + } + return _enabled ? "Enabled" : "Disabled"; } diff --git a/src/hotspot/share/gc/z/zNUMA.hpp b/src/hotspot/share/gc/z/zNUMA.hpp index ac6142475226d..de74086b10ab0 100644 --- a/src/hotspot/share/gc/z/zNUMA.hpp +++ b/src/hotspot/share/gc/z/zNUMA.hpp @@ -24,10 +24,15 @@ #ifndef SHARE_GC_Z_ZNUMA_HPP #define SHARE_GC_Z_ZNUMA_HPP +#include "gc/z/zGlobals.hpp" #include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" class ZNUMA : public AllStatic { + friend class VMStructs; + friend class ZNUMATest; + friend class ZTest; + private: static bool _enabled; static uint32_t _count; @@ -36,13 +41,17 @@ class ZNUMA : public AllStatic { public: static void initialize(); + static bool is_enabled(); + static bool is_faked(); static uint32_t count(); static uint32_t id(); static uint32_t memory_id(uintptr_t addr); + static size_t calculate_share(uint32_t numa_id, size_t total, size_t granule = ZGranuleSize, uint32_t ignore_count = 0); + static const char* to_string(); }; diff --git a/src/hotspot/share/gc/z/zNUMA.inline.hpp b/src/hotspot/share/gc/z/zNUMA.inline.hpp index 4596c8f090bfd..d90b44e905a06 100644 --- a/src/hotspot/share/gc/z/zNUMA.inline.hpp +++ b/src/hotspot/share/gc/z/zNUMA.inline.hpp @@ -26,12 +26,36 @@ #include "gc/z/zNUMA.hpp" +#include "gc/shared/gc_globals.hpp" +#include "gc/z/zGlobals.hpp" +#include "utilities/align.hpp" + inline bool ZNUMA::is_enabled() { return _enabled; } +inline bool ZNUMA::is_faked() { + return ZFakeNUMA > 1; +} + inline uint32_t ZNUMA::count() { return _count; } +inline size_t ZNUMA::calculate_share(uint32_t numa_id, size_t total, size_t granule, uint32_t ignore_count) { + assert(total % granule == 0, "total must be divisible by granule"); + assert(ignore_count < count(), "must not ignore all nodes"); + assert(numa_id < count() - ignore_count, "numa_id must be in bounds"); + + const uint32_t num_nodes = count() - ignore_count; + const size_t base_share = ((total / num_nodes) / granule) * granule; + + const size_t extra_share_nodes = (total - base_share * num_nodes) / granule; + if (numa_id < extra_share_nodes) { + return base_share + granule; + } + + return base_share; +} + #endif // SHARE_GC_Z_ZNUMA_INLINE_HPP diff --git a/src/hotspot/share/gc/z/zObjectAllocator.cpp b/src/hotspot/share/gc/z/zObjectAllocator.cpp index 81a92aa6cc646..54724c1b48ed4 100644 --- a/src/hotspot/share/gc/z/zObjectAllocator.cpp +++ b/src/hotspot/share/gc/z/zObjectAllocator.cpp @@ -138,10 +138,10 @@ zaddress ZObjectAllocator::alloc_object_in_medium_page(size_t size, } if (is_null(addr)) { - // When a new medium page is required, we synchronize the allocation - // of the new page using a lock. This is to avoid having multiple - // threads requesting a medium page from the page cache when we know - // only one of the will succeed in installing the page at this layer. + // When a new medium page is required, we synchronize the allocation of the + // new page using a lock. This is to avoid having multiple threads allocate + // medium pages when we know only one of them will succeed in installing + // the page at this layer. ZLocker locker(&_medium_page_alloc_lock); // When holding the lock we can't allow the page allocator to stall, diff --git a/src/hotspot/share/gc/z/zPage.cpp b/src/hotspot/share/gc/z/zPage.cpp index 5264076c8a9bf..f4cc754205234 100644 --- a/src/hotspot/share/gc/z/zPage.cpp +++ b/src/hotspot/share/gc/z/zPage.cpp @@ -23,42 +23,47 @@ #include "gc/shared/gc_globals.hpp" #include "gc/z/zGeneration.inline.hpp" -#include "gc/z/zList.inline.hpp" #include "gc/z/zPage.inline.hpp" -#include "gc/z/zPhysicalMemory.inline.hpp" +#include "gc/z/zPageAge.hpp" #include "gc/z/zRememberedSet.inline.hpp" -#include "gc/z/zVirtualMemory.inline.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" -#include "utilities/growableArray.hpp" -ZPage::ZPage(ZPageType type, const ZVirtualMemory& vmem, const ZPhysicalMemory& pmem) +ZPage::ZPage(ZPageType type, ZPageAge age, const ZVirtualMemory& vmem, ZMultiPartitionTracker* multi_partition_tracker, uint32_t partition_id) : _type(type), - _generation_id(ZGenerationId::young), - _age(ZPageAge::eden), - _numa_id((uint8_t)-1), - _seqnum(0), - _seqnum_other(0), + _generation_id(/* set in reset */), + _age(/* set in reset */), + _seqnum(/* set in reset */), + _seqnum_other(/* set in reset */), + _single_partition_id(partition_id), _virtual(vmem), _top(to_zoffset_end(start())), _livemap(object_max_count()), _remembered_set(), - _last_used(0), - _physical(pmem), - _node() { + _multi_partition_tracker(multi_partition_tracker) { assert(!_virtual.is_null(), "Should not be null"); - assert(!_physical.is_null(), "Should not be null"); - assert(_virtual.size() == _physical.size(), "Virtual/Physical size mismatch"); assert((_type == ZPageType::small && size() == ZPageSizeSmall) || (_type == ZPageType::medium && size() == ZPageSizeMedium) || (_type == ZPageType::large && is_aligned(size(), ZGranuleSize)), "Page type/size mismatch"); + reset(age); + + if (is_old()) { + remset_alloc(); + } } -ZPage* ZPage::clone_limited() const { +ZPage::ZPage(ZPageType type, ZPageAge age, const ZVirtualMemory& vmem, uint32_t partition_id) + : ZPage(type, age, vmem, nullptr /* multi_partition_tracker */, partition_id) {} + +ZPage::ZPage(ZPageType type, ZPageAge age, const ZVirtualMemory& vmem, ZMultiPartitionTracker* multi_partition_tracker) + : ZPage(type, age, vmem, multi_partition_tracker, -1u /* partition_id */) {} + +ZPage* ZPage::clone_for_promotion() const { + assert(_age != ZPageAge::old, "must be used for promotion"); // Only copy type and memory layouts, and also update _top. Let the rest be // lazily reconstructed when needed. - ZPage* const page = new ZPage(_type, _virtual, _physical); + ZPage* const page = new ZPage(_type, ZPageAge::old, _virtual, _multi_partition_tracker, _single_partition_id); page->_top = _top; return page; @@ -85,19 +90,16 @@ void ZPage::remset_alloc() { _remembered_set.initialize(size()); } -void ZPage::remset_delete() { - _remembered_set.delete_all(); -} - -void ZPage::reset(ZPageAge age) { +ZPage* ZPage::reset(ZPageAge age) { _age = age; - _last_used = 0; _generation_id = age == ZPageAge::old ? ZGenerationId::old : ZGenerationId::young; reset_seqnum(); + + return this; } void ZPage::reset_livemap() { @@ -108,59 +110,6 @@ void ZPage::reset_top_for_allocation() { _top = to_zoffset_end(start()); } -void ZPage::reset_type_and_size(ZPageType type) { - _type = type; - _livemap.resize(object_max_count()); -} - -ZPage* ZPage::retype(ZPageType type) { - assert(_type != type, "Invalid retype"); - reset_type_and_size(type); - return this; -} - -ZPage* ZPage::split(size_t split_of_size) { - return split(type_from_size(split_of_size), split_of_size); -} - -ZPage* ZPage::split_with_pmem(ZPageType type, const ZPhysicalMemory& pmem) { - // Resize this page - const ZVirtualMemory vmem = _virtual.split(pmem.size()); - assert(vmem.end() == _virtual.start(), "Should be consecutive"); - - reset_type_and_size(type_from_size(_virtual.size())); - - log_trace(gc, page)("Split page [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT "]", - untype(vmem.start()), - untype(vmem.end()), - untype(_virtual.end())); - - // Create new page - return new ZPage(type, vmem, pmem); -} - -ZPage* ZPage::split(ZPageType type, size_t split_of_size) { - assert(_virtual.size() > split_of_size, "Invalid split"); - - const ZPhysicalMemory pmem = _physical.split(split_of_size); - - return split_with_pmem(type, pmem); -} - -ZPage* ZPage::split_committed() { - // Split any committed part of this page into a separate page, - // leaving this page with only uncommitted physical memory. - const ZPhysicalMemory pmem = _physical.split_committed(); - if (pmem.is_null()) { - // Nothing committed - return nullptr; - } - - assert(!_physical.is_null(), "Should not be null"); - - return split_with_pmem(type_from_size(pmem.size()), pmem); -} - class ZFindBaseOopClosure : public ObjectClosure { private: volatile zpointer* _p; @@ -215,18 +164,19 @@ void* ZPage::remset_current() { return _remembered_set.current(); } -void ZPage::print_on_msg(outputStream* out, const char* msg) const { - out->print_cr(" %-6s " PTR_FORMAT " " PTR_FORMAT " " PTR_FORMAT " %s/%-4u %s%s%s", +void ZPage::print_on_msg(outputStream* st, const char* msg) const { + st->print_cr("%-6s " PTR_FORMAT " " PTR_FORMAT " " PTR_FORMAT " %s/%-4u %s%s%s%s", type_to_string(), untype(start()), untype(top()), untype(end()), is_young() ? "Y" : "O", seqnum(), - is_allocating() ? " Allocating " : "", is_relocatable() ? " Relocatable" : "", - msg == nullptr ? "" : msg); + is_allocating() ? " Allocating" : "", + is_allocating() && msg != nullptr ? " " : "", + msg != nullptr ? msg : ""); } -void ZPage::print_on(outputStream* out) const { - print_on_msg(out, nullptr); +void ZPage::print_on(outputStream* st) const { + print_on_msg(st, nullptr); } void ZPage::print() const { diff --git a/src/hotspot/share/gc/z/zPage.hpp b/src/hotspot/share/gc/z/zPage.hpp index 9b6c155f77d9f..96900a376803d 100644 --- a/src/hotspot/share/gc/z/zPage.hpp +++ b/src/hotspot/share/gc/z/zPage.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,38 +25,34 @@ #define SHARE_GC_Z_ZPAGE_HPP #include "gc/z/zGenerationId.hpp" -#include "gc/z/zList.hpp" #include "gc/z/zLiveMap.hpp" #include "gc/z/zPageAge.hpp" #include "gc/z/zPageType.hpp" -#include "gc/z/zPhysicalMemory.hpp" #include "gc/z/zRememberedSet.hpp" #include "gc/z/zVirtualMemory.hpp" #include "memory/allocation.hpp" +#include "oops/oopsHierarchy.hpp" class ZGeneration; +class ZMultiPartitionTracker; class ZPage : public CHeapObj { friend class VMStructs; - friend class ZList; friend class ZForwardingTest; private: - ZPageType _type; - ZGenerationId _generation_id; - ZPageAge _age; - uint8_t _numa_id; - uint32_t _seqnum; - uint32_t _seqnum_other; - ZVirtualMemory _virtual; - volatile zoffset_end _top; - ZLiveMap _livemap; - ZRememberedSet _remembered_set; - uint64_t _last_used; - ZPhysicalMemory _physical; - ZListNode _node; - - ZPageType type_from_size(size_t size) const; + const ZPageType _type; + ZGenerationId _generation_id; + ZPageAge _age; + uint32_t _seqnum; + uint32_t _seqnum_other; + const uint32_t _single_partition_id; + const ZVirtualMemory _virtual; + volatile zoffset_end _top; + ZLiveMap _livemap; + ZRememberedSet _remembered_set; + ZMultiPartitionTracker* const _multi_partition_tracker; + const char* type_to_string() const; BitMap::idx_t bit_index(zaddress addr) const; @@ -71,12 +67,13 @@ class ZPage : public CHeapObj { void reset_seqnum(); - ZPage* split_with_pmem(ZPageType type, const ZPhysicalMemory& pmem); + ZPage(ZPageType type, ZPageAge age, const ZVirtualMemory& vmem, ZMultiPartitionTracker* multi_partition_tracker, uint32_t partition_id); public: - ZPage(ZPageType type, const ZVirtualMemory& vmem, const ZPhysicalMemory& pmem); + ZPage(ZPageType type, ZPageAge age, const ZVirtualMemory& vmem, uint32_t partition_id); + ZPage(ZPageType type, ZPageAge age, const ZVirtualMemory& vmem, ZMultiPartitionTracker* multi_partition_tracker); - ZPage* clone_limited() const; + ZPage* clone_for_promotion() const; uint32_t object_max_count() const; size_t object_alignment_shift() const; @@ -99,28 +96,20 @@ class ZPage : public CHeapObj { size_t used() const; const ZVirtualMemory& virtual_memory() const; - const ZPhysicalMemory& physical_memory() const; - ZPhysicalMemory& physical_memory(); - uint8_t numa_id(); + uint32_t single_partition_id() const; + bool is_multi_partition() const; + ZMultiPartitionTracker* multi_partition_tracker() const; + ZPageAge age() const; uint32_t seqnum() const; bool is_allocating() const; bool is_relocatable() const; - uint64_t last_used() const; - void set_last_used(); - - void reset(ZPageAge age); + ZPage* reset(ZPageAge age); void reset_livemap(); void reset_top_for_allocation(); - void reset_type_and_size(ZPageType type); - - ZPage* retype(ZPageType type); - ZPage* split(size_t split_of_size); - ZPage* split(ZPageType type, size_t split_of_size); - ZPage* split_committed(); bool is_in(zoffset offset) const; bool is_in(zaddress addr) const; @@ -156,7 +145,6 @@ class ZPage : public CHeapObj { void swap_remset_bitmaps(); void remset_alloc(); - void remset_delete(); ZBitMap::ReverseIterator remset_reverse_iterator_previous(); BitMap::Iterator remset_iterator_limited_current(uintptr_t l_offset, size_t size); @@ -193,8 +181,8 @@ class ZPage : public CHeapObj { void log_msg(const char* msg_format, ...) const ATTRIBUTE_PRINTF(2, 3); - void print_on_msg(outputStream* out, const char* msg) const; - void print_on(outputStream* out) const; + void print_on_msg(outputStream* st, const char* msg) const; + void print_on(outputStream* st) const; void print() const; // Verification diff --git a/src/hotspot/share/gc/z/zPage.inline.hpp b/src/hotspot/share/gc/z/zPage.inline.hpp index 5d476f273d3e2..f6c2029ac06d4 100644 --- a/src/hotspot/share/gc/z/zPage.inline.hpp +++ b/src/hotspot/share/gc/z/zPage.inline.hpp @@ -30,28 +30,14 @@ #include "gc/z/zGeneration.inline.hpp" #include "gc/z/zGlobals.hpp" #include "gc/z/zLiveMap.inline.hpp" -#include "gc/z/zNUMA.hpp" -#include "gc/z/zPhysicalMemory.inline.hpp" #include "gc/z/zRememberedSet.inline.hpp" -#include "gc/z/zUtils.inline.hpp" #include "gc/z/zVirtualMemory.inline.hpp" #include "logging/logStream.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "utilities/align.hpp" -#include "utilities/checkedCast.hpp" #include "utilities/debug.hpp" -inline ZPageType ZPage::type_from_size(size_t size) const { - if (size == ZPageSizeSmall) { - return ZPageType::small; - } else if (size == ZPageSizeMedium) { - return ZPageType::medium; - } else { - return ZPageType::large; - } -} - inline const char* ZPage::type_to_string() const { switch (type()) { case ZPageType::small: @@ -170,20 +156,16 @@ inline const ZVirtualMemory& ZPage::virtual_memory() const { return _virtual; } -inline const ZPhysicalMemory& ZPage::physical_memory() const { - return _physical; +inline uint32_t ZPage::single_partition_id() const { + return _single_partition_id; } -inline ZPhysicalMemory& ZPage::physical_memory() { - return _physical; +inline bool ZPage::is_multi_partition() const { + return _multi_partition_tracker != nullptr; } -inline uint8_t ZPage::numa_id() { - if (_numa_id == (uint8_t)-1) { - _numa_id = checked_cast(ZNUMA::memory_id(untype(ZOffset::address(start())))); - } - - return _numa_id; +inline ZMultiPartitionTracker* ZPage::multi_partition_tracker() const { + return _multi_partition_tracker; } inline ZPageAge ZPage::age() const { @@ -202,14 +184,6 @@ inline bool ZPage::is_relocatable() const { return _seqnum < generation()->seqnum(); } -inline uint64_t ZPage::last_used() const { - return _last_used; -} - -inline void ZPage::set_last_used() { - _last_used = (uint64_t)ceil(os::elapsedTime()); -} - inline bool ZPage::is_in(zoffset offset) const { return offset >= start() && offset < top(); } diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index 7913aa68fbe1b..444f7a9b84565 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -23,6 +23,8 @@ #include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/suspendibleThreadSet.hpp" +#include "gc/z/zAddress.hpp" +#include "gc/z/zAllocationFlags.hpp" #include "gc/z/zArray.inline.hpp" #include "gc/z/zDriver.hpp" #include "gc/z/zFuture.inline.hpp" @@ -31,71 +33,361 @@ #include "gc/z/zGlobals.hpp" #include "gc/z/zLargePages.inline.hpp" #include "gc/z/zLock.inline.hpp" +#include "gc/z/zMappedCache.hpp" +#include "gc/z/zNUMA.inline.hpp" #include "gc/z/zPage.inline.hpp" #include "gc/z/zPageAge.hpp" #include "gc/z/zPageAllocator.inline.hpp" -#include "gc/z/zPageCache.hpp" +#include "gc/z/zPageType.hpp" +#include "gc/z/zPhysicalMemoryManager.hpp" #include "gc/z/zSafeDelete.inline.hpp" #include "gc/z/zStat.hpp" #include "gc/z/zTask.hpp" #include "gc/z/zUncommitter.hpp" -#include "gc/z/zUnmapper.hpp" +#include "gc/z/zValue.inline.hpp" +#include "gc/z/zVirtualMemory.inline.hpp" +#include "gc/z/zVirtualMemoryManager.inline.hpp" #include "gc/z/zWorkers.hpp" #include "jfr/jfrEvents.hpp" #include "logging/log.hpp" +#include "memory/allocation.hpp" +#include "nmt/memTag.hpp" #include "runtime/globals.hpp" #include "runtime/init.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" +#include "utilities/align.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/ticks.hpp" +#include "utilities/vmError.hpp" + +#include + +class ZMemoryAllocation; static const ZStatCounter ZCounterMutatorAllocationRate("Memory", "Allocation Rate", ZStatUnitBytesPerSecond); -static const ZStatCounter ZCounterPageCacheFlush("Memory", "Page Cache Flush", ZStatUnitBytesPerSecond); +static const ZStatCounter ZCounterMappedCacheHarvest("Memory", "Mapped Cache Harvest", ZStatUnitBytesPerSecond); static const ZStatCounter ZCounterDefragment("Memory", "Defragment", ZStatUnitOpsPerSecond); static const ZStatCriticalPhase ZCriticalPhaseAllocationStall("Allocation Stall"); -ZSafePageRecycle::ZSafePageRecycle(ZPageAllocator* page_allocator) - : _page_allocator(page_allocator), - _unsafe_to_recycle() {} - -void ZSafePageRecycle::activate() { - _unsafe_to_recycle.activate(); +static void check_numa_mismatch(const ZVirtualMemory& vmem, uint32_t desired_id) { + if (ZNUMA::is_enabled()) { + // Check if memory ended up on desired NUMA node or not + const uint32_t actual_id = ZNUMA::memory_id(untype(ZOffset::address(vmem.start()))); + if (actual_id != desired_id) { + log_debug(gc, heap)("NUMA Mismatch: desired %d, actual %d", desired_id, actual_id); + } + } } -void ZSafePageRecycle::deactivate() { - auto delete_function = [&](ZPage* page) { - _page_allocator->safe_destroy_page(page); - }; +class ZMemoryAllocation : public CHeapObj { +private: + const size_t _size; + ZPartition* _partition; + ZVirtualMemory _satisfied_from_cache_vmem; + ZArray _partial_vmems; + int _num_harvested; + size_t _harvested; + size_t _increased_capacity; + size_t _committed_capacity; + bool _commit_failed; + + explicit ZMemoryAllocation(const ZMemoryAllocation& other) + : ZMemoryAllocation(other._size) { + // Transfer the partition + set_partition(other._partition); + + // Reserve space for the partial vmems + _partial_vmems.reserve(other._partial_vmems.length() + (other._satisfied_from_cache_vmem.is_null() ? 1 : 0)); + + // Transfer the claimed capacity + transfer_claimed_capacity(other); + } - _unsafe_to_recycle.deactivate_and_apply(delete_function); -} + ZMemoryAllocation(const ZMemoryAllocation& a1, const ZMemoryAllocation& a2) + : ZMemoryAllocation(a1._size + a2._size) { + // Transfer the partition + assert(a1._partition == a2._partition, "only merge with same partition"); + set_partition(a1._partition); -ZPage* ZSafePageRecycle::register_and_clone_if_activated(ZPage* page) { - if (!_unsafe_to_recycle.is_activated()) { - // The page has no concurrent readers. - // Recycle original page. - return page; + // Reserve space for the partial vmems + const int num_vmems_a1 = a1._partial_vmems.length() + (a1._satisfied_from_cache_vmem.is_null() ? 1 : 0); + const int num_vmems_a2 = a2._partial_vmems.length() + (a2._satisfied_from_cache_vmem.is_null() ? 1 : 0); + _partial_vmems.reserve(num_vmems_a1 + num_vmems_a2); + + // Transfer the claimed capacity + transfer_claimed_capacity(a1); + transfer_claimed_capacity(a2); } - // The page could have concurrent readers. - // It would be unsafe to recycle this page at this point. + void transfer_claimed_capacity(const ZMemoryAllocation& from) { + assert(from._committed_capacity == 0, "Unexpected value %zu", from._committed_capacity); + assert(!from._commit_failed, "Unexpected value"); + + // Transfer increased capacity + _increased_capacity += from._increased_capacity; - // As soon as the page is added to _unsafe_to_recycle, it - // must not be used again. Hence, the extra double-checked - // locking to only clone the page if it is believed to be - // unsafe to recycle the page. - ZPage* const cloned_page = page->clone_limited(); - if (!_unsafe_to_recycle.add_if_activated(page)) { - // It became safe to recycle the page after the is_activated check - delete cloned_page; - return page; + // Transfer satisfying vmem or partial mappings + const ZVirtualMemory vmem = from._satisfied_from_cache_vmem; + if (!vmem.is_null()) { + assert(_partial_vmems.is_empty(), "Must either have result or partial vmems"); + _partial_vmems.push(vmem); + _num_harvested += 1; + _harvested += vmem.size(); + } else { + _partial_vmems.appendAll(&from._partial_vmems); + _num_harvested += from._num_harvested; + _harvested += from._harvested; + } } - // The original page has been registered to be deleted by another thread. - // Recycle the cloned page. - return cloned_page; -} +public: + explicit ZMemoryAllocation(size_t size) + : _size(size), + _partition(nullptr), + _satisfied_from_cache_vmem(), + _partial_vmems(0), + _num_harvested(0), + _harvested(0), + _increased_capacity(0), + _committed_capacity(0), + _commit_failed(false) {} + + void reset_for_retry() { + assert(_satisfied_from_cache_vmem.is_null(), "Incompatible with reset"); + + _partition = nullptr; + _partial_vmems.clear(); + _num_harvested = 0; + _harvested = 0; + _increased_capacity = 0; + _committed_capacity = 0; + _commit_failed = false; + } + + size_t size() const { + return _size; + } + + ZPartition& partition() const { + assert(_partition != nullptr, "Should have been initialized"); + return *_partition; + } + + void set_partition(ZPartition* partition) { + assert(_partition == nullptr, "Should be initialized only once"); + _partition = partition; + } + + ZVirtualMemory satisfied_from_cache_vmem() const { + return _satisfied_from_cache_vmem; + } + + void set_satisfied_from_cache_vmem(ZVirtualMemory vmem) { + precond(_satisfied_from_cache_vmem.is_null()); + precond(vmem.size() == size()); + precond(_partial_vmems.is_empty()); + + _satisfied_from_cache_vmem = vmem; + } + + ZArray* partial_vmems() { + return &_partial_vmems; + } + + const ZArray* partial_vmems() const { + return &_partial_vmems; + } + + int num_harvested() const { + return _num_harvested; + } + + size_t harvested() const { + return _harvested; + } + + void set_harvested(int num_harvested, size_t harvested) { + _num_harvested = num_harvested; + _harvested = harvested; + } + + size_t increased_capacity() const { + return _increased_capacity; + } + + void set_increased_capacity(size_t increased_capacity) { + _increased_capacity = increased_capacity; + } + + size_t committed_capacity() const { + return _committed_capacity; + } + + void set_committed_capacity(size_t committed_capacity) { + assert(_committed_capacity == 0, "Should only commit once"); + _committed_capacity = committed_capacity; + _commit_failed = committed_capacity != _increased_capacity; + } + + bool commit_failed() const { + return _commit_failed; + } + + static void destroy(ZMemoryAllocation* allocation) { + delete allocation; + } + + static void merge(const ZMemoryAllocation& allocation, ZMemoryAllocation** merge_location) { + ZMemoryAllocation* const other_allocation = *merge_location; + if (other_allocation == nullptr) { + // First allocation, allocate new partition + *merge_location = new ZMemoryAllocation(allocation); + } else { + // Merge with other allocation + *merge_location = new ZMemoryAllocation(allocation, *other_allocation); + + // Delete old allocation + delete other_allocation; + } + } +}; + +class ZSinglePartitionAllocation { +private: + ZMemoryAllocation _allocation; + +public: + ZSinglePartitionAllocation(size_t size) + : _allocation(size) {} + + size_t size() const { + return _allocation.size(); + } + + ZMemoryAllocation* allocation() { + return &_allocation; + } + + const ZMemoryAllocation* allocation() const { + return &_allocation; + } + + void reset_for_retry() { + _allocation.reset_for_retry(); + } +}; + +class ZMultiPartitionAllocation : public StackObj { +private: + const size_t _size; + ZArray _allocations; + +public: + ZMultiPartitionAllocation(size_t size) + : _size(size), + _allocations(0) {} + + ~ZMultiPartitionAllocation() { + for (ZMemoryAllocation* allocation : _allocations) { + ZMemoryAllocation::destroy(allocation); + } + } + + void initialize() { + precond(_allocations.is_empty()); + + // The multi-partition allocation creates at most one allocation per partition. + const int length = (int)ZNUMA::count(); + + _allocations.reserve(length); + } + + void reset_for_retry() { + for (ZMemoryAllocation* allocation : _allocations) { + ZMemoryAllocation::destroy(allocation); + } + _allocations.clear(); + } + + size_t size() const { + return _size; + } + + ZArray* allocations() { + return &_allocations; + } + + const ZArray* allocations() const { + return &_allocations; + } + + void register_allocation(const ZMemoryAllocation& allocation) { + ZMemoryAllocation** const slot = allocation_slot(allocation.partition().numa_id()); + + ZMemoryAllocation::merge(allocation, slot); + } + + ZMemoryAllocation** allocation_slot(uint32_t numa_id) { + // Try to find an existing allocation for numa_id + for (int i = 0; i < _allocations.length(); ++i) { + ZMemoryAllocation** const slot_addr = _allocations.adr_at(i); + ZMemoryAllocation* const allocation = *slot_addr; + if (allocation->partition().numa_id() == numa_id) { + // Found an existing slot + return slot_addr; + } + } + + // Push an empty slot for the numa_id + _allocations.push(nullptr); + + // Return the address of the slot + return &_allocations.last(); + } + + int sum_num_harvested_vmems() const { + int total = 0; + + for (const ZMemoryAllocation* allocation : _allocations) { + total += allocation->num_harvested(); + } + + return total; + } + + size_t sum_harvested() const { + size_t total = 0; + + for (const ZMemoryAllocation* allocation : _allocations) { + total += allocation->harvested(); + } + + return total; + } + + size_t sum_committed_increased_capacity() const { + size_t total = 0; + + for (const ZMemoryAllocation* allocation : _allocations) { + total += allocation->committed_capacity(); + } + + return total; + } +}; + +struct ZPageAllocationStats { + int _num_harvested_vmems; + size_t _total_harvested; + size_t _total_committed_capacity; + + ZPageAllocationStats(int num_harvested_vmems, size_t total_harvested, size_t total_committed_capacity) + : _num_harvested_vmems(num_harvested_vmems), + _total_harvested(total_harvested), + _total_committed_capacity(total_committed_capacity) {} +}; class ZPageAllocation : public StackObj { friend class ZList; @@ -104,27 +396,39 @@ class ZPageAllocation : public StackObj { const ZPageType _type; const size_t _size; const ZAllocationFlags _flags; + const ZPageAge _age; + const Ticks _start_timestamp; const uint32_t _young_seqnum; const uint32_t _old_seqnum; - size_t _flushed; - size_t _committed; - ZList _pages; + const uint32_t _initiating_numa_id; + bool _is_multi_partition; + ZSinglePartitionAllocation _single_partition_allocation; + ZMultiPartitionAllocation _multi_partition_allocation; ZListNode _node; ZFuture _stall_result; public: - ZPageAllocation(ZPageType type, size_t size, ZAllocationFlags flags) + ZPageAllocation(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age) : _type(type), _size(size), _flags(flags), + _age(age), + _start_timestamp(Ticks::now()), _young_seqnum(ZGeneration::young()->seqnum()), _old_seqnum(ZGeneration::old()->seqnum()), - _flushed(0), - _committed(0), - _pages(), + _initiating_numa_id(ZNUMA::id()), + _is_multi_partition(false), + _single_partition_allocation(size), + _multi_partition_allocation(size), _node(), _stall_result() {} + void reset_for_retry() { + _is_multi_partition = false; + _single_partition_allocation.reset_for_retry(); + _multi_partition_allocation.reset_for_retry(); + } + ZPageType type() const { return _type; } @@ -137,6 +441,10 @@ class ZPageAllocation : public StackObj { return _flags; } + ZPageAge age() const { + return _age; + } + uint32_t young_seqnum() const { return _young_seqnum; } @@ -145,28 +453,54 @@ class ZPageAllocation : public StackObj { return _old_seqnum; } - size_t flushed() const { - return _flushed; + uint32_t initiating_numa_id() const { + return _initiating_numa_id; + } + + bool is_multi_partition() const { + return _is_multi_partition; } - void set_flushed(size_t flushed) { - _flushed = flushed; + void initiate_multi_partition_allocation() { + assert(!_is_multi_partition, "Reinitialization?"); + _is_multi_partition = true; + _multi_partition_allocation.initialize(); } - size_t committed() const { - return _committed; + ZMultiPartitionAllocation* multi_partition_allocation() { + assert(_is_multi_partition, "multi-partition allocation must be initiated"); + + return &_multi_partition_allocation; } - void set_committed(size_t committed) { - _committed = committed; + const ZMultiPartitionAllocation* multi_partition_allocation() const { + assert(_is_multi_partition, "multi-partition allocation must be initiated"); + + return &_multi_partition_allocation; } - bool wait() { - return _stall_result.get(); + ZSinglePartitionAllocation* single_partition_allocation() { + assert(!_is_multi_partition, "multi-partition allocation must not have been initiated"); + + return &_single_partition_allocation; + } + + const ZSinglePartitionAllocation* single_partition_allocation() const { + assert(!_is_multi_partition, "multi-partition allocation must not have been initiated"); + + return &_single_partition_allocation; + } + + ZVirtualMemory satisfied_from_cache_vmem() const { + precond(!_is_multi_partition); + + const ZMemoryAllocation* const allocation = _single_partition_allocation.allocation(); + + return allocation->satisfied_from_cache_vmem(); } - ZList* pages() { - return &_pages; + bool wait() { + return _stall_result.get(); } void satisfy(bool result) { @@ -176,165 +510,869 @@ class ZPageAllocation : public StackObj { bool gc_relocation() const { return _flags.gc_relocation(); } -}; - -ZPageAllocator::ZPageAllocator(size_t min_capacity, - size_t initial_capacity, - size_t soft_max_capacity, - size_t max_capacity) - : _lock(), - _cache(), - _virtual(max_capacity), - _physical(max_capacity), - _min_capacity(min_capacity), - _initial_capacity(initial_capacity), - _max_capacity(max_capacity), - _current_max_capacity(max_capacity), - _capacity(0), - _claimed(0), - _used(0), - _used_generations{0, 0}, - _collection_stats{{0, 0}, {0, 0}}, - _stalled(), - _unmapper(new ZUnmapper(this)), - _uncommitter(new ZUncommitter(this)), - _safe_destroy(), - _safe_recycle(this), - _initialized(false) { - if (!_virtual.is_initialized() || !_physical.is_initialized()) { - return; + ZPageAllocationStats stats() const { + if (_is_multi_partition) { + return ZPageAllocationStats( + _multi_partition_allocation.sum_num_harvested_vmems(), + _multi_partition_allocation.sum_harvested(), + _multi_partition_allocation.sum_committed_increased_capacity()); + } else { + return ZPageAllocationStats( + _single_partition_allocation.allocation()->num_harvested(), + _single_partition_allocation.allocation()->harvested(), + _single_partition_allocation.allocation()->committed_capacity()); + } } - log_info_p(gc, init)("Min Capacity: %zuM", min_capacity / M); - log_info_p(gc, init)("Initial Capacity: %zuM", initial_capacity / M); - log_info_p(gc, init)("Max Capacity: %zuM", max_capacity / M); - log_info_p(gc, init)("Soft Max Capacity: %zuM", soft_max_capacity / M); - if (ZPageSizeMedium > 0) { - log_info_p(gc, init)("Medium Page Size: %zuM", ZPageSizeMedium / M); - } else { - log_info_p(gc, init)("Medium Page Size: N/A"); + void send_event(bool successful) { + EventZPageAllocation event; + + Ticks end_timestamp = Ticks::now(); + const ZPageAllocationStats st = stats(); + + event.commit(_start_timestamp, + end_timestamp, + (u8)_type, + _size, + st._total_harvested, + st._total_committed_capacity, + (unsigned)st._num_harvested_vmems, + _is_multi_partition, + successful, + _flags.non_blocking()); } - log_info_p(gc, init)("Pre-touch: %s", AlwaysPreTouch ? "Enabled" : "Disabled"); - - // Warn if system limits could stop us from reaching max capacity - _physical.warn_commit_limits(max_capacity); - - // Check if uncommit should and can be enabled - _physical.try_enable_uncommit(min_capacity, max_capacity); +}; - // Successfully initialized - _initialized = true; +const ZVirtualMemoryManager& ZPartition::virtual_memory_manager() const { + return _page_allocator->_virtual; } -bool ZPageAllocator::is_initialized() const { - return _initialized; +ZVirtualMemoryManager& ZPartition::virtual_memory_manager() { + return _page_allocator->_virtual; } -class ZPreTouchTask : public ZTask { -private: - volatile uintptr_t _current; - const uintptr_t _end; +const ZPhysicalMemoryManager& ZPartition::physical_memory_manager() const { + return _page_allocator->_physical; +} - static void pretouch(zaddress zaddr, size_t size) { - const uintptr_t addr = untype(zaddr); - const size_t page_size = ZLargePages::is_explicit() ? ZGranuleSize : os::vm_page_size(); - os::pretouch_memory((void*)addr, (void*)(addr + size), page_size); - } +ZPhysicalMemoryManager& ZPartition::physical_memory_manager() { + return _page_allocator->_physical; +} -public: - ZPreTouchTask(zoffset start, zoffset_end end) - : ZTask("ZPreTouchTask"), - _current(untype(start)), - _end(untype(end)) {} +#ifdef ASSERT - virtual void work() { - const size_t size = ZGranuleSize; +void ZPartition::verify_virtual_memory_multi_partition_association(const ZVirtualMemory& vmem) const { + const ZVirtualMemoryManager& manager = virtual_memory_manager(); - for (;;) { - // Claim an offset for this thread - const uintptr_t claimed = Atomic::fetch_then_add(&_current, size); - if (claimed >= _end) { - // Done - break; - } + assert(manager.is_in_multi_partition(vmem), + "Virtual memory must be associated with the extra space " + "actual: %u", virtual_memory_manager().lookup_partition_id(vmem)); +} - // At this point we know that we have a valid zoffset / zaddress. - const zoffset offset = to_zoffset(claimed); - const zaddress addr = ZOffset::address(offset); +void ZPartition::verify_virtual_memory_association(const ZVirtualMemory& vmem, bool check_multi_partition) const { + const ZVirtualMemoryManager& manager = virtual_memory_manager(); - // Pre-touch the granule - pretouch(addr, size); - } + if (check_multi_partition && manager.is_in_multi_partition(vmem)) { + // We allow claim/free/commit physical operation in multi-partition allocations + // to use virtual memory associated with the extra space. + return; } -}; -bool ZPageAllocator::prime_cache(ZWorkers* workers, size_t size) { - ZAllocationFlags flags; - flags.set_non_blocking(); - flags.set_low_address(); + const uint32_t vmem_numa_id = virtual_memory_manager().lookup_partition_id(vmem); + assert(_numa_id == vmem_numa_id, + "Virtual memory must be associated with the current partition " + "expected: %u, actual: %u", _numa_id, vmem_numa_id); +} - ZPage* const page = alloc_page(ZPageType::large, size, flags, ZPageAge::eden); - if (page == nullptr) { - return false; +void ZPartition::verify_virtual_memory_association(const ZArray* vmems) const { + for (const ZVirtualMemory& vmem : *vmems) { + verify_virtual_memory_association(vmem); } +} - if (AlwaysPreTouch) { - // Pre-touch page - ZPreTouchTask task(page->start(), page->end()); - workers->run_all(&task); - } +void ZPartition::verify_memory_allocation_association(const ZMemoryAllocation* allocation) const { + assert(this == &allocation->partition(), + "Memory allocation must be associated with the current partition " + "expected: %u, actual: %u", _numa_id, allocation->partition().numa_id()); +} - free_page(page, false /* allow_defragment */); +#endif // ASSERT - return true; -} +ZPartition::ZPartition(uint32_t numa_id, ZPageAllocator* page_allocator) + : _page_allocator(page_allocator), + _cache(), + _uncommitter(numa_id, this), + _min_capacity(ZNUMA::calculate_share(numa_id, page_allocator->min_capacity())), + _max_capacity(ZNUMA::calculate_share(numa_id, page_allocator->max_capacity())), + _current_max_capacity(_max_capacity), + _capacity(0), + _claimed(0), + _used(0), + _last_commit(0.0), + _last_uncommit(0.0), + _to_uncommit(0), + _numa_id(numa_id) {} -size_t ZPageAllocator::initial_capacity() const { - return _initial_capacity; +uint32_t ZPartition::numa_id() const { + return _numa_id; } -size_t ZPageAllocator::min_capacity() const { - return _min_capacity; +size_t ZPartition::available() const { + return _current_max_capacity - _used - _claimed; } -size_t ZPageAllocator::max_capacity() const { - return _max_capacity; -} +size_t ZPartition::increase_capacity(size_t size) { + const size_t increased = MIN2(size, _current_max_capacity - _capacity); -size_t ZPageAllocator::soft_max_capacity() const { - // Note that SoftMaxHeapSize is a manageable flag - const size_t soft_max_capacity = Atomic::load(&SoftMaxHeapSize); - const size_t current_max_capacity = Atomic::load(&_current_max_capacity); - return MIN2(soft_max_capacity, current_max_capacity); + if (increased > 0) { + // Update atomically since we have concurrent readers + Atomic::add(&_capacity, increased); + + _last_commit = os::elapsedTime(); + _last_uncommit = 0; + _cache.reset_min(); + } + + return increased; } -size_t ZPageAllocator::capacity() const { - return Atomic::load(&_capacity); +void ZPartition::decrease_capacity(size_t size, bool set_max_capacity) { + // Update capacity atomically since we have concurrent readers + Atomic::sub(&_capacity, size); + + // Adjust current max capacity to avoid further attempts to increase capacity + if (set_max_capacity) { + const size_t current_max_capacity_before = _current_max_capacity; + Atomic::store(&_current_max_capacity, _capacity); + + log_debug_p(gc)("Forced to lower max partition (%u) capacity from " + "%zuM(%.0f%%) to %zuM(%.0f%%)", + _numa_id, + current_max_capacity_before / M, percent_of(current_max_capacity_before, _max_capacity), + _current_max_capacity / M, percent_of(_current_max_capacity, _max_capacity)); + } } -size_t ZPageAllocator::used() const { - return Atomic::load(&_used); +void ZPartition::increase_used(size_t size) { + // The partition usage tracking is only read and updated under the page + // allocator lock. Usage statistics for generations and GC cycles are + // collected on the ZPageAllocator level. + _used += size; } -size_t ZPageAllocator::used_generation(ZGenerationId id) const { - return Atomic::load(&_used_generations[(int)id]); +void ZPartition::decrease_used(size_t size) { + // The partition usage tracking is only read and updated under the page + // allocator lock. Usage statistics for generations and GC cycles are + // collected on the ZPageAllocator level. + _used -= size; } -size_t ZPageAllocator::unused() const { - const ssize_t capacity = (ssize_t)Atomic::load(&_capacity); - const ssize_t used = (ssize_t)Atomic::load(&_used); - const ssize_t claimed = (ssize_t)Atomic::load(&_claimed); +void ZPartition::free_memory(const ZVirtualMemory& vmem) { + const size_t size = vmem.size(); + + // Cache the vmem + _cache.insert(vmem); + + // Update accounting + decrease_used(size); +} + +void ZPartition::claim_from_cache_or_increase_capacity(ZMemoryAllocation* allocation) { + const size_t size = allocation->size(); + ZArray* const out = allocation->partial_vmems(); + + // We are guaranteed to succeed the claiming of capacity here + assert(available() >= size, "Must be"); + + // Associate the allocation with this partition. + allocation->set_partition(this); + + // Try to allocate one contiguous vmem + ZVirtualMemory vmem = _cache.remove_contiguous(size); + if (!vmem.is_null()) { + // Found a satisfying vmem in the cache + allocation->set_satisfied_from_cache_vmem(vmem); + + // Done + return; + } + + // Try increase capacity + const size_t increased_capacity = increase_capacity(size); + + allocation->set_increased_capacity(increased_capacity); + + if (increased_capacity == size) { + // Capacity increase covered the entire request, done. + return; + } + + // Could not increase capacity enough to satisfy the allocation completely. + // Try removing multiple vmems from the mapped cache. + const size_t remaining = size - increased_capacity; + const size_t harvested = _cache.remove_discontiguous(remaining, out); + const int num_harvested = out->length(); + + allocation->set_harvested(num_harvested, harvested); + + assert(harvested + increased_capacity == size, + "Mismatch harvested: %zu increased_capacity: %zu size: %zu", + harvested, increased_capacity, size); + + return; +} + +bool ZPartition::claim_capacity(ZMemoryAllocation* allocation) { + const size_t size = allocation->size(); + + if (available() < size) { + // Out of memory + return false; + } + + claim_from_cache_or_increase_capacity(allocation); + + // Updated used statistics + increase_used(size); + + // Success + return true; +} + +size_t ZPartition::uncommit(uint64_t* timeout) { + ZArray flushed_vmems; + size_t flushed = 0; + + { + // We need to join the suspendible thread set while manipulating capacity + // and used, to make sure GC safepoints will have a consistent view. + SuspendibleThreadSetJoiner sts_joiner; + ZLocker locker(&_page_allocator->_lock); + + const double now = os::elapsedTime(); + const double time_since_last_commit = std::floor(now - _last_commit); + const double time_since_last_uncommit = std::floor(now - _last_uncommit); + + if (time_since_last_commit < double(ZUncommitDelay)) { + // We have committed within the delay, stop uncommitting. + *timeout = uint64_t(double(ZUncommitDelay) - time_since_last_commit); + return 0; + } + + // We flush out and uncommit chunks at a time (~0.8% of the max capacity, + // but at least one granule and at most 256M), in case demand for memory + // increases while we are uncommitting. + const size_t limit_upper_bound = MAX2(ZGranuleSize, align_down(256 * M / ZNUMA::count(), ZGranuleSize)); + const size_t limit = MIN2(align_up(_current_max_capacity >> 7, ZGranuleSize), limit_upper_bound); + + if (limit == 0) { + // This may occur if the current max capacity for this partition is 0 + + // Set timeout to ZUncommitDelay + *timeout = ZUncommitDelay; + return 0; + } + + if (time_since_last_uncommit < double(ZUncommitDelay)) { + // We are in the uncommit phase + const size_t num_uncommits_left = _to_uncommit / limit; + const double time_left = double(ZUncommitDelay) - time_since_last_uncommit; + if (time_left < *timeout * num_uncommits_left) { + // Running out of time, speed up. + uint64_t new_timeout = uint64_t(std::floor(time_left / double(num_uncommits_left + 1))); + *timeout = new_timeout; + } + } else { + // We are about to start uncommitting + _to_uncommit = _cache.reset_min(); + _last_uncommit = now; + + const size_t split = _to_uncommit / limit + 1; + uint64_t new_timeout = ZUncommitDelay / split; + *timeout = new_timeout; + } + + // Never uncommit below min capacity. + const size_t retain = MAX2(_used, _min_capacity); + const size_t release = _capacity - retain; + const size_t flush = MIN3(release, limit, _to_uncommit); + + if (flush == 0) { + // Nothing to flush + return 0; + } + + // Flush memory from the mapped cache to uncommit + flushed = _cache.remove_from_min(flush, &flushed_vmems); + if (flushed == 0) { + // Nothing flushed + return 0; + } + + // Record flushed memory as claimed and how much we've flushed for this partition + Atomic::add(&_claimed, flushed); + _to_uncommit -= flushed; + } + + // Unmap and uncommit flushed memory + for (const ZVirtualMemory vmem : flushed_vmems) { + unmap_virtual(vmem); + uncommit_physical(vmem); + free_physical(vmem); + free_virtual(vmem); + } + + { + SuspendibleThreadSetJoiner sts_joiner; + ZLocker locker(&_page_allocator->_lock); + + // Adjust claimed and capacity to reflect the uncommit + Atomic::sub(&_claimed, flushed); + decrease_capacity(flushed, false /* set_max_capacity */); + } + + return flushed; +} + +void ZPartition::sort_segments_physical(const ZVirtualMemory& vmem) { + verify_virtual_memory_association(vmem, true /* check_multi_partition */); + + ZPhysicalMemoryManager& manager = physical_memory_manager(); + + // Sort physical segments + manager.sort_segments_physical(vmem); +} + +void ZPartition::claim_physical(const ZVirtualMemory& vmem) { + verify_virtual_memory_association(vmem, true /* check_multi_partition */); + + ZPhysicalMemoryManager& manager = physical_memory_manager(); + + // Alloc physical memory + manager.alloc(vmem, _numa_id); +} + +void ZPartition::free_physical(const ZVirtualMemory& vmem) { + verify_virtual_memory_association(vmem, true /* check_multi_partition */); + + ZPhysicalMemoryManager& manager = physical_memory_manager(); + + // Free physical memory + manager.free(vmem, _numa_id); +} + +size_t ZPartition::commit_physical(const ZVirtualMemory& vmem) { + verify_virtual_memory_association(vmem, true /* check_multi_partition */); + + ZPhysicalMemoryManager& manager = physical_memory_manager(); + + // Commit physical memory + return manager.commit(vmem, _numa_id); +} + +size_t ZPartition::uncommit_physical(const ZVirtualMemory& vmem) { + assert(ZUncommit, "should not uncommit when uncommit is disabled"); + verify_virtual_memory_association(vmem); + + ZPhysicalMemoryManager& manager = physical_memory_manager(); + + // Uncommit physical memory + return manager.uncommit(vmem); +} + +void ZPartition::map_virtual(const ZVirtualMemory& vmem) { + verify_virtual_memory_association(vmem); + + ZPhysicalMemoryManager& manager = physical_memory_manager(); + + // Map virtual memory to physical memory + manager.map(vmem, _numa_id); +} + +void ZPartition::unmap_virtual(const ZVirtualMemory& vmem) { + verify_virtual_memory_association(vmem); + + ZPhysicalMemoryManager& manager = physical_memory_manager(); + + // Unmap virtual memory from physical memory + manager.unmap(vmem); +} + +void ZPartition::map_virtual_from_multi_partition(const ZVirtualMemory& vmem) { + verify_virtual_memory_multi_partition_association(vmem); + + ZPhysicalMemoryManager& manager = physical_memory_manager(); + + // Sort physical segments + manager.sort_segments_physical(vmem); + + // Map virtual memory to physical memory + manager.map(vmem, _numa_id); +} + +void ZPartition::unmap_virtual_from_multi_partition(const ZVirtualMemory& vmem) { + verify_virtual_memory_multi_partition_association(vmem); + + ZPhysicalMemoryManager& manager = physical_memory_manager(); + + // Unmap virtual memory from physical memory + manager.unmap(vmem); +} + +ZVirtualMemory ZPartition::claim_virtual(size_t size) { + ZVirtualMemoryManager& manager = virtual_memory_manager(); + + return manager.remove_from_low(size, _numa_id); +} + +size_t ZPartition::claim_virtual(size_t size, ZArray* vmems_out) { + ZVirtualMemoryManager& manager = virtual_memory_manager(); + + return manager.remove_from_low_many_at_most(size, _numa_id, vmems_out); +} + +void ZPartition::free_virtual(const ZVirtualMemory& vmem) { + verify_virtual_memory_association(vmem); + + ZVirtualMemoryManager& manager = virtual_memory_manager(); + + // Free virtual memory + manager.insert(vmem, _numa_id); +} + +void ZPartition::free_and_claim_virtual_from_low_many(const ZVirtualMemory& vmem, ZArray* vmems_out) { + verify_virtual_memory_association(vmem); + + ZVirtualMemoryManager& manager = virtual_memory_manager(); + + // Shuffle virtual memory + manager.insert_and_remove_from_low_many(vmem, _numa_id, vmems_out); +} + +ZVirtualMemory ZPartition::free_and_claim_virtual_from_low_exact_or_many(size_t size, ZArray* vmems_in_out) { + verify_virtual_memory_association(vmems_in_out); + + ZVirtualMemoryManager& manager = virtual_memory_manager(); + + // Shuffle virtual memory + return manager.insert_and_remove_from_low_exact_or_many(size, _numa_id, vmems_in_out); +} + +static void pretouch_memory(zoffset start, size_t size) { + // At this point we know that we have a valid zoffset / zaddress. + const zaddress zaddr = ZOffset::address(start); + const uintptr_t addr = untype(zaddr); + const size_t page_size = ZLargePages::is_explicit() ? ZGranuleSize : os::vm_page_size(); + os::pretouch_memory((void*)addr, (void*)(addr + size), page_size); +} + +class ZPreTouchTask : public ZTask { +private: + volatile uintptr_t _current; + const uintptr_t _end; + +public: + ZPreTouchTask(zoffset start, zoffset_end end) + : ZTask("ZPreTouchTask"), + _current(untype(start)), + _end(untype(end)) {} + + virtual void work() { + const size_t size = ZGranuleSize; + + for (;;) { + // Claim an offset for this thread + const uintptr_t claimed = Atomic::fetch_then_add(&_current, size); + if (claimed >= _end) { + // Done + break; + } + + // At this point we know that we have a valid zoffset / zaddress. + const zoffset offset = to_zoffset(claimed); + + // Pre-touch the granule + pretouch_memory(offset, size); + } + } +}; + +bool ZPartition::prime(ZWorkers* workers, size_t size) { + if (size == 0) { + return true; + } + + // Claim virtual memory + const ZVirtualMemory vmem = claim_virtual(size); + + // Increase capacity + increase_capacity(size); + + // Claim the backing physical memory + claim_physical(vmem); + + // Commit the claimed physical memory + const size_t committed = commit_physical(vmem); + + if (committed != vmem.size()) { + // This is a failure state. We do not cleanup the maybe partially committed memory. + return false; + } + + map_virtual(vmem); + + check_numa_mismatch(vmem, _numa_id); + + if (AlwaysPreTouch) { + // Pre-touch memory + ZPreTouchTask task(vmem.start(), vmem.end()); + workers->run_all(&task); + } + + // We don't have to take a lock here as no other threads will access the cache + // until we're finished + _cache.insert(vmem); + + return true; +} + +ZVirtualMemory ZPartition::prepare_harvested_and_claim_virtual(ZMemoryAllocation* allocation) { + verify_memory_allocation_association(allocation); + + // Unmap virtual memory + for (const ZVirtualMemory vmem : *allocation->partial_vmems()) { + unmap_virtual(vmem); + } + + const size_t harvested = allocation->harvested(); + const int granule_count = (int)(harvested >> ZGranuleSizeShift); + ZPhysicalMemoryManager& manager = physical_memory_manager(); + + // Stash segments + ZArray stash(granule_count); + manager.stash_segments(*allocation->partial_vmems(), &stash); + + // Shuffle virtual memory. We attempt to allocate enough memory to cover the + // entire allocation size, not just for the harvested memory. + const ZVirtualMemory result = free_and_claim_virtual_from_low_exact_or_many(allocation->size(), allocation->partial_vmems()); + + // Restore segments + if (!result.is_null()) { + // Got exact match. Restore stashed physical segments for the harvested part. + manager.restore_segments(result.first_part(harvested), stash); + } else { + // Got many partial vmems + manager.restore_segments(*allocation->partial_vmems(), stash); + } + + if (result.is_null()) { + // Before returning harvested memory to the cache it must be mapped. + for (const ZVirtualMemory vmem : *allocation->partial_vmems()) { + map_virtual(vmem); + } + } + + return result; +} + +void ZPartition::copy_physical_segments_to_partition(const ZVirtualMemory& at, const ZVirtualMemory& from) { + verify_virtual_memory_association(at); + verify_virtual_memory_association(from, true /* check_multi_partition */); + + ZPhysicalMemoryManager& manager = physical_memory_manager(); + + // Copy segments + manager.copy_physical_segments(at, from); +} + +void ZPartition::copy_physical_segments_from_partition(const ZVirtualMemory& at, const ZVirtualMemory& to) { + verify_virtual_memory_association(at); + verify_virtual_memory_association(to, true /* check_multi_partition */); + + ZPhysicalMemoryManager& manager = physical_memory_manager(); + + + // Copy segments + manager.copy_physical_segments(to, at); +} + +void ZPartition::commit_increased_capacity(ZMemoryAllocation* allocation, const ZVirtualMemory& vmem) { + assert(allocation->increased_capacity() > 0, "Nothing to commit"); + + const size_t already_committed = allocation->harvested(); + + const ZVirtualMemory already_committed_vmem = vmem.first_part(already_committed); + const ZVirtualMemory to_be_committed_vmem = vmem.last_part(already_committed); + + // Try to commit the uncommitted physical memory + const size_t committed = commit_physical(to_be_committed_vmem); + + // Keep track of the committed amount + allocation->set_committed_capacity(committed); +} + +void ZPartition::map_memory(ZMemoryAllocation* allocation, const ZVirtualMemory& vmem) { + sort_segments_physical(vmem); + map_virtual(vmem); + + check_numa_mismatch(vmem, allocation->partition().numa_id()); +} + +void ZPartition::free_memory_alloc_failed(ZMemoryAllocation* allocation) { + verify_memory_allocation_association(allocation); + + // Only decrease the overall used and not the generation used, + // since the allocation failed and generation used wasn't bumped. + decrease_used(allocation->size()); + + size_t freed = 0; + + // Free mapped memory + for (const ZVirtualMemory vmem : *allocation->partial_vmems()) { + freed += vmem.size(); + _cache.insert(vmem); + } + assert(allocation->harvested() + allocation->committed_capacity() == freed, "must have freed all"); + + // Adjust capacity to reflect the failed capacity increase + const size_t remaining = allocation->size() - freed; + if (remaining > 0) { + const bool set_max_capacity = allocation->commit_failed(); + decrease_capacity(remaining, set_max_capacity); + } +} + +void ZPartition::threads_do(ThreadClosure* tc) const { + tc->do_thread(const_cast(&_uncommitter)); +} + +void ZPartition::print_on(outputStream* st) const { + st->print("Partition %u", _numa_id); + st->fill_to(17); + st->print_cr("used %zuM, capacity %zuM, max capacity %zuM", + _used / M, _capacity / M, _max_capacity / M); + + streamIndentor indentor(st, 1); + print_cache_on(st); +} + +void ZPartition::print_cache_on(outputStream* st) const { + _cache.print_on(st); +} + +void ZPartition::print_extended_on_error(outputStream* st) const { + st->print_cr("Partition %u", _numa_id); + + streamIndentor indentor(st, 1); + + _cache.print_extended_on(st); +} + +class ZMultiPartitionTracker : CHeapObj { +private: + struct Element { + ZVirtualMemory _vmem; + ZPartition* _partition; + }; + + ZArray _map; + + ZMultiPartitionTracker(int capacity) + : _map(capacity) {} + + const ZArray* map() const { + return &_map; + } + + ZArray* map() { + return &_map; + } + +public: + void prepare_memory_for_free(const ZVirtualMemory& vmem, ZArray* vmems_out) const { + // Remap memory back to original partition + for (const Element partial_allocation : *map()) { + ZVirtualMemory remaining_vmem = partial_allocation._vmem; + ZPartition& partition = *partial_allocation._partition; + + const size_t size = remaining_vmem.size(); + + // Allocate new virtual address ranges + const int start_index = vmems_out->length(); + const size_t claimed_virtual = partition.claim_virtual(remaining_vmem.size(), vmems_out); + + // We are holding memory associated with this partition, and we do not + // overcommit virtual memory claiming. So virtual memory must always + // be available. + assert(claimed_virtual == size, "must succeed"); + + // Remap to the newly allocated virtual address ranges + for (const ZVirtualMemory& to_vmem : vmems_out->slice_back(start_index)) { + const ZVirtualMemory from_vmem = remaining_vmem.shrink_from_front(to_vmem.size()); + + // Copy physical segments + partition.copy_physical_segments_to_partition(to_vmem, from_vmem); + + // Unmap from_vmem + partition.unmap_virtual_from_multi_partition(from_vmem); + + // Map to_vmem + partition.map_virtual(to_vmem); + } + assert(remaining_vmem.size() == 0, "must have mapped all claimed virtual memory"); + } + } + + static void destroy(const ZMultiPartitionTracker* tracker) { + delete tracker; + } + + static ZMultiPartitionTracker* create(const ZMultiPartitionAllocation* multi_partition_allocation, const ZVirtualMemory& vmem) { + const ZArray* const partial_allocations = multi_partition_allocation->allocations(); + + ZMultiPartitionTracker* const tracker = new ZMultiPartitionTracker(partial_allocations->length()); + + ZVirtualMemory remaining = vmem; + + // Each partial allocation is mapped to the virtual memory in order + for (ZMemoryAllocation* partial_allocation : *partial_allocations) { + // Track each separate vmem's partition + const ZVirtualMemory partial_vmem = remaining.shrink_from_front(partial_allocation->size()); + ZPartition* const partition = &partial_allocation->partition(); + tracker->map()->push({partial_vmem, partition}); + } + + return tracker; + } +}; + +ZPageAllocator::ZPageAllocator(size_t min_capacity, + size_t initial_capacity, + size_t soft_max_capacity, + size_t max_capacity) + : _lock(), + _virtual(max_capacity), + _physical(max_capacity), + _min_capacity(min_capacity), + _max_capacity(max_capacity), + _used(0), + _used_generations{0,0}, + _collection_stats{{0, 0},{0, 0}}, + _partitions(ZValueIdTagType{}, this), + _stalled(), + _safe_destroy(), + _initialized(false) { + + if (!_virtual.is_initialized() || !_physical.is_initialized()) { + return; + } + + log_info_p(gc, init)("Min Capacity: %zuM", min_capacity / M); + log_info_p(gc, init)("Initial Capacity: %zuM", initial_capacity / M); + log_info_p(gc, init)("Max Capacity: %zuM", max_capacity / M); + log_info_p(gc, init)("Soft Max Capacity: %zuM", soft_max_capacity / M); + if (ZPageSizeMedium > 0) { + log_info_p(gc, init)("Medium Page Size: %zuM", ZPageSizeMedium / M); + } else { + log_info_p(gc, init)("Medium Page Size: N/A"); + } + log_info_p(gc, init)("Pre-touch: %s", AlwaysPreTouch ? "Enabled" : "Disabled"); + + // Warn if system limits could stop us from reaching max capacity + _physical.warn_commit_limits(max_capacity); + + // Check if uncommit should and can be enabled + _physical.try_enable_uncommit(min_capacity, max_capacity); + + // Successfully initialized + _initialized = true; +} + +bool ZPageAllocator::is_initialized() const { + return _initialized; +} + +bool ZPageAllocator::prime_cache(ZWorkers* workers, size_t size) { + ZPartitionIterator iter = partition_iterator(); + for (ZPartition* partition; iter.next(&partition);) { + const uint32_t numa_id = partition->numa_id(); + const size_t to_prime = ZNUMA::calculate_share(numa_id, size); + + if (!partition->prime(workers, to_prime)) { + return false; + } + } + + return true; +} + +size_t ZPageAllocator::min_capacity() const { + return _min_capacity; +} + +size_t ZPageAllocator::max_capacity() const { + return _max_capacity; +} + +size_t ZPageAllocator::soft_max_capacity() const { + const size_t current_max_capacity = ZPageAllocator::current_max_capacity(); + const size_t soft_max_heapsize = Atomic::load(&SoftMaxHeapSize); + return MIN2(soft_max_heapsize, current_max_capacity); +} + +size_t ZPageAllocator::current_max_capacity() const { + size_t current_max_capacity = 0; + + ZPartitionConstIterator iter = partition_iterator(); + for (const ZPartition* partition; iter.next(&partition);) { + current_max_capacity += Atomic::load(&partition->_current_max_capacity); + } + + return current_max_capacity; +} + +size_t ZPageAllocator::capacity() const { + size_t capacity = 0; + + ZPartitionConstIterator iter = partition_iterator(); + for (const ZPartition* partition; iter.next(&partition);) { + capacity += Atomic::load(&partition->_capacity); + } + + return capacity; +} + +size_t ZPageAllocator::used() const { + return Atomic::load(&_used); +} + +size_t ZPageAllocator::used_generation(ZGenerationId id) const { + return Atomic::load(&_used_generations[(int)id]); +} + +size_t ZPageAllocator::unused() const { + const ssize_t used = (ssize_t)ZPageAllocator::used(); + ssize_t capacity = 0; + ssize_t claimed = 0; + + ZPartitionConstIterator iter = partition_iterator(); + for (const ZPartition* partition; iter.next(&partition);) { + capacity += (ssize_t)Atomic::load(&partition->_capacity); + claimed += (ssize_t)Atomic::load(&partition->_claimed); + } + const ssize_t unused = capacity - used - claimed; return unused > 0 ? (size_t)unused : 0; } ZPageAllocatorStats ZPageAllocator::stats(ZGeneration* generation) const { ZLocker locker(&_lock); + return ZPageAllocatorStats(_min_capacity, _max_capacity, soft_max_capacity(), - _capacity, + capacity(), _used, _collection_stats[(int)generation->id()]._used_high, _collection_stats[(int)generation->id()]._used_low, @@ -347,435 +1385,796 @@ ZPageAllocatorStats ZPageAllocator::stats(ZGeneration* generation) const { void ZPageAllocator::reset_statistics(ZGenerationId id) { assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); - _collection_stats[(int)id]._used_high = _used; - _collection_stats[(int)id]._used_low = _used; +#ifdef ASSERT + { + // We may free without safepoint synchronization, take the lock to get + // consistent values. + ZLocker locker(&_lock); + size_t total_used = 0; + + ZPartitionIterator iter(&_partitions); + for (ZPartition* partition; iter.next(&partition);) { + total_used += partition->_used; + } + + assert(total_used == _used, "Must be consistent at safepoint %zu == %zu", total_used, _used); + } +#endif + + // Read once, we may have concurrent writers. + const size_t used = Atomic::load(&_used); + + _collection_stats[(int)id]._used_high = used; + _collection_stats[(int)id]._used_low = used; } -size_t ZPageAllocator::increase_capacity(size_t size) { - const size_t increased = MIN2(size, _current_max_capacity - _capacity); +void ZPageAllocator::increase_used_generation(ZGenerationId id, size_t size) { + // Update atomically since we have concurrent readers and writers + Atomic::add(&_used_generations[(int)id], size, memory_order_relaxed); +} - if (increased > 0) { - // Update atomically since we have concurrent readers - Atomic::add(&_capacity, increased); +void ZPageAllocator::decrease_used_generation(ZGenerationId id, size_t size) { + // Update atomically since we have concurrent readers and writers + Atomic::sub(&_used_generations[(int)id], size, memory_order_relaxed); +} + +void ZPageAllocator::promote_used(const ZPage* from, const ZPage* to) { + assert(from->start() == to->start(), "pages start at same offset"); + assert(from->size() == to->size(), "pages are the same size"); + assert(from->age() != ZPageAge::old, "must be promotion"); + assert(to->age() == ZPageAge::old, "must be promotion"); + + decrease_used_generation(ZGenerationId::young, to->size()); + increase_used_generation(ZGenerationId::old, to->size()); +} - // Record time of last commit. When allocation, we prefer increasing - // the capacity over flushing the cache. That means there could be - // expired pages in the cache at this time. However, since we are - // increasing the capacity we are obviously in need of committed - // memory and should therefore not be uncommitting memory. - _cache.set_last_commit(); +static void check_out_of_memory_during_initialization() { + if (!is_init_completed()) { + vm_exit_during_initialization("java.lang.OutOfMemoryError", "Java heap too small"); } +} - return increased; +ZPage* ZPageAllocator::alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age) { + EventZPageAllocation event; + + ZPageAllocation allocation(type, size, flags, age); + + // Allocate the page + ZPage* const page = alloc_page_inner(&allocation); + if (page == nullptr) { + return nullptr; + } + + // Update allocation statistics. Exclude gc relocations to avoid + // artificial inflation of the allocation rate during relocation. + if (!flags.gc_relocation() && is_init_completed()) { + // Note that there are two allocation rate counters, which have + // different purposes and are sampled at different frequencies. + ZStatInc(ZCounterMutatorAllocationRate, size); + ZStatMutatorAllocRate::sample_allocation(size); + } + + const ZPageAllocationStats stats = allocation.stats(); + const int num_harvested_vmems = stats._num_harvested_vmems; + const size_t harvested = stats._total_harvested; + const size_t committed = stats._total_committed_capacity; + + if (harvested > 0) { + ZStatInc(ZCounterMappedCacheHarvest, harvested); + log_debug(gc, heap)("Mapped Cache Harvested: %zuM (%d)", harvested / M, num_harvested_vmems); + } + + // Send event for successful allocation + allocation.send_event(true /* successful */); + + return page; } -void ZPageAllocator::decrease_capacity(size_t size, bool set_max_capacity) { - // Update atomically since we have concurrent readers - Atomic::sub(&_capacity, size); +bool ZPageAllocator::alloc_page_stall(ZPageAllocation* allocation) { + ZStatTimer timer(ZCriticalPhaseAllocationStall); + EventZAllocationStall event; - if (set_max_capacity) { - // Adjust current max capacity to avoid further attempts to increase capacity - log_error_p(gc)("Forced to lower max Java heap size from " - "%zuM(%.0f%%) to %zuM(%.0f%%)", - _current_max_capacity / M, percent_of(_current_max_capacity, _max_capacity), - _capacity / M, percent_of(_capacity, _max_capacity)); + // We can only block if the VM is fully initialized + check_out_of_memory_during_initialization(); - // Update atomically since we have concurrent readers - Atomic::store(&_current_max_capacity, _capacity); + // Start asynchronous minor GC + const ZDriverRequest request(GCCause::_z_allocation_stall, ZYoungGCThreads, 0); + ZDriver::minor()->collect(request); + + // Wait for allocation to complete or fail + const bool result = allocation->wait(); + + { + // Guard deletion of underlying semaphore. This is a workaround for + // a bug in sem_post() in glibc < 2.21, where it's not safe to destroy + // the semaphore immediately after returning from sem_wait(). The + // reason is that sem_post() can touch the semaphore after a waiting + // thread have returned from sem_wait(). To avoid this race we are + // forcing the waiting thread to acquire/release the lock held by the + // posting thread. https://sourceware.org/bugzilla/show_bug.cgi?id=12674 + ZLocker locker(&_lock); } + + // Send event + event.commit((u8)allocation->type(), allocation->size()); + + return result; } -void ZPageAllocator::increase_used(size_t size) { - // We don't track generation usage here because this page - // could be allocated by a thread that satisfies a stalling - // allocation. The stalled thread can wake up and potentially - // realize that the page alloc should be undone. If the alloc - // and the undo gets separated by a safepoint, the generation - // statistics could se a decreasing used value between mark - // start and mark end. +ZPage* ZPageAllocator::alloc_page_inner(ZPageAllocation* allocation) { +retry: - // Update atomically since we have concurrent readers - const size_t used = Atomic::add(&_used, size); + // Claim the capacity needed for this allocation. + // + // The claimed capacity comes from memory already mapped in the cache, or + // from increasing the capacity. The increased capacity allows us to allocate + // physical memory from the physical memory manager later on. + // + // Note that this call might block in a safepoint if the non-blocking flag is + // not set. + if (!claim_capacity_or_stall(allocation)) { + // Out of memory + return nullptr; + } - // Update used high - for (auto& stats : _collection_stats) { - if (used > stats._used_high) { - stats._used_high = used; + // If the entire claimed capacity came from claiming a single vmem from the + // mapped cache then the allocation has been satisfied and we are done. + const ZVirtualMemory cached_vmem = satisfied_from_cache_vmem(allocation); + if (!cached_vmem.is_null()) { + return create_page(allocation, cached_vmem); + } + + // We couldn't find a satisfying vmem in the cache, so we need to build one. + + // Claim virtual memory, either from remapping harvested vmems from the + // mapped cache or by claiming it straight from the virtual memory manager. + const ZVirtualMemory vmem = claim_virtual_memory(allocation); + if (vmem.is_null()) { + log_error(gc)("Out of address space"); + free_after_alloc_page_failed(allocation); + + // Crash in debug builds for more information + DEBUG_ONLY(fatal("Out of address space");) + + return nullptr; + } + + // Claim physical memory for the increased capacity. The previous claiming of + // capacity guarantees that this will succeed. + claim_physical_for_increased_capacity(allocation, vmem); + + // Commit memory for the increased capacity and map the entire vmem. + if (!commit_and_map(allocation, vmem)) { + free_after_alloc_page_failed(allocation); + goto retry; + } + + return create_page(allocation, vmem); +} + +bool ZPageAllocator::claim_capacity_or_stall(ZPageAllocation* allocation) { + { + ZLocker locker(&_lock); + + // Try to claim memory + if (claim_capacity(allocation)) { + // Keep track of usage + increase_used(allocation->size()); + + return true; + } + + // Failed to claim memory + if (allocation->flags().non_blocking()) { + // Don't stall + return false; } + + // Enqueue allocation request + _stalled.insert_last(allocation); } + + // Stall + return alloc_page_stall(allocation); } -void ZPageAllocator::decrease_used(size_t size) { - // Update atomically since we have concurrent readers - const size_t used = Atomic::sub(&_used, size); +bool ZPageAllocator::claim_capacity(ZPageAllocation* allocation) { + const uint32_t start_numa_id = allocation->initiating_numa_id(); + const uint32_t start_partition = start_numa_id; + const uint32_t num_partitions = _partitions.count(); - // Update used low - for (auto& stats : _collection_stats) { - if (used < stats._used_low) { - stats._used_low = used; + // Round robin single-partition claiming + + for (uint32_t i = 0; i < num_partitions; ++i) { + const uint32_t partition_id = (start_partition + i) % num_partitions; + + if (claim_capacity_single_partition(allocation->single_partition_allocation(), partition_id)) { + return true; } } + + if (!is_multi_partition_enabled() || sum_available() < allocation->size()) { + // Multi-partition claiming is not possible + return false; + } + + // Multi-partition claiming + + // Flip allocation to multi-partition allocation + allocation->initiate_multi_partition_allocation(); + + ZMultiPartitionAllocation* const multi_partition_allocation = allocation->multi_partition_allocation(); + + claim_capacity_multi_partition(multi_partition_allocation, start_partition); + + return true; } -void ZPageAllocator::increase_used_generation(ZGenerationId id, size_t size) { - // Update atomically since we have concurrent readers - Atomic::add(&_used_generations[(int)id], size, memory_order_relaxed); +bool ZPageAllocator::claim_capacity_single_partition(ZSinglePartitionAllocation* single_partition_allocation, uint32_t partition_id) { + ZPartition& partition = _partitions.get(partition_id); + + return partition.claim_capacity(single_partition_allocation->allocation()); } -void ZPageAllocator::decrease_used_generation(ZGenerationId id, size_t size) { - // Update atomically since we have concurrent readers - Atomic::sub(&_used_generations[(int)id], size, memory_order_relaxed); +void ZPageAllocator::claim_capacity_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation, uint32_t start_partition) { + const size_t size = multi_partition_allocation->size(); + const uint32_t num_partitions = _partitions.count(); + const size_t split_size = align_up(size / num_partitions, ZGranuleSize); + + size_t remaining = size; + + const auto do_claim_one_partition = [&](ZPartition& partition, bool claim_evenly) { + if (remaining == 0) { + // All memory claimed + return false; + } + + const size_t max_alloc_size = claim_evenly ? MIN2(split_size, remaining) : remaining; + + // This guarantees that claim_physical below will succeed + const size_t alloc_size = MIN2(max_alloc_size, partition.available()); + + // Skip over empty allocations + if (alloc_size == 0) { + // Continue + return true; + } + + ZMemoryAllocation partial_allocation(alloc_size); + + // Claim capacity for this allocation - this should succeed + const bool result = partition.claim_capacity(&partial_allocation); + assert(result, "Should have succeeded"); + + // Register allocation + multi_partition_allocation->register_allocation(partial_allocation); + + // Update remaining + remaining -= alloc_size; + + // Continue + return true; + }; + + // Loops over every partition and claims memory + const auto do_claim_each_partition = [&](bool claim_evenly) { + for (uint32_t i = 0; i < num_partitions; ++i) { + const uint32_t partition_id = (start_partition + i) % num_partitions; + ZPartition& partition = _partitions.get(partition_id); + + if (!do_claim_one_partition(partition, claim_evenly)) { + // All memory claimed + break; + } + } + }; + + // Try to claim from multiple partitions + + // Try to claim up to split_size on each partition + do_claim_each_partition(true /* claim_evenly */); + + // Try claim the remaining + do_claim_each_partition(false /* claim_evenly */); + + assert(remaining == 0, "Must have claimed capacity for the whole allocation"); } -void ZPageAllocator::promote_used(size_t size) { - decrease_used_generation(ZGenerationId::young, size); - increase_used_generation(ZGenerationId::old, size); +ZVirtualMemory ZPageAllocator::satisfied_from_cache_vmem(const ZPageAllocation* allocation) const { + if (allocation->is_multi_partition()) { + // Multi-partition allocations are always harvested and/or committed, so + // there's never a satisfying vmem from the caches. + return {}; + } + + return allocation->satisfied_from_cache_vmem(); } -bool ZPageAllocator::commit_page(ZPage* page) { - // Commit physical memory - return _physical.commit(page->physical_memory()); +ZVirtualMemory ZPageAllocator::claim_virtual_memory(ZPageAllocation* allocation) { + // Note: that the single-partition performs "shuffling" of already harvested + // vmem(s), while the multi-partition searches for available virtual memory + // area without shuffling. + + if (allocation->is_multi_partition()) { + return claim_virtual_memory_multi_partition(allocation->multi_partition_allocation()); + } else { + return claim_virtual_memory_single_partition(allocation->single_partition_allocation()); + } } -void ZPageAllocator::uncommit_page(ZPage* page) { - if (!ZUncommit) { - return; +ZVirtualMemory ZPageAllocator::claim_virtual_memory_single_partition(ZSinglePartitionAllocation* single_partition_allocation) { + ZMemoryAllocation* const allocation = single_partition_allocation->allocation(); + ZPartition& partition = allocation->partition(); + + if (allocation->harvested() > 0) { + // We claim virtual memory from the harvested vmems and perhaps also + // allocate more to match the allocation request. + return partition.prepare_harvested_and_claim_virtual(allocation); + } else { + // Just try to claim virtual memory + return partition.claim_virtual(allocation->size()); } +} - // Uncommit physical memory - _physical.uncommit(page->physical_memory()); +ZVirtualMemory ZPageAllocator::claim_virtual_memory_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation) { + const size_t size = multi_partition_allocation->size(); + + const ZVirtualMemory vmem = _virtual.remove_from_low_multi_partition(size); + if (!vmem.is_null()) { + // Copy claimed multi-partition vmems, we leave the old vmems mapped until + // after we have committed. In case committing fails we can simply + // reinsert the initial vmems. + copy_claimed_physical_multi_partition(multi_partition_allocation, vmem); + } + + return vmem; +} + +void ZPageAllocator::copy_claimed_physical_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation, const ZVirtualMemory& vmem) { + // Start at the new dest offset + ZVirtualMemory remaining_dest_vmem = vmem; + + for (const ZMemoryAllocation* partial_allocation : *multi_partition_allocation->allocations()) { + // Split off the partial allocation's destination vmem + ZVirtualMemory partial_dest_vmem = remaining_dest_vmem.shrink_from_front(partial_allocation->size()); + + // Get the partial allocation's partition + ZPartition& partition = partial_allocation->partition(); + + // Copy all physical segments from the partition to the destination vmem + for (const ZVirtualMemory from_vmem : *partial_allocation->partial_vmems()) { + // Split off destination + const ZVirtualMemory to_vmem = partial_dest_vmem.shrink_from_front(from_vmem.size()); + + // Copy physical segments + partition.copy_physical_segments_from_partition(from_vmem, to_vmem); + } + } } -void ZPageAllocator::map_page(const ZPage* page) const { - // Map physical memory - _physical.map(page->start(), page->physical_memory()); +void ZPageAllocator::claim_physical_for_increased_capacity(ZPageAllocation* allocation, const ZVirtualMemory& vmem) { + assert(allocation->size() == vmem.size(), "vmem should be the final entry"); + + if (allocation->is_multi_partition()) { + claim_physical_for_increased_capacity_multi_partition(allocation->multi_partition_allocation(), vmem); + } else { + claim_physical_for_increased_capacity_single_partition(allocation->single_partition_allocation(), vmem); + } } -void ZPageAllocator::unmap_page(const ZPage* page) const { - // Unmap physical memory - _physical.unmap(page->start(), page->size()); +void ZPageAllocator::claim_physical_for_increased_capacity_single_partition(ZSinglePartitionAllocation* single_partition_allocation, const ZVirtualMemory& vmem) { + claim_physical_for_increased_capacity(single_partition_allocation->allocation(), vmem); } -void ZPageAllocator::safe_destroy_page(ZPage* page) { - // Destroy page safely - _safe_destroy.schedule_delete(page); +void ZPageAllocator::claim_physical_for_increased_capacity_multi_partition(const ZMultiPartitionAllocation* multi_partition_allocation, const ZVirtualMemory& vmem) { + ZVirtualMemory remaining = vmem; + + for (ZMemoryAllocation* allocation : *multi_partition_allocation->allocations()) { + const ZVirtualMemory partial = remaining.shrink_from_front(allocation->size()); + claim_physical_for_increased_capacity(allocation, partial); + } } -void ZPageAllocator::destroy_page(ZPage* page) { - // Free virtual memory - _virtual.free(page->virtual_memory()); +void ZPageAllocator::claim_physical_for_increased_capacity(ZMemoryAllocation* allocation, const ZVirtualMemory& vmem) { + // The previously harvested memory is memory that has already been committed + // and mapped. The rest of the vmem gets physical memory assigned here and + // will be committed in a subsequent function. - // Free physical memory - _physical.free(page->physical_memory()); + const size_t already_committed = allocation->harvested(); + const size_t non_committed = allocation->size() - already_committed; + const size_t increased_capacity = allocation->increased_capacity(); - // Destroy page safely - safe_destroy_page(page); + assert(non_committed == increased_capacity, + "Mismatch non_committed: " PTR_FORMAT " increased_capacity: " PTR_FORMAT, + non_committed, increased_capacity); + + if (non_committed > 0) { + ZPartition& partition = allocation->partition(); + ZVirtualMemory non_committed_vmem = vmem.last_part(already_committed); + partition.claim_physical(non_committed_vmem); + } +} + +bool ZPageAllocator::commit_and_map(ZPageAllocation* allocation, const ZVirtualMemory& vmem) { + assert(allocation->size() == vmem.size(), "vmem should be the final entry"); + + if (allocation->is_multi_partition()) { + return commit_and_map_multi_partition(allocation->multi_partition_allocation(), vmem); + } else { + return commit_and_map_single_partition(allocation->single_partition_allocation(), vmem); + } +} + +bool ZPageAllocator::commit_and_map_single_partition(ZSinglePartitionAllocation* single_partition_allocation, const ZVirtualMemory& vmem) { + const bool commit_successful = commit_single_partition(single_partition_allocation, vmem); + + // Map the vmem + map_committed_single_partition(single_partition_allocation, vmem); + + if (commit_successful) { + return true; + } + + // Commit failed + cleanup_failed_commit_single_partition(single_partition_allocation, vmem); + + return false; +} + +bool ZPageAllocator::commit_and_map_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation, const ZVirtualMemory& vmem) { + if (commit_multi_partition(multi_partition_allocation, vmem)) { + // Commit successful + + // Unmap harvested vmems + unmap_harvested_multi_partition(multi_partition_allocation); + + // Map the vmem + map_committed_multi_partition(multi_partition_allocation, vmem); + + return true; + } + + // Commit failed + cleanup_failed_commit_multi_partition(multi_partition_allocation, vmem); + + return false; +} + +void ZPageAllocator::commit(ZMemoryAllocation* allocation, const ZVirtualMemory& vmem) { + ZPartition& partition = allocation->partition(); + + if (allocation->increased_capacity() > 0) { + // Commit memory + partition.commit_increased_capacity(allocation, vmem); + } +} + +bool ZPageAllocator::commit_single_partition(ZSinglePartitionAllocation* single_partition_allocation, const ZVirtualMemory& vmem) { + ZMemoryAllocation* const allocation = single_partition_allocation->allocation(); + + commit(allocation, vmem); + + return !allocation->commit_failed(); +} + +bool ZPageAllocator::commit_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation, const ZVirtualMemory& vmem) { + bool commit_failed = false; + ZVirtualMemory remaining = vmem; + for (ZMemoryAllocation* const allocation : *multi_partition_allocation->allocations()) { + // Split off the partial allocation's memory range + const ZVirtualMemory partial_vmem = remaining.shrink_from_front(allocation->size()); + + commit(allocation, partial_vmem); + + // Keep track if any partial allocation failed to commit + commit_failed |= allocation->commit_failed(); + } + + assert(remaining.size() == 0, "all memory must be accounted for"); + + return !commit_failed; } -bool ZPageAllocator::should_defragment(const ZPage* page) const { - // A small page can end up at a high address (second half of the address space) - // if we've split a larger page or we have a constrained address space. To help - // fight address space fragmentation we remap such pages to a lower address, if - // a lower address is available. - return page->type() == ZPageType::small && - page->start() >= to_zoffset(_virtual.reserved() / 2) && - page->start() > _virtual.lowest_available_address(); +void ZPageAllocator::unmap_harvested_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation) { + for (ZMemoryAllocation* const allocation : *multi_partition_allocation->allocations()) { + ZPartition& partition = allocation->partition(); + ZArray* const partial_vmems = allocation->partial_vmems(); + + // Unmap harvested vmems + while (!partial_vmems->is_empty()) { + const ZVirtualMemory to_unmap = partial_vmems->pop(); + partition.unmap_virtual(to_unmap); + partition.free_virtual(to_unmap); + } + } } -ZPage* ZPageAllocator::defragment_page(ZPage* page) { - // Harvest the physical memory (which is committed) - ZPhysicalMemory pmem; - ZPhysicalMemory& old_pmem = page->physical_memory(); - pmem.add_segments(old_pmem); - old_pmem.remove_segments(); +void ZPageAllocator::map_committed_single_partition(ZSinglePartitionAllocation* single_partition_allocation, const ZVirtualMemory& vmem) { + ZMemoryAllocation* const allocation = single_partition_allocation->allocation(); + ZPartition& partition = allocation->partition(); + + const size_t total_committed = allocation->harvested() + allocation->committed_capacity(); + const ZVirtualMemory total_committed_vmem = vmem.first_part(total_committed); + + if (total_committed_vmem.size() > 0) { + // Map all the committed memory + partition.map_memory(allocation, total_committed_vmem); + } +} - _unmapper->unmap_and_destroy_page(page); +void ZPageAllocator::map_committed_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation, const ZVirtualMemory& vmem) { + ZVirtualMemory remaining = vmem; + for (ZMemoryAllocation* const allocation : *multi_partition_allocation->allocations()) { + assert(!allocation->commit_failed(), "Sanity check"); - // Allocate new virtual memory at a low address - const ZVirtualMemory vmem = _virtual.alloc(pmem.size(), true /* force_low_address */); + ZPartition& partition = allocation->partition(); - // Create the new page and map it - ZPage* new_page = new ZPage(ZPageType::small, vmem, pmem); - map_page(new_page); + // Split off the partial allocation's memory range + const ZVirtualMemory to_vmem = remaining.shrink_from_front(allocation->size()); - // Update statistics - ZStatInc(ZCounterDefragment); + // Map the partial_allocation to partial_vmem + partition.map_virtual_from_multi_partition(to_vmem); + } - return new_page; + assert(remaining.size() == 0, "all memory must be accounted for"); } -bool ZPageAllocator::is_alloc_allowed(size_t size) const { - const size_t available = _current_max_capacity - _used - _claimed; - return available >= size; -} +void ZPageAllocator::cleanup_failed_commit_single_partition(ZSinglePartitionAllocation* single_partition_allocation, const ZVirtualMemory& vmem) { + ZMemoryAllocation* const allocation = single_partition_allocation->allocation(); -bool ZPageAllocator::alloc_page_common_inner(ZPageType type, size_t size, ZList* pages) { - if (!is_alloc_allowed(size)) { - // Out of memory - return false; - } + assert(allocation->commit_failed(), "Must have failed to commit"); - // Try allocate from the page cache - ZPage* const page = _cache.alloc_page(type, size); - if (page != nullptr) { - // Success - pages->insert_last(page); - return true; - } + const size_t committed = allocation->committed_capacity(); + const ZVirtualMemory non_harvested_vmem = vmem.last_part(allocation->harvested()); + const ZVirtualMemory committed_vmem = non_harvested_vmem.first_part(committed); + const ZVirtualMemory non_committed_vmem = non_harvested_vmem.last_part(committed); - // Try increase capacity - const size_t increased = increase_capacity(size); - if (increased < size) { - // Could not increase capacity enough to satisfy the allocation - // completely. Flush the page cache to satisfy the remainder. - const size_t remaining = size - increased; - _cache.flush_for_allocation(remaining, pages); + if (committed_vmem.size() > 0) { + // Register the committed and mapped memory. We insert the committed + // memory into partial_vmems so that it will be inserted into the cache + // in a subsequent step. + allocation->partial_vmems()->append(committed_vmem); } - // Success - return true; + // Free the virtual and physical memory we fetched to use but failed to commit + ZPartition& partition = allocation->partition(); + partition.free_physical(non_committed_vmem); + partition.free_virtual(non_committed_vmem); } -bool ZPageAllocator::alloc_page_common(ZPageAllocation* allocation) { - const ZPageType type = allocation->type(); - const size_t size = allocation->size(); - const ZAllocationFlags flags = allocation->flags(); - ZList* const pages = allocation->pages(); +void ZPageAllocator::cleanup_failed_commit_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation, const ZVirtualMemory& vmem) { + ZVirtualMemory remaining = vmem; + for (ZMemoryAllocation* const allocation : *multi_partition_allocation->allocations()) { + // Split off the partial allocation's memory range + const ZVirtualMemory partial_vmem = remaining.shrink_from_front(allocation->size()); - if (!alloc_page_common_inner(type, size, pages)) { - // Out of memory - return false; - } + if (allocation->harvested() == allocation->size()) { + // Everything is harvested, the mappings are already in the partial_vmems, + // nothing to cleanup. + continue; + } - // Updated used statistics - increase_used(size); + const size_t committed = allocation->committed_capacity(); + const ZVirtualMemory non_harvested_vmem = vmem.last_part(allocation->harvested()); + const ZVirtualMemory committed_vmem = non_harvested_vmem.first_part(committed); + const ZVirtualMemory non_committed_vmem = non_harvested_vmem.last_part(committed); - // Success - return true; -} + ZPartition& partition = allocation->partition(); -static void check_out_of_memory_during_initialization() { - if (!is_init_completed()) { - vm_exit_during_initialization("java.lang.OutOfMemoryError", "Java heap too small"); - } -} + if (allocation->commit_failed()) { + // Free the physical memory we failed to commit. Virtual memory is later + // freed for the entire multi-partition allocation after all memory + // allocations have been visited. + partition.free_physical(non_committed_vmem); + } -bool ZPageAllocator::alloc_page_stall(ZPageAllocation* allocation) { - ZStatTimer timer(ZCriticalPhaseAllocationStall); - EventZAllocationStall event; + if (committed_vmem.size() == 0) { + // Nothing committed, nothing more to cleanup + continue; + } - // We can only block if the VM is fully initialized - check_out_of_memory_during_initialization(); + // Remove the harvested part + const ZVirtualMemory non_harvest_vmem = partial_vmem.last_part(allocation->harvested()); - // Start asynchronous minor GC - const ZDriverRequest request(GCCause::_z_allocation_stall, ZYoungGCThreads, 0); - ZDriver::minor()->collect(request); + ZArray* const partial_vmems = allocation->partial_vmems(); - // Wait for allocation to complete or fail - const bool result = allocation->wait(); + // Keep track of the start index + const int start_index = partial_vmems->length(); - { - // Guard deletion of underlying semaphore. This is a workaround for - // a bug in sem_post() in glibc < 2.21, where it's not safe to destroy - // the semaphore immediately after returning from sem_wait(). The - // reason is that sem_post() can touch the semaphore after a waiting - // thread have returned from sem_wait(). To avoid this race we are - // forcing the waiting thread to acquire/release the lock held by the - // posting thread. https://sourceware.org/bugzilla/show_bug.cgi?id=12674 - ZLocker locker(&_lock); - } + // Claim virtual memory for the committed part + const size_t claimed_virtual = partition.claim_virtual(committed, partial_vmems); - // Send event - event.commit((u8)allocation->type(), allocation->size()); + // We are holding memory associated with this partition, and we do not + // overcommit virtual memory claiming. So virtual memory must always be + // available. + assert(claimed_virtual == committed, "must succeed"); - return result; -} + // Associate and map the physical memory with the partial vmems -bool ZPageAllocator::alloc_page_or_stall(ZPageAllocation* allocation) { - { - ZLocker locker(&_lock); + ZVirtualMemory remaining_committed_vmem = committed_vmem; + for (const ZVirtualMemory& to_vmem : partial_vmems->slice_back(start_index)) { + const ZVirtualMemory from_vmem = remaining_committed_vmem.shrink_from_front(to_vmem.size()); - if (alloc_page_common(allocation)) { - // Success - return true; - } + // Copy physical mappings + partition.copy_physical_segments_to_partition(to_vmem, from_vmem); - // Failed - if (allocation->flags().non_blocking()) { - // Don't stall - return false; + // Map memory + partition.map_virtual(to_vmem); } - // Enqueue allocation request - _stalled.insert_last(allocation); + assert(remaining_committed_vmem.size() == 0, "all memory must be accounted for"); } - // Stall - return alloc_page_stall(allocation); + assert(remaining.size() == 0, "all memory must be accounted for"); + + // Free the unused virtual memory + _virtual.insert_multi_partition(vmem); } -ZPage* ZPageAllocator::alloc_page_create(ZPageAllocation* allocation) { - const size_t size = allocation->size(); +void ZPageAllocator::free_after_alloc_page_failed(ZPageAllocation* allocation) { + // Send event for failed allocation + allocation->send_event(false /* successful */); - // Allocate virtual memory. To make error handling a lot more straight - // forward, we allocate virtual memory before destroying flushed pages. - // Flushed pages are also unmapped and destroyed asynchronously, so we - // can't immediately reuse that part of the address space anyway. - const ZVirtualMemory vmem = _virtual.alloc(size, allocation->flags().low_address()); - if (vmem.is_null()) { - log_error(gc)("Out of address space"); - return nullptr; - } + ZLocker locker(&_lock); - ZPhysicalMemory pmem; - size_t flushed = 0; + // Free memory + free_memory_alloc_failed(allocation); - // Harvest physical memory from flushed pages - ZListRemoveIterator iter(allocation->pages()); - for (ZPage* page; iter.next(&page);) { - flushed += page->size(); + // Keep track of usage + decrease_used(allocation->size()); + + // Reset allocation for a potential retry + allocation->reset_for_retry(); + + // Try satisfy stalled allocations + satisfy_stalled(); +} - // Harvest flushed physical memory - ZPhysicalMemory& fmem = page->physical_memory(); - pmem.add_segments(fmem); - fmem.remove_segments(); +void ZPageAllocator::free_memory_alloc_failed(ZPageAllocation* allocation) { + // The current max capacity may be decreased, store the value before freeing memory + const size_t current_max_capacity_before = current_max_capacity(); - // Unmap and destroy page - _unmapper->unmap_and_destroy_page(page); + if (allocation->is_multi_partition()) { + free_memory_alloc_failed_multi_partition(allocation->multi_partition_allocation()); + } else { + free_memory_alloc_failed_single_partition(allocation->single_partition_allocation()); } - if (flushed > 0) { - allocation->set_flushed(flushed); + const size_t current_max_capacity_after = current_max_capacity(); - // Update statistics - ZStatInc(ZCounterPageCacheFlush, flushed); - log_debug(gc, heap)("Page Cache Flushed: %zuM", flushed / M); + if (current_max_capacity_before != current_max_capacity_after) { + log_error_p(gc)("Forced to lower max Java heap size from " + "%zuM(%.0f%%) to %zuM(%.0f%%)", + current_max_capacity_before / M, percent_of(current_max_capacity_before, _max_capacity), + current_max_capacity_after / M, percent_of(current_max_capacity_after, _max_capacity)); } +} + +void ZPageAllocator::free_memory_alloc_failed_single_partition(ZSinglePartitionAllocation* single_partition_allocation) { + free_memory_alloc_failed(single_partition_allocation->allocation()); +} - // Allocate any remaining physical memory. Capacity and used has - // already been adjusted, we just need to fetch the memory, which - // is guaranteed to succeed. - if (flushed < size) { - const size_t remaining = size - flushed; - allocation->set_committed(remaining); - _physical.alloc(pmem, remaining); +void ZPageAllocator::free_memory_alloc_failed_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation) { + for (ZMemoryAllocation* allocation : *multi_partition_allocation->allocations()) { + free_memory_alloc_failed(allocation); } +} + +void ZPageAllocator::free_memory_alloc_failed(ZMemoryAllocation* allocation) { + ZPartition& partition = allocation->partition(); - // Create new page - return new ZPage(allocation->type(), vmem, pmem); + partition.free_memory_alloc_failed(allocation); } -bool ZPageAllocator::is_alloc_satisfied(ZPageAllocation* allocation) const { - // The allocation is immediately satisfied if the list of pages contains - // exactly one page, with the type and size that was requested. However, - // even if the allocation is immediately satisfied we might still want to - // return false here to force the page to be remapped to fight address - // space fragmentation. +ZPage* ZPageAllocator::create_page(ZPageAllocation* allocation, const ZVirtualMemory& vmem) { + // We don't track generation usage when claiming capacity, because this page + // could have been allocated by a thread that satisfies a stalling allocation. + // The stalled thread can wake up and potentially realize that the page alloc + // should be undone. If the alloc and the undo gets separated by a safepoint, + // the generation statistics could se a decreasing used value between mark + // start and mark end. At this point an allocation will be successful, so we + // update the generation usage. + const ZGenerationId id = allocation->age() == ZPageAge::old ? ZGenerationId::old : ZGenerationId::young; + increase_used_generation(id, allocation->size()); - if (allocation->pages()->size() != 1) { - // Not a single page - return false; - } + const ZPageType type = allocation->type(); + const ZPageAge age = allocation->age(); - const ZPage* const page = allocation->pages()->first(); - if (page->type() != allocation->type() || - page->size() != allocation->size()) { - // Wrong type or size - return false; + if (allocation->is_multi_partition()) { + const ZMultiPartitionAllocation* const multi_partition_allocation = allocation->multi_partition_allocation(); + ZMultiPartitionTracker* const tracker = ZMultiPartitionTracker::create(multi_partition_allocation, vmem); + + return new ZPage(type, age, vmem, tracker); } - // Allocation immediately satisfied - return true; + const ZSinglePartitionAllocation* const single_partition_allocation = allocation->single_partition_allocation(); + const uint32_t partition_id = single_partition_allocation->allocation()->partition().numa_id(); + + return new ZPage(type, age, vmem, partition_id); } -ZPage* ZPageAllocator::alloc_page_finalize(ZPageAllocation* allocation) { - // Fast path - if (is_alloc_satisfied(allocation)) { - return allocation->pages()->remove_first(); - } +void ZPageAllocator::prepare_memory_for_free(ZPage* page, ZArray* vmems) { + // Extract memory and destroy the page + const ZVirtualMemory vmem = page->virtual_memory(); + const ZPageType page_type = page->type(); + const ZMultiPartitionTracker* const tracker = page->multi_partition_tracker(); - // Slow path - ZPage* const page = alloc_page_create(allocation); - if (page == nullptr) { - // Out of address space - return nullptr; - } + safe_destroy_page(page); - // Commit page - if (commit_page(page)) { - // Success - map_page(page); - return page; - } + // Multi-partition memory is always remapped + if (tracker != nullptr) { + tracker->prepare_memory_for_free(vmem, vmems); + + // Free the virtual memory + _virtual.insert_multi_partition(vmem); - // Failed or partially failed. Split of any successfully committed - // part of the page into a new page and insert it into list of pages, - // so that it will be re-inserted into the page cache. - ZPage* const committed_page = page->split_committed(); - destroy_page(page); + // Destroy the tracker + ZMultiPartitionTracker::destroy(tracker); + return; + } - if (committed_page != nullptr) { - map_page(committed_page); - allocation->pages()->insert_last(committed_page); + // Try to remap and defragment if page is large + if (page_type == ZPageType::large) { + remap_and_defragment(vmem, vmems); + return; } - return nullptr; + // Leave the memory untouched + vmems->append(vmem); } -ZPage* ZPageAllocator::alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age) { - EventZPageAllocation event; +void ZPageAllocator::remap_and_defragment(const ZVirtualMemory& vmem, ZArray* vmems_out) { + ZPartition& partition = partition_from_vmem(vmem); -retry: - ZPageAllocation allocation(type, size, flags); - - // Allocate one or more pages from the page cache. If the allocation - // succeeds but the returned pages don't cover the complete allocation, - // then finalize phase is allowed to allocate the remaining memory - // directly from the physical memory manager. Note that this call might - // block in a safepoint if the non-blocking flag is not set. - if (!alloc_page_or_stall(&allocation)) { - // Out of memory - return nullptr; + // If no lower address can be found, don't remap/defrag + if (_virtual.lowest_available_address(partition.numa_id()) > vmem.start()) { + vmems_out->append(vmem); + return; } - ZPage* const page = alloc_page_finalize(&allocation); - if (page == nullptr) { - // Failed to commit or map. Clean up and retry, in the hope that - // we can still allocate by flushing the page cache (more aggressively). - free_pages_alloc_failed(&allocation); - goto retry; - } + ZStatInc(ZCounterDefragment); - // The generation's used is tracked here when the page is handed out - // to the allocating thread. The overall heap "used" is tracked in - // the lower-level allocation code. - const ZGenerationId id = age == ZPageAge::old ? ZGenerationId::old : ZGenerationId::young; - increase_used_generation(id, size); + // Synchronously unmap the virtual memory + partition.unmap_virtual(vmem); - // Reset page. This updates the page's sequence number and must - // be done after we potentially blocked in a safepoint (stalled) - // where the global sequence number was updated. - page->reset(age); - page->reset_top_for_allocation(); - page->reset_livemap(); - if (age == ZPageAge::old) { - page->remset_alloc(); - } + // Stash segments + ZArray stash(vmem.granule_count()); + _physical.stash_segments(vmem, &stash); - // Update allocation statistics. Exclude gc relocations to avoid - // artificial inflation of the allocation rate during relocation. - if (!flags.gc_relocation() && is_init_completed()) { - // Note that there are two allocation rate counters, which have - // different purposes and are sampled at different frequencies. - ZStatInc(ZCounterMutatorAllocationRate, size); - ZStatMutatorAllocRate::sample_allocation(size); + // Shuffle vmem - put new vmems in vmems_out + const int start_index = vmems_out->length(); + partition.free_and_claim_virtual_from_low_many(vmem, vmems_out); + + // The output array may contain results from other defragmentations as well, + // so we only operate on the result(s) we just got. + ZArraySlice defragmented_vmems = vmems_out->slice_back(start_index); + + // Restore segments + _physical.restore_segments(defragmented_vmems, stash); + + // Map and pre-touch + for (const ZVirtualMemory& claimed_vmem : defragmented_vmems) { + partition.map_virtual(claimed_vmem); + pretouch_memory(claimed_vmem.start(), claimed_vmem.size()); } +} - // Send event - event.commit((u8)type, size, allocation.flushed(), allocation.committed(), - page->physical_memory().nsegments(), flags.non_blocking()); +void ZPageAllocator::free_memory(ZArray* vmems) { + ZLocker locker(&_lock); - return page; + // Free the vmems + for (const ZVirtualMemory vmem : *vmems) { + ZPartition& partition = partition_from_vmem(vmem); + + // Free the vmem + partition.free_memory(vmem); + + // Keep track of usage + decrease_used(vmem.size()); + } + + // Try satisfy stalled allocations + satisfy_stalled(); } void ZPageAllocator::satisfy_stalled() { @@ -786,11 +2185,14 @@ void ZPageAllocator::satisfy_stalled() { return; } - if (!alloc_page_common(allocation)) { + if (!claim_capacity(allocation)) { // Allocation could not be satisfied, give up return; } + // Keep track of usage + increase_used(allocation->size()); + // Allocation succeeded, dequeue and satisfy allocation request. // Note that we must dequeue the allocation request first, since // it will immediately be deallocated once it has been satisfied. @@ -799,164 +2201,94 @@ void ZPageAllocator::satisfy_stalled() { } } -ZPage* ZPageAllocator::prepare_to_recycle(ZPage* page, bool allow_defragment) { - // Make sure we have a page that is safe to recycle - ZPage* const to_recycle = _safe_recycle.register_and_clone_if_activated(page); - - // Defragment the page before recycle if allowed and needed - if (allow_defragment && should_defragment(to_recycle)) { - return defragment_page(to_recycle); - } - - // Remove the remset before recycling - if (to_recycle->is_old() && to_recycle == page) { - to_recycle->remset_delete(); - } - - return to_recycle; +bool ZPageAllocator::is_multi_partition_enabled() const { + return _virtual.is_multi_partition_enabled(); } -void ZPageAllocator::recycle_page(ZPage* page) { - // Set time when last used - page->set_last_used(); - - // Cache page - _cache.free_page(page); +const ZPartition& ZPageAllocator::partition_from_partition_id(uint32_t numa_id) const { + return _partitions.get(numa_id); } -void ZPageAllocator::free_page(ZPage* page, bool allow_defragment) { - const ZGenerationId generation_id = page->generation_id(); - - // Prepare page for recycling before taking the lock - ZPage* const to_recycle = prepare_to_recycle(page, allow_defragment); - - ZLocker locker(&_lock); - - // Update used statistics - const size_t size = to_recycle->size(); - decrease_used(size); - decrease_used_generation(generation_id, size); - - // Free page - recycle_page(to_recycle); - - // Try satisfy stalled allocations - satisfy_stalled(); +ZPartition& ZPageAllocator::partition_from_partition_id(uint32_t numa_id) { + return _partitions.get(numa_id); } -void ZPageAllocator::free_pages(const ZArray* pages) { - ZArray to_recycle_pages; - - size_t young_size = 0; - size_t old_size = 0; - - // Prepare pages for recycling before taking the lock - ZArrayIterator pages_iter(pages); - for (ZPage* page; pages_iter.next(&page);) { - if (page->is_young()) { - young_size += page->size(); - } else { - old_size += page->size(); - } +ZPartition& ZPageAllocator::partition_from_vmem(const ZVirtualMemory& vmem) { + return partition_from_partition_id(_virtual.lookup_partition_id(vmem)); +} - // Prepare to recycle - ZPage* const to_recycle = prepare_to_recycle(page, true /* allow_defragment */); +size_t ZPageAllocator::sum_available() const { + size_t total = 0; - // Register for recycling - to_recycle_pages.push(to_recycle); + ZPartitionConstIterator iter = partition_iterator(); + for (const ZPartition* partition; iter.next(&partition);) { + total += partition->available(); } - ZLocker locker(&_lock); + return total; +} - // Update used statistics - decrease_used(young_size + old_size); - decrease_used_generation(ZGenerationId::young, young_size); - decrease_used_generation(ZGenerationId::old, old_size); +void ZPageAllocator::increase_used(size_t size) { + // Update atomically since we have concurrent readers + const size_t used = Atomic::add(&_used, size); - // Free pages - ZArrayIterator iter(&to_recycle_pages); - for (ZPage* page; iter.next(&page);) { - recycle_page(page); + // Update used high + for (auto& stats : _collection_stats) { + if (used > stats._used_high) { + stats._used_high = used; + } } - - // Try satisfy stalled allocations - satisfy_stalled(); } -void ZPageAllocator::free_pages_alloc_failed(ZPageAllocation* allocation) { - // The page(s) in the allocation are either taken from the cache or a newly - // created, mapped and commited ZPage. These page(s) have not been inserted in - // the page table, nor allocated a remset, so prepare_to_recycle is not required. - ZLocker locker(&_lock); - - // Only decrease the overall used and not the generation used, - // since the allocation failed and generation used wasn't bumped. - decrease_used(allocation->size()); - - size_t freed = 0; +void ZPageAllocator::decrease_used(size_t size) { + // Update atomically since we have concurrent readers + const size_t used = Atomic::sub(&_used, size); - // Free any allocated/flushed pages - ZListRemoveIterator iter(allocation->pages()); - for (ZPage* page; iter.next(&page);) { - freed += page->size(); - recycle_page(page); + // Update used low + for (auto& stats : _collection_stats) { + if (used < stats._used_low) { + stats._used_low = used; + } } - - // Adjust capacity and used to reflect the failed capacity increase - const size_t remaining = allocation->size() - freed; - decrease_capacity(remaining, true /* set_max_capacity */); - - // Try satisfy stalled allocations - satisfy_stalled(); } -size_t ZPageAllocator::uncommit(uint64_t* timeout) { - // We need to join the suspendible thread set while manipulating capacity and - // used, to make sure GC safepoints will have a consistent view. - ZList pages; - size_t flushed; +void ZPageAllocator::safe_destroy_page(ZPage* page) { + // Destroy page safely + _safe_destroy.schedule_delete(page); +} - { - SuspendibleThreadSetJoiner sts_joiner; - ZLocker locker(&_lock); +void ZPageAllocator::free_page(ZPage* page) { + // Extract the id from the page + const ZGenerationId id = page->generation_id(); + const size_t size = page->size(); - // Never uncommit below min capacity. We flush out and uncommit chunks at - // a time (~0.8% of the max capacity, but at least one granule and at most - // 256M), in case demand for memory increases while we are uncommitting. - const size_t retain = MAX2(_used, _min_capacity); - const size_t release = _capacity - retain; - const size_t limit = MIN2(align_up(_current_max_capacity >> 7, ZGranuleSize), 256 * M); - const size_t flush = MIN2(release, limit); + // Extract vmems and destroy the page + ZArray vmems; + prepare_memory_for_free(page, &vmems); - // Flush pages to uncommit - flushed = _cache.flush_for_uncommit(flush, &pages, timeout); - if (flushed == 0) { - // Nothing flushed - return 0; - } + // Updated used statistics + decrease_used_generation(id, size); - // Record flushed pages as claimed - Atomic::add(&_claimed, flushed); - } + // Free the extracted vmems + free_memory(&vmems); +} - // Unmap, uncommit, and destroy flushed pages - ZListRemoveIterator iter(&pages); - for (ZPage* page; iter.next(&page);) { - unmap_page(page); - uncommit_page(page); - destroy_page(page); - } +void ZPageAllocator::free_pages(ZGenerationId id, const ZArray* pages) { + // Prepare memory from pages to be cached + ZArray vmems; + for (ZPage* page : *pages) { + assert(page->generation_id() == id, "All pages must be from the same generation"); + const size_t size = page->size(); - { - SuspendibleThreadSetJoiner sts_joiner; - ZLocker locker(&_lock); + // Extract vmems and destroy the page + prepare_memory_for_free(page, &vmems); - // Adjust claimed and capacity to reflect the uncommit - Atomic::sub(&_claimed, flushed); - decrease_capacity(flushed, false /* set_max_capacity */); + // Updated used statistics + decrease_used_generation(id, size); } - return flushed; + // Free the extracted vmems + free_memory(&vmems); } void ZPageAllocator::enable_safe_destroy() const { @@ -967,14 +2299,6 @@ void ZPageAllocator::disable_safe_destroy() const { _safe_destroy.disable_deferred_delete(); } -void ZPageAllocator::enable_safe_recycle() const { - _safe_recycle.activate(); -} - -void ZPageAllocator::disable_safe_recycle() const { - _safe_recycle.deactivate(); -} - static bool has_alloc_seen_young(const ZPageAllocation* allocation) { return allocation->young_seqnum() != ZGeneration::young()->seqnum(); } @@ -1045,7 +2369,94 @@ void ZPageAllocator::handle_alloc_stalling_for_old(bool cleared_all_soft_refs) { restart_gc(); } +ZPartitionConstIterator ZPageAllocator::partition_iterator() const { + return ZPartitionConstIterator(&_partitions); +} + +ZPartitionIterator ZPageAllocator::partition_iterator() { + return ZPartitionIterator(&_partitions); +} + void ZPageAllocator::threads_do(ThreadClosure* tc) const { - tc->do_thread(_unmapper); - tc->do_thread(_uncommitter); + ZPartitionConstIterator iter = partition_iterator(); + for (const ZPartition* partition; iter.next(&partition);) { + partition->threads_do(tc); + } +} + +void ZPageAllocator::print_on(outputStream* st) const { + ZLocker lock(&_lock); + print_on_inner(st); +} + +static bool try_lock_on_error(ZLock* lock) { + if (VMError::is_error_reported() && VMError::is_error_reported_in_current_thread()) { + return lock->try_lock(); + } + + lock->lock(); + + return true; +} + +void ZPageAllocator::print_extended_on_error(outputStream* st) const { + st->print_cr("ZMappedCache:"); + + streamIndentor indentor(st, 1); + + if (!try_lock_on_error(&_lock)) { + // We can't print without taking the lock since printing the contents of + // the cache requires iterating over the nodes in the cache's tree, which + // is not thread-safe. + st->print_cr(""); + + return; + } + + // Print each partition's cache content + ZPartitionConstIterator iter = partition_iterator(); + for (const ZPartition* partition; iter.next(&partition);) { + partition->print_extended_on_error(st); + } + + _lock.unlock(); +} + +void ZPageAllocator::print_on_error(outputStream* st) const { + const bool locked = try_lock_on_error(&_lock); + + if (!locked) { + st->print_cr(""); + } + + // Print information even though we have not successfully taken the lock. + // This is thread-safe, but may produce inconsistent results. + print_on_inner(st); + + if (locked) { + _lock.unlock(); + } +} + +void ZPageAllocator::print_on_inner(outputStream* st) const { + // Print total usage + st->print("ZHeap"); + st->fill_to(17); + st->print_cr("used %zuM, capacity %zuM, max capacity %zuM", + used() / M, capacity() / M, max_capacity() / M); + + // Print per-partition + + streamIndentor indentor(st, 1); + + if (_partitions.count() == 1) { + // The summary printing is redundant if we only have one partition + _partitions.get(0).print_cache_on(st); + return; + } + + ZPartitionConstIterator iter = partition_iterator(); + for (const ZPartition* partition; iter.next(&partition);) { + partition->print_on(st); + } } diff --git a/src/hotspot/share/gc/z/zPageAllocator.hpp b/src/hotspot/share/gc/z/zPageAllocator.hpp index e80169fe2602d..05b0d6774d9d3 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.hpp +++ b/src/hotspot/share/gc/z/zPageAllocator.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,107 +24,219 @@ #ifndef SHARE_GC_Z_ZPAGEALLOCATOR_HPP #define SHARE_GC_Z_ZPAGEALLOCATOR_HPP +#include "gc/z/zAddress.hpp" #include "gc/z/zAllocationFlags.hpp" #include "gc/z/zArray.hpp" +#include "gc/z/zGenerationId.hpp" +#include "gc/z/zGranuleMap.hpp" #include "gc/z/zList.hpp" #include "gc/z/zLock.hpp" +#include "gc/z/zMappedCache.hpp" +#include "gc/z/zPage.hpp" #include "gc/z/zPageAge.hpp" -#include "gc/z/zPageCache.hpp" #include "gc/z/zPageType.hpp" -#include "gc/z/zPhysicalMemory.hpp" +#include "gc/z/zPhysicalMemoryManager.hpp" #include "gc/z/zSafeDelete.hpp" -#include "gc/z/zVirtualMemory.hpp" +#include "gc/z/zUncommitter.hpp" +#include "gc/z/zValue.hpp" +#include "gc/z/zVirtualMemoryManager.hpp" +#include "utilities/ostream.hpp" class ThreadClosure; class ZGeneration; +class ZMemoryAllocation; +class ZMultiPartitionAllocation; class ZPageAllocation; class ZPageAllocator; class ZPageAllocatorStats; +class ZSegmentStash; +class ZSinglePartitionAllocation; +class ZVirtualMemory; class ZWorkers; -class ZUncommitter; -class ZUnmapper; -class ZSafePageRecycle { +class ZPartition { + friend class VMStructs; + friend class ZPageAllocator; + private: - ZPageAllocator* _page_allocator; - ZActivatedArray _unsafe_to_recycle; + ZPageAllocator* const _page_allocator; + ZMappedCache _cache; + ZUncommitter _uncommitter; + const size_t _min_capacity; + const size_t _max_capacity; + volatile size_t _current_max_capacity; + volatile size_t _capacity; + volatile size_t _claimed; + size_t _used; + double _last_commit; + double _last_uncommit; + size_t _to_uncommit; + const uint32_t _numa_id; + + const ZVirtualMemoryManager& virtual_memory_manager() const; + ZVirtualMemoryManager& virtual_memory_manager(); + + const ZPhysicalMemoryManager& physical_memory_manager() const; + ZPhysicalMemoryManager& physical_memory_manager(); + + void verify_virtual_memory_multi_partition_association(const ZVirtualMemory& vmem) const NOT_DEBUG_RETURN; + void verify_virtual_memory_association(const ZVirtualMemory& vmem, bool check_multi_partition = false) const NOT_DEBUG_RETURN; + void verify_virtual_memory_association(const ZArray* vmems) const NOT_DEBUG_RETURN; + void verify_memory_allocation_association(const ZMemoryAllocation* allocation) const NOT_DEBUG_RETURN; public: - ZSafePageRecycle(ZPageAllocator* page_allocator); + ZPartition(uint32_t numa_id, ZPageAllocator* page_allocator); + + uint32_t numa_id() const; + + size_t available() const; + + size_t increase_capacity(size_t size); + void decrease_capacity(size_t size, bool set_max_capacity); + + void increase_used(size_t size); + void decrease_used(size_t size); + + void free_memory(const ZVirtualMemory& vmem); + + void claim_from_cache_or_increase_capacity(ZMemoryAllocation* allocation); + bool claim_capacity(ZMemoryAllocation* allocation); + + size_t uncommit(uint64_t* timeout); - void activate(); - void deactivate(); + void sort_segments_physical(const ZVirtualMemory& vmem); - ZPage* register_and_clone_if_activated(ZPage* page); + void claim_physical(const ZVirtualMemory& vmem); + void free_physical(const ZVirtualMemory& vmem); + size_t commit_physical(const ZVirtualMemory& vmem); + size_t uncommit_physical(const ZVirtualMemory& vmem); + + void map_virtual(const ZVirtualMemory& vmem); + void unmap_virtual(const ZVirtualMemory& vmem); + + void map_virtual_from_multi_partition(const ZVirtualMemory& vmem); + void unmap_virtual_from_multi_partition(const ZVirtualMemory& vmem); + + ZVirtualMemory claim_virtual(size_t size); + size_t claim_virtual(size_t size, ZArray* vmems_out); + void free_virtual(const ZVirtualMemory& vmem); + + void free_and_claim_virtual_from_low_many(const ZVirtualMemory& vmem, ZArray* vmems_out); + ZVirtualMemory free_and_claim_virtual_from_low_exact_or_many(size_t size, ZArray* vmems_in_out); + + bool prime(ZWorkers* workers, size_t size); + + ZVirtualMemory prepare_harvested_and_claim_virtual(ZMemoryAllocation* allocation); + + void copy_physical_segments_to_partition(const ZVirtualMemory& at, const ZVirtualMemory& from); + void copy_physical_segments_from_partition(const ZVirtualMemory& at, const ZVirtualMemory& to); + + void commit_increased_capacity(ZMemoryAllocation* allocation, const ZVirtualMemory& vmem); + void map_memory(ZMemoryAllocation* allocation, const ZVirtualMemory& vmem); + + void free_memory_alloc_failed(ZMemoryAllocation* allocation); + + void threads_do(ThreadClosure* tc) const; + + void print_on(outputStream* st) const; + void print_cache_on(outputStream* st) const; + void print_extended_on_error(outputStream* st) const; }; +using ZPartitionIterator = ZPerNUMAIterator; +using ZPartitionConstIterator = ZPerNUMAConstIterator; + class ZPageAllocator { friend class VMStructs; - friend class ZUnmapper; + friend class ZMultiPartitionTracker; + friend class ZPartition; friend class ZUncommitter; private: - mutable ZLock _lock; - ZPageCache _cache; - ZVirtualMemoryManager _virtual; - ZPhysicalMemoryManager _physical; - const size_t _min_capacity; - const size_t _initial_capacity; - const size_t _max_capacity; - volatile size_t _current_max_capacity; - volatile size_t _capacity; - volatile size_t _claimed; - volatile size_t _used; - size_t _used_generations[2]; + mutable ZLock _lock; + ZVirtualMemoryManager _virtual; + ZPhysicalMemoryManager _physical; + const size_t _min_capacity; + const size_t _max_capacity; + volatile size_t _used; + volatile size_t _used_generations[2]; struct { - size_t _used_high; - size_t _used_low; - } _collection_stats[2]; - ZList _stalled; - ZUnmapper* _unmapper; - ZUncommitter* _uncommitter; - mutable ZSafeDelete _safe_destroy; - mutable ZSafePageRecycle _safe_recycle; - bool _initialized; + size_t _used_high; + size_t _used_low; + } _collection_stats[2]; + ZPerNUMA _partitions; + ZList _stalled; + mutable ZSafeDelete _safe_destroy; + bool _initialized; - size_t increase_capacity(size_t size); - void decrease_capacity(size_t size, bool set_max_capacity); + bool alloc_page_stall(ZPageAllocation* allocation); + ZPage* alloc_page_inner(ZPageAllocation* allocation); - void increase_used(size_t size); - void decrease_used(size_t size); + bool claim_capacity_or_stall(ZPageAllocation* allocation); + bool claim_capacity(ZPageAllocation* allocation); + bool claim_capacity_single_partition(ZSinglePartitionAllocation* single_partition_allocation, uint32_t partition_id); + void claim_capacity_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation, uint32_t start_partition); - void increase_used_generation(ZGenerationId id, size_t size); - void decrease_used_generation(ZGenerationId id, size_t size); + ZVirtualMemory satisfied_from_cache_vmem(const ZPageAllocation* allocation) const; - bool commit_page(ZPage* page); - void uncommit_page(ZPage* page); + ZVirtualMemory claim_virtual_memory(ZPageAllocation* allocation); + ZVirtualMemory claim_virtual_memory_single_partition(ZSinglePartitionAllocation* single_partition_allocation); + ZVirtualMemory claim_virtual_memory_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation); - void map_page(const ZPage* page) const; - void unmap_page(const ZPage* page) const; + void copy_claimed_physical_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation, const ZVirtualMemory& vmem); - void destroy_page(ZPage* page); + void claim_physical_for_increased_capacity(ZPageAllocation* allocation, const ZVirtualMemory& vmem); + void claim_physical_for_increased_capacity_single_partition(ZSinglePartitionAllocation* allocation, const ZVirtualMemory& vmem); + void claim_physical_for_increased_capacity_multi_partition(const ZMultiPartitionAllocation* multi_partition_allocation, const ZVirtualMemory& vmem); + void claim_physical_for_increased_capacity(ZMemoryAllocation* allocation, const ZVirtualMemory& vmem); - bool should_defragment(const ZPage* page) const; - ZPage* defragment_page(ZPage* page); + bool commit_and_map(ZPageAllocation* allocation, const ZVirtualMemory& vmem); + bool commit_and_map_single_partition(ZSinglePartitionAllocation* single_partition_allocation, const ZVirtualMemory& vmem); + bool commit_and_map_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation, const ZVirtualMemory& vmem); - bool is_alloc_allowed(size_t size) const; + void commit(ZMemoryAllocation* allocation, const ZVirtualMemory& vmem); + bool commit_single_partition(ZSinglePartitionAllocation* single_partition_allocation, const ZVirtualMemory& vmem); + bool commit_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation, const ZVirtualMemory& vmem); - bool alloc_page_common_inner(ZPageType type, size_t size, ZList* pages); - bool alloc_page_common(ZPageAllocation* allocation); - bool alloc_page_stall(ZPageAllocation* allocation); - bool alloc_page_or_stall(ZPageAllocation* allocation); - bool is_alloc_satisfied(ZPageAllocation* allocation) const; - ZPage* alloc_page_create(ZPageAllocation* allocation); - ZPage* alloc_page_finalize(ZPageAllocation* allocation); - void free_pages_alloc_failed(ZPageAllocation* allocation); + void unmap_harvested_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation); + + void map_committed_single_partition(ZSinglePartitionAllocation* single_partition_allocation, const ZVirtualMemory& vmem); + void map_committed_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation, const ZVirtualMemory& vmem); + + void cleanup_failed_commit_single_partition(ZSinglePartitionAllocation* single_partition_allocation, const ZVirtualMemory& vmem); + void cleanup_failed_commit_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation, const ZVirtualMemory& vmem); + + void free_after_alloc_page_failed(ZPageAllocation* allocation); + + void free_memory_alloc_failed(ZPageAllocation* allocation); + void free_memory_alloc_failed_single_partition(ZSinglePartitionAllocation* single_partition_allocation); + void free_memory_alloc_failed_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation); + void free_memory_alloc_failed(ZMemoryAllocation* allocation); + + ZPage* create_page(ZPageAllocation* allocation, const ZVirtualMemory& vmem); + + void prepare_memory_for_free(ZPage* page, ZArray* vmems); + void remap_and_defragment(const ZVirtualMemory& vmem, ZArray* vmems_out); + void free_memory(ZArray* vmems); void satisfy_stalled(); - size_t uncommit(uint64_t* timeout); + bool is_multi_partition_enabled() const; + + const ZPartition& partition_from_partition_id(uint32_t partition_id) const; + ZPartition& partition_from_partition_id(uint32_t partition_id); + ZPartition& partition_from_vmem(const ZVirtualMemory& vmem); + + size_t sum_available() const; + + void increase_used(size_t size); + void decrease_used(size_t size); void notify_out_of_memory(); void restart_gc() const; + void print_on_inner(outputStream* st) const; + public: ZPageAllocator(size_t min_capacity, size_t initial_capacity, @@ -135,56 +247,61 @@ class ZPageAllocator { bool prime_cache(ZWorkers* workers, size_t size); - size_t initial_capacity() const; size_t min_capacity() const; size_t max_capacity() const; size_t soft_max_capacity() const; + size_t current_max_capacity() const; size_t capacity() const; size_t used() const; size_t used_generation(ZGenerationId id) const; size_t unused() const; - void promote_used(size_t size); + void increase_used_generation(ZGenerationId id, size_t size); + void decrease_used_generation(ZGenerationId id, size_t size); + + void promote_used(const ZPage* from, const ZPage* to); ZPageAllocatorStats stats(ZGeneration* generation) const; void reset_statistics(ZGenerationId id); ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age); - ZPage* prepare_to_recycle(ZPage* page, bool allow_defragment); - void recycle_page(ZPage* page); void safe_destroy_page(ZPage* page); - void free_page(ZPage* page, bool allow_defragment); - void free_pages(const ZArray* pages); + void free_page(ZPage* page); + void free_pages(ZGenerationId id, const ZArray* pages); void enable_safe_destroy() const; void disable_safe_destroy() const; - void enable_safe_recycle() const; - void disable_safe_recycle() const; - bool is_alloc_stalling() const; bool is_alloc_stalling_for_old() const; void handle_alloc_stalling_for_young(); void handle_alloc_stalling_for_old(bool cleared_soft_refs); + ZPartitionConstIterator partition_iterator() const; + ZPartitionIterator partition_iterator(); + void threads_do(ThreadClosure* tc) const; + + void print_on(outputStream* st) const; + void print_extended_on_error(outputStream* st) const; + void print_on_error(outputStream* st) const; }; class ZPageAllocatorStats { private: - size_t _min_capacity; - size_t _max_capacity; - size_t _soft_max_capacity; - size_t _capacity; - size_t _used; - size_t _used_high; - size_t _used_low; - size_t _used_generation; - size_t _freed; - size_t _promoted; - size_t _compacted; - size_t _allocation_stalls; + const size_t _min_capacity; + const size_t _max_capacity; + const size_t _soft_max_capacity; + const size_t _capacity; + const size_t _used; + const size_t _used_high; + const size_t _used_low; + const size_t _used_generation; + const size_t _freed; + const size_t _promoted; + const size_t _compacted; + const size_t _allocation_stalls; public: ZPageAllocatorStats(size_t min_capacity, diff --git a/src/hotspot/share/gc/z/zPageCache.cpp b/src/hotspot/share/gc/z/zPageCache.cpp deleted file mode 100644 index c8e8ec9bdbdb7..0000000000000 --- a/src/hotspot/share/gc/z/zPageCache.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "gc/z/zGlobals.hpp" -#include "gc/z/zList.inline.hpp" -#include "gc/z/zNUMA.inline.hpp" -#include "gc/z/zPage.inline.hpp" -#include "gc/z/zPageCache.hpp" -#include "gc/z/zStat.hpp" -#include "gc/z/zValue.inline.hpp" -#include "memory/allocation.hpp" -#include "runtime/globals.hpp" -#include "runtime/os.hpp" - -static const ZStatCounter ZCounterPageCacheHitL1("Memory", "Page Cache Hit L1", ZStatUnitOpsPerSecond); -static const ZStatCounter ZCounterPageCacheHitL2("Memory", "Page Cache Hit L2", ZStatUnitOpsPerSecond); -static const ZStatCounter ZCounterPageCacheHitL3("Memory", "Page Cache Hit L3", ZStatUnitOpsPerSecond); -static const ZStatCounter ZCounterPageCacheMiss("Memory", "Page Cache Miss", ZStatUnitOpsPerSecond); - -class ZPageCacheFlushClosure : public StackObj { - friend class ZPageCache; - -protected: - const size_t _requested; - size_t _flushed; - -public: - ZPageCacheFlushClosure(size_t requested); - virtual bool do_page(const ZPage* page) = 0; -}; - -ZPageCacheFlushClosure::ZPageCacheFlushClosure(size_t requested) - : _requested(requested), - _flushed(0) {} - -ZPageCache::ZPageCache() - : _small(), - _medium(), - _large(), - _last_commit(0) {} - -ZPage* ZPageCache::alloc_small_page() { - const uint32_t numa_id = ZNUMA::id(); - const uint32_t numa_count = ZNUMA::count(); - - // Try NUMA local page cache - ZPage* const l1_page = _small.get(numa_id).remove_first(); - if (l1_page != nullptr) { - ZStatInc(ZCounterPageCacheHitL1); - return l1_page; - } - - // Try NUMA remote page cache(s) - uint32_t remote_numa_id = numa_id + 1; - const uint32_t remote_numa_count = numa_count - 1; - for (uint32_t i = 0; i < remote_numa_count; i++) { - if (remote_numa_id == numa_count) { - remote_numa_id = 0; - } - - ZPage* const l2_page = _small.get(remote_numa_id).remove_first(); - if (l2_page != nullptr) { - ZStatInc(ZCounterPageCacheHitL2); - return l2_page; - } - - remote_numa_id++; - } - - return nullptr; -} - -ZPage* ZPageCache::alloc_medium_page() { - ZPage* const page = _medium.remove_first(); - if (page != nullptr) { - ZStatInc(ZCounterPageCacheHitL1); - return page; - } - - return nullptr; -} - -ZPage* ZPageCache::alloc_large_page(size_t size) { - // Find a page with the right size - ZListIterator iter(&_large); - for (ZPage* page; iter.next(&page);) { - if (size == page->size()) { - // Page found - _large.remove(page); - ZStatInc(ZCounterPageCacheHitL1); - return page; - } - } - - return nullptr; -} - -ZPage* ZPageCache::alloc_oversized_medium_page(size_t size) { - if (size <= ZPageSizeMedium) { - return _medium.remove_first(); - } - - return nullptr; -} - -ZPage* ZPageCache::alloc_oversized_large_page(size_t size) { - // Find a page that is large enough - ZListIterator iter(&_large); - for (ZPage* page; iter.next(&page);) { - if (size <= page->size()) { - // Page found - _large.remove(page); - return page; - } - } - - return nullptr; -} - -ZPage* ZPageCache::alloc_oversized_page(size_t size) { - ZPage* page = alloc_oversized_large_page(size); - if (page == nullptr) { - page = alloc_oversized_medium_page(size); - } - - if (page != nullptr) { - ZStatInc(ZCounterPageCacheHitL3); - } - - return page; -} - -ZPage* ZPageCache::alloc_page(ZPageType type, size_t size) { - ZPage* page; - - // Try allocate exact page - if (type == ZPageType::small) { - page = alloc_small_page(); - } else if (type == ZPageType::medium) { - page = alloc_medium_page(); - } else { - page = alloc_large_page(size); - } - - if (page == nullptr) { - // Try allocate potentially oversized page - ZPage* const oversized = alloc_oversized_page(size); - if (oversized != nullptr) { - if (size < oversized->size()) { - // Split oversized page - page = oversized->split(type, size); - - // Cache remainder - free_page(oversized); - } else { - // Re-type correctly sized page - page = oversized->retype(type); - } - } - } - - if (page == nullptr) { - ZStatInc(ZCounterPageCacheMiss); - } - - return page; -} - -void ZPageCache::free_page(ZPage* page) { - const ZPageType type = page->type(); - if (type == ZPageType::small) { - _small.get(page->numa_id()).insert_first(page); - } else if (type == ZPageType::medium) { - _medium.insert_first(page); - } else { - _large.insert_first(page); - } -} - -bool ZPageCache::flush_list_inner(ZPageCacheFlushClosure* cl, ZList* from, ZList* to) { - ZPage* const page = from->last(); - if (page == nullptr || !cl->do_page(page)) { - // Don't flush page - return false; - } - - // Flush page - from->remove(page); - to->insert_last(page); - return true; -} - -void ZPageCache::flush_list(ZPageCacheFlushClosure* cl, ZList* from, ZList* to) { - while (flush_list_inner(cl, from, to)); -} - -void ZPageCache::flush_per_numa_lists(ZPageCacheFlushClosure* cl, ZPerNUMA >* from, ZList* to) { - const uint32_t numa_count = ZNUMA::count(); - uint32_t numa_done = 0; - uint32_t numa_next = 0; - - // Flush lists round-robin - while (numa_done < numa_count) { - ZList* const numa_list = from->addr(numa_next); - if (++numa_next == numa_count) { - numa_next = 0; - } - - if (flush_list_inner(cl, numa_list, to)) { - // Not done - numa_done = 0; - } else { - // Done - numa_done++; - } - } -} - -void ZPageCache::flush(ZPageCacheFlushClosure* cl, ZList* to) { - // Prefer flushing large, then medium and last small pages - flush_list(cl, &_large, to); - flush_list(cl, &_medium, to); - flush_per_numa_lists(cl, &_small, to); - - if (cl->_flushed > cl->_requested) { - // Overflushed, re-insert part of last page into the cache - const size_t overflushed = cl->_flushed - cl->_requested; - ZPage* const reinsert = to->last()->split(overflushed); - free_page(reinsert); - cl->_flushed -= overflushed; - } -} - -class ZPageCacheFlushForAllocationClosure : public ZPageCacheFlushClosure { -public: - ZPageCacheFlushForAllocationClosure(size_t requested) - : ZPageCacheFlushClosure(requested) {} - - virtual bool do_page(const ZPage* page) { - if (_flushed < _requested) { - // Flush page - _flushed += page->size(); - return true; - } - - // Don't flush page - return false; - } -}; - -void ZPageCache::flush_for_allocation(size_t requested, ZList* to) { - ZPageCacheFlushForAllocationClosure cl(requested); - flush(&cl, to); -} - -class ZPageCacheFlushForUncommitClosure : public ZPageCacheFlushClosure { -private: - const uint64_t _now; - uint64_t* _timeout; - -public: - ZPageCacheFlushForUncommitClosure(size_t requested, uint64_t now, uint64_t* timeout) - : ZPageCacheFlushClosure(requested), - _now(now), - _timeout(timeout) { - // Set initial timeout - *_timeout = ZUncommitDelay; - } - - virtual bool do_page(const ZPage* page) { - const uint64_t expires = page->last_used() + ZUncommitDelay; - if (expires > _now) { - // Don't flush page, record shortest non-expired timeout - *_timeout = MIN2(*_timeout, expires - _now); - return false; - } - - if (_flushed >= _requested) { - // Don't flush page, requested amount flushed - return false; - } - - // Flush page - _flushed += page->size(); - return true; - } -}; - -size_t ZPageCache::flush_for_uncommit(size_t requested, ZList* to, uint64_t* timeout) { - const uint64_t now = (uint64_t)os::elapsedTime(); - const uint64_t expires = _last_commit + ZUncommitDelay; - if (expires > now) { - // Delay uncommit, set next timeout - *timeout = expires - now; - return 0; - } - - if (requested == 0) { - // Nothing to flush, set next timeout - *timeout = ZUncommitDelay; - return 0; - } - - ZPageCacheFlushForUncommitClosure cl(requested, now, timeout); - flush(&cl, to); - - return cl._flushed; -} - -void ZPageCache::set_last_commit() { - _last_commit = (uint64_t)ceil(os::elapsedTime()); -} diff --git a/src/hotspot/share/gc/z/zPageCache.hpp b/src/hotspot/share/gc/z/zPageCache.hpp deleted file mode 100644 index b28aaa6c10d40..0000000000000 --- a/src/hotspot/share/gc/z/zPageCache.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2015, 2023, 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_GC_Z_ZPAGECACHE_HPP -#define SHARE_GC_Z_ZPAGECACHE_HPP - -#include "gc/z/zList.hpp" -#include "gc/z/zPage.hpp" -#include "gc/z/zPageType.hpp" -#include "gc/z/zValue.hpp" - -class ZPageCacheFlushClosure; - -class ZPageCache { -private: - ZPerNUMA > _small; - ZList _medium; - ZList _large; - uint64_t _last_commit; - - ZPage* alloc_small_page(); - ZPage* alloc_medium_page(); - ZPage* alloc_large_page(size_t size); - - ZPage* alloc_oversized_medium_page(size_t size); - ZPage* alloc_oversized_large_page(size_t size); - ZPage* alloc_oversized_page(size_t size); - - bool flush_list_inner(ZPageCacheFlushClosure* cl, ZList* from, ZList* to); - void flush_list(ZPageCacheFlushClosure* cl, ZList* from, ZList* to); - void flush_per_numa_lists(ZPageCacheFlushClosure* cl, ZPerNUMA >* from, ZList* to); - void flush(ZPageCacheFlushClosure* cl, ZList* to); - -public: - ZPageCache(); - - ZPage* alloc_page(ZPageType type, size_t size); - void free_page(ZPage* page); - - void flush_for_allocation(size_t requested, ZList* to); - size_t flush_for_uncommit(size_t requested, ZList* to, uint64_t* timeout); - - void set_last_commit(); -}; - -#endif // SHARE_GC_Z_ZPAGECACHE_HPP diff --git a/src/hotspot/share/gc/z/zPageTable.cpp b/src/hotspot/share/gc/z/zPageTable.cpp index d960270c45123..5bf94c6bae379 100644 --- a/src/hotspot/share/gc/z/zPageTable.cpp +++ b/src/hotspot/share/gc/z/zPageTable.cpp @@ -81,11 +81,9 @@ ZGenerationPagesParallelIterator::ZGenerationPagesParallelIterator(const ZPageTa _generation_id(id), _page_allocator(page_allocator) { _page_allocator->enable_safe_destroy(); - _page_allocator->enable_safe_recycle(); } ZGenerationPagesParallelIterator::~ZGenerationPagesParallelIterator() { - _page_allocator->disable_safe_recycle(); _page_allocator->disable_safe_destroy(); } @@ -94,10 +92,8 @@ ZGenerationPagesIterator::ZGenerationPagesIterator(const ZPageTable* page_table, _generation_id(id), _page_allocator(page_allocator) { _page_allocator->enable_safe_destroy(); - _page_allocator->enable_safe_recycle(); } ZGenerationPagesIterator::~ZGenerationPagesIterator() { - _page_allocator->disable_safe_recycle(); _page_allocator->disable_safe_destroy(); } diff --git a/src/hotspot/share/gc/z/zPageTable.inline.hpp b/src/hotspot/share/gc/z/zPageTable.inline.hpp index 583017d5c9cd9..6310a2104dff8 100644 --- a/src/hotspot/share/gc/z/zPageTable.inline.hpp +++ b/src/hotspot/share/gc/z/zPageTable.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,11 +103,9 @@ inline bool ZGenerationPagesIterator::next(ZPage** page) { template inline void ZGenerationPagesIterator::yield(Function function) { _page_allocator->disable_safe_destroy(); - _page_allocator->disable_safe_recycle(); function(); - _page_allocator->enable_safe_recycle(); _page_allocator->enable_safe_destroy(); } diff --git a/src/hotspot/share/gc/z/zPhysicalMemory.cpp b/src/hotspot/share/gc/z/zPhysicalMemory.cpp deleted file mode 100644 index 5b209a4c01c36..0000000000000 --- a/src/hotspot/share/gc/z/zPhysicalMemory.cpp +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/z/zAddress.inline.hpp" -#include "gc/z/zArray.inline.hpp" -#include "gc/z/zGlobals.hpp" -#include "gc/z/zLargePages.inline.hpp" -#include "gc/z/zList.inline.hpp" -#include "gc/z/zNMT.hpp" -#include "gc/z/zNUMA.inline.hpp" -#include "gc/z/zPhysicalMemory.inline.hpp" -#include "logging/log.hpp" -#include "runtime/globals.hpp" -#include "runtime/globals_extension.hpp" -#include "runtime/init.hpp" -#include "runtime/os.hpp" -#include "utilities/align.hpp" -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/powerOfTwo.hpp" - -ZPhysicalMemory::ZPhysicalMemory() - : _segments() {} - -ZPhysicalMemory::ZPhysicalMemory(const ZPhysicalMemorySegment& segment) - : _segments() { - _segments.append(segment); -} - -ZPhysicalMemory::ZPhysicalMemory(const ZPhysicalMemory& pmem) - : _segments(pmem.nsegments()) { - _segments.appendAll(&pmem._segments); -} - -const ZPhysicalMemory& ZPhysicalMemory::operator=(const ZPhysicalMemory& pmem) { - // Check for self-assignment - if (this == &pmem) { - return *this; - } - - // Free and copy segments - _segments.clear_and_deallocate(); - _segments.reserve(pmem.nsegments()); - _segments.appendAll(&pmem._segments); - - return *this; -} - -size_t ZPhysicalMemory::size() const { - size_t size = 0; - - for (int i = 0; i < _segments.length(); i++) { - size += _segments.at(i).size(); - } - - return size; -} - -void ZPhysicalMemory::insert_segment(int index, zoffset start, size_t size, bool committed) { - _segments.insert_before(index, ZPhysicalMemorySegment(start, size, committed)); -} - -void ZPhysicalMemory::replace_segment(int index, zoffset start, size_t size, bool committed) { - _segments.at_put(index, ZPhysicalMemorySegment(start, size, committed)); -} - -void ZPhysicalMemory::remove_segment(int index) { - _segments.remove_at(index); -} - -void ZPhysicalMemory::add_segments(const ZPhysicalMemory& pmem) { - for (int i = 0; i < pmem.nsegments(); i++) { - add_segment(pmem.segment(i)); - } -} - -void ZPhysicalMemory::remove_segments() { - _segments.clear_and_deallocate(); -} - -static bool is_mergable(const ZPhysicalMemorySegment& before, const ZPhysicalMemorySegment& after) { - return before.end() == after.start() && before.is_committed() == after.is_committed(); -} - -void ZPhysicalMemory::add_segment(const ZPhysicalMemorySegment& segment) { - // Insert segments in address order, merge segments when possible - for (int i = _segments.length(); i > 0; i--) { - const int current = i - 1; - - if (_segments.at(current).end() <= segment.start()) { - if (is_mergable(_segments.at(current), segment)) { - if (current + 1 < _segments.length() && is_mergable(segment, _segments.at(current + 1))) { - // Merge with end of current segment and start of next segment - const zoffset start = _segments.at(current).start(); - const size_t size = _segments.at(current).size() + segment.size() + _segments.at(current + 1).size(); - replace_segment(current, start, size, segment.is_committed()); - remove_segment(current + 1); - return; - } - - // Merge with end of current segment - const zoffset start = _segments.at(current).start(); - const size_t size = _segments.at(current).size() + segment.size(); - replace_segment(current, start, size, segment.is_committed()); - return; - } else if (current + 1 < _segments.length() && is_mergable(segment, _segments.at(current + 1))) { - // Merge with start of next segment - const zoffset start = segment.start(); - const size_t size = segment.size() + _segments.at(current + 1).size(); - replace_segment(current + 1, start, size, segment.is_committed()); - return; - } - - // Insert after current segment - insert_segment(current + 1, segment.start(), segment.size(), segment.is_committed()); - return; - } - } - - if (_segments.length() > 0 && is_mergable(segment, _segments.at(0))) { - // Merge with start of first segment - const zoffset start = segment.start(); - const size_t size = segment.size() + _segments.at(0).size(); - replace_segment(0, start, size, segment.is_committed()); - return; - } - - // Insert before first segment - insert_segment(0, segment.start(), segment.size(), segment.is_committed()); -} - -bool ZPhysicalMemory::commit_segment(int index, size_t size) { - assert(size <= _segments.at(index).size(), "Invalid size"); - assert(!_segments.at(index).is_committed(), "Invalid state"); - - if (size == _segments.at(index).size()) { - // Completely committed - _segments.at(index).set_committed(true); - return true; - } - - if (size > 0) { - // Partially committed, split segment - insert_segment(index + 1, _segments.at(index).start() + size, _segments.at(index).size() - size, false /* committed */); - replace_segment(index, _segments.at(index).start(), size, true /* committed */); - } - - return false; -} - -bool ZPhysicalMemory::uncommit_segment(int index, size_t size) { - assert(size <= _segments.at(index).size(), "Invalid size"); - assert(_segments.at(index).is_committed(), "Invalid state"); - - if (size == _segments.at(index).size()) { - // Completely uncommitted - _segments.at(index).set_committed(false); - return true; - } - - if (size > 0) { - // Partially uncommitted, split segment - insert_segment(index + 1, _segments.at(index).start() + size, _segments.at(index).size() - size, true /* committed */); - replace_segment(index, _segments.at(index).start(), size, false /* committed */); - } - - return false; -} - -ZPhysicalMemory ZPhysicalMemory::split(size_t size) { - ZPhysicalMemory pmem; - int nsegments = 0; - - for (int i = 0; i < _segments.length(); i++) { - const ZPhysicalMemorySegment& segment = _segments.at(i); - if (pmem.size() < size) { - if (pmem.size() + segment.size() <= size) { - // Transfer segment - pmem.add_segment(segment); - } else { - // Split segment - const size_t split_size = size - pmem.size(); - pmem.add_segment(ZPhysicalMemorySegment(segment.start(), split_size, segment.is_committed())); - _segments.at_put(nsegments++, ZPhysicalMemorySegment(segment.start() + split_size, segment.size() - split_size, segment.is_committed())); - } - } else { - // Keep segment - _segments.at_put(nsegments++, segment); - } - } - - _segments.trunc_to(nsegments); - - return pmem; -} - -ZPhysicalMemory ZPhysicalMemory::split_committed() { - ZPhysicalMemory pmem; - int nsegments = 0; - - for (int i = 0; i < _segments.length(); i++) { - const ZPhysicalMemorySegment& segment = _segments.at(i); - if (segment.is_committed()) { - // Transfer segment - pmem.add_segment(segment); - } else { - // Keep segment - _segments.at_put(nsegments++, segment); - } - } - - _segments.trunc_to(nsegments); - - return pmem; -} - -ZPhysicalMemoryManager::ZPhysicalMemoryManager(size_t max_capacity) - : _backing(max_capacity) { - // Make the whole range free - _manager.register_range(zoffset(0), max_capacity); -} - -bool ZPhysicalMemoryManager::is_initialized() const { - return _backing.is_initialized(); -} - -void ZPhysicalMemoryManager::warn_commit_limits(size_t max_capacity) const { - _backing.warn_commit_limits(max_capacity); -} - -void ZPhysicalMemoryManager::try_enable_uncommit(size_t min_capacity, size_t max_capacity) { - assert(!is_init_completed(), "Invalid state"); - - // If uncommit is not explicitly disabled, max capacity is greater than - // min capacity, and uncommit is supported by the platform, then uncommit - // will be enabled. - if (!ZUncommit) { - log_info_p(gc, init)("Uncommit: Disabled"); - return; - } - - if (max_capacity == min_capacity) { - log_info_p(gc, init)("Uncommit: Implicitly Disabled (-Xms equals -Xmx)"); - FLAG_SET_ERGO(ZUncommit, false); - return; - } - - // Test if uncommit is supported by the operating system by committing - // and then uncommitting a granule. - ZPhysicalMemory pmem(ZPhysicalMemorySegment(zoffset(0), ZGranuleSize, false /* committed */)); - if (!commit(pmem) || !uncommit(pmem)) { - log_info_p(gc, init)("Uncommit: Implicitly Disabled (Not supported by operating system)"); - FLAG_SET_ERGO(ZUncommit, false); - return; - } - - log_info_p(gc, init)("Uncommit: Enabled"); - log_info_p(gc, init)("Uncommit Delay: %zus", ZUncommitDelay); -} - -void ZPhysicalMemoryManager::alloc(ZPhysicalMemory& pmem, size_t size) { - assert(is_aligned(size, ZGranuleSize), "Invalid size"); - - // Allocate segments - while (size > 0) { - size_t allocated = 0; - const zoffset start = _manager.alloc_low_address_at_most(size, &allocated); - assert(start != zoffset(UINTPTR_MAX), "Allocation should never fail"); - pmem.add_segment(ZPhysicalMemorySegment(start, allocated, false /* committed */)); - size -= allocated; - } -} - -void ZPhysicalMemoryManager::free(const ZPhysicalMemory& pmem) { - // Free segments - for (int i = 0; i < pmem.nsegments(); i++) { - const ZPhysicalMemorySegment& segment = pmem.segment(i); - _manager.free(segment.start(), segment.size()); - } -} - -bool ZPhysicalMemoryManager::commit(ZPhysicalMemory& pmem) { - // Commit segments - for (int i = 0; i < pmem.nsegments(); i++) { - const ZPhysicalMemorySegment& segment = pmem.segment(i); - if (segment.is_committed()) { - // Segment already committed - continue; - } - - // Commit segment - const size_t committed = _backing.commit(segment.start(), segment.size()); - - // Register with NMT - if (committed > 0) { - ZNMT::commit(segment.start(), committed); - } - - // Register committed segment - if (!pmem.commit_segment(i, committed)) { - // Failed or partially failed - return false; - } - } - - // Success - return true; -} - -bool ZPhysicalMemoryManager::uncommit(ZPhysicalMemory& pmem) { - // Commit segments - for (int i = 0; i < pmem.nsegments(); i++) { - const ZPhysicalMemorySegment& segment = pmem.segment(i); - if (!segment.is_committed()) { - // Segment already uncommitted - continue; - } - - // Uncommit segment - const size_t uncommitted = _backing.uncommit(segment.start(), segment.size()); - - // Unregister with NMT - if (uncommitted > 0) { - ZNMT::uncommit(segment.start(), uncommitted); - } - - // Deregister uncommitted segment - if (!pmem.uncommit_segment(i, uncommitted)) { - // Failed or partially failed - return false; - } - } - - // Success - return true; -} - -// Map virtual memory to physcial memory -void ZPhysicalMemoryManager::map(zoffset offset, const ZPhysicalMemory& pmem) const { - const zaddress_unsafe addr = ZOffset::address_unsafe(offset); - - size_t size = 0; - - // Map segments - for (int i = 0; i < pmem.nsegments(); i++) { - const ZPhysicalMemorySegment& segment = pmem.segment(i); - _backing.map(addr + size, segment.size(), segment.start()); - size += segment.size(); - } - - // Setup NUMA interleaving for large pages - if (ZNUMA::is_enabled() && ZLargePages::is_explicit()) { - // To get granule-level NUMA interleaving when using large pages, - // we simply let the kernel interleave the memory for us at page - // fault time. - os::numa_make_global((char*)addr, size); - } -} - -// Unmap virtual memory from physical memory -void ZPhysicalMemoryManager::unmap(zoffset offset, size_t size) const { - const zaddress_unsafe addr = ZOffset::address_unsafe(offset); - - _backing.unmap(addr, size); -} diff --git a/src/hotspot/share/gc/z/zPhysicalMemory.hpp b/src/hotspot/share/gc/z/zPhysicalMemory.hpp deleted file mode 100644 index 09f7101325863..0000000000000 --- a/src/hotspot/share/gc/z/zPhysicalMemory.hpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2015, 2024, 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_GC_Z_ZPHYSICALMEMORY_HPP -#define SHARE_GC_Z_ZPHYSICALMEMORY_HPP - -#include "gc/z/zAddress.hpp" -#include "gc/z/zArray.hpp" -#include "gc/z/zMemory.hpp" -#include "memory/allocation.hpp" -#include OS_HEADER(gc/z/zPhysicalMemoryBacking) - -class ZPhysicalMemorySegment : public CHeapObj { -private: - zoffset _start; - zoffset_end _end; - bool _committed; - -public: - ZPhysicalMemorySegment(); - ZPhysicalMemorySegment(zoffset start, size_t size, bool committed); - - zoffset start() const; - zoffset_end end() const; - size_t size() const; - - bool is_committed() const; - void set_committed(bool committed); -}; - -class ZPhysicalMemory { -private: - ZArray _segments; - - void insert_segment(int index, zoffset start, size_t size, bool committed); - void replace_segment(int index, zoffset start, size_t size, bool committed); - void remove_segment(int index); - -public: - ZPhysicalMemory(); - ZPhysicalMemory(const ZPhysicalMemorySegment& segment); - ZPhysicalMemory(const ZPhysicalMemory& pmem); - const ZPhysicalMemory& operator=(const ZPhysicalMemory& pmem); - - bool is_null() const; - size_t size() const; - - int nsegments() const; - const ZPhysicalMemorySegment& segment(int index) const; - - void add_segments(const ZPhysicalMemory& pmem); - void remove_segments(); - - void add_segment(const ZPhysicalMemorySegment& segment); - bool commit_segment(int index, size_t size); - bool uncommit_segment(int index, size_t size); - - ZPhysicalMemory split(size_t size); - ZPhysicalMemory split_committed(); -}; - -class ZPhysicalMemoryManager { -private: - ZPhysicalMemoryBacking _backing; - ZMemoryManager _manager; - -public: - ZPhysicalMemoryManager(size_t max_capacity); - - bool is_initialized() const; - - void warn_commit_limits(size_t max_capacity) const; - void try_enable_uncommit(size_t min_capacity, size_t max_capacity); - - void alloc(ZPhysicalMemory& pmem, size_t size); - void free(const ZPhysicalMemory& pmem); - - bool commit(ZPhysicalMemory& pmem); - bool uncommit(ZPhysicalMemory& pmem); - - void map(zoffset offset, const ZPhysicalMemory& pmem) const; - void unmap(zoffset offset, size_t size) const; -}; - -#endif // SHARE_GC_Z_ZPHYSICALMEMORY_HPP diff --git a/src/hotspot/share/gc/z/zPhysicalMemory.inline.hpp b/src/hotspot/share/gc/z/zPhysicalMemory.inline.hpp deleted file mode 100644 index 6d2380c90137e..0000000000000 --- a/src/hotspot/share/gc/z/zPhysicalMemory.inline.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2015, 2024, 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_GC_Z_ZPHYSICALMEMORY_INLINE_HPP -#define SHARE_GC_Z_ZPHYSICALMEMORY_INLINE_HPP - -#include "gc/z/zPhysicalMemory.hpp" - -#include "gc/z/zAddress.inline.hpp" -#include "utilities/debug.hpp" - -inline ZPhysicalMemorySegment::ZPhysicalMemorySegment() - : _start(zoffset(UINTPTR_MAX)), - _end(zoffset_end(UINTPTR_MAX)), - _committed(false) {} - -inline ZPhysicalMemorySegment::ZPhysicalMemorySegment(zoffset start, size_t size, bool committed) - : _start(start), - _end(to_zoffset_end(start, size)), - _committed(committed) {} - -inline zoffset ZPhysicalMemorySegment::start() const { - return _start; -} - -inline zoffset_end ZPhysicalMemorySegment::end() const { - return _end; -} - -inline size_t ZPhysicalMemorySegment::size() const { - return _end - _start; -} - -inline bool ZPhysicalMemorySegment::is_committed() const { - return _committed; -} - -inline void ZPhysicalMemorySegment::set_committed(bool committed) { - _committed = committed; -} - -inline bool ZPhysicalMemory::is_null() const { - return _segments.length() == 0; -} - -inline int ZPhysicalMemory::nsegments() const { - return _segments.length(); -} - -inline const ZPhysicalMemorySegment& ZPhysicalMemory::segment(int index) const { - return _segments.at(index); -} - -#endif // SHARE_GC_Z_ZPHYSICALMEMORY_INLINE_HPP diff --git a/src/hotspot/share/gc/z/zPhysicalMemoryManager.cpp b/src/hotspot/share/gc/z/zPhysicalMemoryManager.cpp new file mode 100644 index 0000000000000..8f9b8f2a285d1 --- /dev/null +++ b/src/hotspot/share/gc/z/zPhysicalMemoryManager.cpp @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "gc/shared/gcLogPrecious.hpp" +#include "gc/z/zAddress.inline.hpp" +#include "gc/z/zArray.inline.hpp" +#include "gc/z/zGlobals.hpp" +#include "gc/z/zLargePages.inline.hpp" +#include "gc/z/zList.inline.hpp" +#include "gc/z/zNMT.hpp" +#include "gc/z/zNUMA.inline.hpp" +#include "gc/z/zPhysicalMemoryManager.hpp" +#include "gc/z/zRangeRegistry.inline.hpp" +#include "gc/z/zUtils.inline.hpp" +#include "gc/z/zValue.inline.hpp" +#include "gc/z/zVirtualMemory.inline.hpp" +#include "logging/log.hpp" +#include "runtime/globals.hpp" +#include "runtime/globals_extension.hpp" +#include "runtime/init.hpp" +#include "runtime/os.hpp" +#include "utilities/align.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/powerOfTwo.hpp" + +ZPhysicalMemoryManager::ZPhysicalMemoryManager(size_t max_capacity) + : _backing(max_capacity), + _physical_mappings(ZAddressOffsetMax) { + assert(is_aligned(max_capacity, ZGranuleSize), "must be granule aligned"); + + // Setup backing storage limits + ZBackingOffsetMax = max_capacity; + ZBackingIndexMax = checked_cast(max_capacity >> ZGranuleSizeShift); + + // Install capacity into the registry + const size_t num_segments_total = max_capacity >> ZGranuleSizeShift; + zbacking_index_end next_index = zbacking_index_end::zero; + uint32_t numa_id; + ZPerNUMAIterator iter(&_partition_registries); + for (ZBackingIndexRegistry* registry; iter.next(®istry, &numa_id);) { + const size_t num_segments = ZNUMA::calculate_share(numa_id, num_segments_total, 1 /* granule */); + + if (num_segments == 0) { + // If the capacity consist of less granules than the number of partitions, + // some partitions will be empty. + break; + } + + const zbacking_index index = to_zbacking_index(next_index); + + // Insert the next number of segment indices into id's partition's registry + registry->insert({index, num_segments}); + + // Advance to next index by the inserted number of segment indices + next_index += num_segments; + } + + assert(untype(next_index) == ZBackingIndexMax, "must insert all capacity"); +} + +bool ZPhysicalMemoryManager::is_initialized() const { + return _backing.is_initialized(); +} + +void ZPhysicalMemoryManager::warn_commit_limits(size_t max_capacity) const { + _backing.warn_commit_limits(max_capacity); +} + +void ZPhysicalMemoryManager::try_enable_uncommit(size_t min_capacity, size_t max_capacity) { + assert(!is_init_completed(), "Invalid state"); + + // If uncommit is not explicitly disabled, max capacity is greater than + // min capacity, and uncommit is supported by the platform, then uncommit + // will be enabled. + if (!ZUncommit) { + log_info_p(gc, init)("Uncommit: Disabled"); + return; + } + + if (max_capacity == min_capacity) { + log_info_p(gc, init)("Uncommit: Implicitly Disabled (-Xms equals -Xmx)"); + FLAG_SET_ERGO(ZUncommit, false); + return; + } + + // Test if uncommit is supported by the operating system by committing + // and then uncommitting a granule. + const ZVirtualMemory vmem(zoffset(0), ZGranuleSize); + if (!commit(vmem, (uint32_t)-1) || !uncommit(vmem)) { + log_info_p(gc, init)("Uncommit: Implicitly Disabled (Not supported by operating system)"); + FLAG_SET_ERGO(ZUncommit, false); + return; + } + + log_info_p(gc, init)("Uncommit: Enabled"); + log_info_p(gc, init)("Uncommit Delay: %zus", ZUncommitDelay); +} + +void ZPhysicalMemoryManager::alloc(const ZVirtualMemory& vmem, uint32_t numa_id) { + zbacking_index* const pmem = _physical_mappings.addr(vmem.start()); + const size_t size = vmem.size(); + + assert(is_aligned(size, ZGranuleSize), "Invalid size"); + + size_t current_segment = 0; + size_t remaining_segments = size >> ZGranuleSizeShift; + + while (remaining_segments != 0) { + // Allocate a range of backing segment indices + ZBackingIndexRegistry& registry = _partition_registries.get(numa_id); + const ZBackingIndexRange range = registry.remove_from_low_at_most(remaining_segments); + assert(!range.is_null(), "Allocation should never fail"); + + const size_t num_allocated_segments = range.size(); + + // Insert backing segment indices in pmem + const zbacking_index start_i = range.start(); + for (size_t i = 0; i < num_allocated_segments; i++) { + pmem[current_segment + i] = start_i + i; + } + + // Advance by number of allocated segments + remaining_segments -= num_allocated_segments; + current_segment += num_allocated_segments; + } +} + +template +struct IterateInvoker { + template + bool operator()(Function function, zbacking_offset segment_start, size_t segment_size) const { + return function(segment_start, segment_size); + } +}; + +template<> +struct IterateInvoker { + template + bool operator()(Function function, zbacking_offset segment_start, size_t segment_size) const { + function(segment_start, segment_size); + return true; + } +}; + +template +bool for_each_segment_apply(const zbacking_index* pmem, size_t size, Function function) { + IterateInvoker invoker; + + // Total number of segment indices + const size_t num_segments = size >> ZGranuleSizeShift; + + // Apply the function over all zbacking_offset ranges consisting of consecutive indices + for (size_t i = 0; i < num_segments; i++) { + const size_t start_i = i; + + // Find index corresponding to the last index in the consecutive range starting at start_i + while (i + 1 < num_segments && to_zbacking_index_end(pmem[i], 1) == pmem[i + 1]) { + i++; + } + + const size_t last_i = i; + + // [start_i, last_i] now forms a consecutive range of indicies in pmem + const size_t num_indicies = last_i - start_i + 1; + const zbacking_offset start = to_zbacking_offset(pmem[start_i]); + const size_t size = num_indicies * ZGranuleSize; + + // Invoke function on zbacking_offset Range [start, start + size[ + if (!invoker(function, start, size)) { + return false; + } + } + + return true; +} + +void ZPhysicalMemoryManager::free(const ZVirtualMemory& vmem, uint32_t numa_id) { + zbacking_index* const pmem = _physical_mappings.addr(vmem.start()); + const size_t size = vmem.size(); + + // Free segments + for_each_segment_apply(pmem, size, [&](zbacking_offset segment_start, size_t segment_size) { + const size_t num_segments = segment_size >> ZGranuleSizeShift; + const zbacking_index index = to_zbacking_index(segment_start); + + // Insert the free segment indices + _partition_registries.get(numa_id).insert({index, num_segments}); + }); +} + +size_t ZPhysicalMemoryManager::commit(const ZVirtualMemory& vmem, uint32_t numa_id) { + zbacking_index* const pmem = _physical_mappings.addr(vmem.start()); + const size_t size = vmem.size(); + + size_t total_committed = 0; + + // Commit segments + for_each_segment_apply(pmem, size, [&](zbacking_offset segment_start, size_t segment_size) { + // Commit segment + const size_t committed = _backing.commit(segment_start, segment_size, numa_id); + + total_committed += committed; + + // Register with NMT + if (committed > 0) { + ZNMT::commit(segment_start, committed); + } + + return segment_size == committed; + }); + + // Success + return total_committed; +} + +size_t ZPhysicalMemoryManager::uncommit(const ZVirtualMemory& vmem) { + zbacking_index* const pmem = _physical_mappings.addr(vmem.start()); + const size_t size = vmem.size(); + + size_t total_uncommitted = 0; + + // Uncommit segments + for_each_segment_apply(pmem, size, [&](zbacking_offset segment_start, size_t segment_size) { + // Uncommit segment + const size_t uncommitted = _backing.uncommit(segment_start, segment_size); + + total_uncommitted += uncommitted; + + // Unregister with NMT + if (uncommitted > 0) { + ZNMT::uncommit(segment_start, uncommitted); + } + + return segment_size == uncommitted; + }); + + // Success + return total_uncommitted; +} + +// Map virtual memory to physical memory +void ZPhysicalMemoryManager::map(const ZVirtualMemory& vmem, uint32_t numa_id) const { + const zbacking_index* const pmem = _physical_mappings.addr(vmem.start()); + const zaddress_unsafe addr = ZOffset::address_unsafe(vmem.start()); + const size_t size = vmem.size(); + + size_t mapped = 0; + + for_each_segment_apply(pmem, size, [&](zbacking_offset segment_start, size_t segment_size) { + _backing.map(addr + mapped, segment_size, segment_start); + mapped += segment_size; + }); + + postcond(mapped == size); + + // Setup NUMA preferred for large pages + if (ZNUMA::is_enabled() && ZLargePages::is_explicit()) { + os::numa_make_local((char*)addr, size, (int)numa_id); + } +} + +// Unmap virtual memory from physical memory +void ZPhysicalMemoryManager::unmap(const ZVirtualMemory& vmem) const { + const zaddress_unsafe addr = ZOffset::address_unsafe(vmem.start()); + const size_t size = vmem.size(); + _backing.unmap(addr, size); +} + +void ZPhysicalMemoryManager::copy_physical_segments(const ZVirtualMemory& to, const ZVirtualMemory& from) { + assert(to.size() == from.size(), "must be of the same size"); + + zbacking_index* const dest = _physical_mappings.addr(to.start()); + const zbacking_index* const src = _physical_mappings.addr(from.start()); + const int granule_count = from.granule_count(); + + ZUtils::copy_disjoint(dest, src, granule_count); +} + +static void sort_zbacking_index_array(zbacking_index* array, int count) { + ZUtils::sort(array, count, [](const zbacking_index* e1, const zbacking_index* e2) { + return *e1 < *e2 ? -1 : 1; + }); +} + +void ZPhysicalMemoryManager::sort_segments_physical(const ZVirtualMemory& vmem) { + zbacking_index* const pmem = _physical_mappings.addr(vmem.start()); + const int granule_count = vmem.granule_count(); + + // Sort physical segments + sort_zbacking_index_array(pmem, granule_count); +} + +void ZPhysicalMemoryManager::copy_to_stash(ZArraySlice stash, const ZVirtualMemory& vmem) const { + zbacking_index* const dest = stash.adr_at(0); + const zbacking_index* const src = _physical_mappings.addr(vmem.start()); + const int granule_count = vmem.granule_count(); + + // Check bounds + assert(granule_count <= stash.length(), "Copy overflow %d <= %d", granule_count, stash.length()); + + // Copy to stash + ZUtils::copy_disjoint(dest, src, granule_count); +} + +void ZPhysicalMemoryManager::copy_from_stash(const ZArraySlice stash, const ZVirtualMemory& vmem) { + zbacking_index* const dest = _physical_mappings.addr(vmem.start()); + const zbacking_index* const src = stash.adr_at(0); + const int granule_count = vmem.granule_count(); + + // Check bounds + assert(granule_count <= stash.length(), "Copy overflow %d <= %d", granule_count, stash.length()); + + // Copy from stash + ZUtils::copy_disjoint(dest, src, granule_count); +} + +void ZPhysicalMemoryManager::stash_segments(const ZVirtualMemory& vmem, ZArray* stash_out) const { + precond(stash_out->is_empty()); + + stash_out->at_grow(vmem.granule_count() - 1); + copy_to_stash(*stash_out, vmem); + sort_zbacking_index_array(stash_out->adr_at(0), stash_out->length()); +} + +void ZPhysicalMemoryManager::restore_segments(const ZVirtualMemory& vmem, const ZArray& stash) { + assert(vmem.granule_count() == stash.length(), "Must match stash size"); + + copy_from_stash(stash, vmem); +} + +void ZPhysicalMemoryManager::stash_segments(const ZArraySlice& vmems, ZArray* stash_out) const { + precond(stash_out->is_empty()); + + int stash_index = 0; + for (const ZVirtualMemory& vmem : vmems) { + const int granule_count = vmem.granule_count(); + stash_out->at_grow(stash_index + vmem.granule_count() - 1); + copy_to_stash(stash_out->slice_back(stash_index), vmem); + stash_index += granule_count; + } + + sort_zbacking_index_array(stash_out->adr_at(0), stash_out->length()); + +} + +void ZPhysicalMemoryManager::restore_segments(const ZArraySlice& vmems, const ZArray& stash) { + int stash_index = 0; + + for (const ZVirtualMemory& vmem : vmems) { + copy_from_stash(stash.slice_back(stash_index), vmem); + stash_index += vmem.granule_count(); + } + + assert(stash_index == stash.length(), "Must have emptied the stash"); +} diff --git a/src/hotspot/share/gc/z/zPhysicalMemoryManager.hpp b/src/hotspot/share/gc/z/zPhysicalMemoryManager.hpp new file mode 100644 index 0000000000000..99de34beda74f --- /dev/null +++ b/src/hotspot/share/gc/z/zPhysicalMemoryManager.hpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_Z_ZPHYSICALMEMORYMANAGER_HPP +#define SHARE_GC_Z_ZPHYSICALMEMORYMANAGER_HPP + +#include "gc/z/zAddress.hpp" +#include "gc/z/zArray.hpp" +#include "gc/z/zGranuleMap.hpp" +#include "gc/z/zRange.hpp" +#include "gc/z/zRangeRegistry.hpp" +#include "gc/z/zValue.hpp" +#include "memory/allocation.hpp" +#include OS_HEADER(gc/z/zPhysicalMemoryBacking) + +class ZVirtualMemory; + +using ZBackingIndexRange = ZRange; + +class ZPhysicalMemoryManager { +private: + using ZBackingIndexRegistry = ZRangeRegistry; + + ZPhysicalMemoryBacking _backing; + ZPerNUMA _partition_registries; + ZGranuleMap _physical_mappings; + + void copy_to_stash(ZArraySlice stash, const ZVirtualMemory& vmem) const; + void copy_from_stash(const ZArraySlice stash, const ZVirtualMemory& vmem); + +public: + ZPhysicalMemoryManager(size_t max_capacity); + + bool is_initialized() const; + + void warn_commit_limits(size_t max_capacity) const; + void try_enable_uncommit(size_t min_capacity, size_t max_capacity); + + void alloc(const ZVirtualMemory& vmem, uint32_t numa_id); + void free(const ZVirtualMemory& vmem, uint32_t numa_id); + + size_t commit(const ZVirtualMemory& vmem, uint32_t numa_id); + size_t uncommit(const ZVirtualMemory& vmem); + + void map(const ZVirtualMemory& vmem, uint32_t numa_id) const; + void unmap(const ZVirtualMemory& vmem) const; + + void copy_physical_segments(const ZVirtualMemory& to, const ZVirtualMemory& from); + + void sort_segments_physical(const ZVirtualMemory& vmem); + + void stash_segments(const ZVirtualMemory& vmem, ZArray* stash_out) const; + void restore_segments(const ZVirtualMemory& vmem, const ZArray& stash); + + void stash_segments(const ZArraySlice& vmems, ZArray* stash_out) const; + void restore_segments(const ZArraySlice& vmems, const ZArray& stash); +}; + +#endif // SHARE_GC_Z_ZPHYSICALMEMORYMANAGER_HPP diff --git a/src/hotspot/share/gc/z/zRange.hpp b/src/hotspot/share/gc/z/zRange.hpp new file mode 100644 index 0000000000000..53c9980608e85 --- /dev/null +++ b/src/hotspot/share/gc/z/zRange.hpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_Z_ZRANGE_HPP +#define SHARE_GC_Z_ZRANGE_HPP + +#include "utilities/globalDefinitions.hpp" + +template +class ZRange { + friend class VMStructs; + +public: + using offset = Start; + using offset_end = End; + +private: + End _start; + size_t _size; + + // Used internally to create a ZRange. + // + // The end parameter is only used for verification and to distinguish + // the constructors if End == Start. + ZRange(End start, size_t size, End end); + +public: + ZRange(); + ZRange(Start start, size_t size); + + bool is_null() const; + + Start start() const; + End end() const; + + size_t size() const; + + bool operator==(const ZRange& other) const; + bool operator!=(const ZRange& other) const; + + bool contains(const ZRange& other) const; + + void grow_from_front(size_t size); + void grow_from_back(size_t size); + + ZRange shrink_from_front(size_t size); + ZRange shrink_from_back(size_t size); + + ZRange partition(size_t offset, size_t partition_size) const; + ZRange first_part(size_t split_offset) const; + ZRange last_part(size_t split_offset) const; + + bool adjacent_to(const ZRange& other) const; +}; + +#endif // SHARE_GC_Z_ZRANGE_HPP diff --git a/src/hotspot/share/gc/z/zRange.inline.hpp b/src/hotspot/share/gc/z/zRange.inline.hpp new file mode 100644 index 0000000000000..d99cbefd32a86 --- /dev/null +++ b/src/hotspot/share/gc/z/zRange.inline.hpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_Z_ZRANGE_INLINE_HPP +#define SHARE_GC_Z_ZRANGE_INLINE_HPP + +#include "gc/z/zRange.hpp" + +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" + +template +inline ZRange::ZRange(End start, size_t size, End end) + : _start(start), + _size(size) { + postcond(this->end() == end); +} + +template +inline ZRange::ZRange() + : _start(End::invalid), + _size(0) {} + +template +inline ZRange::ZRange(Start start, size_t size) + : _start(to_end_type(start, 0)), + _size(size) {} + +template +inline bool ZRange::is_null() const { + return _start == End::invalid; +} + +template +inline Start ZRange::start() const { + return to_start_type(_start); +} + +template +inline End ZRange::end() const { + return _start + _size; +} + +template +inline size_t ZRange::size() const { + return _size; +} + +template +inline bool ZRange::operator==(const ZRange& other) const { + precond(!is_null()); + precond(!other.is_null()); + + return _start == other._start && _size == other._size; +} + +template +inline bool ZRange::operator!=(const ZRange& other) const { + return !operator==(other); +} + +template +inline bool ZRange::contains(const ZRange& other) const { + precond(!is_null()); + precond(!other.is_null()); + + return _start <= other._start && other.end() <= end(); +} + +template +inline void ZRange::grow_from_front(size_t size) { + precond(size_t(start()) >= size); + + _start -= size; + _size += size; +} + +template +inline void ZRange::grow_from_back(size_t size) { + _size += size; +} + +template +inline ZRange ZRange::shrink_from_front(size_t size) { + precond(this->size() >= size); + + _start += size; + _size -= size; + + return ZRange(_start - size, size, _start); +} + +template +inline ZRange ZRange::shrink_from_back(size_t size) { + precond(this->size() >= size); + + _size -= size; + + return ZRange(end(), size, end() + size); +} + +template +inline ZRange ZRange::partition(size_t offset, size_t partition_size) const { + precond(size() - offset >= partition_size); + + return ZRange(_start + offset, partition_size, _start + offset + partition_size); +} + +template +inline ZRange ZRange::first_part(size_t split_offset) const { + return partition(0, split_offset); +} + +template +inline ZRange ZRange::last_part(size_t split_offset) const { + return partition(split_offset, size() - split_offset); +} + +template +inline bool ZRange::adjacent_to(const ZRange& other) const { + return end() == other.start() || other.end() == start(); +} + +#endif // SHARE_GC_Z_ZRANGE_INLINE_HPP diff --git a/src/hotspot/share/gc/z/zRangeRegistry.hpp b/src/hotspot/share/gc/z/zRangeRegistry.hpp new file mode 100644 index 0000000000000..8a5ba74da6e9f --- /dev/null +++ b/src/hotspot/share/gc/z/zRangeRegistry.hpp @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_Z_ZRANGEREGISTRY_HPP +#define SHARE_GC_Z_ZRANGEREGISTRY_HPP + +#include "gc/z/zAddress.hpp" +#include "gc/z/zList.hpp" +#include "gc/z/zLock.hpp" +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" + +template +class ZArray; + +template +class ZRangeRegistry { + friend class ZVirtualMemoryManagerTest; + +private: + // The node type for the list of Ranges + class Node; + +public: + using offset = typename Range::offset; + using offset_end = typename Range::offset_end; + + typedef void (*CallbackPrepare)(const Range& range); + typedef void (*CallbackResize)(const Range& from, const Range& to); + + struct Callbacks { + CallbackPrepare _prepare_for_hand_out; + CallbackPrepare _prepare_for_hand_back; + CallbackResize _grow; + CallbackResize _shrink; + + Callbacks(); + }; + +private: + mutable ZLock _lock; + ZList _list; + Callbacks _callbacks; + Range _limits; + + void move_into(const Range& range); + + void insert_inner(const Range& range); + void register_inner(const Range& range); + + void grow_from_front(Range* range, size_t size); + void grow_from_back(Range* range, size_t size); + + Range shrink_from_front(Range* range, size_t size); + Range shrink_from_back(Range* range, size_t size); + + Range remove_from_low_inner(size_t size); + Range remove_from_low_at_most_inner(size_t size); + + size_t remove_from_low_many_at_most_inner(size_t size, ZArray* out); + + bool check_limits(const Range& range) const; + +public: + ZRangeRegistry(); + + void register_callbacks(const Callbacks& callbacks); + + void register_range(const Range& range); + bool unregister_first(Range* out); + + bool is_empty() const; + bool is_contiguous() const; + + void anchor_limits(); + bool limits_contain(const Range& range) const; + + offset peek_low_address() const; + offset_end peak_high_address_end() const; + + void insert(const Range& range); + + void insert_and_remove_from_low_many(const Range& range, ZArray* out); + Range insert_and_remove_from_low_exact_or_many(size_t size, ZArray* in_out); + + Range remove_from_low(size_t size); + Range remove_from_low_at_most(size_t size); + size_t remove_from_low_many_at_most(size_t size, ZArray* out); + Range remove_from_high(size_t size); + + void transfer_from_low(ZRangeRegistry* other, size_t size); +}; + +template +class ZRangeRegistry::Node : public CHeapObj { + friend class ZList; + +private: + using offset = typename Range::offset; + using offset_end = typename Range::offset_end; + + Range _range; + ZListNode _node; + +public: + Node(offset start, size_t size) + : _range(start, size), + _node() {} + + Node(const Range& other) + : Node(other.start(), other.size()) {} + + Range* range() { + return &_range; + } + + offset start() const { + return _range.start(); + } + + offset_end end() const { + return _range.end(); + } + + size_t size() const { + return _range.size(); + } +}; + +#endif // SHARE_GC_Z_ZRANGEREGISTRY_HPP diff --git a/src/hotspot/share/gc/z/zRangeRegistry.inline.hpp b/src/hotspot/share/gc/z/zRangeRegistry.inline.hpp new file mode 100644 index 0000000000000..de34aca07c4f1 --- /dev/null +++ b/src/hotspot/share/gc/z/zRangeRegistry.inline.hpp @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_Z_ZRANGEREGISTRY_INLINE_HPP +#define SHARE_GC_Z_ZRANGEREGISTRY_INLINE_HPP + +#include "gc/z/zRangeRegistry.hpp" + +#include "gc/z/zAddress.inline.hpp" +#include "gc/z/zList.inline.hpp" +#include "gc/z/zLock.inline.hpp" + +template +void ZRangeRegistry::move_into(const Range& range) { + assert(!range.is_null(), "Invalid range"); + assert(check_limits(range), "Range outside limits"); + + const offset start = range.start(); + const offset_end end = range.end(); + const size_t size = range.size(); + + ZListIterator iter(&_list); + for (Node* node; iter.next(&node);) { + if (node->start() < start) { + continue; + } + + Node* const prev = _list.prev(node); + if (prev != nullptr && start == prev->end()) { + if (end == node->start()) { + // Merge with prev and current ranges + grow_from_back(prev->range(), size); + grow_from_back(prev->range(), node->size()); + _list.remove(node); + delete node; + } else { + // Merge with prev range + grow_from_back(prev->range(), size); + } + } else if (end == node->start()) { + // Merge with current range + grow_from_front(node->range(), size); + } else { + // Insert range before current range + assert(end < node->start(), "Areas must not overlap"); + Node* const new_node = new Node(start, size); + _list.insert_before(node, new_node); + } + + // Done + return; + } + + // Insert last + Node* const last = _list.last(); + if (last != nullptr && start == last->end()) { + // Merge with last range + grow_from_back(last->range(), size); + } else { + // Insert new node last + Node* const new_node = new Node(start, size); + _list.insert_last(new_node); + } +} + +template +void ZRangeRegistry::insert_inner(const Range& range) { + if (_callbacks._prepare_for_hand_back != nullptr) { + _callbacks._prepare_for_hand_back(range); + } + move_into(range); +} + +template +void ZRangeRegistry::register_inner(const Range& range) { + move_into(range); +} + +template +void ZRangeRegistry::grow_from_front(Range* range, size_t size) { + if (_callbacks._grow != nullptr) { + const Range from = *range; + const Range to = Range(from.start() - size, from.size() + size); + _callbacks._grow(from, to); + } + range->grow_from_front(size); +} + +template +void ZRangeRegistry::grow_from_back(Range* range, size_t size) { + if (_callbacks._grow != nullptr) { + const Range from = *range; + const Range to = Range(from.start(), from.size() + size); + _callbacks._grow(from, to); + } + range->grow_from_back(size); +} + +template +Range ZRangeRegistry::shrink_from_front(Range* range, size_t size) { + if (_callbacks._shrink != nullptr) { + const Range from = *range; + const Range to = from.last_part(size); + _callbacks._shrink(from, to); + } + return range->shrink_from_front(size); +} + +template +Range ZRangeRegistry::shrink_from_back(Range* range, size_t size) { + if (_callbacks._shrink != nullptr) { + const Range from = *range; + const Range to = from.first_part(from.size() - size); + _callbacks._shrink(from, to); + } + return range->shrink_from_back(size); +} + +template +Range ZRangeRegistry::remove_from_low_inner(size_t size) { + ZListIterator iter(&_list); + for (Node* node; iter.next(&node);) { + if (node->size() >= size) { + Range range; + + if (node->size() == size) { + // Exact match, remove range + _list.remove(node); + range = *node->range(); + delete node; + } else { + // Larger than requested, shrink range + range = shrink_from_front(node->range(), size); + } + + if (_callbacks._prepare_for_hand_out != nullptr) { + _callbacks._prepare_for_hand_out(range); + } + + return range; + } + } + + // Out of memory + return Range(); +} + +template +Range ZRangeRegistry::remove_from_low_at_most_inner(size_t size) { + Node* const node = _list.first(); + if (node == nullptr) { + // List is empty + return Range(); + } + + Range range; + + if (node->size() <= size) { + // Smaller than or equal to requested, remove range + _list.remove(node); + range = *node->range(); + delete node; + } else { + // Larger than requested, shrink range + range = shrink_from_front(node->range(), size); + } + + if (_callbacks._prepare_for_hand_out) { + _callbacks._prepare_for_hand_out(range); + } + + return range; +} + +template +size_t ZRangeRegistry::remove_from_low_many_at_most_inner(size_t size, ZArray* out) { + size_t to_remove = size; + + while (to_remove > 0) { + const Range range = remove_from_low_at_most_inner(to_remove); + + if (range.is_null()) { + // The requested amount is not available + return size - to_remove; + } + + to_remove -= range.size(); + out->append(range); + } + + return size; +} + +template +ZRangeRegistry::Callbacks::Callbacks() + : _prepare_for_hand_out(nullptr), + _prepare_for_hand_back(nullptr), + _grow(nullptr), + _shrink(nullptr) {} + +template +ZRangeRegistry::ZRangeRegistry() + : _list(), + _callbacks(), + _limits() {} + +template +void ZRangeRegistry::register_callbacks(const Callbacks& callbacks) { + _callbacks = callbacks; +} + +template +void ZRangeRegistry::register_range(const Range& range) { + ZLocker locker(&_lock); + register_inner(range); +} + +template +bool ZRangeRegistry::unregister_first(Range* out) { + // Unregistering a range doesn't call a "prepare_to_hand_out" callback + // because the range is unregistered and not handed out to be used. + + ZLocker locker(&_lock); + + if (_list.is_empty()) { + return false; + } + + // Don't invoke the "prepare_to_hand_out" callback + + Node* const node = _list.remove_first(); + + // Return the range + *out = *node->range(); + + delete node; + + return true; +} + +template +inline bool ZRangeRegistry::is_empty() const { + return _list.is_empty(); +} + +template +bool ZRangeRegistry::is_contiguous() const { + return _list.size() == 1; +} + +template +void ZRangeRegistry::anchor_limits() { + assert(_limits.is_null(), "Should only anchor limits once"); + + if (_list.is_empty()) { + return; + } + + const offset start = _list.first()->start(); + const size_t size = _list.last()->end() - start; + + _limits = Range(start, size); +} + +template +bool ZRangeRegistry::limits_contain(const Range& range) const { + if (_limits.is_null() || range.is_null()) { + return false; + } + + return range.start() >= _limits.start() && range.end() <= _limits.end(); +} + +template +bool ZRangeRegistry::check_limits(const Range& range) const { + if (_limits.is_null()) { + // Limits not anchored + return true; + } + + // Otherwise, check that other is within the limits + return limits_contain(range); +} + +template +typename ZRangeRegistry::offset ZRangeRegistry::peek_low_address() const { + ZLocker locker(&_lock); + + const Node* const node = _list.first(); + if (node != nullptr) { + return node->start(); + } + + // Out of memory + return offset::invalid; +} + +template +typename ZRangeRegistry::offset_end ZRangeRegistry::peak_high_address_end() const { + ZLocker locker(&_lock); + + const Node* const node = _list.last(); + if (node != nullptr) { + return node->end(); + } + + // Out of memory + return offset_end::invalid; +} + +template +void ZRangeRegistry::insert(const Range& range) { + ZLocker locker(&_lock); + insert_inner(range); +} + +template +void ZRangeRegistry::insert_and_remove_from_low_many(const Range& range, ZArray* out) { + ZLocker locker(&_lock); + + const size_t size = range.size(); + + // Insert the range + insert_inner(range); + + // Remove (hopefully) at a lower address + const size_t removed = remove_from_low_many_at_most_inner(size, out); + + // This should always succeed since we freed the same amount. + assert(removed == size, "must succeed"); +} + +template +Range ZRangeRegistry::insert_and_remove_from_low_exact_or_many(size_t size, ZArray* in_out) { + ZLocker locker(&_lock); + + size_t inserted = 0; + + // Insert everything + ZArrayIterator iter(in_out); + for (Range mem; iter.next(&mem);) { + insert_inner(mem); + inserted += mem.size(); + } + + // Clear stored memory so that we can populate it below + in_out->clear(); + + // Try to find and remove a contiguous chunk + Range range = remove_from_low_inner(size); + if (!range.is_null()) { + return range; + } + + // Failed to find a contiguous chunk, split it up into smaller chunks and + // only remove up to as much that has been inserted. + size_t removed = remove_from_low_many_at_most_inner(inserted, in_out); + assert(removed == inserted, "Should be able to get back as much as we previously inserted"); + return Range(); +} + +template +Range ZRangeRegistry::remove_from_low(size_t size) { + ZLocker locker(&_lock); + Range range = remove_from_low_inner(size); + return range; +} + +template +Range ZRangeRegistry::remove_from_low_at_most(size_t size) { + ZLocker lock(&_lock); + Range range = remove_from_low_at_most_inner(size); + return range; +} + +template +size_t ZRangeRegistry::remove_from_low_many_at_most(size_t size, ZArray* out) { + ZLocker lock(&_lock); + return remove_from_low_many_at_most_inner(size, out); +} + +template +Range ZRangeRegistry::remove_from_high(size_t size) { + ZLocker locker(&_lock); + + ZListReverseIterator iter(&_list); + for (Node* node; iter.next(&node);) { + if (node->size() >= size) { + Range range; + + if (node->size() == size) { + // Exact match, remove range + _list.remove(node); + range = *node->range(); + delete node; + } else { + // Larger than requested, shrink range + range = shrink_from_back(node->range(), size); + } + + if (_callbacks._prepare_for_hand_out != nullptr) { + _callbacks._prepare_for_hand_out(range); + } + + return range; + } + } + + // Out of memory + return Range(); +} + +template +void ZRangeRegistry::transfer_from_low(ZRangeRegistry* other, size_t size) { + assert(other->_list.is_empty(), "Should only be used for initialization"); + + ZLocker locker(&_lock); + size_t to_move = size; + + ZListIterator iter(&_list); + for (Node* node; iter.next(&node);) { + Node* to_transfer; + + if (node->size() <= to_move) { + // Smaller than or equal to requested, remove range + _list.remove(node); + to_transfer = node; + } else { + // Larger than requested, shrink range + const Range range = shrink_from_front(node->range(), to_move); + to_transfer = new Node(range); + } + + // Insert into the other list + // + // The from list is sorted, the other list starts empty, and the inserts + // come in sort order, so we can insert_last here. + other->_list.insert_last(to_transfer); + + to_move -= to_transfer->size(); + if (to_move == 0) { + break; + } + } + + assert(to_move == 0, "Should have transferred requested size"); +} + +#endif // SHARE_GC_Z_ZRANGEREGISTRY_INLINE_HPP diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 213452e8d05d5..b4ae78bc8d984 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -410,7 +410,7 @@ static void retire_target_page(ZGeneration* generation, ZPage* page) { // relocate the remaining objects, leaving the target page empty when // relocation completed. if (page->used() == 0) { - ZHeap::heap()->free_page(page, true /* allow_defragment */); + ZHeap::heap()->free_page(page); } } @@ -841,14 +841,12 @@ class ZRelocateWork : public StackObj { const bool promotion = _forwarding->is_promotion(); // Promotions happen through a new cloned page - ZPage* const to_page = promotion ? from_page->clone_limited() : from_page; + ZPage* const to_page = promotion + ? from_page->clone_for_promotion() + : from_page->reset(to_age); // Reset page for in-place relocation - to_page->reset(to_age); to_page->reset_top_for_allocation(); - if (promotion) { - to_page->remset_alloc(); - } // Verify that the inactive remset is clear when resetting the page for // in-place relocation. @@ -1011,7 +1009,7 @@ class ZRelocateWork : public StackObj { page->log_msg(" (relocate page done normal)"); // Free page - ZHeap::heap()->free_page(page, true /* allow_defragment */); + ZHeap::heap()->free_page(page); } } }; @@ -1260,14 +1258,12 @@ class ZFlipAgePagesTask : public ZTask { prev_page->log_msg(promotion ? " (flip promoted)" : " (flip survived)"); // Setup to-space page - ZPage* const new_page = promotion ? prev_page->clone_limited() : prev_page; + ZPage* const new_page = promotion + ? prev_page->clone_for_promotion() + : prev_page->reset(to_age); // Reset page for flip aging - new_page->reset(to_age); new_page->reset_livemap(); - if (promotion) { - new_page->remset_alloc(); - } if (promotion) { ZGeneration::young()->flip_promote(prev_page, new_page); diff --git a/src/hotspot/share/gc/z/zRemembered.cpp b/src/hotspot/share/gc/z/zRemembered.cpp index 3bb17152d4192..b94d676242c4b 100644 --- a/src/hotspot/share/gc/z/zRemembered.cpp +++ b/src/hotspot/share/gc/z/zRemembered.cpp @@ -473,11 +473,9 @@ class ZRememberedScanMarkFollowTask : public ZRestartableTask { _remset_table_iterator(remembered) { _mark->prepare_work(); _remembered->_page_allocator->enable_safe_destroy(); - _remembered->_page_allocator->enable_safe_recycle(); } ~ZRememberedScanMarkFollowTask() { - _remembered->_page_allocator->disable_safe_recycle(); _remembered->_page_allocator->disable_safe_destroy(); _mark->finish_work(); // We are done scanning the set of old pages. diff --git a/src/hotspot/share/gc/z/zRememberedSet.cpp b/src/hotspot/share/gc/z/zRememberedSet.cpp index f833c5b233616..2de62752d91aa 100644 --- a/src/hotspot/share/gc/z/zRememberedSet.cpp +++ b/src/hotspot/share/gc/z/zRememberedSet.cpp @@ -54,12 +54,6 @@ void ZRememberedSet::initialize(size_t page_size) { _bitmap[1].initialize(size_in_bits, true /* clear */); } -void ZRememberedSet::delete_all() { - assert(is_initialized(), "precondition"); - _bitmap[0].resize(0); - _bitmap[1].resize(0); -} - bool ZRememberedSet::is_cleared_current() const { return current()->is_empty(); } diff --git a/src/hotspot/share/gc/z/zRememberedSet.hpp b/src/hotspot/share/gc/z/zRememberedSet.hpp index c3c6e8bc31317..6aca8b2d74e27 100644 --- a/src/hotspot/share/gc/z/zRememberedSet.hpp +++ b/src/hotspot/share/gc/z/zRememberedSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,7 +114,6 @@ class ZRememberedSet { bool is_initialized() const; void initialize(size_t page_size); - void delete_all(); bool at_current(uintptr_t offset) const; bool at_previous(uintptr_t offset) const; diff --git a/src/hotspot/share/gc/z/zUncommitter.cpp b/src/hotspot/share/gc/z/zUncommitter.cpp index 50731592108c6..7993bbd56a9dd 100644 --- a/src/hotspot/share/gc/z/zUncommitter.cpp +++ b/src/hotspot/share/gc/z/zUncommitter.cpp @@ -31,11 +31,12 @@ static const ZStatCounter ZCounterUncommit("Memory", "Uncommit", ZStatUnitBytesPerSecond); -ZUncommitter::ZUncommitter(ZPageAllocator* page_allocator) - : _page_allocator(page_allocator), +ZUncommitter::ZUncommitter(uint32_t id, ZPartition* partition) + : _id(id), + _partition(partition), _lock(), _stop(false) { - set_name("ZUncommitter"); + set_name("ZUncommitter#%u", id); create_and_start(); } @@ -46,7 +47,7 @@ bool ZUncommitter::wait(uint64_t timeout) const { } if (!_stop && timeout > 0) { - log_debug(gc, heap)("Uncommit Timeout: " UINT64_FORMAT "s", timeout); + log_debug(gc, heap)("Uncommitter (%u) Timeout: " UINT64_FORMAT "s", _id, timeout); _lock.wait(timeout * MILLIUNITS); } @@ -63,27 +64,27 @@ void ZUncommitter::run_thread() { while (wait(timeout)) { EventZUncommit event; - size_t uncommitted = 0; + size_t total_uncommitted = 0; while (should_continue()) { // Uncommit chunk - const size_t flushed = _page_allocator->uncommit(&timeout); - if (flushed == 0) { + const size_t uncommitted = _partition->uncommit(&timeout); + if (uncommitted == 0) { // Done break; } - uncommitted += flushed; + total_uncommitted += uncommitted; } - if (uncommitted > 0) { + if (total_uncommitted > 0) { // Update statistics - ZStatInc(ZCounterUncommit, uncommitted); - log_info(gc, heap)("Uncommitted: %zuM(%.0f%%)", - uncommitted / M, percent_of(uncommitted, ZHeap::heap()->max_capacity())); + ZStatInc(ZCounterUncommit, total_uncommitted); + log_info(gc, heap)("Uncommitter (%u) Uncommitted: %zuM(%.0f%%)", + _id, total_uncommitted / M, percent_of(total_uncommitted, ZHeap::heap()->max_capacity())); // Send event - event.commit(uncommitted); + event.commit(total_uncommitted); } } } diff --git a/src/hotspot/share/gc/z/zUncommitter.hpp b/src/hotspot/share/gc/z/zUncommitter.hpp index b626df8dddfe9..f8630f7b7fb3b 100644 --- a/src/hotspot/share/gc/z/zUncommitter.hpp +++ b/src/hotspot/share/gc/z/zUncommitter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,11 +27,12 @@ #include "gc/z/zLock.hpp" #include "gc/z/zThread.hpp" -class ZPageAllocator; +class ZPartition; class ZUncommitter : public ZThread { private: - ZPageAllocator* const _page_allocator; + const uint32_t _id; + ZPartition* const _partition; mutable ZConditionLock _lock; bool _stop; @@ -43,7 +44,7 @@ class ZUncommitter : public ZThread { virtual void terminate(); public: - ZUncommitter(ZPageAllocator* page_allocator); + ZUncommitter(uint32_t id, ZPartition* partition); }; #endif // SHARE_GC_Z_ZUNCOMMITTER_HPP diff --git a/src/hotspot/share/gc/z/zUnmapper.cpp b/src/hotspot/share/gc/z/zUnmapper.cpp deleted file mode 100644 index edd31805c49eb..0000000000000 --- a/src/hotspot/share/gc/z/zUnmapper.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "gc/shared/gc_globals.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/z/zList.inline.hpp" -#include "gc/z/zLock.inline.hpp" -#include "gc/z/zPage.inline.hpp" -#include "gc/z/zPageAllocator.hpp" -#include "gc/z/zUnmapper.hpp" -#include "jfr/jfrEvents.hpp" -#include "runtime/globals.hpp" - -ZUnmapper::ZUnmapper(ZPageAllocator* page_allocator) - : _page_allocator(page_allocator), - _lock(), - _queue(), - _enqueued_bytes(0), - _warned_sync_unmapping(false), - _stop(false) { - set_name("ZUnmapper"); - create_and_start(); -} - -ZPage* ZUnmapper::dequeue() { - ZLocker locker(&_lock); - - for (;;) { - if (_stop) { - return nullptr; - } - - ZPage* const page = _queue.remove_first(); - if (page != nullptr) { - _enqueued_bytes -= page->size(); - return page; - } - - _lock.wait(); - } -} - -bool ZUnmapper::try_enqueue(ZPage* page) { - // Enqueue for asynchronous unmap and destroy - ZLocker locker(&_lock); - if (is_saturated()) { - // The unmapper thread is lagging behind and is unable to unmap memory fast enough - if (!_warned_sync_unmapping) { - _warned_sync_unmapping = true; - log_warning_p(gc)("WARNING: Encountered synchronous unmapping because asynchronous unmapping could not keep up"); - } - log_debug(gc, unmap)("Synchronous unmapping %zuM page", page->size() / M); - return false; - } - - log_trace(gc, unmap)("Asynchronous unmapping %zuM page (%zuM / %zuM enqueued)", - page->size() / M, _enqueued_bytes / M, queue_capacity() / M); - - _queue.insert_last(page); - _enqueued_bytes += page->size(); - _lock.notify_all(); - - return true; -} - -size_t ZUnmapper::queue_capacity() const { - return align_up((size_t)(_page_allocator->max_capacity() * ZAsyncUnmappingLimit / 100.0), ZGranuleSize); -} - -bool ZUnmapper::is_saturated() const { - return _enqueued_bytes >= queue_capacity(); -} - -void ZUnmapper::do_unmap_and_destroy_page(ZPage* page) const { - EventZUnmap event; - const size_t unmapped = page->size(); - - // Unmap and destroy - _page_allocator->unmap_page(page); - _page_allocator->destroy_page(page); - - // Send event - event.commit(unmapped); -} - -void ZUnmapper::unmap_and_destroy_page(ZPage* page) { - if (!try_enqueue(page)) { - // Synchronously unmap and destroy - do_unmap_and_destroy_page(page); - } -} - -void ZUnmapper::run_thread() { - for (;;) { - ZPage* const page = dequeue(); - if (page == nullptr) { - // Stop - return; - } - - do_unmap_and_destroy_page(page); - } -} - -void ZUnmapper::terminate() { - ZLocker locker(&_lock); - _stop = true; - _lock.notify_all(); -} diff --git a/src/hotspot/share/gc/z/zUtils.hpp b/src/hotspot/share/gc/z/zUtils.hpp index 59e789d5b380f..731136c4c99b3 100644 --- a/src/hotspot/share/gc/z/zUtils.hpp +++ b/src/hotspot/share/gc/z/zUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,16 @@ class ZUtils : public AllStatic { // Memory static void fill(uintptr_t* addr, size_t count, uintptr_t value); + template + static void copy_disjoint(T* dest, const T* src, size_t count); + template + static void copy_disjoint(T* dest, const T* src, int count); + + // Sort + template + static void sort(T* array, size_t count, Comparator comparator); + template + static void sort(T* array, int count, Comparator comparator); }; #endif // SHARE_GC_Z_ZUTILS_HPP diff --git a/src/hotspot/share/gc/z/zUtils.inline.hpp b/src/hotspot/share/gc/z/zUtils.inline.hpp index b6acf12df3020..07a49f144e912 100644 --- a/src/hotspot/share/gc/z/zUtils.inline.hpp +++ b/src/hotspot/share/gc/z/zUtils.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,4 +69,35 @@ inline void ZUtils::object_copy_conjoint(zaddress from, zaddress to, size_t size } } +template +inline void ZUtils::copy_disjoint(T* dest, const T* src, size_t count) { + memcpy(dest, src, sizeof(T) * count); +} + +template +inline void ZUtils::copy_disjoint(T* dest, const T* src, int count) { + assert(count >= 0, "must be positive %d", count); + + copy_disjoint(dest, src, static_cast(count)); +} + +template +inline void ZUtils::sort(T* array, size_t count, Comparator comparator) { + using SortType = int(const void*, const void*); + using ComparatorType = int(const T*, const T*); + + static constexpr bool IsComparatorCompatible = std::is_assignable::value; + static_assert(IsComparatorCompatible, "Incompatible Comparator, must decay to plain function pointer"); + + // We rely on ABI compatibility between ComparatorType and SortType + qsort(array, count, sizeof(T), reinterpret_cast(static_cast(comparator))); +} + +template +inline void ZUtils::sort(T* array, int count, Comparator comparator) { + assert(count >= 0, "must be positive %d", count); + + sort(array, static_cast(count), comparator); +} + #endif // SHARE_GC_Z_ZUTILS_INLINE_HPP diff --git a/src/hotspot/share/gc/z/zValue.hpp b/src/hotspot/share/gc/z/zValue.hpp index 2661a906dff15..ab27c6a922739 100644 --- a/src/hotspot/share/gc/z/zValue.hpp +++ b/src/hotspot/share/gc/z/zValue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,8 +76,12 @@ class ZPerWorkerStorage : public ZValueStorage { // Value // +struct ZValueIdTagType {}; + template class ZValue : public CHeapObj { + friend class VMStructs; + private: const uintptr_t _addr; @@ -86,6 +90,8 @@ class ZValue : public CHeapObj { public: ZValue(); ZValue(const T& value); + template + ZValue(ZValueIdTagType, Args&&... args); const T* addr(uint32_t value_id = S::id()) const; T* addr(uint32_t value_id = S::id()); @@ -95,6 +101,8 @@ class ZValue : public CHeapObj { void set(const T& value, uint32_t value_id = S::id()); void set_all(const T& value); + + uint32_t count() const; }; template using ZContended = ZValue; @@ -106,16 +114,23 @@ template using ZPerWorker = ZValue; // Iterator // +template +class ZValueConstIterator; + template class ZValueIterator { + friend class ZValueConstIterator; + private: ZValue* const _value; uint32_t _value_id; public: ZValueIterator(ZValue* value); + ZValueIterator(const ZValueIterator&) = default; bool next(T** value); + bool next(T** value, uint32_t* value_id); }; template using ZPerCPUIterator = ZValueIterator; @@ -130,6 +145,8 @@ class ZValueConstIterator { public: ZValueConstIterator(const ZValue* value); + ZValueConstIterator(const ZValueIterator& other); + ZValueConstIterator(const ZValueConstIterator&) = default; bool next(const T** value); }; diff --git a/src/hotspot/share/gc/z/zValue.inline.hpp b/src/hotspot/share/gc/z/zValue.inline.hpp index c2aa8bbbb4004..f0ff891c3bcea 100644 --- a/src/hotspot/share/gc/z/zValue.inline.hpp +++ b/src/hotspot/share/gc/z/zValue.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ #include "gc/shared/workerThread.hpp" #include "gc/z/zCPU.inline.hpp" #include "gc/z/zGlobals.hpp" -#include "gc/z/zNUMA.hpp" +#include "gc/z/zNUMA.inline.hpp" #include "gc/z/zUtils.inline.hpp" #include "runtime/globals.hpp" #include "utilities/align.hpp" @@ -142,6 +142,18 @@ inline ZValue::ZValue(const T& value) } } +template +template +inline ZValue::ZValue(ZValueIdTagType, Args&&... args) + : _addr(S::alloc(sizeof(T))) { + // Initialize all instances + uint32_t value_id; + ZValueIterator iter(this); + for (T* addr; iter.next(&addr, &value_id);) { + ::new (addr) T(value_id, args...); + } +} + template inline const T* ZValue::addr(uint32_t value_id) const { return reinterpret_cast(value_addr(value_id)); @@ -175,6 +187,11 @@ inline void ZValue::set_all(const T& value) { } } +template +uint32_t ZValue::count() const { + return S::count(); +} + // // Iterator // @@ -192,12 +209,26 @@ inline bool ZValueIterator::next(T** value) { } return false; } +template +inline bool ZValueIterator::next(T** value, uint32_t* value_id) { + if (_value_id < S::count()) { + *value_id = _value_id; + *value = _value->addr(_value_id++); + return true; + } + return false; +} template inline ZValueConstIterator::ZValueConstIterator(const ZValue* value) : _value(value), _value_id(0) {} +template +inline ZValueConstIterator::ZValueConstIterator(const ZValueIterator& other) + : _value(other._value), + _value_id(other._value_id) {} + template inline bool ZValueConstIterator::next(const T** value) { if (_value_id < S::count()) { diff --git a/src/hotspot/share/gc/z/zVirtualMemory.cpp b/src/hotspot/share/gc/z/zVirtualMemory.cpp deleted file mode 100644 index 471fc6f505e5e..0000000000000 --- a/src/hotspot/share/gc/z/zVirtualMemory.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "gc/shared/gc_globals.hpp" -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/z/zAddress.inline.hpp" -#include "gc/z/zAddressSpaceLimit.hpp" -#include "gc/z/zGlobals.hpp" -#include "gc/z/zInitialize.hpp" -#include "gc/z/zNMT.hpp" -#include "gc/z/zVirtualMemory.inline.hpp" -#include "utilities/align.hpp" -#include "utilities/debug.hpp" - -ZVirtualMemoryManager::ZVirtualMemoryManager(size_t max_capacity) - : _manager(), - _reserved(0), - _initialized(false) { - - assert(max_capacity <= ZAddressOffsetMax, "Too large max_capacity"); - - // Initialize platform specific parts before reserving address space - pd_initialize_before_reserve(); - - // Register the Windows callbacks - pd_register_callbacks(&_manager); - - // Reserve address space - if (!reserve(max_capacity)) { - ZInitialize::error_d("Failed to reserve enough address space for Java heap"); - return; - } - - // Set ZAddressOffsetMax to the highest address end available after reservation - ZAddressOffsetMax = untype(highest_available_address_end()); - - // Successfully initialized - _initialized = true; -} - -#ifdef ASSERT -size_t ZVirtualMemoryManager::force_reserve_discontiguous(size_t size) { - const size_t min_range = calculate_min_range(size); - const size_t max_range = MAX2(align_down(size / ZForceDiscontiguousHeapReservations, ZGranuleSize), min_range); - size_t reserved = 0; - - // Try to reserve ZForceDiscontiguousHeapReservations number of virtual memory - // ranges. Starting with higher addresses. - uintptr_t end = ZAddressOffsetMax; - while (reserved < size && end >= max_range) { - const size_t remaining = size - reserved; - const size_t reserve_size = MIN2(max_range, remaining); - const uintptr_t reserve_start = end - reserve_size; - - if (reserve_contiguous(to_zoffset(reserve_start), reserve_size)) { - reserved += reserve_size; - } - - end -= reserve_size * 2; - } - - // If (reserved < size) attempt to reserve the rest via normal divide and conquer - uintptr_t start = 0; - while (reserved < size && start < ZAddressOffsetMax) { - const size_t remaining = MIN2(size - reserved, ZAddressOffsetMax - start); - reserved += reserve_discontiguous(to_zoffset(start), remaining, min_range); - start += remaining; - } - - return reserved; -} -#endif - -size_t ZVirtualMemoryManager::reserve_discontiguous(zoffset start, size_t size, size_t min_range) { - if (size < min_range) { - // Too small - return 0; - } - - assert(is_aligned(size, ZGranuleSize), "Misaligned"); - - if (reserve_contiguous(start, size)) { - return size; - } - - const size_t half = size / 2; - if (half < min_range) { - // Too small - return 0; - } - - // Divide and conquer - const size_t first_part = align_down(half, ZGranuleSize); - const size_t second_part = size - first_part; - const size_t first_size = reserve_discontiguous(start, first_part, min_range); - const size_t second_size = reserve_discontiguous(start + first_part, second_part, min_range); - return first_size + second_size; -} - -size_t ZVirtualMemoryManager::calculate_min_range(size_t size) { - // Don't try to reserve address ranges smaller than 1% of the requested size. - // This avoids an explosion of reservation attempts in case large parts of the - // address space is already occupied. - return align_up(size / ZMaxVirtualReservations, ZGranuleSize); -} - -size_t ZVirtualMemoryManager::reserve_discontiguous(size_t size) { - const size_t min_range = calculate_min_range(size); - uintptr_t start = 0; - size_t reserved = 0; - - // Reserve size somewhere between [0, ZAddressOffsetMax) - while (reserved < size && start < ZAddressOffsetMax) { - const size_t remaining = MIN2(size - reserved, ZAddressOffsetMax - start); - reserved += reserve_discontiguous(to_zoffset(start), remaining, min_range); - start += remaining; - } - - return reserved; -} - -bool ZVirtualMemoryManager::reserve_contiguous(zoffset start, size_t size) { - assert(is_aligned(size, ZGranuleSize), "Must be granule aligned 0x%zx", size); - - // Reserve address views - const zaddress_unsafe addr = ZOffset::address_unsafe(start); - - // Reserve address space - if (!pd_reserve(addr, size)) { - return false; - } - - // Register address views with native memory tracker - ZNMT::reserve(addr, size); - - // Make the address range free - _manager.register_range(start, size); - - return true; -} - -bool ZVirtualMemoryManager::reserve_contiguous(size_t size) { - // Allow at most 8192 attempts spread evenly across [0, ZAddressOffsetMax) - const size_t unused = ZAddressOffsetMax - size; - const size_t increment = MAX2(align_up(unused / 8192, ZGranuleSize), ZGranuleSize); - - for (uintptr_t start = 0; start + size <= ZAddressOffsetMax; start += increment) { - if (reserve_contiguous(to_zoffset(start), size)) { - // Success - return true; - } - } - - // Failed - return false; -} - -bool ZVirtualMemoryManager::reserve(size_t max_capacity) { - const size_t limit = MIN2(ZAddressOffsetMax, ZAddressSpaceLimit::heap()); - const size_t size = MIN2(max_capacity * ZVirtualToPhysicalRatio, limit); - - auto do_reserve = [&]() { -#ifdef ASSERT - if (ZForceDiscontiguousHeapReservations > 0) { - return force_reserve_discontiguous(size); - } -#endif - - // Prefer a contiguous address space - if (reserve_contiguous(size)) { - return size; - } - - // Fall back to a discontiguous address space - return reserve_discontiguous(size); - }; - - const size_t reserved = do_reserve(); - - const bool contiguous = _manager.free_is_contiguous(); - - log_info_p(gc, init)("Address Space Type: %s/%s/%s", - (contiguous ? "Contiguous" : "Discontiguous"), - (limit == ZAddressOffsetMax ? "Unrestricted" : "Restricted"), - (reserved == size ? "Complete" : "Degraded")); - log_info_p(gc, init)("Address Space Size: %zuM", reserved / M); - - // Record reserved - _reserved = reserved; - - return reserved >= max_capacity; -} - -void ZVirtualMemoryManager::unreserve(zoffset start, size_t size) { - const zaddress_unsafe addr = ZOffset::address_unsafe(start); - - // Unregister the reserved memory from NMT - ZNMT::unreserve(addr, size); - - // Unreserve address space - pd_unreserve(addr, size); -} - -void ZVirtualMemoryManager::unreserve_all() { - zoffset start; - size_t size; - - while (_manager.unregister_first(&start, &size)) { - unreserve(start, size); - } -} - -bool ZVirtualMemoryManager::is_initialized() const { - return _initialized; -} - -ZVirtualMemory ZVirtualMemoryManager::alloc(size_t size, bool force_low_address) { - zoffset start; - - // Small pages are allocated at low addresses, while medium/large pages - // are allocated at high addresses (unless forced to be at a low address). - if (force_low_address || size <= ZPageSizeSmall) { - start = _manager.alloc_low_address(size); - } else { - start = _manager.alloc_high_address(size); - } - - if (start == zoffset(UINTPTR_MAX)) { - return ZVirtualMemory(); - } - - return ZVirtualMemory(start, size); -} - -void ZVirtualMemoryManager::free(const ZVirtualMemory& vmem) { - _manager.free(vmem.start(), vmem.size()); -} diff --git a/src/hotspot/share/gc/z/zVirtualMemory.hpp b/src/hotspot/share/gc/z/zVirtualMemory.hpp index f5185549e8a53..46fec6ac79e7f 100644 --- a/src/hotspot/share/gc/z/zVirtualMemory.hpp +++ b/src/hotspot/share/gc/z/zVirtualMemory.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,67 +25,16 @@ #define SHARE_GC_Z_ZVIRTUALMEMORY_HPP #include "gc/z/zAddress.hpp" -#include "gc/z/zMemory.hpp" - -class ZVirtualMemory { - friend class VMStructs; - -private: - zoffset _start; - zoffset_end _end; +#include "gc/z/zRange.hpp" +#include "utilities/globalDefinitions.hpp" +class ZVirtualMemory : public ZRange { public: ZVirtualMemory(); ZVirtualMemory(zoffset start, size_t size); + ZVirtualMemory(const ZRange& range); - bool is_null() const; - zoffset start() const; - zoffset_end end() const; - size_t size() const; - - ZVirtualMemory split(size_t size); -}; - -class ZVirtualMemoryManager { - friend class ZMapperTest; - friend class ZVirtualMemoryManagerTest; - -private: - static size_t calculate_min_range(size_t size); - - ZMemoryManager _manager; - size_t _reserved; - bool _initialized; - - // Platform specific implementation - void pd_initialize_before_reserve(); - void pd_register_callbacks(ZMemoryManager* manager); - bool pd_reserve(zaddress_unsafe addr, size_t size); - void pd_unreserve(zaddress_unsafe addr, size_t size); - - bool reserve_contiguous(zoffset start, size_t size); - bool reserve_contiguous(size_t size); - size_t reserve_discontiguous(zoffset start, size_t size, size_t min_range); - size_t reserve_discontiguous(size_t size); - bool reserve(size_t max_capacity); - - void unreserve(zoffset start, size_t size); - - DEBUG_ONLY(size_t force_reserve_discontiguous(size_t size);) - -public: - ZVirtualMemoryManager(size_t max_capacity); - - bool is_initialized() const; - - size_t reserved() const; - zoffset lowest_available_address() const; - zoffset_end highest_available_address_end() const; - - ZVirtualMemory alloc(size_t size, bool force_low_address); - void free(const ZVirtualMemory& vmem); - - void unreserve_all(); + int granule_count() const; }; #endif // SHARE_GC_Z_ZVIRTUALMEMORY_HPP diff --git a/src/hotspot/share/gc/z/zVirtualMemory.inline.hpp b/src/hotspot/share/gc/z/zVirtualMemory.inline.hpp index 9d5fe7dd57afd..3cbe1409b523a 100644 --- a/src/hotspot/share/gc/z/zVirtualMemory.inline.hpp +++ b/src/hotspot/share/gc/z/zVirtualMemory.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,47 +26,32 @@ #include "gc/z/zVirtualMemory.hpp" -#include "gc/z/zMemory.inline.hpp" +#include "gc/z/zAddress.inline.hpp" +#include "gc/z/zGlobals.hpp" +#include "gc/z/zRange.inline.hpp" +#include "utilities/align.hpp" +#include "utilities/debug.hpp" inline ZVirtualMemory::ZVirtualMemory() - : _start(zoffset(UINTPTR_MAX)), - _end(zoffset_end(UINTPTR_MAX)) {} + : ZRange() {} inline ZVirtualMemory::ZVirtualMemory(zoffset start, size_t size) - : _start(start), - _end(to_zoffset_end(start, size)) {} - -inline bool ZVirtualMemory::is_null() const { - return _start == zoffset(UINTPTR_MAX); -} - -inline zoffset ZVirtualMemory::start() const { - return _start; -} - -inline zoffset_end ZVirtualMemory::end() const { - return _end; + : ZRange(start, size) { + // ZVirtualMemory is only used for ZGranuleSize multiple ranges + assert(is_aligned(untype(start), ZGranuleSize), "must be multiple of ZGranuleSize"); + assert(is_aligned(size, ZGranuleSize), "must be multiple of ZGranuleSize"); } -inline size_t ZVirtualMemory::size() const { - return _end - _start; -} +inline ZVirtualMemory::ZVirtualMemory(const ZRange& range) + : ZVirtualMemory(range.start(), range.size()) {} -inline ZVirtualMemory ZVirtualMemory::split(size_t size) { - _start += size; - return ZVirtualMemory(_start - size, size); -} +inline int ZVirtualMemory::granule_count() const { + const size_t granule_count = size() >> ZGranuleSizeShift; -inline size_t ZVirtualMemoryManager::reserved() const { - return _reserved; -} - -inline zoffset ZVirtualMemoryManager::lowest_available_address() const { - return _manager.peek_low_address(); -} + assert(granule_count <= static_cast(std::numeric_limits::max()), + "must not overflow an int %zu", granule_count); -inline zoffset_end ZVirtualMemoryManager::highest_available_address_end() const { - return _manager.peak_high_address_end(); + return static_cast(granule_count); } #endif // SHARE_GC_Z_ZVIRTUALMEMORY_INLINE_HPP diff --git a/src/hotspot/share/gc/z/zVirtualMemoryManager.cpp b/src/hotspot/share/gc/z/zVirtualMemoryManager.cpp new file mode 100644 index 0000000000000..2f81a5cfe0988 --- /dev/null +++ b/src/hotspot/share/gc/z/zVirtualMemoryManager.cpp @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcLogPrecious.hpp" +#include "gc/z/zAddress.inline.hpp" +#include "gc/z/zAddressSpaceLimit.hpp" +#include "gc/z/zArray.hpp" +#include "gc/z/zGlobals.hpp" +#include "gc/z/zInitialize.hpp" +#include "gc/z/zNMT.hpp" +#include "gc/z/zNUMA.inline.hpp" +#include "gc/z/zValue.inline.hpp" +#include "gc/z/zVirtualMemory.inline.hpp" +#include "gc/z/zVirtualMemoryManager.inline.hpp" +#include "utilities/align.hpp" +#include "utilities/debug.hpp" + +ZVirtualMemoryReserver::ZVirtualMemoryReserver(size_t size) + : _registry(), + _reserved(reserve(size)) {} + +void ZVirtualMemoryReserver::initialize_partition_registry(ZVirtualMemoryRegistry* partition_registry, size_t size) { + assert(partition_registry->is_empty(), "Should be empty when initializing"); + + // Registers the Windows callbacks + pd_register_callbacks(partition_registry); + + _registry.transfer_from_low(partition_registry, size); + + // Set the limits according to the virtual memory given to this partition + partition_registry->anchor_limits(); +} + +void ZVirtualMemoryReserver::unreserve(const ZVirtualMemory& vmem) { + const zaddress_unsafe addr = ZOffset::address_unsafe(vmem.start()); + + // Unregister the reserved memory from NMT + ZNMT::unreserve(addr, vmem.size()); + + // Unreserve address space + pd_unreserve(addr, vmem.size()); +} + +void ZVirtualMemoryReserver::unreserve_all() { + for (ZVirtualMemory vmem; _registry.unregister_first(&vmem);) { + unreserve(vmem); + } +} + +bool ZVirtualMemoryReserver::is_empty() const { + return _registry.is_empty(); +} + +bool ZVirtualMemoryReserver::is_contiguous() const { + return _registry.is_contiguous(); +} + +size_t ZVirtualMemoryReserver::reserved() const { + return _reserved; +} + +zoffset_end ZVirtualMemoryReserver::highest_available_address_end() const { + return _registry.peak_high_address_end(); +} + +#ifdef ASSERT +size_t ZVirtualMemoryReserver::force_reserve_discontiguous(size_t size) { + const size_t min_range = calculate_min_range(size); + const size_t max_range = MAX2(align_down(size / ZForceDiscontiguousHeapReservations, ZGranuleSize), min_range); + size_t reserved = 0; + + // Try to reserve ZForceDiscontiguousHeapReservations number of virtual memory + // ranges. Starting with higher addresses. + uintptr_t end = ZAddressOffsetMax; + while (reserved < size && end >= max_range) { + const size_t remaining = size - reserved; + const size_t reserve_size = MIN2(max_range, remaining); + const uintptr_t reserve_start = end - reserve_size; + + if (reserve_contiguous(to_zoffset(reserve_start), reserve_size)) { + reserved += reserve_size; + } + + end -= reserve_size * 2; + } + + // If (reserved < size) attempt to reserve the rest via normal divide and conquer + uintptr_t start = 0; + while (reserved < size && start < ZAddressOffsetMax) { + const size_t remaining = MIN2(size - reserved, ZAddressOffsetMax - start); + reserved += reserve_discontiguous(to_zoffset(start), remaining, min_range); + start += remaining; + } + + return reserved; +} +#endif + +size_t ZVirtualMemoryReserver::reserve_discontiguous(zoffset start, size_t size, size_t min_range) { + if (size < min_range) { + // Too small + return 0; + } + + assert(is_aligned(size, ZGranuleSize), "Misaligned"); + + if (reserve_contiguous(start, size)) { + return size; + } + + const size_t half = size / 2; + if (half < min_range) { + // Too small + return 0; + } + + // Divide and conquer + const size_t first_part = align_down(half, ZGranuleSize); + const size_t second_part = size - first_part; + const size_t first_size = reserve_discontiguous(start, first_part, min_range); + const size_t second_size = reserve_discontiguous(start + first_part, second_part, min_range); + return first_size + second_size; +} + +size_t ZVirtualMemoryReserver::calculate_min_range(size_t size) { + // Don't try to reserve address ranges smaller than 1% of the requested size. + // This avoids an explosion of reservation attempts in case large parts of the + // address space is already occupied. + return align_up(size / ZMaxVirtualReservations, ZGranuleSize); +} + +size_t ZVirtualMemoryReserver::reserve_discontiguous(size_t size) { + const size_t min_range = calculate_min_range(size); + uintptr_t start = 0; + size_t reserved = 0; + + // Reserve size somewhere between [0, ZAddressOffsetMax) + while (reserved < size && start < ZAddressOffsetMax) { + const size_t remaining = MIN2(size - reserved, ZAddressOffsetMax - start); + reserved += reserve_discontiguous(to_zoffset(start), remaining, min_range); + start += remaining; + } + + return reserved; +} + +bool ZVirtualMemoryReserver::reserve_contiguous(zoffset start, size_t size) { + assert(is_aligned(size, ZGranuleSize), "Must be granule aligned 0x%zx", size); + + // Reserve address views + const zaddress_unsafe addr = ZOffset::address_unsafe(start); + + // Reserve address space + if (!pd_reserve(addr, size)) { + return false; + } + + // Register address views with native memory tracker + ZNMT::reserve(addr, size); + + // Register the memory reservation + _registry.register_range({start, size}); + + return true; +} + +bool ZVirtualMemoryReserver::reserve_contiguous(size_t size) { + // Allow at most 8192 attempts spread evenly across [0, ZAddressOffsetMax) + const size_t unused = ZAddressOffsetMax - size; + const size_t increment = MAX2(align_up(unused / 8192, ZGranuleSize), ZGranuleSize); + + for (uintptr_t start = 0; start + size <= ZAddressOffsetMax; start += increment) { + if (reserve_contiguous(to_zoffset(start), size)) { + // Success + return true; + } + } + + // Failed + return false; +} + +size_t ZVirtualMemoryReserver::reserve(size_t size) { + // Register Windows callbacks + pd_register_callbacks(&_registry); + + // Reserve address space + +#ifdef ASSERT + if (ZForceDiscontiguousHeapReservations > 0) { + return force_reserve_discontiguous(size); + } +#endif + + // Prefer a contiguous address space + if (reserve_contiguous(size)) { + return size; + } + + // Fall back to a discontiguous address space + return reserve_discontiguous(size); +} + +ZVirtualMemoryManager::ZVirtualMemoryManager(size_t max_capacity) + : _partition_registries(), + _multi_partition_registry(), + _is_multi_partition_enabled(false), + _initialized(false) { + + assert(max_capacity <= ZAddressOffsetMax, "Too large max_capacity"); + + ZAddressSpaceLimit::print_limits(); + + const size_t limit = MIN2(ZAddressOffsetMax, ZAddressSpaceLimit::heap()); + + const size_t desired_for_partitions = max_capacity * ZVirtualToPhysicalRatio; + const size_t desired_for_multi_partition = ZNUMA::count() > 1 ? desired_for_partitions : 0; + + const size_t desired = desired_for_partitions + desired_for_multi_partition; + const size_t requested = desired <= limit + ? desired + : MIN2(desired_for_partitions, limit); + + // Reserve virtual memory for the heap + ZVirtualMemoryReserver reserver(requested); + + const size_t reserved = reserver.reserved(); + const bool is_contiguous = reserver.is_contiguous(); + + log_debug_p(gc, init)("Reserved Space: limit " EXACTFMT ", desired " EXACTFMT ", requested " EXACTFMT, + EXACTFMTARGS(limit), EXACTFMTARGS(desired), EXACTFMTARGS(requested)); + + if (reserved < max_capacity) { + ZInitialize::error_d("Failed to reserve " EXACTFMT " address space for Java heap", EXACTFMTARGS(max_capacity)); + return; + } + + // Set ZAddressOffsetMax to the highest address end available after reservation + ZAddressOffsetMax = untype(reserver.highest_available_address_end()); + + const size_t size_for_partitions = MIN2(reserved, desired_for_partitions); + + // Divide size_for_partitions virtual memory over the NUMA nodes + initialize_partitions(&reserver, size_for_partitions); + + // Set up multi-partition or unreserve the surplus memory + if (desired_for_multi_partition > 0 && reserved == desired) { + // Enough left to setup the multi-partition memory reservation + reserver.initialize_partition_registry(&_multi_partition_registry, desired_for_multi_partition); + _is_multi_partition_enabled = true; + } else { + // Failed to reserve enough memory for multi-partition, unreserve unused memory + reserver.unreserve_all(); + } + + assert(reserver.is_empty(), "Must have handled all reserved memory"); + + log_info_p(gc, init)("Reserved Space Type: %s/%s/%s", + (is_contiguous ? "Contiguous" : "Discontiguous"), + (requested == desired ? "Unrestricted" : "Restricted"), + (reserved == desired ? "Complete" : ((reserved < desired_for_partitions) ? "Degraded" : "NUMA-Degraded"))); + log_info_p(gc, init)("Reserved Space Size: " EXACTFMT, EXACTFMTARGS(reserved)); + + // Successfully initialized + _initialized = true; +} + +void ZVirtualMemoryManager::initialize_partitions(ZVirtualMemoryReserver* reserver, size_t size_for_partitions) { + precond(is_aligned(size_for_partitions, ZGranuleSize)); + + // If the capacity consist of less granules than the number of partitions + // some partitions will be empty. Distribute these shares on the none empty + // partitions. + const uint32_t first_empty_numa_id = MIN2(static_cast(size_for_partitions >> ZGranuleSizeShift), ZNUMA::count()); + const uint32_t ignore_count = ZNUMA::count() - first_empty_numa_id; + + // Install reserved memory into registry(s) + uint32_t numa_id; + ZPerNUMAIterator iter(&_partition_registries); + for (ZVirtualMemoryRegistry* registry; iter.next(®istry, &numa_id);) { + if (numa_id == first_empty_numa_id) { + break; + } + + // Calculate how much reserved memory this partition gets + const size_t reserved_for_partition = ZNUMA::calculate_share(numa_id, size_for_partitions, ZGranuleSize, ignore_count); + + // Transfer reserved memory + reserver->initialize_partition_registry(registry, reserved_for_partition); + } +} + +bool ZVirtualMemoryManager::is_initialized() const { + return _initialized; +} + +ZVirtualMemoryRegistry& ZVirtualMemoryManager::registry(uint32_t partition_id) { + return _partition_registries.get(partition_id); +} + +const ZVirtualMemoryRegistry& ZVirtualMemoryManager::registry(uint32_t partition_id) const { + return _partition_registries.get(partition_id); +} + +zoffset ZVirtualMemoryManager::lowest_available_address(uint32_t partition_id) const { + return registry(partition_id).peek_low_address(); +} + +void ZVirtualMemoryManager::insert(const ZVirtualMemory& vmem, uint32_t partition_id) { + assert(partition_id == lookup_partition_id(vmem), "wrong partition_id for vmem"); + registry(partition_id).insert(vmem); +} + +void ZVirtualMemoryManager::insert_multi_partition(const ZVirtualMemory& vmem) { + _multi_partition_registry.insert(vmem); +} + +size_t ZVirtualMemoryManager::remove_from_low_many_at_most(size_t size, uint32_t partition_id, ZArray* vmems_out) { + return registry(partition_id).remove_from_low_many_at_most(size, vmems_out); +} + +ZVirtualMemory ZVirtualMemoryManager::remove_from_low(size_t size, uint32_t partition_id) { + return registry(partition_id).remove_from_low(size); +} + +ZVirtualMemory ZVirtualMemoryManager::remove_from_low_multi_partition(size_t size) { + return _multi_partition_registry.remove_from_low(size); +} + +void ZVirtualMemoryManager::insert_and_remove_from_low_many(const ZVirtualMemory& vmem, uint32_t partition_id, ZArray* vmems_out) { + registry(partition_id).insert_and_remove_from_low_many(vmem, vmems_out); +} + +ZVirtualMemory ZVirtualMemoryManager::insert_and_remove_from_low_exact_or_many(size_t size, uint32_t partition_id, ZArray* vmems_in_out) { + return registry(partition_id).insert_and_remove_from_low_exact_or_many(size, vmems_in_out); +} diff --git a/src/hotspot/share/gc/z/zVirtualMemoryManager.hpp b/src/hotspot/share/gc/z/zVirtualMemoryManager.hpp new file mode 100644 index 0000000000000..a9ab86761acb9 --- /dev/null +++ b/src/hotspot/share/gc/z/zVirtualMemoryManager.hpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_Z_ZVIRTUALMEMORYMANAGER_HPP +#define SHARE_GC_Z_ZVIRTUALMEMORYMANAGER_HPP + +#include "gc/z/zAddress.hpp" +#include "gc/z/zArray.hpp" +#include "gc/z/zRangeRegistry.hpp" +#include "gc/z/zValue.hpp" +#include "gc/z/zVirtualMemory.hpp" + +using ZVirtualMemoryRegistry = ZRangeRegistry; + +class ZVirtualMemoryReserver { + friend class ZMapperTest; + friend class ZVirtualMemoryManagerTest; + +private: + + ZVirtualMemoryRegistry _registry; + const size_t _reserved; + + static size_t calculate_min_range(size_t size); + + // Platform specific implementation + void pd_register_callbacks(ZVirtualMemoryRegistry* registry); + bool pd_reserve(zaddress_unsafe addr, size_t size); + void pd_unreserve(zaddress_unsafe addr, size_t size); + + bool reserve_contiguous(zoffset start, size_t size); + bool reserve_contiguous(size_t size); + size_t reserve_discontiguous(zoffset start, size_t size, size_t min_range); + size_t reserve_discontiguous(size_t size); + + size_t reserve(size_t size); + void unreserve(const ZVirtualMemory& vmem); + + DEBUG_ONLY(size_t force_reserve_discontiguous(size_t size);) + +public: + ZVirtualMemoryReserver(size_t size); + + void initialize_partition_registry(ZVirtualMemoryRegistry* partition_registry, size_t size); + + void unreserve_all(); + + bool is_empty() const; + bool is_contiguous() const; + + size_t reserved() const; + + zoffset_end highest_available_address_end() const; +}; + +class ZVirtualMemoryManager { +private: + ZPerNUMA _partition_registries; + ZVirtualMemoryRegistry _multi_partition_registry; + bool _is_multi_partition_enabled; + bool _initialized; + + ZVirtualMemoryRegistry& registry(uint32_t partition_id); + const ZVirtualMemoryRegistry& registry(uint32_t partition_id) const; + +public: + ZVirtualMemoryManager(size_t max_capacity); + + void initialize_partitions(ZVirtualMemoryReserver* reserver, size_t size_for_partitions); + + bool is_initialized() const; + bool is_multi_partition_enabled() const; + bool is_in_multi_partition(const ZVirtualMemory& vmem) const; + + uint32_t lookup_partition_id(const ZVirtualMemory& vmem) const; + zoffset lowest_available_address(uint32_t partition_id) const; + + void insert(const ZVirtualMemory& vmem, uint32_t partition_id); + void insert_multi_partition(const ZVirtualMemory& vmem); + + size_t remove_from_low_many_at_most(size_t size, uint32_t partition_id, ZArray* vmems_out); + ZVirtualMemory remove_from_low(size_t size, uint32_t partition_id); + ZVirtualMemory remove_from_low_multi_partition(size_t size); + + void insert_and_remove_from_low_many(const ZVirtualMemory& vmem, uint32_t partition_id, ZArray* vmems_out); + ZVirtualMemory insert_and_remove_from_low_exact_or_many(size_t size, uint32_t partition_id, ZArray* vmems_in_out); +}; + +#endif // SHARE_GC_Z_ZVIRTUALMEMORYMANAGER_HPP diff --git a/src/hotspot/share/gc/z/zVirtualMemoryManager.inline.hpp b/src/hotspot/share/gc/z/zVirtualMemoryManager.inline.hpp new file mode 100644 index 0000000000000..78f966d0f845e --- /dev/null +++ b/src/hotspot/share/gc/z/zVirtualMemoryManager.inline.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_Z_ZVIRTUALMEMORYMANAGER_INLINE_HPP +#define SHARE_GC_Z_ZVIRTUALMEMORYMANAGER_INLINE_HPP + +#include "gc/z/zVirtualMemoryManager.hpp" + +#include "utilities/globalDefinitions.hpp" +#include "gc/z/zRangeRegistry.inline.hpp" + + +inline bool ZVirtualMemoryManager::is_multi_partition_enabled() const { + return _is_multi_partition_enabled; +} + +inline bool ZVirtualMemoryManager::is_in_multi_partition(const ZVirtualMemory& vmem) const { + return _multi_partition_registry.limits_contain(vmem); +} + +inline uint32_t ZVirtualMemoryManager::lookup_partition_id(const ZVirtualMemory& vmem) const { + const uint32_t num_partitions = _partition_registries.count(); + for (uint32_t partition_id = 0; partition_id < num_partitions; partition_id++) { + if (registry(partition_id).limits_contain(vmem)) { + return partition_id; + } + } + + ShouldNotReachHere(); +} + +#endif // SHARE_GC_Z_ZVIRTUALMEMORYMANAGER_INLINE_HPP diff --git a/src/hotspot/share/gc/z/z_globals.hpp b/src/hotspot/share/gc/z/z_globals.hpp index 4555b470cac92..17a77a12ca444 100644 --- a/src/hotspot/share/gc/z/z_globals.hpp +++ b/src/hotspot/share/gc/z/z_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,13 +68,6 @@ product(bool, ZCollectionIntervalOnly, false, \ "Only use timers for GC heuristics") \ \ - product(double, ZAsyncUnmappingLimit, 100.0, DIAGNOSTIC, \ - "Specify the max amount (percentage of max heap size) of async " \ - "unmapping that can be in-flight before unmapping requests are " \ - "temporarily forced to be synchronous instead. " \ - "The default means after an amount of pages proportional to the " \ - "max capacity is enqueued, we resort to synchronous unmapping.") \ - \ product(uint, ZStatisticsInterval, 10, DIAGNOSTIC, \ "Time between statistics print outs (in seconds)") \ range(1, (uint)-1) \ @@ -118,6 +111,11 @@ develop(bool, ZVerifyOops, false, \ "Verify accessed oops") \ \ + develop(uint, ZFakeNUMA, 1, \ + "ZFakeNUMA is used to test the internal NUMA memory support " \ + "without the need for UseNUMA") \ + range(1, 16) \ + \ develop(size_t, ZForceDiscontiguousHeapReservations, 0, \ "The gc will attempt to split the heap reservation into this " \ "many reservations, subject to available virtual address space " \ diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 562d31b828d3e..6aa3e05cda135 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -1,7 +1,7 @@ U+2015 - return ((outChar != '\u2014')? outChar: '\u2015'); - } else { - int adjust = c2 < 0x9F ? 1 : 0; - int rowOffset = c1 < 0xA0 ? 0x70 : 0xB0; - int cellOffset = (adjust == 1) ? (c2 > 0x7F ? 0x20 : 0x1F) : 0x7E; - int b1 = ((c1 - rowOffset) << 1) - adjust; - int b2 = c2 - cellOffset; - char outChar2 = jis0208.decodeDouble(b1, b2); - return outChar2; - } - } - } - - private static class Encoder extends SJIS_OLD.Encoder { - - private JIS_X_0201_OLD.Encoder jis0201; - - private static final short[] j0208Index1 = - JIS_X_0208_Solaris_Encoder.getIndex1(); - private static final String[] j0208Index2 = - JIS_X_0208_Solaris_Encoder.getIndex2(); - - private Encoder(Charset cs) { - super(cs); - jis0201 = new JIS_X_0201_OLD.Encoder(cs); - } - - protected int encodeDouble(char ch) { - int result = 0; - - // PCK uses JIS_X_0208:1983 rather than JIS_X_0208:1997 - - switch (ch) { - case '\u2015': - return 0x815C; - case '\u2014': - return 0; - default: - break; - } - - if ((result = super.encodeDouble(ch)) != 0) { - return result; - } - else { - int offset = j0208Index1[ch >> 8] << 8; - int pos = j0208Index2[offset >> 12].charAt((offset & 0xfff) + (ch & 0xff)); - if (pos != 0) { - int c1 = (pos >> 8) & 0xff; - int c2 = pos & 0xff; - int rowOffset = c1 < 0x5F ? 0x70 : 0xB0; - int cellOffset = (c1 % 2 == 1) ? (c2 > 0x5F ? 0x20 : 0x1F) : 0x7E; - result = ((((c1 + 1 ) >> 1) + rowOffset) << 8) | (c2 + cellOffset); - } - } - return result; - } - } -} diff --git a/test/jdk/sun/nio/cs/OLD/SJIS_OLD.java b/test/jdk/sun/nio/cs/OLD/SJIS_OLD.java deleted file mode 100644 index 2647e3a7d191b..0000000000000 --- a/test/jdk/sun/nio/cs/OLD/SJIS_OLD.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2002, 2012, 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. - */ - -/* - */ - -import java.nio.*; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; -import sun.nio.cs.HistoricallyNamedCharset; - -public class SJIS_OLD - extends Charset - implements HistoricallyNamedCharset -{ - - public SJIS_OLD() { - super("Shift_JIS_OLD", null); - } - - public String historicalName() { - return "SJIS"; - } - - public boolean contains(Charset cs) { - return ((cs.name().equals("US-ASCII")) - || (cs instanceof JIS_X_0201_OLD) - || (cs instanceof SJIS_OLD) - || (cs instanceof JIS_X_0208_OLD)); - } - - public CharsetDecoder newDecoder() { - return new Decoder(this); - } - - public CharsetEncoder newEncoder() { - - // Need to force the replacement byte to 0x3f - // because JIS_X_0208_Encoder defines its own - // alternative 2 byte substitution to permit it - // to exist as a self-standing Encoder - - byte[] replacementBytes = { (byte)0x3f }; - return new Encoder(this).replaceWith(replacementBytes); - } - - static class Decoder extends JIS_X_0208_Decoder { - - JIS_X_0201_OLD.Decoder jis0201; - - protected Decoder(Charset cs) { - super(cs); - jis0201 = new JIS_X_0201_OLD.Decoder(cs); - } - - protected char decodeSingle(int b) { - // If the high bits are all off, it's ASCII == Unicode - if ((b & 0xFF80) == 0) { - return (char)b; - } - return jis0201.decode(b); - } - - protected char decodeDouble(int c1, int c2) { - int adjust = c2 < 0x9F ? 1 : 0; - int rowOffset = c1 < 0xA0 ? 0x70 : 0xB0; - int cellOffset = (adjust == 1) ? (c2 > 0x7F ? 0x20 : 0x1F) : 0x7E; - int b1 = ((c1 - rowOffset) << 1) - adjust; - int b2 = c2 - cellOffset; - return super.decodeDouble(b1, b2); - } - - // Make some protected methods public for use by JISAutoDetect - public CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) { - return super.decodeLoop(src, dst); - } - public void implReset() { - super.implReset(); - } - public CoderResult implFlush(CharBuffer out) { - return super.implFlush(out); - } - } - - static class Encoder extends JIS_X_0208_Encoder { - - private JIS_X_0201_OLD.Encoder jis0201; - - private static final short[] j0208Index1 = - JIS_X_0208_Encoder.getIndex1(); - private static final String[] j0208Index2 = - JIS_X_0208_Encoder.getIndex2(); - - protected Encoder(Charset cs) { - super(cs); - jis0201 = new JIS_X_0201_OLD.Encoder(cs); - } - - protected int encodeSingle(char inputChar) { - byte b; - - // \u0000 - \u007F map straight through - if ((inputChar & 0xFF80) == 0) - return (byte)inputChar; - - if ((b = jis0201.encode(inputChar)) == 0) - return -1; - else - return b; - } - - protected int encodeDouble(char ch) { - int offset = j0208Index1[ch >> 8] << 8; - int pos = j0208Index2[offset >> 12].charAt((offset & 0xfff) + (ch & 0xff)); - if (pos == 0) { - /* Zero value indicates this Unicode has no mapping to - * JIS0208. - * We bail here because the JIS -> SJIS algorithm produces - * bogus SJIS values for invalid JIS input. Zero should be - * the only invalid JIS value in our table. - */ - return 0; - } - /* - * This algorithm for converting from JIS to SJIS comes from - * Ken Lunde's "Understanding Japanese Information Processing", - * pg 163. - */ - int c1 = (pos >> 8) & 0xff; - int c2 = pos & 0xff; - int rowOffset = c1 < 0x5F ? 0x70 : 0xB0; - int cellOffset = (c1 % 2 == 1) ? (c2 > 0x5F ? 0x20 : 0x1F) : 0x7E; - return ((((c1 + 1 ) >> 1) + rowOffset) << 8) | (c2 + cellOffset); - } - } -} diff --git a/test/jdk/sun/nio/cs/OLD/SimpleEUCDecoder.java b/test/jdk/sun/nio/cs/OLD/SimpleEUCDecoder.java deleted file mode 100644 index ee9e267e6cf29..0000000000000 --- a/test/jdk/sun/nio/cs/OLD/SimpleEUCDecoder.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2003, 2006, 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. - */ - -/* - */ - -/** - * Simple EUC-like decoder used by IBM01383 and IBM970 - * supports G1 - no support for G2 or G3 - */ - - -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CoderResult; - -abstract class SimpleEUCDecoder - extends CharsetDecoder -{ - private final int SS2 = 0x8E; - private final int SS3 = 0x8F; - - protected static String mappingTableG1; - protected static String byteToCharTable; - - protected SimpleEUCDecoder(Charset cs) { - super(cs, 0.5f, 1.0f); - } - - private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) { - byte[] sa = src.array(); - int sp = src.arrayOffset() + src.position(); - int sl = src.arrayOffset() + src.limit(); - assert (sp <= sl); - sp = (sp <= sl ? sp : sl); - char[] da = dst.array(); - int dp = dst.arrayOffset() + dst.position(); - int dl = dst.arrayOffset() + dst.limit(); - assert (dp <= dl); - dp = (dp <= dl ? dp : dl); - - try { - while (sp < sl) { - int byte1, byte2; - int inputSize = 1; - char outputChar = '\uFFFD'; - - byte1 = sa[sp] & 0xff; - - if ( byte1 <= 0x9f ) { // < 0x9f has its own table (G0) - if (byte1 == SS2 || byte1 == SS3 ) { - // No support provided for G2/G3 at this time. - return CoderResult.malformedForLength(1); - } - outputChar = byteToCharTable.charAt(byte1); - } else if (byte1 < 0xa1 || byte1 > 0xfe) { // invalid range? - return CoderResult.malformedForLength(1); - } else { // (G1) - if (sl - sp < 2) { - return CoderResult.UNDERFLOW; - } - byte2 = sa[sp + 1] & 0xff; - inputSize++; - if ( byte2 < 0xa1 || byte2 > 0xfe) { - return CoderResult.malformedForLength(2); - } - outputChar = mappingTableG1.charAt(((byte1 - 0xa1) * 94) + byte2 - 0xa1); - } - if (outputChar == '\uFFFD') { - return CoderResult.unmappableForLength(inputSize); - } - if (dl - dp < 1) - return CoderResult.OVERFLOW; - da[dp++] = outputChar; - sp += inputSize; - } - return CoderResult.UNDERFLOW; - } finally { - src.position(sp - src.arrayOffset()); - dst.position(dp - dst.arrayOffset()); - } - } - - private CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) { - int mark = src.position(); - - try { - while (src.hasRemaining()) { - char outputChar = '\uFFFD'; - int inputSize = 1; - int byte1, byte2; - - byte1 = src.get() & 0xff; - if ( byte1 <= 0x9f ) { - if (byte1 == SS2 || byte1 == SS3 ) { - return CoderResult.malformedForLength(1); - } - outputChar = byteToCharTable.charAt(byte1); - } else if (byte1 < 0xa1 || byte1 > 0xfe) { - return CoderResult.malformedForLength(1); - } else { - if (!src.hasRemaining()) { - return CoderResult.UNDERFLOW; - } - byte2 = src.get() & 0xff; - inputSize++; - if ( byte2 < 0xa1 || byte2 > 0xfe) { - return CoderResult.malformedForLength(2); - } - outputChar = mappingTableG1.charAt(((byte1 - 0xa1) * 94) + byte2 - 0xa1); - } - if (outputChar == '\uFFFD') { - return CoderResult.unmappableForLength(inputSize); - } - if (!dst.hasRemaining()) - return CoderResult.OVERFLOW; - dst.put(outputChar); - mark += inputSize; - } - return CoderResult.UNDERFLOW; - } finally { - src.position(mark); - } - } - - protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) { - if (src.hasArray() && dst.hasArray()) - return decodeArrayLoop(src, dst); - else - return decodeBufferLoop(src, dst); - } -} diff --git a/test/jdk/sun/nio/cs/OLD/SingleByteDecoder.java b/test/jdk/sun/nio/cs/OLD/SingleByteDecoder.java deleted file mode 100644 index b3d1972bf589c..0000000000000 --- a/test/jdk/sun/nio/cs/OLD/SingleByteDecoder.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2000, 2012, 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. - */ - -/* - */ - - -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.MalformedInputException; -import java.nio.charset.UnmappableCharacterException; - - -public abstract class SingleByteDecoder - extends CharsetDecoder -{ - - private final String byteToCharTable; - - protected SingleByteDecoder(Charset cs, String byteToCharTable) { - super(cs, 1.0f, 1.0f); - this.byteToCharTable = byteToCharTable; - } - - private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) { - byte[] sa = src.array(); - int sp = src.arrayOffset() + src.position(); - int sl = src.arrayOffset() + src.limit(); - assert (sp <= sl); - sp = (sp <= sl ? sp : sl); - char[] da = dst.array(); - int dp = dst.arrayOffset() + dst.position(); - int dl = dst.arrayOffset() + dst.limit(); - assert (dp <= dl); - dp = (dp <= dl ? dp : dl); - - try { - while (sp < sl) { - int b = sa[sp]; - - char c = decode(b); - if (c == '\uFFFD') - return CoderResult.unmappableForLength(1); - if (dl - dp < 1) - return CoderResult.OVERFLOW; - da[dp++] = c; - sp++; - } - return CoderResult.UNDERFLOW; - } finally { - src.position(sp - src.arrayOffset()); - dst.position(dp - dst.arrayOffset()); - } - } - - private CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) { - int mark = src.position(); - try { - while (src.hasRemaining()) { - int b = src.get(); - - char c = decode(b); - if (c == '\uFFFD') - return CoderResult.unmappableForLength(1); - if (!dst.hasRemaining()) - return CoderResult.OVERFLOW; - mark++; - dst.put(c); - } - return CoderResult.UNDERFLOW; - } finally { - src.position(mark); - } - } - - protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) { - if (true && src.hasArray() && dst.hasArray()) - return decodeArrayLoop(src, dst); - else - return decodeBufferLoop(src, dst); - } - - public char decode(int byteIndex) { - int n = byteIndex + 128; - if (n >= byteToCharTable.length() || n < 0) - return '\uFFFD'; - return byteToCharTable.charAt(n); - } -} diff --git a/test/jdk/sun/nio/cs/OLD/SingleByteEncoder.java b/test/jdk/sun/nio/cs/OLD/SingleByteEncoder.java deleted file mode 100644 index fb488297367a3..0000000000000 --- a/test/jdk/sun/nio/cs/OLD/SingleByteEncoder.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2000, 2012, 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. - */ - -/* - */ - - -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.MalformedInputException; -import java.nio.charset.UnmappableCharacterException; -import sun.nio.cs.Surrogate; - - -public abstract class SingleByteEncoder - extends CharsetEncoder -{ - - private final short index1[]; - private final String index2; - private final int mask1; - private final int mask2; - private final int shift; - - private final Surrogate.Parser sgp = new Surrogate.Parser(); - - protected SingleByteEncoder(Charset cs, - short[] index1, String index2, - int mask1, int mask2, int shift) - { - super(cs, 1.0f, 1.0f); - this.index1 = index1; - this.index2 = index2; - this.mask1 = mask1; - this.mask2 = mask2; - this.shift = shift; - } - - public boolean canEncode(char c) { - char testEncode = index2.charAt(index1[(c & mask1) >> shift] - + (c & mask2)); - return testEncode != '\u0000' || c == '\u0000'; - } - - private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { - char[] sa = src.array(); - int sp = src.arrayOffset() + src.position(); - int sl = src.arrayOffset() + src.limit(); - assert (sp <= sl); - sp = (sp <= sl ? sp : sl); - byte[] da = dst.array(); - int dp = dst.arrayOffset() + dst.position(); - int dl = dst.arrayOffset() + dst.limit(); - assert (dp <= dl); - dp = (dp <= dl ? dp : dl); - - try { - while (sp < sl) { - char c = sa[sp]; - if (Character.isSurrogate(c)) { - if (sgp.parse(c, sa, sp, sl) < 0) - return sgp.error(); - return sgp.unmappableResult(); - } - if (c >= '\uFFFE') - return CoderResult.unmappableForLength(1); - if (dl - dp < 1) - return CoderResult.OVERFLOW; - - char e = index2.charAt(index1[(c & mask1) >> shift] - + (c & mask2)); - - // If output byte is zero because input char is zero - // then character is mappable, o.w. fail - if (e == '\u0000' && c != '\u0000') - return CoderResult.unmappableForLength(1); - - sp++; - da[dp++] = (byte)e; - } - return CoderResult.UNDERFLOW; - } finally { - src.position(sp - src.arrayOffset()); - dst.position(dp - dst.arrayOffset()); - } - } - - private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) { - int mark = src.position(); - try { - while (src.hasRemaining()) { - char c = src.get(); - if (Character.isSurrogate(c)) { - if (sgp.parse(c, src) < 0) - return sgp.error(); - return sgp.unmappableResult(); - } - if (c >= '\uFFFE') - return CoderResult.unmappableForLength(1); - if (!dst.hasRemaining()) - return CoderResult.OVERFLOW; - - char e = index2.charAt(index1[(c & mask1) >> shift] - + (c & mask2)); - - // If output byte is zero because input char is zero - // then character is mappable, o.w. fail - if (e == '\u0000' && c != '\u0000') - return CoderResult.unmappableForLength(1); - - mark++; - dst.put((byte)e); - } - return CoderResult.UNDERFLOW; - } finally { - src.position(mark); - } - } - - protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) { - if (true && src.hasArray() && dst.hasArray()) - return encodeArrayLoop(src, dst); - else - return encodeBufferLoop(src, dst); - } - - public byte encode(char inputChar) { - return (byte)index2.charAt(index1[(inputChar & mask1) >> shift] + - (inputChar & mask2)); - } -} diff --git a/test/jdk/sun/nio/cs/OLD/TestIBMDB.java b/test/jdk/sun/nio/cs/OLD/TestIBMDB.java deleted file mode 100644 index f2e3cbcee7927..0000000000000 --- a/test/jdk/sun/nio/cs/OLD/TestIBMDB.java +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 6843578 - * @summary Test old and new implementation of db charsets - * @build IBM930_OLD IBM933_OLD IBM935_OLD IBM937_OLD IBM939_OLD IBM942_OLD IBM943_OLD IBM948_OLD IBM949_OLD IBM950_OLD IBM970_OLD IBM942C_OLD IBM943C_OLD IBM949C_OLD IBM1381_OLD IBM1383_OLD EUC_CN_OLD EUC_KR_OLD GBK_OLD Johab_OLD MS932_OLD MS936_OLD MS949_OLD MS950_OLD SJIS_OLD PCK_OLD EUC_JP_OLD EUC_JP_LINUX_OLD EUC_JP_Open_OLD - * @modules java.base/sun.nio.cs jdk.charsets/sun.nio.cs.ext - * @run main TestIBMDB - */ - -import java.nio.charset.*; -import java.nio.*; -import java.util.*; - -public class TestIBMDB { - static class Time { - long t; - } - static int iteration = 200; - - static char[] decode(byte[] bb, Charset cs, boolean testDirect, Time t) - throws Exception { - String csn = cs.name(); - CharsetDecoder dec = cs.newDecoder(); - ByteBuffer bbf; - CharBuffer cbf; - if (testDirect) { - bbf = ByteBuffer.allocateDirect(bb.length); - cbf = ByteBuffer.allocateDirect(bb.length*2).asCharBuffer(); - bbf.put(bb); - } else { - bbf = ByteBuffer.wrap(bb); - cbf = CharBuffer.allocate(bb.length); - } - CoderResult cr = null; - long t1 = System.nanoTime()/1000; - for (int i = 0; i < iteration; i++) { - bbf.rewind(); - cbf.clear(); - dec.reset(); - cr = dec.decode(bbf, cbf, true); - } - long t2 = System.nanoTime()/1000; - t.t = (t2 - t1)/iteration; - if (cr != CoderResult.UNDERFLOW) { - System.out.println("DEC-----------------"); - int pos = bbf.position(); - System.out.printf(" cr=%s, bbf.pos=%d, bb[pos]=%x,%x,%x,%x%n", - cr.toString(), pos, - bb[pos++]&0xff, bb[pos++]&0xff,bb[pos++]&0xff, bb[pos++]&0xff); - throw new RuntimeException("Decoding err: " + csn); - } - char[] cc = new char[cbf.position()]; - cbf.flip(); cbf.get(cc); - return cc; - - } - - static CoderResult decodeCR(byte[] bb, Charset cs, boolean testDirect) - throws Exception { - CharsetDecoder dec = cs.newDecoder(); - ByteBuffer bbf; - CharBuffer cbf; - if (testDirect) { - bbf = ByteBuffer.allocateDirect(bb.length); - cbf = ByteBuffer.allocateDirect(bb.length*2).asCharBuffer(); - bbf.put(bb).flip(); - } else { - bbf = ByteBuffer.wrap(bb); - cbf = CharBuffer.allocate(bb.length); - } - CoderResult cr = null; - for (int i = 0; i < iteration; i++) { - bbf.rewind(); - cbf.clear(); - dec.reset(); - cr = dec.decode(bbf, cbf, true); - } - return cr; - } - - static byte[] encode(char[] cc, Charset cs, boolean testDirect, Time t) - throws Exception { - ByteBuffer bbf; - CharBuffer cbf; - CharsetEncoder enc = cs.newEncoder(); - String csn = cs.name(); - if (testDirect) { - bbf = ByteBuffer.allocateDirect(cc.length * 4); - cbf = ByteBuffer.allocateDirect(cc.length * 2).asCharBuffer(); - cbf.put(cc).flip(); - } else { - bbf = ByteBuffer.allocate(cc.length * 4); - cbf = CharBuffer.wrap(cc); - } - CoderResult cr = null; - long t1 = System.nanoTime()/1000; - for (int i = 0; i < iteration; i++) { - cbf.rewind(); - bbf.clear(); - enc.reset(); - cr = enc.encode(cbf, bbf, true); - } - long t2 = System.nanoTime()/1000; - t.t = (t2 - t1)/iteration; - if (cr != CoderResult.UNDERFLOW) { - System.out.println("ENC-----------------"); - int pos = cbf.position(); - System.out.printf(" cr=%s, cbf.pos=%d, cc[pos]=%x%n", - cr.toString(), pos, cc[pos]&0xffff); - throw new RuntimeException("Encoding err: " + csn); - } - byte[] bb = new byte[bbf.position()]; - bbf.flip(); bbf.get(bb); - return bb; - } - - static CoderResult encodeCR(char[] cc, Charset cs, boolean testDirect) - throws Exception { - ByteBuffer bbf; - CharBuffer cbf; - CharsetEncoder enc = cs.newEncoder(); - if (testDirect) { - bbf = ByteBuffer.allocateDirect(cc.length * 4); - cbf = ByteBuffer.allocateDirect(cc.length * 2).asCharBuffer(); - cbf.put(cc).flip(); - } else { - bbf = ByteBuffer.allocate(cc.length * 4); - cbf = CharBuffer.wrap(cc); - } - CoderResult cr = null; - for (int i = 0; i < iteration; i++) { - cbf.rewind(); - bbf.clear(); - enc.reset(); - cr = enc.encode(cbf, bbf, true); - } - return cr; - } - - static void printEntry(char c, Charset cs) { - byte[] bb = new String(new char[] {c}).getBytes(cs); - for (byte b:bb) - System.out.printf("%x", b&0xff); - System.out.printf(" %x", c & 0xffff); - String s2 = new String(bb, cs); - System.out.printf(" %x%n", s2.charAt(0) & 0xffff); - } - - // check and compare canEncoding/Encoding - static char[] checkEncoding(Charset oldCS, Charset newCS) - throws Exception { - System.out.printf("Encoding <%s> <%s>...%n", oldCS.name(), newCS.name()); - CharsetEncoder encOLD = oldCS.newEncoder(); - CharsetEncoder encNew = newCS.newEncoder(); - char[] cc = new char[0x10000]; - int pos = 0; - boolean is970 = "x-IBM970-Old".equals(oldCS.name()); - - for (char c = 0; c < 0xffff; c++) { - boolean canOld = encOLD.canEncode(c); - boolean canNew = encNew.canEncode(c); - - if (is970 && c == 0x2299) - continue; - - if (canOld != canNew) { - if (canNew) { - System.out.printf(" NEW(only): "); - printEntry(c, newCS); - } else { - if (is970) { - byte[] bb = new String(new char[] {c}).getBytes(oldCS); - if (bb.length == 2 && bb[0] == (byte)0xa2 && bb[1] == (byte)0xc1) { - // we know 970 has bogus nnnn -> a2c1 -> 2299 - continue; - } - } - System.out.printf(" OLD(only): "); - printEntry(c, oldCS); - } - } else if (canNew) { - byte[] bbNew = new String(new char[] {c}).getBytes(newCS); - byte[] bbOld = new String(new char[] {c}).getBytes(oldCS); - if (!Arrays.equals(bbNew, bbOld)) { - System.out.printf(" c->b NEW: "); - printEntry(c, newCS); - System.out.printf(" c->b OLD: "); - printEntry(c, oldCS); - } else { - String sNew = new String(bbNew, newCS); - String sOld = new String(bbOld, oldCS); - if (!sNew.equals(sOld)) { - System.out.printf(" b2c NEW (c=%x):", c&0xffff); - printEntry(sNew.charAt(0), newCS); - System.out.printf(" b2c OLD:"); - printEntry(sOld.charAt(0), oldCS); - } - } - } - if (canNew & canOld) { // added only both for now - cc[pos++] = c; - } - } - return Arrays.copyOf(cc, pos); - } - - - // check and compare canEncoding/Encoding - static void checkDecoding(Charset oldCS, Charset newCS) - throws Exception - { - System.out.printf("Decoding <%s> <%s>...%n", oldCS.name(), newCS.name()); - boolean isEBCDIC = oldCS.name().startsWith("x-IBM93"); - - //Try singlebyte first - byte[] bb = new byte[1]; - System.out.printf(" trying SB...%n"); - for (int b = 0; b < 0x100; b++) { - bb[0] = (byte)b; - String sOld = new String(bb, oldCS); - String sNew = new String(bb, newCS); - if (!sOld.equals(sNew)) { - System.out.printf(" b=%x: %x/%d(old) %x/%d(new)%n", - b& 0xff, - sOld.charAt(0) & 0xffff, sOld.length(), - sNew.charAt(0) & 0xffff, sNew.length()); - } - } - - System.out.printf(" trying DB...%n"); - bb = new byte[isEBCDIC?4:2]; - int b1Min = 0x40; - int b1Max = 0xfe; - for (int b1 = 0x40; b1 < 0xff; b1++) { - if (!isEBCDIC) { - // decodable singlebyte b1 - bb[0] = (byte)b1; - String sOld = new String(bb, oldCS); - String sNew = new String(bb, newCS); - if (!sOld.equals(sNew)) { - if (sOld.length() != 2 && sOld.charAt(0) != 0) { - // only prints we are NOT expected. above two are known issue - System.out.printf(" b1=%x: %x/%d(old) %x/%d(new)%n", - b1 & 0xff, - sOld.charAt(0) & 0xffff, sOld.length(), - sNew.charAt(0) & 0xffff, sNew.length()); - continue; - } - } - } - for (int b2 = 0x40; b2 < 0xff; b2++) { - if (isEBCDIC) { - bb[0] = 0x0e; - bb[1] = (byte)b1; - bb[2] = (byte)b2; - bb[3] = 0x0f; - } else { - bb[0] = (byte)b1; - bb[1] = (byte)b2; - } - String sOld = new String(bb, oldCS); - String sNew = new String(bb, newCS); - //if (!sOld.equals(sNew)) { - if (sOld.charAt(0) != sNew.charAt(0)) { - -if (sOld.charAt(0) == 0 && sNew.charAt(0) == 0xfffd) - continue; // known issude in old implementation - - System.out.printf(" bb=<%x,%x> c(old)=%x, c(new)=%x%n", - b1, b2, sOld.charAt(0) & 0xffff, sNew.charAt(0) & 0xffff); - } - } - } - } - - static void checkInit(String csn) throws Exception { - System.out.printf("Check init <%s>...%n", csn); - Charset.forName("Big5"); // load in the ExtendedCharsets - long t1 = System.nanoTime()/1000; - Charset cs = Charset.forName(csn); - long t2 = System.nanoTime()/1000; - System.out.printf(" charset :%d%n", t2 - t1); - t1 = System.nanoTime()/1000; - cs.newDecoder(); - t2 = System.nanoTime()/1000; - System.out.printf(" new Decoder :%d%n", t2 - t1); - - t1 = System.nanoTime()/1000; - cs.newEncoder(); - t2 = System.nanoTime()/1000; - System.out.printf(" new Encoder :%d%n", t2 - t1); - } - - static void compare(Charset cs1, Charset cs2, char[] cc) throws Exception { - System.gc(); // enqueue finalizable objects - Thread.sleep(1000); - System.gc(); // enqueue finalizable objects - - String csn1 = cs1.name(); - String csn2 = cs2.name(); - System.out.printf("Diff <%s> <%s>...%n", csn1, csn2); - - Time t1 = new Time(); - Time t2 = new Time(); - - byte[] bb1 = encode(cc, cs1, false, t1); - byte[] bb2 = encode(cc, cs2, false, t2); - - System.out.printf(" Encoding TimeRatio %s/%s: %d,%d :%f%n", - csn2, csn1, - t2.t, t1.t, - (double)(t2.t)/(t1.t)); - if (!Arrays.equals(bb1, bb2)) { - System.out.printf(" encoding failed%n"); - } - - char[] cc2 = decode(bb1, cs2, false, t2); - char[] cc1 = decode(bb1, cs1, false, t1); - System.out.printf(" Decoding TimeRatio %s/%s: %d,%d :%f%n", - csn2, csn1, - t2.t, t1.t, - (double)(t2.t)/(t1.t)); - if (!Arrays.equals(cc1, cc2)) { - System.out.printf(" decoding failed%n"); - } - - bb1 = encode(cc, cs1, true, t1); - bb2 = encode(cc, cs2, true, t2); - - System.out.printf(" Encoding(dir) TimeRatio %s/%s: %d,%d :%f%n", - csn2, csn1, - t2.t, t1.t, - (double)(t2.t)/(t1.t)); - - if (!Arrays.equals(bb1, bb2)) - System.out.printf(" encoding (direct) failed%n"); - - cc1 = decode(bb1, cs1, true, t1); - cc2 = decode(bb1, cs2, true, t2); - System.out.printf(" Decoding(dir) TimeRatio %s/%s: %d,%d :%f%n", - csn2, csn1, - t2.t, t1.t, - (double)(t2.t)/(t1.t)); - if (!Arrays.equals(cc1, cc2)) { - System.out.printf(" decoding (direct) failed%n"); - } - } - - /* The first byte is the length of malformed bytes - byte[][] malformed = { - {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0x80, (byte)0xC0 }, - }; - */ - - static void checkMalformed(Charset cs, byte[][] malformed) - throws Exception - { - boolean failed = false; - String csn = cs.name(); - System.out.printf("Check malformed <%s>...%n", csn); - for (boolean direct: new boolean[] {false, true}) { - for (byte[] bins : malformed) { - int mlen = bins[0]; - byte[] bin = Arrays.copyOfRange(bins, 1, bins.length); - CoderResult cr = decodeCR(bin, cs, direct); - String ashex = ""; - for (int i = 0; i < bin.length; i++) { - if (i > 0) ashex += " "; - ashex += Integer.toString((int)bin[i] & 0xff, 16); - } - if (!cr.isMalformed()) { - System.out.printf(" FAIL(direct=%b): [%s] not malformed. -->cr=%s\n", direct, ashex, cr.toString()); - failed = true; - } else if (cr.length() != mlen) { - System.out.printf(" FAIL(direct=%b): [%s] malformed[len=%d].\n", direct, ashex, cr.length()); - failed = true; - } - } - } - if (failed) - throw new RuntimeException("Check malformed failed " + csn); - } - - static boolean check(CharsetDecoder dec, byte[] bytes, boolean direct, int[] flow) { - int inPos = flow[0]; - int inLen = flow[1]; - int outPos = flow[2]; - int outLen = flow[3]; - int expedInPos = flow[4]; - int expedOutPos = flow[5]; - CoderResult expedCR = (flow[6]==0)?CoderResult.UNDERFLOW - :CoderResult.OVERFLOW; - ByteBuffer bbf; - CharBuffer cbf; - if (direct) { - bbf = ByteBuffer.allocateDirect(inPos + bytes.length); - cbf = ByteBuffer.allocateDirect((outPos + outLen)*2).asCharBuffer(); - } else { - bbf = ByteBuffer.allocate(inPos + bytes.length); - cbf = CharBuffer.allocate(outPos + outLen); - } - bbf.position(inPos); - bbf.put(bytes).flip().position(inPos).limit(inPos + inLen); - cbf.position(outPos); - dec.reset(); - CoderResult cr = dec.decode(bbf, cbf, false); - if (cr != expedCR || - bbf.position() != expedInPos || - cbf.position() != expedOutPos) { - System.out.printf("Expected(direct=%5b): [", direct); - for (int i:flow) System.out.print(" " + i); - System.out.println("] CR=" + cr + - ", inPos=" + bbf.position() + - ", outPos=" + cbf.position()); - return false; - } - return true; - } - - static void checkUnderOverflow(Charset cs) throws Exception { - String csn = cs.name(); - System.out.printf("Check under/overflow <%s>...%n", csn); - CharsetDecoder dec = cs.newDecoder(); - boolean failed = false; - - //7f, a1a1, 8ea2a1a1, 8ea3a1a1, 8ea7a1a1 - //0 1 2 3 7 11 - byte[] bytes = new String("\u007f\u3000\u4e42\u4e28\ud840\udc55").getBytes("EUC_TW"); - int inlen = bytes.length; - - int MAXOFF = 20; - for (int inoff = 0; inoff < MAXOFF; inoff++) { - for (int outoff = 0; outoff < MAXOFF; outoff++) { - int[][] Flows = { - //inpos, inLen, outPos, outLen, inPosEP, outposEP, under(0)/over(1) - //overflow - {inoff, inlen, outoff, 1, inoff + 1, outoff + 1, 1}, - {inoff, inlen, outoff, 2, inoff + 3, outoff + 2, 1}, - {inoff, inlen, outoff, 3, inoff + 7, outoff + 3, 1}, - {inoff, inlen, outoff, 4, inoff + 11, outoff + 4, 1}, - {inoff, inlen, outoff, 5, inoff + 11, outoff + 4, 1}, - {inoff, inlen, outoff, 6, inoff + 15, outoff + 6, 0}, - //underflow - {inoff, 1, outoff, 6, inoff + 1, outoff + 1, 0}, - {inoff, 2, outoff, 6, inoff + 1, outoff + 1, 0}, - {inoff, 3, outoff, 6, inoff + 3, outoff + 2, 0}, - {inoff, 4, outoff, 6, inoff + 3, outoff + 2, 0}, - {inoff, 5, outoff, 6, inoff + 3, outoff + 2, 0}, - {inoff, 8, outoff, 6, inoff + 7, outoff + 3, 0}, - {inoff, 9, outoff, 6, inoff + 7, outoff + 3, 0}, - {inoff, 10, outoff, 6, inoff + 7, outoff + 3, 0}, - {inoff, 11, outoff, 6, inoff +11, outoff + 4, 0}, - {inoff, 12, outoff, 6, inoff +11, outoff + 4, 0}, - {inoff, 15, outoff, 6, inoff +15, outoff + 6, 0}, - // 2-byte under/overflow - {inoff, 2, outoff, 1, inoff + 1, outoff + 1, 0}, - {inoff, 3, outoff, 1, inoff + 1, outoff + 1, 1}, - {inoff, 3, outoff, 2, inoff + 3, outoff + 2, 0}, - }; - for (boolean direct: new boolean[] {false, true}) { - for (int[] flow: Flows) { - if (!check(dec, bytes, direct, flow)) - failed = true; - } - }}} - if (failed) - throw new RuntimeException("Check under/overflow failed " + csn); - } - - static String[] csnames = new String[] { - - "IBM930", - "IBM933", - "IBM935", - "IBM937", - "IBM939", - "IBM942", - "IBM943", - "IBM948", - "IBM949", - "IBM950", - "IBM970", - "IBM942C", - "IBM943C", - "IBM949C", - "IBM1381", - "IBM1383", - - "EUC_CN", - "EUC_KR", - "GBK", - "Johab", - "MS932", - "MS936", - "MS949", - "MS950", - - "EUC_JP", - "EUC_JP_LINUX", - "EUC_JP_Open", - "SJIS", - "PCK", - }; - - public static void main(String[] args) throws Exception { - for (String csname: csnames) { - System.out.printf("-----------------------------------%n"); - String oldname = csname + "_OLD"; - if ("EUC_JP_Open".equals(csname)) - csname = "eucjp-open"; - checkInit(csname); - Charset csOld = (Charset)Class.forName(oldname).newInstance(); - Charset csNew = Charset.forName(csname); - char[] cc = checkEncoding(csOld, csNew); - checkDecoding(csOld, csNew); - compare(csNew, csOld, cc); - - if (csname.startsWith("x-IBM93")) { - //ecdbic - checkMalformed(csNew, new byte[][] { - {1, 0x26, 0x0f, 0x27}, // in SBSC, no SI - {1, 0x0e, 0x41, 0x41, 0xe}, // in DBSC, no SO - {2, 0x0e, 0x40, 0x41, 0xe}, // illegal DB - }); - } else if (csname.equals("x-IBM970") || - csname.equals("x-IBM1383")) { - //euc_simple - checkMalformed(csNew, new byte[][] { - {1, 0x26, (byte)0x8f, 0x27}, // SS2 - {1, (byte)0xa1, (byte)0xa1, (byte)0x8e, 0x51}, // SS3 - }); - } - } - } -} diff --git a/test/jdk/sun/nio/cs/TestEUC_TW.java b/test/jdk/sun/nio/cs/TestEUC_TW.java index 4453a2cbead02..ef663bbb30910 100644 --- a/test/jdk/sun/nio/cs/TestEUC_TW.java +++ b/test/jdk/sun/nio/cs/TestEUC_TW.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 6831794 6229811 + * @bug 6831794 6229811 8343157 * @summary Test EUC_TW charset * @modules java.base/sun.nio.cs */ @@ -131,25 +131,7 @@ static byte[] encode(char[] cc, Charset cs, boolean testDirect, Time t) return bb; } - static CoderResult encodeCR(char[] cc, Charset cs, boolean testDirect) - throws Exception { - ByteBuffer bbf; - CharBuffer cbf; - CharsetEncoder enc = cs.newEncoder(); - if (testDirect) { - bbf = ByteBuffer.allocateDirect(cc.length * 4); - cbf = ByteBuffer.allocateDirect(cc.length * 2).asCharBuffer(); - cbf.put(cc).flip(); - } else { - bbf = ByteBuffer.allocate(cc.length * 4); - cbf = CharBuffer.wrap(cc); - } - return enc.encode(cbf, bbf, true); - } - static char[] getEUC_TWChars(boolean skipNR) { - //CharsetEncoder encOLD = Charset.forName("EUC_TW_OLD").newEncoder(); - CharsetEncoder encOLD = new EUC_TW_OLD().newEncoder(); CharsetEncoder enc = Charset.forName("EUC_TW").newEncoder(); char[] cc = new char[0x20000]; char[] c2 = new char[2]; @@ -160,12 +142,6 @@ static char[] getEUC_TWChars(boolean skipNR) { //SKIP these 3 NR codepoints if compared to EUC_TW if (skipNR && (i == 0x4ea0 || i == 0x51ab || i == 0x52f9)) continue; - if (encOLD.canEncode((char)i) != enc.canEncode((char)i)) { - System.out.printf(" Err i=%x: old=%b new=%b%n", i, - encOLD.canEncode((char)i), - enc.canEncode((char)i)); - throw new RuntimeException("canEncode() err!"); - } if (enc.canEncode((char)i)) { cc[pos++] = (char)i; @@ -178,10 +154,6 @@ static char[] getEUC_TWChars(boolean skipNR) { Character.toChars(i, c2, 0); cb.clear();cb.put(c2[0]);cb.put(c2[1]);cb.flip(); - if (encOLD.canEncode(cb) != enc.canEncode(cb)) { - throw new RuntimeException("canEncode() err!"); - } - if (enc.canEncode(cb)) { //System.out.printf("cp=%x, (%x, %x) %n", i, c2[0] & 0xffff, c2[1] & 0xffff); cc[pos++] = c2[0]; @@ -227,91 +199,6 @@ static void checkInit(String csn) throws Exception { System.out.printf(" new Encoder :%d%n", t2 - t1); } - static void compare(Charset cs1, Charset cs2) throws Exception { - char[] cc = getEUC_TWChars(true); - - String csn1 = cs1.name(); - String csn2 = cs2.name(); - System.out.printf("Diff <%s> <%s>...%n", csn1, csn2); - - Time t1 = new Time(); - Time t2 = new Time(); - - byte[] bb1 = encode(cc, cs1, false, t1); - byte[] bb2 = encode(cc, cs2, false, t2); - - System.out.printf(" Encoding TimeRatio %s/%s: %d,%d :%f%n", - csn2, csn1, - t2.t, t1.t, - (double)(t2.t)/(t1.t)); - if (!Arrays.equals(bb1, bb2)) { - System.out.printf(" encoding failed%n"); - } - - char[] cc2 = decode(bb1, cs2, false, t2); - char[] cc1 = decode(bb1, cs1, false, t1); - System.out.printf(" Decoding TimeRatio %s/%s: %d,%d :%f%n", - csn2, csn1, - t2.t, t1.t, - (double)(t2.t)/(t1.t)); - if (!Arrays.equals(cc1, cc2)) { - System.out.printf(" decoding failed%n"); - } - - bb1 = encode(cc, cs1, true, t1); - bb2 = encode(cc, cs2, true, t2); - - System.out.printf(" Encoding(dir) TimeRatio %s/%s: %d,%d :%f%n", - csn2, csn1, - t2.t, t1.t, - (double)(t2.t)/(t1.t)); - - if (!Arrays.equals(bb1, bb2)) - System.out.printf(" encoding (direct) failed%n"); - - cc1 = decode(bb1, cs1, true, t1); - cc2 = decode(bb1, cs2, true, t2); - System.out.printf(" Decoding(dir) TimeRatio %s/%s: %d,%d :%f%n", - csn2, csn1, - t2.t, t1.t, - (double)(t2.t)/(t1.t)); - if (!Arrays.equals(cc1, cc2)) { - System.out.printf(" decoding (direct) failed%n"); - } - } - - // The first byte is the length of malformed bytes - static byte[][] malformed = { - //{5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0x80, (byte)0xC0 }, - }; - - static void checkMalformed(Charset cs) throws Exception { - boolean failed = false; - String csn = cs.name(); - System.out.printf("Check malformed <%s>...%n", csn); - for (boolean direct: new boolean[] {false, true}) { - for (byte[] bins : malformed) { - int mlen = bins[0]; - byte[] bin = Arrays.copyOfRange(bins, 1, bins.length); - CoderResult cr = decodeCR(bin, cs, direct); - String ashex = ""; - for (int i = 0; i < bin.length; i++) { - if (i > 0) ashex += " "; - ashex += Integer.toBinaryString((int)bin[i] & 0xff); - } - if (!cr.isMalformed()) { - System.out.printf(" FAIL(direct=%b): [%s] not malformed.\n", direct, ashex); - failed = true; - } else if (cr.length() != mlen) { - System.out.printf(" FAIL(direct=%b): [%s] malformed[len=%d].\n", direct, ashex, cr.length()); - failed = true; - } - } - } - if (failed) - throw new RuntimeException("Check malformed failed " + csn); - } - static boolean check(CharsetDecoder dec, byte[] bytes, boolean direct, int[] flow) { int inPos = flow[0]; int inLen = flow[1]; @@ -419,12 +306,9 @@ static void checkUnderOverflow(Charset cs) throws Exception { public static void main(String[] args) throws Exception { // be the first one - //checkInit("EUC_TW_OLD"); checkInit("EUC_TW"); Charset euctw = Charset.forName("EUC_TW"); checkRoundtrip(euctw); - compare(euctw, new EUC_TW_OLD()); - checkMalformed(euctw); checkUnderOverflow(euctw); } } From 43b194741cc307a73bd8dd2da877ab1b16250fc1 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Mon, 14 Apr 2025 16:22:07 +0000 Subject: [PATCH 0570/1101] 8344883: Force clients to explicitly pass mem_tag value, even if it is mtNone Co-authored-by: Stefan Karlsson Reviewed-by: stefank, jsjolen --- .../cpu/aarch64/compressedKlass_aarch64.cpp | 4 +-- .../bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp | 2 +- src/hotspot/os/linux/os_linux.cpp | 4 +-- src/hotspot/os/posix/os_posix.cpp | 4 +-- src/hotspot/os/posix/perfMemory_posix.cpp | 2 +- src/hotspot/os/windows/os_windows.cpp | 20 ++++++------- src/hotspot/os/windows/perfMemory_windows.cpp | 2 +- src/hotspot/share/cds/archiveBuilder.cpp | 3 +- src/hotspot/share/cds/filemap.cpp | 10 +++---- src/hotspot/share/cds/metaspaceShared.cpp | 12 +++++--- .../share/classfile/compactHashtable.cpp | 2 +- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 3 +- .../share/gc/parallel/parMarkBitMap.cpp | 3 +- .../share/gc/parallel/psParallelCompact.cpp | 3 +- src/hotspot/share/gc/shared/cardTable.cpp | 2 +- .../gc/shenandoah/shenandoahCardTable.cpp | 4 +-- .../share/gc/shenandoah/shenandoahHeap.cpp | 6 ++-- .../jfr/recorder/storage/jfrVirtualMemory.cpp | 3 +- .../share/memory/allocation.inline.hpp | 4 +-- src/hotspot/share/memory/memoryReserver.cpp | 8 +++--- src/hotspot/share/memory/memoryReserver.hpp | 4 +-- src/hotspot/share/memory/metaspace.cpp | 5 ++-- .../share/memory/metaspace/testHelpers.cpp | 3 +- .../memory/metaspace/virtualSpaceNode.cpp | 2 +- src/hotspot/share/nmt/memReporter.cpp | 2 +- src/hotspot/share/nmt/memReporter.hpp | 2 +- src/hotspot/share/nmt/memTracker.hpp | 4 +-- .../share/nmt/virtualMemoryTracker.hpp | 4 +-- src/hotspot/share/prims/jni.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 6 ++-- src/hotspot/share/runtime/os.cpp | 12 ++++---- src/hotspot/share/runtime/os.hpp | 16 +++++------ .../share/runtime/safepointMechanism.cpp | 2 +- src/hotspot/share/utilities/debug.cpp | 2 +- .../gtest/gc/g1/test_stressCommitUncommit.cpp | 10 ++++--- test/hotspot/gtest/gc/z/test_zForwarding.cpp | 2 +- .../gtest/memory/test_virtualspace.cpp | 24 ++++++++++------ .../gtest/nmt/test_nmt_locationprinting.cpp | 2 +- .../runtime/test_committed_virtualmemory.cpp | 6 ++-- test/hotspot/gtest/runtime/test_os.cpp | 28 +++++++++---------- test/hotspot/gtest/runtime/test_os_aix.cpp | 4 +-- test/hotspot/gtest/runtime/test_os_linux.cpp | 2 +- .../gtest/runtime/test_os_reserve_between.cpp | 6 ++-- .../runtime/NMT/MallocRoundingReportTest.java | 4 +-- .../jtreg/runtime/NMT/MallocTestType.java | 6 ++-- .../runtime/NMT/MallocTrackingVerify.java | 4 +-- .../runtime/NMT/ThreadedMallocTestType.java | 4 +-- 47 files changed, 143 insertions(+), 126 deletions(-) diff --git a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp index 0c2d9a32c8c13..3874c8cd54ef9 100644 --- a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp @@ -70,7 +70,7 @@ static char* reserve_at_eor_compatible_address(size_t size, bool aslr) { const uint64_t immediate = ((uint64_t)immediates[index]) << 32; assert(immediate > 0 && Assembler::operand_valid_for_logical_immediate(/*is32*/false, immediate), "Invalid immediate %d " UINT64_FORMAT, index, immediate); - result = os::attempt_reserve_memory_at((char*)immediate, size, false); + result = os::attempt_reserve_memory_at((char*)immediate, size, mtNone); if (result == nullptr) { log_trace(metaspace, map)("Failed to attach at " UINT64_FORMAT_X, immediate); } @@ -114,7 +114,7 @@ char* CompressedKlassPointers::reserve_address_space_for_compressed_classes(size if (result == nullptr) { constexpr size_t alignment = nth_bit(32); log_debug(metaspace, map)("Trying to reserve at a 32-bit-aligned address"); - result = os::reserve_memory_aligned(size, alignment, false); + result = os::reserve_memory_aligned(size, alignment, mtNone); } return result; diff --git a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp index 86549e878cb74..861fda7a71d7a 100644 --- a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp +++ b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp @@ -77,7 +77,7 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity) _initialized(false) { // Reserve address space for backing memory - _base = (uintptr_t)os::reserve_memory(max_capacity, false, mtJavaHeap); + _base = (uintptr_t)os::reserve_memory(max_capacity, mtJavaHeap); if (_base == 0) { // Failed ZInitialize::error("Failed to reserve address space for backing memory"); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 4e26797cd5b3a..a8dce39ce5d53 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4577,7 +4577,7 @@ static void workaround_expand_exec_shield_cs_limit() { */ char* hint = (char*)(os::Linux::initial_thread_stack_bottom() - (StackOverflow::stack_guard_zone_size() + page_size)); - char* codebuf = os::attempt_reserve_memory_at(hint, page_size, false, mtThread); + char* codebuf = os::attempt_reserve_memory_at(hint, page_size, mtThread); if (codebuf == nullptr) { // JDK-8197429: There may be a stack gap of one megabyte between @@ -4585,7 +4585,7 @@ static void workaround_expand_exec_shield_cs_limit() { // Linux kernel workaround for CVE-2017-1000364. If we failed to // map our codebuf, try again at an address one megabyte lower. hint -= 1 * M; - codebuf = os::attempt_reserve_memory_at(hint, page_size, false, mtThread); + codebuf = os::attempt_reserve_memory_at(hint, page_size, mtThread); } if ((codebuf == nullptr) || (!os::commit_memory(codebuf, page_size, true))) { diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index a36d6b87641e5..8df488768be8e 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -491,9 +491,9 @@ static char* chop_extra_memory(size_t size, size_t alignment, char* extra_base, // Multiple threads can race in this code, and can remap over each other with MAP_FIXED, // so on posix, unmap the section at the start and at the end of the chunk that we mapped // rather than unmapping and remapping the whole chunk to get requested alignment. -char* os::reserve_memory_aligned(size_t size, size_t alignment, bool exec) { +char* os::reserve_memory_aligned(size_t size, size_t alignment, MemTag mem_tag, bool exec) { size_t extra_size = calculate_aligned_extra_size(size, alignment); - char* extra_base = os::reserve_memory(extra_size, exec); + char* extra_base = os::reserve_memory(extra_size, mem_tag, exec); if (extra_base == nullptr) { return nullptr; } diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index 4d6fc1e4b8c9e..cbbecea3a6a0a 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -64,7 +64,7 @@ static char* backing_store_file_name = nullptr; // name of the backing store static char* create_standard_memory(size_t size) { // allocate an aligned chuck of memory - char* mapAddress = os::reserve_memory(size); + char* mapAddress = os::reserve_memory(size, mtInternal); if (mapAddress == nullptr) { return nullptr; diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 84e89334feb63..843272f57b584 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -3019,7 +3019,7 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, PAGE_READWRITE); // If reservation failed, return null if (p_buf == nullptr) return nullptr; - MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC, mtNone); os::release_memory(p_buf, bytes + chunk_size); // we still need to round up to a page boundary (in case we are using large pages) @@ -3080,7 +3080,7 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, // need to create a dummy 'reserve' record to match // the release. MemTracker::record_virtual_memory_reserve((address)p_buf, - bytes_to_release, CALLER_PC); + bytes_to_release, CALLER_PC, mtNone); os::release_memory(p_buf, bytes_to_release); } #ifdef ASSERT @@ -3098,9 +3098,9 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, // Although the memory is allocated individually, it is returned as one. // NMT records it as one block. if ((flags & MEM_COMMIT) != 0) { - MemTracker::record_virtual_memory_reserve_and_commit((address)p_buf, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)p_buf, bytes, CALLER_PC, mtNone); } else { - MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, CALLER_PC, mtNone); } // made it this far, success @@ -3240,7 +3240,7 @@ char* os::replace_existing_mapping_with_file_mapping(char* base, size_t size, in // Multiple threads can race in this code but it's not possible to unmap small sections of // virtual space to get requested alignment, like posix-like os's. // Windows prevents multiple thread from remapping over each other so this loop is thread-safe. -static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int file_desc, MemTag mem_tag = mtNone) { +static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int file_desc, MemTag mem_tag) { assert(is_aligned(alignment, os::vm_allocation_granularity()), "Alignment must be a multiple of allocation granularity (page size)"); assert(is_aligned(size, os::vm_allocation_granularity()), @@ -3254,7 +3254,7 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi for (int attempt = 0; attempt < max_attempts && aligned_base == nullptr; attempt ++) { char* extra_base = file_desc != -1 ? os::map_memory_to_file(extra_size, file_desc, mem_tag) : - os::reserve_memory(extra_size, false, mem_tag); + os::reserve_memory(extra_size, mem_tag); if (extra_base == nullptr) { return nullptr; } @@ -3271,7 +3271,7 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi // Attempt to map, into the just vacated space, the slightly smaller aligned area. // Which may fail, hence the loop. aligned_base = file_desc != -1 ? os::attempt_map_memory_to_file_at(aligned_base, size, file_desc, mem_tag) : - os::attempt_reserve_memory_at(aligned_base, size, false, mem_tag); + os::attempt_reserve_memory_at(aligned_base, size, mem_tag); } assert(aligned_base != nullptr, @@ -3280,9 +3280,9 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi return aligned_base; } -char* os::reserve_memory_aligned(size_t size, size_t alignment, bool exec) { +char* os::reserve_memory_aligned(size_t size, size_t alignment, MemTag mem_tag, bool exec) { // exec can be ignored - return map_or_reserve_memory_aligned(size, alignment, -1 /* file_desc */); + return map_or_reserve_memory_aligned(size, alignment, -1/* file_desc */, mem_tag); } char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int fd, MemTag mem_tag) { @@ -5187,7 +5187,7 @@ char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, } // Record virtual memory allocation - MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, CALLER_PC, mtNone); DWORD bytes_read; OVERLAPPED overlapped; diff --git a/src/hotspot/os/windows/perfMemory_windows.cpp b/src/hotspot/os/windows/perfMemory_windows.cpp index dda0acde79346..322b844f413a2 100644 --- a/src/hotspot/os/windows/perfMemory_windows.cpp +++ b/src/hotspot/os/windows/perfMemory_windows.cpp @@ -54,7 +54,7 @@ typedef BOOL (WINAPI *SetSecurityDescriptorControlFnPtr)( static char* create_standard_memory(size_t size) { // allocate an aligned chuck of memory - char* mapAddress = os::reserve_memory(size); + char* mapAddress = os::reserve_memory(size, mtInternal); if (mapAddress == nullptr) { return nullptr; diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index c309de17b4cad..fa65d7d27bf95 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -309,7 +309,8 @@ address ArchiveBuilder::reserve_buffer() { size_t buffer_size = LP64_ONLY(CompressedClassSpaceSize) NOT_LP64(256 * M); ReservedSpace rs = MemoryReserver::reserve(buffer_size, MetaspaceShared::core_region_alignment(), - os::vm_page_size()); + os::vm_page_size(), + mtClassShared); if (!rs.is_reserved()) { log_error(cds)("Failed to reserve %zu bytes of output buffer.", buffer_size); MetaspaceShared::unrecoverable_writing_error(); diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 580699b60b583..1b5d455485c63 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -1066,10 +1066,10 @@ void FileMapInfo::close() { */ static char* map_memory(int fd, const char* file_name, size_t file_offset, char *addr, size_t bytes, bool read_only, - bool allow_exec, MemTag mem_tag = mtNone) { + bool allow_exec, MemTag mem_tag) { char* mem = os::map_memory(fd, file_name, file_offset, addr, bytes, - AlwaysPreTouch ? false : read_only, - allow_exec, mem_tag); + mem_tag, AlwaysPreTouch ? false : read_only, + allow_exec); if (mem != nullptr && AlwaysPreTouch) { os::pretouch_memory(mem, mem + bytes); } @@ -1094,7 +1094,7 @@ bool FileMapInfo::remap_shared_readonly_as_readwrite() { assert(WINDOWS_ONLY(false) NOT_WINDOWS(true), "Don't call on Windows"); // Replace old mapping with new one that is writable. char *base = os::map_memory(_fd, _full_path, r->file_offset(), - addr, size, false /* !read_only */, + addr, size, mtNone, false /* !read_only */, r->allow_exec()); close(); // These have to be errors because the shared region is now unmapped. @@ -1620,7 +1620,7 @@ bool FileMapInfo::map_heap_region_impl() { } else { base = map_memory(_fd, _full_path, r->file_offset(), addr, _mapped_heap_memregion.byte_size(), r->read_only(), - r->allow_exec()); + r->allow_exec(), mtJavaHeap); if (base == nullptr || base != addr) { dealloc_heap_region(); log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap. " diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index ef2a6dcb8e63c..3ca1985843033 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -1537,7 +1537,8 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma archive_space_rs = MemoryReserver::reserve((char*)base_address, archive_space_size, archive_space_alignment, - os::vm_page_size()); + os::vm_page_size(), + mtNone); if (archive_space_rs.is_reserved()) { assert(base_address == nullptr || (address)archive_space_rs.base() == base_address, "Sanity"); @@ -1605,11 +1606,13 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma archive_space_rs = MemoryReserver::reserve((char*)base_address, archive_space_size, archive_space_alignment, - os::vm_page_size()); + os::vm_page_size(), + mtNone); class_space_rs = MemoryReserver::reserve((char*)ccs_base, class_space_size, class_space_alignment, - os::vm_page_size()); + os::vm_page_size(), + mtNone); } if (!archive_space_rs.is_reserved() || !class_space_rs.is_reserved()) { release_reserved_spaces(total_space_rs, archive_space_rs, class_space_rs); @@ -1622,7 +1625,8 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma total_space_rs = MemoryReserver::reserve((char*) base_address, total_range_size, base_address_alignment, - os::vm_page_size()); + os::vm_page_size(), + mtNone); } else { // We did not manage to reserve at the preferred address, or were instructed to relocate. In that // case we reserve wherever possible, but the start address needs to be encodable as narrow Klass diff --git a/src/hotspot/share/classfile/compactHashtable.cpp b/src/hotspot/share/classfile/compactHashtable.cpp index 8d50e8136a3be..15ae5ba8013e0 100644 --- a/src/hotspot/share/classfile/compactHashtable.cpp +++ b/src/hotspot/share/classfile/compactHashtable.cpp @@ -226,7 +226,7 @@ HashtableTextDump::HashtableTextDump(const char* filename) : _fd(-1) { if (_fd < 0) { quit("Unable to open hashtable dump file", filename); } - _base = os::map_memory(_fd, filename, 0, nullptr, _size, true, false); + _base = os::map_memory(_fd, filename, 0, nullptr, _size, mtNone, true, false); if (_base == nullptr) { quit("Unable to map hashtable dump file", filename); } diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 31f0cc12aa5ee..44fb790f7055f 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -1230,7 +1230,8 @@ G1RegionToSpaceMapper* G1CollectedHeap::create_aux_memory_mapper(const char* des // Allocate a new reserved space, preferring to use large pages. ReservedSpace rs = MemoryReserver::reserve(size, alignment, - preferred_page_size); + preferred_page_size, + mtGC); size_t page_size = rs.page_size(); G1RegionToSpaceMapper* result = diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp index f33d7f93f1db6..d2d168cc2c0db 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp @@ -48,7 +48,8 @@ ParMarkBitMap::initialize(MemRegion covered_region) ReservedSpace rs = MemoryReserver::reserve(_reserved_byte_size, rs_align, - page_sz); + page_sz, + mtGC); if (!rs.is_reserved()) { // Failed to reserve memory for the bitmap, diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 99b975c282a91..84ed77986910f 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -246,7 +246,8 @@ ParallelCompactData::create_vspace(size_t count, size_t element_size) ReservedSpace rs = MemoryReserver::reserve(_reserved_byte_size, rs_align, - page_sz); + page_sz, + mtGC); if (!rs.is_reserved()) { // Failed to reserve memory. diff --git a/src/hotspot/share/gc/shared/cardTable.cpp b/src/hotspot/share/gc/shared/cardTable.cpp index 3236d73933c49..24546618edbcc 100644 --- a/src/hotspot/share/gc/shared/cardTable.cpp +++ b/src/hotspot/share/gc/shared/cardTable.cpp @@ -80,7 +80,7 @@ void CardTable::initialize(void* region0_start, void* region1_start) { HeapWord* high_bound = _whole_heap.end(); const size_t rs_align = MAX2(_page_size, os::vm_allocation_granularity()); - ReservedSpace rs = MemoryReserver::reserve(_byte_map_size, rs_align, _page_size); + ReservedSpace rs = MemoryReserver::reserve(_byte_map_size, rs_align, _page_size, mtGC); if (!rs.is_reserved()) { vm_exit_during_initialization("Could not reserve enough space for the " diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCardTable.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCardTable.cpp index 00f119384895b..e9e52475fb92b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCardTable.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCardTable.cpp @@ -45,7 +45,7 @@ void ShenandoahCardTable::initialize() { // ReservedSpace constructor would assert rs_align >= os::vm_page_size(). const size_t rs_align = MAX2(_page_size, granularity); - ReservedSpace write_space = MemoryReserver::reserve(_byte_map_size, rs_align, _page_size); + ReservedSpace write_space = MemoryReserver::reserve(_byte_map_size, rs_align, _page_size, mtGC); initialize(write_space); // The assembler store_check code will do an unsigned shift of the oop, @@ -60,7 +60,7 @@ void ShenandoahCardTable::initialize() { _write_byte_map = _byte_map; _write_byte_map_base = _byte_map_base; - ReservedSpace read_space = MemoryReserver::reserve(_byte_map_size, rs_align, _page_size); + ReservedSpace read_space = MemoryReserver::reserve(_byte_map_size, rs_align, _page_size, mtGC); initialize(read_space); _read_byte_map = (CardValue*) read_space.base(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 045f485090d2c..ce4b9fc2406e4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -166,7 +166,7 @@ static ReservedSpace reserve(size_t size, size_t preferred_page_size) { size = align_up(size, alignment); } - const ReservedSpace reserved = MemoryReserver::reserve(size, alignment, preferred_page_size); + const ReservedSpace reserved = MemoryReserver::reserve(size, alignment, preferred_page_size, mtGC); if (!reserved.is_reserved()) { vm_exit_during_initialization("Could not reserve space"); } @@ -380,7 +380,7 @@ jint ShenandoahHeap::initialize() { for (uintptr_t addr = min; addr <= max; addr <<= 1u) { char* req_addr = (char*)addr; assert(is_aligned(req_addr, cset_align), "Should be aligned"); - cset_rs = MemoryReserver::reserve(req_addr, cset_size, cset_align, cset_page_size); + cset_rs = MemoryReserver::reserve(req_addr, cset_size, cset_align, cset_page_size, mtGC); if (cset_rs.is_reserved()) { assert(cset_rs.base() == req_addr, "Allocated where requested: " PTR_FORMAT ", " PTR_FORMAT, p2i(cset_rs.base()), addr); _collection_set = new ShenandoahCollectionSet(this, cset_rs, sh_rs.base()); @@ -389,7 +389,7 @@ jint ShenandoahHeap::initialize() { } if (_collection_set == nullptr) { - cset_rs = MemoryReserver::reserve(cset_size, cset_align, os::vm_page_size()); + cset_rs = MemoryReserver::reserve(cset_size, cset_align, os::vm_page_size(), mtGC); if (!cset_rs.is_reserved()) { vm_exit_during_initialization("Cannot reserve memory for collection set"); } diff --git a/src/hotspot/share/jfr/recorder/storage/jfrVirtualMemory.cpp b/src/hotspot/share/jfr/recorder/storage/jfrVirtualMemory.cpp index 97f2b8a1990b0..0ba54fc79bed3 100644 --- a/src/hotspot/share/jfr/recorder/storage/jfrVirtualMemory.cpp +++ b/src/hotspot/share/jfr/recorder/storage/jfrVirtualMemory.cpp @@ -106,7 +106,8 @@ bool JfrVirtualMemorySegment::initialize(size_t reservation_size_request_bytes) assert(is_aligned(reservation_size_request_bytes, os::vm_allocation_granularity()), "invariant"); _rs = MemoryReserver::reserve(reservation_size_request_bytes, os::vm_allocation_granularity(), - os::vm_page_size()); + os::vm_page_size(), + mtTracing); if (!_rs.is_reserved()) { return false; } diff --git a/src/hotspot/share/memory/allocation.inline.hpp b/src/hotspot/share/memory/allocation.inline.hpp index 8d531c6dd2318..01af1616ce18f 100644 --- a/src/hotspot/share/memory/allocation.inline.hpp +++ b/src/hotspot/share/memory/allocation.inline.hpp @@ -58,7 +58,7 @@ template E* MmapArrayAllocator::allocate_or_null(size_t length, MemTag mem_tag) { size_t size = size_for(length); - char* addr = os::reserve_memory(size, !ExecMem, mem_tag); + char* addr = os::reserve_memory(size, mem_tag); if (addr == nullptr) { return nullptr; } @@ -75,7 +75,7 @@ template E* MmapArrayAllocator::allocate(size_t length, MemTag mem_tag) { size_t size = size_for(length); - char* addr = os::reserve_memory(size, !ExecMem, mem_tag); + char* addr = os::reserve_memory(size, mem_tag); if (addr == nullptr) { vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "Allocator (reserve)"); } diff --git a/src/hotspot/share/memory/memoryReserver.cpp b/src/hotspot/share/memory/memoryReserver.cpp index 43cc71355ffce..457818139cda9 100644 --- a/src/hotspot/share/memory/memoryReserver.cpp +++ b/src/hotspot/share/memory/memoryReserver.cpp @@ -90,13 +90,13 @@ static char* reserve_memory_inner(char* requested_address, assert(is_aligned(requested_address, alignment), "Requested address " PTR_FORMAT " must be aligned to %zu", p2i(requested_address), alignment); - return os::attempt_reserve_memory_at(requested_address, size, exec, mem_tag); + return os::attempt_reserve_memory_at(requested_address, size, mem_tag, exec); } // Optimistically assume that the OS returns an aligned base pointer. // When reserving a large address range, most OSes seem to align to at // least 64K. - char* base = os::reserve_memory(size, exec, mem_tag); + char* base = os::reserve_memory(size, mem_tag, exec); if (is_aligned(base, alignment)) { return base; } @@ -107,7 +107,7 @@ static char* reserve_memory_inner(char* requested_address, } // Map using the requested alignment. - return os::reserve_memory_aligned(size, alignment, exec); + return os::reserve_memory_aligned(size, alignment, mem_tag, exec); } ReservedSpace MemoryReserver::reserve_memory(char* requested_address, @@ -261,7 +261,7 @@ static char* map_memory_to_file(char* requested_address, // Optimistically assume that the OS returns an aligned base pointer. // When reserving a large address range, most OSes seem to align to at // least 64K. - char* base = os::map_memory_to_file(size, fd); + char* base = os::map_memory_to_file(size, fd, mem_tag); if (is_aligned(base, alignment)) { return base; } diff --git a/src/hotspot/share/memory/memoryReserver.hpp b/src/hotspot/share/memory/memoryReserver.hpp index 1e16ec252a9de..f8f642cca9537 100644 --- a/src/hotspot/share/memory/memoryReserver.hpp +++ b/src/hotspot/share/memory/memoryReserver.hpp @@ -58,12 +58,12 @@ class MemoryReserver : AllStatic { size_t size, size_t alignment, size_t page_size, - MemTag mem_tag = mtNone); + MemTag mem_tag); static ReservedSpace reserve(size_t size, size_t alignment, size_t page_size, - MemTag mem_tag = mtNone); + MemTag mem_tag); static ReservedSpace reserve(size_t size, MemTag mem_tag); diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index 04e5d807f3244..33cd4a75d7e5d 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -594,7 +594,7 @@ ReservedSpace Metaspace::reserve_address_space_for_compressed_classes(size_t siz if (result == nullptr) { // Fallback: reserve anywhere log_debug(metaspace, map)("Trying anywhere..."); - result = os::reserve_memory_aligned(size, Metaspace::reserve_alignment(), false); + result = os::reserve_memory_aligned(size, Metaspace::reserve_alignment(), mtClass); } // Wrap resulting range in ReservedSpace @@ -767,7 +767,8 @@ void Metaspace::global_initialize() { rs = MemoryReserver::reserve((char*)base, size, Metaspace::reserve_alignment(), - os::vm_page_size()); + os::vm_page_size(), + mtClass); if (rs.is_reserved()) { log_info(metaspace)("Successfully forced class space address to " PTR_FORMAT, p2i(base)); diff --git a/src/hotspot/share/memory/metaspace/testHelpers.cpp b/src/hotspot/share/memory/metaspace/testHelpers.cpp index 76fa1e36c4523..f06f6c855bed5 100644 --- a/src/hotspot/share/memory/metaspace/testHelpers.cpp +++ b/src/hotspot/share/memory/metaspace/testHelpers.cpp @@ -82,7 +82,7 @@ MetaspaceTestContext::MetaspaceTestContext(const char* name, size_t commit_limit reserve_limit, Metaspace::reserve_alignment_words()); if (reserve_limit > 0) { // have reserve limit -> non-expandable context - _rs = MemoryReserver::reserve(reserve_limit * BytesPerWord, Metaspace::reserve_alignment(), os::vm_page_size()); + _rs = MemoryReserver::reserve(reserve_limit * BytesPerWord, Metaspace::reserve_alignment(), os::vm_page_size(), mtTest); _context = MetaspaceContext::create_nonexpandable_context(name, _rs, &_commit_limiter); } else { // no reserve limit -> expandable vslist @@ -142,4 +142,3 @@ size_t MetaspaceTestContext::reserved_words() const { } } // namespace metaspace - diff --git a/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp b/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp index 66644c805a938..bb59192cf16cb 100644 --- a/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp +++ b/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp @@ -256,7 +256,7 @@ VirtualSpaceNode* VirtualSpaceNode::create_node(size_t word_size, ReservedSpace rs = MemoryReserver::reserve(word_size * BytesPerWord, Settings::virtual_space_node_reserve_alignment_words() * BytesPerWord, - os::vm_page_size()); + os::vm_page_size(), mtMetaspace); if (!rs.is_reserved()) { vm_exit_out_of_memory(word_size * BytesPerWord, OOM_MMAP_ERROR, "Failed to reserve memory for metaspace"); } diff --git a/src/hotspot/share/nmt/memReporter.cpp b/src/hotspot/share/nmt/memReporter.cpp index c7327782a4ad7..512e197592962 100644 --- a/src/hotspot/share/nmt/memReporter.cpp +++ b/src/hotspot/share/nmt/memReporter.cpp @@ -249,7 +249,7 @@ void MemSummaryReporter::report_summary_of_tag(MemTag mem_tag, // report malloc'd memory if (amount_in_current_scale(MAX2(malloc_memory->malloc_size(), pk_malloc)) > 0) { - print_malloc(malloc_memory->malloc_counter()); + print_malloc(malloc_memory->malloc_counter(), mem_tag); out->cr(); } diff --git a/src/hotspot/share/nmt/memReporter.hpp b/src/hotspot/share/nmt/memReporter.hpp index 05b1588f38b34..2238d42f15fbd 100644 --- a/src/hotspot/share/nmt/memReporter.hpp +++ b/src/hotspot/share/nmt/memReporter.hpp @@ -108,7 +108,7 @@ class MemReporterBase : public StackObj { // Print summary total, malloc and virtual memory void print_total(size_t reserved, size_t committed, size_t peak = 0) const; - void print_malloc(const MemoryCounter* c, MemTag mem_tag = mtNone) const; + void print_malloc(const MemoryCounter* c, MemTag mem_tag) const; void print_virtual_memory(size_t reserved, size_t committed, size_t peak) const; void print_arena(const MemoryCounter* c) const; diff --git a/src/hotspot/share/nmt/memTracker.hpp b/src/hotspot/share/nmt/memTracker.hpp index 981e991a41ef4..3918e81dab72b 100644 --- a/src/hotspot/share/nmt/memTracker.hpp +++ b/src/hotspot/share/nmt/memTracker.hpp @@ -127,7 +127,7 @@ class MemTracker : AllStatic { // (we do not do any reservations before that). static inline void record_virtual_memory_reserve(void* addr, size_t size, const NativeCallStack& stack, - MemTag mem_tag = mtNone) { + MemTag mem_tag) { assert_post_init(); if (!enabled()) return; if (addr != nullptr) { @@ -153,7 +153,7 @@ class MemTracker : AllStatic { } static inline void record_virtual_memory_reserve_and_commit(void* addr, size_t size, - const NativeCallStack& stack, MemTag mem_tag = mtNone) { + const NativeCallStack& stack, MemTag mem_tag) { assert_post_init(); if (!enabled()) return; if (addr != nullptr) { diff --git a/src/hotspot/share/nmt/virtualMemoryTracker.hpp b/src/hotspot/share/nmt/virtualMemoryTracker.hpp index 74d299e6637f6..2b3b572257114 100644 --- a/src/hotspot/share/nmt/virtualMemoryTracker.hpp +++ b/src/hotspot/share/nmt/virtualMemoryTracker.hpp @@ -297,7 +297,7 @@ class ReservedMemoryRegion : public VirtualMemoryRegion { public: ReservedMemoryRegion(address base, size_t size, const NativeCallStack& stack, - MemTag mem_tag = mtNone) : + MemTag mem_tag) : VirtualMemoryRegion(base, size), _stack(stack), _mem_tag(mem_tag) { } @@ -380,7 +380,7 @@ class VirtualMemoryTracker : AllStatic { public: static bool initialize(NMT_TrackingLevel level); - static bool add_reserved_region (address base_addr, size_t size, const NativeCallStack& stack, MemTag mem_tag = mtNone); + static bool add_reserved_region (address base_addr, size_t size, const NativeCallStack& stack, MemTag mem_tag); static bool add_committed_region (address base_addr, size_t size, const NativeCallStack& stack); static bool remove_uncommitted_region (address base_addr, size_t size); diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index d2916fad1850d..c988745f7b628 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -2400,7 +2400,7 @@ static char* get_bad_address() { static char* bad_address = nullptr; if (bad_address == nullptr) { size_t size = os::vm_allocation_granularity(); - bad_address = os::reserve_memory(size, false, mtInternal); + bad_address = os::reserve_memory(size, mtInternal); if (bad_address != nullptr) { os::protect_memory(bad_address, size, os::MEM_PROT_READ, /*is_committed*/false); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index e08a5ba5ebd12..884fbf981382a 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -728,11 +728,11 @@ WB_ENTRY(void, WB_NMTFree(JNIEnv* env, jobject o, jlong mem)) WB_END WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size)) - return (jlong)(uintptr_t)os::reserve_memory(size, false, mtTest); + return (jlong)(uintptr_t)os::reserve_memory(size, mtTest); WB_END WB_ENTRY(jlong, WB_NMTAttemptReserveMemoryAt(JNIEnv* env, jobject o, jlong addr, jlong size)) - return (jlong)(uintptr_t)os::attempt_reserve_memory_at((char*)(uintptr_t)addr, (size_t)size, false, mtTest); + return (jlong)(uintptr_t)os::attempt_reserve_memory_at((char*)(uintptr_t)addr, (size_t)size, mtTest); WB_END WB_ENTRY(void, WB_NMTCommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size)) @@ -1524,7 +1524,7 @@ WB_ENTRY(void, WB_ReadReservedMemory(JNIEnv* env, jobject o)) static char c; static volatile char* p; - p = os::reserve_memory(os::vm_allocation_granularity()); + p = os::reserve_memory(os::vm_allocation_granularity(), mtTest); if (p == nullptr) { THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "Failed to reserve memory"); } diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index cbe40ca214bba..7695fed564dbe 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1916,7 +1916,7 @@ bool os::create_stack_guard_pages(char* addr, size_t bytes) { return os::pd_create_stack_guard_pages(addr, bytes); } -char* os::reserve_memory(size_t bytes, bool executable, MemTag mem_tag) { +char* os::reserve_memory(size_t bytes, MemTag mem_tag, bool executable) { char* result = pd_reserve_memory(bytes, executable); if (result != nullptr) { MemTracker::record_virtual_memory_reserve(result, bytes, CALLER_PC, mem_tag); @@ -1927,7 +1927,7 @@ char* os::reserve_memory(size_t bytes, bool executable, MemTag mem_tag) { return result; } -char* os::attempt_reserve_memory_at(char* addr, size_t bytes, bool executable, MemTag mem_tag) { +char* os::attempt_reserve_memory_at(char* addr, size_t bytes, MemTag mem_tag, bool executable) { char* result = SimulateFullAddressSpace ? nullptr : pd_attempt_reserve_memory_at(addr, bytes, executable); if (result != nullptr) { MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC, mem_tag); @@ -2133,7 +2133,7 @@ char* os::attempt_reserve_memory_between(char* min, char* max, size_t bytes, siz assert(is_aligned(result, alignment), "alignment invalid (" ERRFMT ")", ERRFMTARGS); log_trace(os, map)(ERRFMT, ERRFMTARGS); log_debug(os, map)("successfully attached at " PTR_FORMAT, p2i(result)); - MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC, mtNone); } else { log_debug(os, map)("failed to attach anywhere in [" PTR_FORMAT "-" PTR_FORMAT ")", p2i(min), p2i(max)); } @@ -2300,8 +2300,8 @@ char* os::attempt_map_memory_to_file_at(char* addr, size_t bytes, int file_desc, } char* os::map_memory(int fd, const char* file_name, size_t file_offset, - char *addr, size_t bytes, bool read_only, - bool allow_exec, MemTag mem_tag) { + char *addr, size_t bytes, MemTag mem_tag, + bool read_only, bool allow_exec) { char* result = pd_map_memory(fd, file_name, file_offset, addr, bytes, read_only, allow_exec); if (result != nullptr) { MemTracker::record_virtual_memory_reserve_and_commit((address)result, bytes, CALLER_PC, mem_tag); @@ -2339,7 +2339,7 @@ char* os::reserve_memory_special(size_t size, size_t alignment, size_t page_size char* result = pd_reserve_memory_special(size, alignment, page_size, addr, executable); if (result != nullptr) { // The memory is committed - MemTracker::record_virtual_memory_reserve_and_commit((address)result, size, CALLER_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)result, size, CALLER_PC, mtNone); log_debug(os, map)("Reserved and committed " RANGEFMT, RANGEFMTARGS(result, size)); } else { log_info(os, map)("Reserve and commit failed (%zu bytes)", size); diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 242959034afb1..b9a3bf564f7e4 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -457,14 +457,14 @@ class os: AllStatic { inline static size_t cds_core_region_alignment(); // Reserves virtual memory. - static char* reserve_memory(size_t bytes, bool executable = false, MemTag mem_tag = mtNone); + static char* reserve_memory(size_t bytes, MemTag mem_tag, bool executable = false); // Reserves virtual memory that starts at an address that is aligned to 'alignment'. - static char* reserve_memory_aligned(size_t size, size_t alignment, bool executable = false); + static char* reserve_memory_aligned(size_t size, size_t alignment, MemTag mem_tag, bool executable = false); // Attempts to reserve the virtual memory at [addr, addr + bytes). // Does not overwrite existing mappings. - static char* attempt_reserve_memory_at(char* addr, size_t bytes, bool executable = false, MemTag mem_tag = mtNone); + static char* attempt_reserve_memory_at(char* addr, size_t bytes, MemTag mem_tag, bool executable = false); // Given an address range [min, max), attempts to reserve memory within this area, with the given alignment. // If randomize is true, the location will be randomized. @@ -516,16 +516,16 @@ class os: AllStatic { static int create_file_for_heap(const char* dir); // Map memory to the file referred by fd. This function is slightly different from map_memory() // and is added to be used for implementation of -XX:AllocateHeapAt - static char* map_memory_to_file(size_t size, int fd, MemTag mem_tag = mtNone); - static char* map_memory_to_file_aligned(size_t size, size_t alignment, int fd, MemTag mem_tag = mtNone); + static char* map_memory_to_file(size_t size, int fd, MemTag mem_tag); + static char* map_memory_to_file_aligned(size_t size, size_t alignment, int fd, MemTag mem_tag); static char* map_memory_to_file(char* base, size_t size, int fd); - static char* attempt_map_memory_to_file_at(char* base, size_t size, int fd, MemTag mem_tag = mtNone); + static char* attempt_map_memory_to_file_at(char* base, size_t size, int fd, MemTag mem_tag); // Replace existing reserved memory with file mapping static char* replace_existing_mapping_with_file_mapping(char* base, size_t size, int fd); static char* map_memory(int fd, const char* file_name, size_t file_offset, - char *addr, size_t bytes, bool read_only = false, - bool allow_exec = false, MemTag mem_tag = mtNone); + char *addr, size_t bytes, MemTag mem_tag, bool read_only = false, + bool allow_exec = false); static bool unmap_memory(char *addr, size_t bytes); static void disclaim_memory(char *addr, size_t bytes); static void realign_memory(char *addr, size_t bytes, size_t alignment_hint); diff --git a/src/hotspot/share/runtime/safepointMechanism.cpp b/src/hotspot/share/runtime/safepointMechanism.cpp index 51038d764bb63..71224bbff4c88 100644 --- a/src/hotspot/share/runtime/safepointMechanism.cpp +++ b/src/hotspot/share/runtime/safepointMechanism.cpp @@ -57,7 +57,7 @@ void SafepointMechanism::default_initialize() { // Polling page const size_t page_size = os::vm_page_size(); const size_t allocation_size = 2 * page_size; - char* polling_page = os::reserve_memory(allocation_size, !ExecMem, mtSafepoint); + char* polling_page = os::reserve_memory(allocation_size, mtSafepoint); os::commit_memory_or_exit(polling_page, allocation_size, !ExecMem, "Unable to commit Safepoint polling page"); char* bad_page = polling_page; diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp index 9413f1f72d7a9..abe3d6757b5fb 100644 --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -712,7 +712,7 @@ struct TestMultipleStaticAssertFormsInClassScope { // Support for showing register content on asserts/guarantees. #ifdef CAN_SHOW_REGISTERS_ON_ASSERT void initialize_assert_poison() { - char* page = os::reserve_memory(os::vm_page_size(), !ExecMem, mtInternal); + char* page = os::reserve_memory(os::vm_page_size(), mtInternal); if (page) { if (os::commit_memory(page, os::vm_page_size(), !ExecMem) && os::protect_memory(page, os::vm_page_size(), os::MEM_PROT_NONE)) { diff --git a/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp b/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp index bc0ed0f3c597f..45da22ce116be 100644 --- a/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp +++ b/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp @@ -82,7 +82,8 @@ TEST_VM(G1RegionToSpaceMapper, smallStressAdjacent) { ReservedSpace rs = MemoryReserver::reserve(size, os::vm_allocation_granularity(), - os::vm_page_size()); + os::vm_page_size(), + mtTest); G1RegionToSpaceMapper* small_mapper = G1RegionToSpaceMapper::create_mapper(rs, @@ -90,7 +91,7 @@ TEST_VM(G1RegionToSpaceMapper, smallStressAdjacent) { page_size, region_size, G1BlockOffsetTable::heap_map_factor(), - mtGC); + mtTest); @@ -108,14 +109,15 @@ TEST_VM(G1RegionToSpaceMapper, largeStressAdjacent) { ReservedSpace rs = MemoryReserver::reserve(size, os::vm_allocation_granularity(), - os::vm_page_size()); + os::vm_page_size(), + mtTest); G1RegionToSpaceMapper* large_mapper = G1RegionToSpaceMapper::create_mapper(rs, size, page_size, region_size, G1BlockOffsetTable::heap_map_factor(), - mtGC); + mtTest); G1TestCommitUncommit task(large_mapper); G1MapperWorkers::run_task(&task); diff --git a/test/hotspot/gtest/gc/z/test_zForwarding.cpp b/test/hotspot/gtest/gc/z/test_zForwarding.cpp index 71fb83827c747..f22eef5085827 100644 --- a/test/hotspot/gtest/gc/z/test_zForwarding.cpp +++ b/test/hotspot/gtest/gc/z/test_zForwarding.cpp @@ -56,7 +56,7 @@ class ZForwardingTest : public Test { const size_t increment = MAX2(align_up(unused / 100, ZGranuleSize), ZGranuleSize); for (uintptr_t start = 0; start + ZGranuleSize <= ZAddressOffsetMax; start += increment) { - char* const reserved = os::attempt_reserve_memory_at((char*)ZAddressHeapBase + start, ZGranuleSize, false /* executable */); + char* const reserved = os::attempt_reserve_memory_at((char*)ZAddressHeapBase + start, ZGranuleSize, mtTest); if (reserved != nullptr) { // Success return reserved; diff --git a/test/hotspot/gtest/memory/test_virtualspace.cpp b/test/hotspot/gtest/memory/test_virtualspace.cpp index d3fed31da0bfc..d2f8927ba28f7 100644 --- a/test/hotspot/gtest/memory/test_virtualspace.cpp +++ b/test/hotspot/gtest/memory/test_virtualspace.cpp @@ -73,7 +73,7 @@ namespace { static void test_reserved_size_alignment(size_t size, size_t alignment) { ASSERT_PRED2(is_size_aligned, size, alignment) << "Incorrect input parameters"; size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); - ReservedSpace rs = MemoryReserver::reserve(size, alignment, page_size); + ReservedSpace rs = MemoryReserver::reserve(size, alignment, page_size, mtTest); ASSERT_TRUE(rs.base() != nullptr) << "rs.special = " << rs.special(); ASSERT_EQ(size, rs.size()) << "rs.special = " << rs.special(); @@ -101,7 +101,7 @@ namespace { bool large = maybe_large && UseLargePages && size >= os::large_page_size(); size_t page_size = large ? os::large_page_size() : os::vm_page_size(); - ReservedSpace rs = MemoryReserver::reserve(size, alignment, page_size); + ReservedSpace rs = MemoryReserver::reserve(size, alignment, page_size, mtTest); MemoryReleaser releaser(&rs); EXPECT_TRUE(rs.base() != nullptr) << "rs.special: " << rs.special(); @@ -217,7 +217,8 @@ namespace { case Commit: return MemoryReserver::reserve(reserve_size_aligned, os::vm_allocation_granularity(), - os::vm_page_size()); + os::vm_page_size(), + mtTest); } } @@ -296,7 +297,7 @@ TEST_VM(VirtualSpace, actual_committed_space_one_large_page) { size_t large_page_size = os::large_page_size(); - ReservedSpace reserved = MemoryReserver::reserve(large_page_size, large_page_size, large_page_size); + ReservedSpace reserved = MemoryReserver::reserve(large_page_size, large_page_size, large_page_size, mtTest); ReservedSpaceReleaser releaser(&reserved); ASSERT_TRUE(reserved.is_reserved()); @@ -365,7 +366,8 @@ class TestReservedSpace : AllStatic { size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); ReservedSpace rs = MemoryReserver::reserve(size, alignment, - page_size); + page_size, + mtTest); EXPECT_TRUE(rs.base() != nullptr); EXPECT_EQ(rs.size(), size) << "rs.size: " << rs.size(); @@ -410,7 +412,8 @@ class TestReservedSpace : AllStatic { ReservedSpace rs = MemoryReserver::reserve(size, alignment, - page_size); + page_size, + mtTest); EXPECT_TRUE(rs.base() != nullptr); EXPECT_EQ(rs.size(), size) << "rs.size: " << rs.size(); @@ -514,12 +517,14 @@ class TestVirtualSpace : AllStatic { default: case Default: case Reserve: - return MemoryReserver::reserve(reserve_size_aligned, mtTest); + return MemoryReserver::reserve(reserve_size_aligned, + mtTest); case Disable: case Commit: return MemoryReserver::reserve(reserve_size_aligned, os::vm_allocation_granularity(), - os::vm_page_size()); + os::vm_page_size(), + mtTest); } } @@ -576,7 +581,8 @@ class TestVirtualSpace : AllStatic { ReservedSpace reserved = MemoryReserver::reserve(large_page_size, large_page_size, - large_page_size); + large_page_size, + mtTest); ASSERT_TRUE(reserved.is_reserved()); diff --git a/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp b/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp index e0e3c28910225..c8711004f1052 100644 --- a/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp @@ -113,7 +113,7 @@ TEST_VM(NMT, DISABLED_location_printing_cheap_dead_7) { test_for_dead_c_heap_blo #endif static void test_for_mmap(size_t sz, ssize_t offset) { - char* addr = os::reserve_memory(sz, false, mtTest); + char* addr = os::reserve_memory(sz, mtTest); if (MemTracker::enabled()) { test_pointer(addr + offset, true, "in mmap'd memory region"); } else { diff --git a/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp index de63e1807c13f..f07b45bc32d6b 100644 --- a/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp +++ b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp @@ -91,7 +91,7 @@ class CommittedVirtualMemoryTest { static void test_committed_region_impl(size_t num_pages, size_t touch_pages, int* page_num) { const size_t page_sz = os::vm_page_size(); const size_t size = num_pages * page_sz; - char* base = os::reserve_memory(size, !ExecMem, mtThreadStack); + char* base = os::reserve_memory(size, mtThreadStack); bool result = os::commit_memory(base, size, !ExecMem); size_t index; ASSERT_NE(base, (char*)nullptr); @@ -159,7 +159,7 @@ class CommittedVirtualMemoryTest { const size_t page_sz = os::vm_page_size(); const size_t num_pages = 4; const size_t size = num_pages * page_sz; - char* base = os::reserve_memory(size, !ExecMem, mtTest); + char* base = os::reserve_memory(size, mtTest); ASSERT_NE(base, (char*)nullptr); result = os::commit_memory(base, size, !ExecMem); @@ -205,7 +205,7 @@ class CommittedVirtualMemoryTest { const size_t page_sz = os::vm_page_size(); const size_t size = num_pages * page_sz; - char* base = os::reserve_memory(size, !ExecMem, mtTest); + char* base = os::reserve_memory(size, mtTest); ASSERT_NE(base, (char*)nullptr); result = os::commit_memory(base, size, !ExecMem); diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index ee6d1427d0b8b..6b7653f5eecfd 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -258,7 +258,7 @@ TEST_VM(os, test_print_hex_dump) { // two pages, first one protected. const size_t ps = os::vm_page_size(); - char* two_pages = os::reserve_memory(ps * 2, false, mtTest); + char* two_pages = os::reserve_memory(ps * 2, mtTest); os::commit_memory(two_pages, ps * 2, false); os::protect_memory(two_pages, ps, os::MEM_PROT_NONE, true); @@ -492,7 +492,7 @@ TEST_VM(os, realpath) { static inline bool can_reserve_executable_memory(void) { bool executable = true; size_t len = 128; - char* p = os::reserve_memory(len, executable); + char* p = os::reserve_memory(len, mtTest, executable); bool exec_supported = (p != nullptr); if (exec_supported) { os::release_memory(p, len); @@ -530,7 +530,7 @@ static address reserve_multiple(int num_stripes, size_t stripe_len) { for (int tries = 0; tries < 256 && p == nullptr; tries ++) { size_t total_range_len = num_stripes * stripe_len; // Reserve a large contiguous area to get the address space... - p = (address)os::reserve_memory(total_range_len); + p = (address)os::reserve_memory(total_range_len, mtTest); EXPECT_NE(p, (address)nullptr); // .. release it... EXPECT_TRUE(os::release_memory((char*)p, total_range_len)); @@ -544,7 +544,7 @@ static address reserve_multiple(int num_stripes, size_t stripe_len) { #else const bool executable = stripe % 2 == 0; #endif - q = (address)os::attempt_reserve_memory_at((char*)q, stripe_len, executable); + q = (address)os::attempt_reserve_memory_at((char*)q, stripe_len, mtTest, executable); if (q == nullptr) { // Someone grabbed that area concurrently. Cleanup, then retry. tty->print_cr("reserve_multiple: retry (%d)...", stripe); @@ -564,7 +564,7 @@ static address reserve_multiple(int num_stripes, size_t stripe_len) { static address reserve_one_commit_multiple(int num_stripes, size_t stripe_len) { assert(is_aligned(stripe_len, os::vm_allocation_granularity()), "Sanity"); size_t total_range_len = num_stripes * stripe_len; - address p = (address)os::reserve_memory(total_range_len); + address p = (address)os::reserve_memory(total_range_len, mtTest); EXPECT_NE(p, (address)nullptr); for (int stripe = 0; stripe < num_stripes; stripe++) { address q = p + (stripe * stripe_len); @@ -631,7 +631,7 @@ TEST_VM(os, release_multi_mappings) { PRINT_MAPPINGS("B"); // ...re-reserve the middle stripes. This should work unless release silently failed. - address p2 = (address)os::attempt_reserve_memory_at((char*)p_middle_stripes, middle_stripe_len); + address p2 = (address)os::attempt_reserve_memory_at((char*)p_middle_stripes, middle_stripe_len, mtTest); ASSERT_EQ(p2, p_middle_stripes); @@ -654,7 +654,7 @@ TEST_VM_ASSERT_MSG(os, release_bad_ranges, ".*bad release") { #else TEST_VM(os, release_bad_ranges) { #endif - char* p = os::reserve_memory(4 * M); + char* p = os::reserve_memory(4 * M, mtTest); ASSERT_NE(p, (char*)nullptr); // Release part of range ASSERT_FALSE(os::release_memory(p, M)); @@ -689,7 +689,7 @@ TEST_VM(os, release_one_mapping_multi_commits) { // // make things even more difficult by trying to reserve at the border of the region address border = p + num_stripes * stripe_len; - address p2 = (address)os::attempt_reserve_memory_at((char*)border, stripe_len); + address p2 = (address)os::attempt_reserve_memory_at((char*)border, stripe_len, mtTest); PRINT_MAPPINGS("B"); ASSERT_TRUE(p2 == nullptr || p2 == border); @@ -730,7 +730,7 @@ TEST_VM(os, show_mappings_small_range) { TEST_VM(os, show_mappings_full_range) { // Reserve a small range and fill it with a marker string, should show up // on implementations displaying range snippets - char* p = os::reserve_memory(1 * M, false, mtInternal); + char* p = os::reserve_memory(1 * M, mtTest); if (p != nullptr) { if (os::commit_memory(p, 1 * M, false)) { strcpy(p, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); @@ -754,7 +754,7 @@ TEST_VM(os, find_mapping_simple) { // A simple allocation { - address p = (address)os::reserve_memory(total_range_len); + address p = (address)os::reserve_memory(total_range_len, mtTest); ASSERT_NE(p, (address)nullptr); PRINT_MAPPINGS("A"); for (size_t offset = 0; offset < total_range_len; offset += 4711) { @@ -1059,9 +1059,9 @@ TEST_VM(os, open_O_CLOEXEC) { } TEST_VM(os, reserve_at_wish_address_shall_not_replace_mappings_smallpages) { - char* p1 = os::reserve_memory(M, false, mtTest); + char* p1 = os::reserve_memory(M, mtTest); ASSERT_NE(p1, nullptr); - char* p2 = os::attempt_reserve_memory_at(p1, M); + char* p2 = os::attempt_reserve_memory_at(p1, M, mtTest); ASSERT_EQ(p2, nullptr); // should have failed os::release_memory(p1, M); } @@ -1069,7 +1069,7 @@ TEST_VM(os, reserve_at_wish_address_shall_not_replace_mappings_smallpages) { TEST_VM(os, reserve_at_wish_address_shall_not_replace_mappings_largepages) { if (UseLargePages && !os::can_commit_large_page_memory()) { // aka special const size_t lpsz = os::large_page_size(); - char* p1 = os::reserve_memory_aligned(lpsz, lpsz, false); + char* p1 = os::reserve_memory_aligned(lpsz, lpsz, mtTest); ASSERT_NE(p1, nullptr); char* p2 = os::reserve_memory_special(lpsz, lpsz, lpsz, p1, false); ASSERT_EQ(p2, nullptr); // should have failed @@ -1095,7 +1095,7 @@ TEST_VM(os, free_without_uncommit) { const size_t pages = 64; const size_t size = pages * page_sz; - char* base = os::reserve_memory(size, false, mtTest); + char* base = os::reserve_memory(size, mtTest); ASSERT_NE(base, (char*) nullptr); ASSERT_TRUE(os::commit_memory(base, size, false)); diff --git a/test/hotspot/gtest/runtime/test_os_aix.cpp b/test/hotspot/gtest/runtime/test_os_aix.cpp index 9fcb2f9c691a9..73ed55dc3ce74 100644 --- a/test/hotspot/gtest/runtime/test_os_aix.cpp +++ b/test/hotspot/gtest/runtime/test_os_aix.cpp @@ -34,9 +34,9 @@ TEST_VM(os_aix, aix_reserve_at_non_shmlba_aligned_address) { if (os::vm_page_size() != 4*K && !os::Aix::supports_64K_mmap_pages()) { // With this condition true shmget() is used inside - char* p = os::attempt_reserve_memory_at((char*)0x1f00000, M); + char* p = os::attempt_reserve_memory_at((char*)0x1f00000, M, mtTest); ASSERT_EQ(p, nullptr); // should have failed - p = os::attempt_reserve_memory_at((char*)((64 * G) + M), M); + p = os::attempt_reserve_memory_at((char*)((64 * G) + M), M, mtTest); ASSERT_EQ(p, nullptr); // should have failed } } diff --git a/test/hotspot/gtest/runtime/test_os_linux.cpp b/test/hotspot/gtest/runtime/test_os_linux.cpp index caa227c5e35aa..21133788a3668 100644 --- a/test/hotspot/gtest/runtime/test_os_linux.cpp +++ b/test/hotspot/gtest/runtime/test_os_linux.cpp @@ -354,7 +354,7 @@ TEST_VM(os_linux, pretouch_thp_and_use_concurrent) { const size_t size = 1 * G; const bool useThp = UseTransparentHugePages; UseTransparentHugePages = true; - char* const heap = os::reserve_memory(size, false, mtInternal); + char* const heap = os::reserve_memory(size, mtTest); EXPECT_NE(heap, nullptr); EXPECT_TRUE(os::commit_memory(heap, size, false)); diff --git a/test/hotspot/gtest/runtime/test_os_reserve_between.cpp b/test/hotspot/gtest/runtime/test_os_reserve_between.cpp index 34dd26dcf1769..ee91ff49ded52 100644 --- a/test/hotspot/gtest/runtime/test_os_reserve_between.cpp +++ b/test/hotspot/gtest/runtime/test_os_reserve_between.cpp @@ -157,7 +157,7 @@ struct SpaceWithHole { // the hole. const uintptr_t candidate = nth_bit(i); if ((candidate + _len) <= ARMB_constants::absolute_max) { - _base = os::attempt_reserve_memory_at((char*)candidate, _len); + _base = os::attempt_reserve_memory_at((char*)candidate, _len, mtTest); } } if (_base == nullptr) { @@ -165,8 +165,8 @@ struct SpaceWithHole { } // Release total mapping, remap the individual non-holy parts os::release_memory(_base, _len); - _p1 = os::attempt_reserve_memory_at(_base + _p1_offset, _p1_size); - _p2 = os::attempt_reserve_memory_at(_base + _p2_offset, _p2_size); + _p1 = os::attempt_reserve_memory_at(_base + _p1_offset, _p1_size, mtTest); + _p2 = os::attempt_reserve_memory_at(_base + _p2_offset, _p2_size, mtTest); if (_p1 == nullptr || _p2 == nullptr) { return false; } diff --git a/test/hotspot/jtreg/runtime/NMT/MallocRoundingReportTest.java b/test/hotspot/jtreg/runtime/NMT/MallocRoundingReportTest.java index 30a03f973bf21..a0c14d7083132 100644 --- a/test/hotspot/jtreg/runtime/NMT/MallocRoundingReportTest.java +++ b/test/hotspot/jtreg/runtime/NMT/MallocRoundingReportTest.java @@ -57,7 +57,7 @@ public static void main(String args[]) throws Exception { // NMT does not track memory allocations less than 1KB, and rounds to the nearest KB NMTTestUtils.runJcmdSummaryReportAndCheckOutput( "Test (reserved=" + numKB + "KB, committed=" + numKB + "KB)", - "(malloc=" + numKB + "KB #1) (at peak)" + "(malloc=" + numKB + "KB tag=Test #1) (at peak)" // (malloc=1KB tag=Test #1) (at peak) ); wb.NMTFree(mallocd_total); @@ -65,7 +65,7 @@ public static void main(String args[]) throws Exception { // Run 'jcmd VM.native_memory summary', check for expected output NMTTestUtils.runJcmdSummaryReportAndCheckOutput( "Test (reserved=0KB, committed=0KB)", - "(malloc=0KB) (peak=" + numKB + "KB #1)" + "(malloc=0KB tag=Test) (peak=" + numKB + "KB #1)" ); } } diff --git a/test/hotspot/jtreg/runtime/NMT/MallocTestType.java b/test/hotspot/jtreg/runtime/NMT/MallocTestType.java index 67df864e7b41c..1612cbd81c0a3 100644 --- a/test/hotspot/jtreg/runtime/NMT/MallocTestType.java +++ b/test/hotspot/jtreg/runtime/NMT/MallocTestType.java @@ -46,7 +46,7 @@ public static void main(String args[]) throws Exception { NMTTestUtils.runJcmdSummaryReportAndCheckOutput( new String[]{"Test (reserved=384KB, committed=384KB)", - "(malloc=384KB #2) (at peak)"}); + "(malloc=384KB tag=Test #2) (at peak)"}); wb.NMTFree(memAlloc3); // current +256K #1 peak +384K #2 long memAlloc1 = wb.NMTMalloc(512 * 1024); // current +768K #2 peak +768K #2 @@ -54,13 +54,13 @@ public static void main(String args[]) throws Exception { NMTTestUtils.runJcmdSummaryReportAndCheckOutput( new String[]{"Test (reserved=512KB, committed=512KB)", - "(malloc=512KB #1) (peak=768KB #2)"}); + "(malloc=512KB tag=Test #1) (peak=768KB #2)"}); // Free the memory allocated by NMTAllocTest wb.NMTFree(memAlloc1); // current 0K #0 peak +768K #2 NMTTestUtils.runJcmdSummaryReportAndCheckOutput( new String[]{"Test (reserved=0KB, committed=0KB)", - "(malloc=0KB) (peak=768KB #2)"}); + "(malloc=0KB tag=Test) (peak=768KB #2)"}); } } diff --git a/test/hotspot/jtreg/runtime/NMT/MallocTrackingVerify.java b/test/hotspot/jtreg/runtime/NMT/MallocTrackingVerify.java index 0c08e07fd2588..141ef9f2ac3fe 100644 --- a/test/hotspot/jtreg/runtime/NMT/MallocTrackingVerify.java +++ b/test/hotspot/jtreg/runtime/NMT/MallocTrackingVerify.java @@ -72,7 +72,7 @@ public static void main(String args[]) throws Exception { NMTTestUtils.runJcmdSummaryReportAndCheckOutput( "Test (reserved=4KB, committed=4KB)", - "(malloc=4KB #" + mallocd_memory.size() + ") (at peak)" + "(malloc=4KB tag=Test #" + mallocd_memory.size() + ") (at peak)" ); // Free @@ -83,7 +83,7 @@ public static void main(String args[]) throws Exception { // Run 'jcmd VM.native_memory summary', check for expected output NMTTestUtils.runJcmdSummaryReportAndCheckOutput( "Test (reserved=0KB, committed=0KB)", - "(malloc=0KB) (peak=4KB #" + + mallocd_memory.size() + ")" + "(malloc=0KB tag=Test) (peak=4KB #" + + mallocd_memory.size() + ")" ); } diff --git a/test/hotspot/jtreg/runtime/NMT/ThreadedMallocTestType.java b/test/hotspot/jtreg/runtime/NMT/ThreadedMallocTestType.java index 290984c41854f..f6b0f3baf041a 100644 --- a/test/hotspot/jtreg/runtime/NMT/ThreadedMallocTestType.java +++ b/test/hotspot/jtreg/runtime/NMT/ThreadedMallocTestType.java @@ -61,7 +61,7 @@ public void run() { // Run 'jcmd VM.native_memory summary' NMTTestUtils.runJcmdSummaryReportAndCheckOutput( "Test (reserved=896KB, committed=896KB)", - "(malloc=896KB #3) (at peak)" + "(malloc=896KB tag=Test #3) (at peak)" ); Thread freeThread = new Thread() { @@ -78,7 +78,7 @@ public void run() { NMTTestUtils.runJcmdSummaryReportAndCheckOutput( "Test (reserved=0KB, committed=0KB)", - "(malloc=0KB) (peak=896KB #3)" + "(malloc=0KB tag=Test) (peak=896KB #3)" ); } } From d684867066edb886bc444c864ef9db3eff318c34 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Mon, 14 Apr 2025 16:55:37 +0000 Subject: [PATCH 0571/1101] 8346230: [perf] scalability issue for the specjvm2008::xml.transform workload Reviewed-by: joehw, jbhateja --- .../xml/internal/utils/XMLReaderManager.java | 34 ++++++------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/XMLReaderManager.java b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/XMLReaderManager.java index 91a6597a60341..f0cd5062d2ba2 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/XMLReaderManager.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/XMLReaderManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -37,7 +37,7 @@ * Creates XMLReader objects and caches them for re-use. * This class follows the singleton pattern. * - * @LastModified: Nov 2024 + * @LastModified: Apr 2025 */ public class XMLReaderManager { @@ -52,11 +52,6 @@ public class XMLReaderManager { */ private ThreadLocal m_readers; - /** - * Keeps track of whether an XMLReader object is in use. - */ - private HashMap m_inUse; - private boolean m_overrideDefaultParser; private boolean _secureProcessing; @@ -89,11 +84,10 @@ public static XMLReaderManager getInstance(boolean overrideDefaultParser) { /** * Retrieves a cached XMLReader for this thread, or creates a new - * XMLReader, if the existing reader is in use. When the caller no - * longer needs the reader, it must release it with a call to - * {@link #releaseXMLReader}. + * XMLReader. When the caller no longer needs the reader, it must + * release it with a call to {@link #releaseXMLReader}. */ - public synchronized XMLReader getXMLReader() throws SAXException { + public XMLReader getXMLReader() throws SAXException { XMLReader reader; if (m_readers == null) { @@ -101,14 +95,9 @@ public synchronized XMLReader getXMLReader() throws SAXException { // on a thread, a new XMLReader will automatically be created. m_readers = new ThreadLocal<>(); } - - if (m_inUse == null) { - m_inUse = new HashMap<>(); - } - /** * Constructs a new XMLReader if: - * (1) the cached reader for this thread is in use, or + * (1) the cached reader for this thread is not defined, or * (2) the requirement for overriding has changed, * (3) the cached reader isn't an instance of the class set in the * 'org.xml.sax.driver' property @@ -119,10 +108,9 @@ public synchronized XMLReader getXMLReader() throws SAXException { boolean threadHasReader = (rw != null); reader = threadHasReader ? rw.reader : null; String factory = System.getProperty(property); - if (threadHasReader && m_inUse.get(reader) != Boolean.TRUE && + if (threadHasReader && (rw.overrideDefaultParser == m_overrideDefaultParser) && ( factory == null || reader.getClass().getName().equals(factory))) { - m_inUse.put(reader, Boolean.TRUE); JdkXmlUtils.setReaderProperty(reader, _xmlSecurityManager, _useCatalog, _catalogFeatures); } else { @@ -133,10 +121,9 @@ public synchronized XMLReader getXMLReader() throws SAXException { // a reader for this thread. if (!threadHasReader) { m_readers.set(new ReaderWrapper(reader, m_overrideDefaultParser)); - m_inUse.put(reader, Boolean.TRUE); } - } + } //reader is cached, but this property might have been reset JdkXmlUtils.setXMLReaderPropertyIfSupport(reader, XMLConstants.ACCESS_EXTERNAL_DTD, _accessExternalDTD, true); @@ -153,9 +140,9 @@ public synchronized XMLReader getXMLReader() throws SAXException { * * @param reader The XMLReader that's being released. */ - public synchronized void releaseXMLReader(XMLReader reader) { + public void releaseXMLReader(XMLReader reader) { // If the reader that's being released is the cached reader - // for this thread, remove it from the m_inUse list. + // for this thread, reset it. ReaderWrapper rw = m_readers.get(); if (rw != null && rw.reader == reader && reader != null) { // reset the reader for reuse @@ -167,7 +154,6 @@ public synchronized void releaseXMLReader(XMLReader reader) { } catch (SAXNotRecognizedException | SAXNotSupportedException ex) { // shouldn't happen as the property is supported. } - m_inUse.remove(reader); } } From 46a6fc84ef17f38eedd49f59a3c05f7c95fe23bc Mon Sep 17 00:00:00 2001 From: Phil Race Date: Mon, 14 Apr 2025 16:58:06 +0000 Subject: [PATCH 0572/1101] 8353483: Open source some JProgressBar tests Reviewed-by: honkar, serb --- .../JProgressBar/RightLeftOrientation.java | 147 ++++++++++++++++++ .../javax/swing/JProgressBar/bug4230391.java | 139 +++++++++++++++++ .../javax/swing/JProgressBar/bug4393042.java | 90 +++++++++++ .../javax/swing/JProgressBar/bug5003022.java | 82 ++++++++++ 4 files changed, 458 insertions(+) create mode 100644 test/jdk/javax/swing/JProgressBar/RightLeftOrientation.java create mode 100644 test/jdk/javax/swing/JProgressBar/bug4230391.java create mode 100644 test/jdk/javax/swing/JProgressBar/bug4393042.java create mode 100644 test/jdk/javax/swing/JProgressBar/bug5003022.java diff --git a/test/jdk/javax/swing/JProgressBar/RightLeftOrientation.java b/test/jdk/javax/swing/JProgressBar/RightLeftOrientation.java new file mode 100644 index 0000000000000..5cc183b1e8e4d --- /dev/null +++ b/test/jdk/javax/swing/JProgressBar/RightLeftOrientation.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4230355 + * @summary + * This test checks if progress bars lay out correctly when their + * ComponentOrientation property is set to RIGHT_TO_LEFT. This test is + * manual. The tester is asked to compare left-to-right and + * right-to-left progress bars and judge whether they are mirror images + * of each other. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual RightLeftOrientation + */ + +import java.awt.ComponentOrientation; +import java.awt.Container; +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.LookAndFeel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.UIManager; + +public class RightLeftOrientation { + + static final String INSTRUCTIONS = """ + This test checks progress bars for correct Right-To-Left Component Orientation. + The progress bars in the left column should fill up from the left while the bars in + the right column should fill up from the right. + If this is so, the test PASSES, otherwise it FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Progress Bar Orientation Test Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(RightLeftOrientation::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("Progress Bar Orientation Test"); + Container contentPane = frame.getContentPane(); + contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.X_AXIS)); + contentPane.add(createBarSet(ComponentOrientation.LEFT_TO_RIGHT)); + contentPane.add(createBarSet(ComponentOrientation.RIGHT_TO_LEFT)); + frame.pack(); + return frame; + } + + static JPanel createBarSet(ComponentOrientation o) { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + JLabel header; + if (o.isLeftToRight()) + header = new JLabel("Left To Right"); + else + header = new JLabel("Right To Left"); + panel.add(header); + + UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels(); + for (int i = 0; i < lafs.length; i++) { + if (i > 0) + panel.add(Box.createVerticalStrut(10)); + panel.add(createProgressBars(lafs[i].getName(), + lafs[i].getClassName(), o)); + } + + return panel; + } + + static JPanel createProgressBars(String name, String plaf, + ComponentOrientation o) { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + JLabel label = new JLabel(name); + panel.add(label); + try { + LookAndFeel save = UIManager.getLookAndFeel(); + UIManager.setLookAndFeel(plaf); + + panel.add(createProgressBar(true, 0, o)); + panel.add(Box.createVerticalStrut(5)); + + panel.add(createProgressBar(true, 5, o)); + panel.add(Box.createVerticalStrut(5)); + + panel.add(createProgressBar(true, 10, o)); + panel.add(Box.createVerticalStrut(5)); + + panel.add(createProgressBar(true, 20, o)); + panel.add(Box.createVerticalStrut(5)); + + UIManager.put("ProgressBar.cellSpacing", Integer.valueOf(2)); + UIManager.put("ProgressBar.cellLength", Integer.valueOf(7)); + + panel.add(createProgressBar(false, 5, o)); + panel.add(Box.createVerticalStrut(5)); + + panel.add(createProgressBar(false, 20, o)); + + UIManager.setLookAndFeel(save); + } catch (Exception e) { + System.err.println(e); + } + return panel; + } + + static JProgressBar createProgressBar(boolean paintStr, int value, + ComponentOrientation o) { + JProgressBar p = new JProgressBar(JProgressBar.HORIZONTAL, 0, 20); + p.setStringPainted(paintStr); + p.setValue(value); + p.setComponentOrientation(o); + return p; + } + +} diff --git a/test/jdk/javax/swing/JProgressBar/bug4230391.java b/test/jdk/javax/swing/JProgressBar/bug4230391.java new file mode 100644 index 0000000000000..473862d83a338 --- /dev/null +++ b/test/jdk/javax/swing/JProgressBar/bug4230391.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4230391 + * @summary Tests that JProgressBar draws correctly when Insets are not zero + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4230391 +*/ + +import java.awt.ComponentOrientation; +import java.awt.Container; +import java.awt.Insets; +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.LookAndFeel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.UIManager; + +public class bug4230391 { + + static final String INSTRUCTIONS = """ + Tests that progress bars honor insets in different L&Fs. + Different L&Fs render the progress bar differently, and may or may + not have a different colored background around the progress bar, + and may or may not draw a border around the bar+background. + The progress bars should be of equal width and the progress + rendering line/bar should not extend past/overlap any border. + If it is as described, the test PASSES. + """; + + static class InsetProgressBar extends JProgressBar { + private Insets insets = new Insets(12, 12, 12, 12); + + public InsetProgressBar(boolean horiz, int low, int hi) { + super((horiz)?JProgressBar.HORIZONTAL:JProgressBar.VERTICAL, low, hi); + } + + public Insets getInsets() { + return insets; + } + } + + static JPanel createBarSet() { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + panel.setBorder(BorderFactory.createEmptyBorder(20,20,20,20)); + UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels(); + for (int i = 0; i < lafs.length; i++) { + if (i > 0) { + panel.add(Box.createVerticalStrut(10)); + } + panel.add(createProgressBars(lafs[i].getName(), lafs[i].getClassName())); + } + return panel; + } + + static JPanel createProgressBars(String name, String plaf) { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); + try { + LookAndFeel save = UIManager.getLookAndFeel(); + UIManager.setLookAndFeel(plaf); + + ComponentOrientation ltr = ComponentOrientation.LEFT_TO_RIGHT; + + Box b = Box.createVerticalBox(); + panel.add(b); + panel.add(Box.createHorizontalStrut(5)); + panel.add(createProgressBar(false, true, ltr)); + UIManager.setLookAndFeel(save); + } catch (Exception e) { + System.err.println(e); + } + return panel; + } + + static JProgressBar createProgressBar(boolean solid, boolean horiz, + ComponentOrientation o) { + if (solid) { + UIManager.put("ProgressBar.cellSpacing", Integer.valueOf(0)); + UIManager.put("ProgressBar.cellLength", Integer.valueOf(1)); + } else { + UIManager.put("ProgressBar.cellSpacing", Integer.valueOf(2)); + UIManager.put("ProgressBar.cellLength", Integer.valueOf(7)); + } + + JProgressBar p = new InsetProgressBar(horiz, 0, 20); + p.setStringPainted(solid); + p.setValue(20); + p.setComponentOrientation(o); + + return p; + } + + static JFrame createUI() { + JFrame frame = new JFrame("Progress Bar Insets Test"); + Container contentPane = frame.getContentPane(); + contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.X_AXIS)); + contentPane.add(createBarSet()); + frame.setSize(400, 300); + return frame; + } + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Progress Bar Insets Test Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(bug4230391::createUI) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/javax/swing/JProgressBar/bug4393042.java b/test/jdk/javax/swing/JProgressBar/bug4393042.java new file mode 100644 index 0000000000000..f17d70a1309d5 --- /dev/null +++ b/test/jdk/javax/swing/JProgressBar/bug4393042.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4393042 + * @summary JProgressBar should update painting when maximum value is very large + * @key headful + */ + +import java.awt.Graphics; +import javax.swing.JFrame; +import javax.swing.JProgressBar; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class bug4393042 extends JProgressBar { + + static final int MAXIMUM = Integer.MAX_VALUE - 100; + static volatile int value = 0; + static volatile bug4393042 progressBar; + static JFrame frame; + static volatile int paintCount = 0; + + public void paintComponent(Graphics g) { + super.paintComponent(g); + System.out.println("paint count=" + (++paintCount)); + } + + public bug4393042(int min, int max) { + super(min, max); + } + + public static void main(String[] args) throws Exception { + + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + + try { + SwingUtilities.invokeAndWait(bug4393042::createUI); + + value = 0; + for (int i = 0; i <= 10; i++) { + Thread.sleep(1000); + SwingUtilities.invokeAndWait(() -> { + progressBar.setValue(value); + }); + value += MAXIMUM / 10; + } + + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + if (paintCount < 10 || paintCount > 100) { + throw new RuntimeException("Unexpected paint count : " + paintCount); + } + } + + static void createUI() { + frame = new JFrame("bug4393042"); + progressBar = new bug4393042(0, MAXIMUM); + progressBar.setStringPainted(true); + progressBar.setValue(0); + frame.add(progressBar); + frame.setSize(400, 200); + frame.setVisible(true); + } +} diff --git a/test/jdk/javax/swing/JProgressBar/bug5003022.java b/test/jdk/javax/swing/JProgressBar/bug5003022.java new file mode 100644 index 0000000000000..57f5fdfc45da0 --- /dev/null +++ b/test/jdk/javax/swing/JProgressBar/bug5003022.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5003022 + * @summary Test that setting zero value on JProgressBar works in GTK L&F + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug5003022 +*/ + +import java.awt.FlowLayout; +import javax.swing.JFrame; +import javax.swing.JProgressBar; +import javax.swing.UIManager; + +public class bug5003022 { + + static final String INSTRUCTIONS = """ + There are two progress bars, they should display progress strings. + The first progress bar should display 0% and the bar should show no progress color fill. + The second progress bar should display 30% and the bar should show 30% progress color fill. + If it is as described, the test PASSES, otherwise it FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug5003022 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(bug5003022::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + try { + /* This will only succeed on Linux, but the test is valid for other platforms and L&Fs */ + UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); + } catch (Exception e) { + e.printStackTrace(); + } + + JFrame frame = new JFrame("bug5003022"); + JProgressBar pb1 = new JProgressBar(); + pb1.setValue(0); + pb1.setStringPainted(true); + + JProgressBar pb2 = new JProgressBar(); + pb2.setValue(30); + pb2.setStringPainted(true); + + frame.setLayout(new FlowLayout()); + frame.add(pb1); + frame.add(pb2); + + frame.setSize(300, 300); + return frame; + } + +} From de0e6488449303bd15d4590480a2e47b8026a9b1 Mon Sep 17 00:00:00 2001 From: Andrej Pecimuth Date: Mon, 14 Apr 2025 18:31:27 +0000 Subject: [PATCH 0573/1101] 8352724: Verify bounds for primitive array reads in JVMCI Reviewed-by: dnsimon --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 13 ++++-- .../test/TestConstantReflectionProvider.java | 46 ++++++++++++++++--- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 2e42d5df55b9b..cffac62c1c8b8 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -2253,14 +2253,21 @@ static jobject read_field_value(Handle obj, long displacement, jchar type_char, if (!aligned) { JVMCI_THROW_MSG_NULL(IllegalArgumentException, "read is unaligned"); } + if (obj->is_array()) { + // Disallow reading after the last element of an array + size_t array_length = arrayOop(obj())->length(); + int lh = obj->klass()->layout_helper(); + size_t size_in_bytes = array_length << Klass::layout_helper_log2_element_size(lh); + size_in_bytes += Klass::layout_helper_header_size(lh); + if ((size_t) displacement + basic_type_elemsize > size_in_bytes) { + JVMCI_THROW_MSG_NULL(IllegalArgumentException, "reading after last array element"); + } + } if (basic_type == T_OBJECT) { if (obj->is_objArray()) { if (displacement < arrayOopDesc::base_offset_in_bytes(T_OBJECT)) { JVMCI_THROW_MSG_NULL(IllegalArgumentException, "reading from array header"); } - if (displacement + heapOopSize > arrayOopDesc::base_offset_in_bytes(T_OBJECT) + arrayOop(obj())->length() * heapOopSize) { - JVMCI_THROW_MSG_NULL(IllegalArgumentException, "reading after last array element"); - } if (((displacement - arrayOopDesc::base_offset_in_bytes(T_OBJECT)) % heapOopSize) != 0) { JVMCI_THROW_MSG_NULL(IllegalArgumentException, "misaligned object read from array"); } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java index 4a9585d995f95..128430b1902be 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,11 +41,7 @@ import java.lang.reflect.Array; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; /** * Tests for {@link ConstantReflectionProvider}. It assumes an implementation of the interface that @@ -138,4 +134,42 @@ public void unboxTest() { assertNull(constantReflection.unboxPrimitive(JavaConstant.NULL_POINTER)); } + + static class ArrayConstants { + static final byte[] BYTE_ARRAY_CONST = new byte[]{0}; + static final Object[] OBJECT_ARRAY_CONST = new Object[]{null}; + } + + @Test + public void readOnePastLastArrayElementTest() { + for (ConstantValue cv : readConstants(ArrayConstants.class)) { + if (cv.boxed != null && cv.boxed.getClass().isArray()) { + JavaKind kind = metaAccess.lookupJavaType(cv.value).getComponentType().getJavaKind(); + long offset = metaAccess.getArrayBaseOffset(kind) + (long) metaAccess.getArrayIndexScale(kind) * Array.getLength(cv.boxed); + // read array[array.length] + assertThrows(IllegalArgumentException.class, () -> { + if (kind == JavaKind.Object) { + constantReflection.getMemoryAccessProvider().readObjectConstant(cv.value, offset); + } else { + constantReflection.getMemoryAccessProvider().readPrimitiveConstant(kind, cv.value, offset, kind.getBitCount()); + } + }); + } + } + } + + static class IntArrayConstants { + static final int[] INT_ARRAY_CONST = new int[]{0}; + } + + @Test + public void readPartiallyOutOfBoundsTest() { + for (ConstantValue cv : readConstants(IntArrayConstants.class)) { + JavaKind kind = metaAccess.lookupJavaType(cv.value).getComponentType().getJavaKind(); + long offset = metaAccess.getArrayBaseOffset(kind) + (long) metaAccess.getArrayIndexScale(kind) * (Array.getLength(cv.boxed) - 1); + // read a long from array[array.length - 1], which is partially out of bounds + JavaKind accessKind = JavaKind.Long; + assertThrows(IllegalArgumentException.class, () -> constantReflection.getMemoryAccessProvider().readPrimitiveConstant(accessKind, cv.value, offset, accessKind.getBitCount())); + } + } } From 0da480a91d31ee8dc2532cfec76bbf5b1d6c4eeb Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Mon, 14 Apr 2025 18:47:59 +0000 Subject: [PATCH 0574/1101] 8354535: [BACKOUT] Force clients to explicitly pass mem_tag value, even if it is mtNone Reviewed-by: stefank, jsjolen --- .../cpu/aarch64/compressedKlass_aarch64.cpp | 4 +-- .../bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp | 2 +- src/hotspot/os/linux/os_linux.cpp | 4 +-- src/hotspot/os/posix/os_posix.cpp | 4 +-- src/hotspot/os/posix/perfMemory_posix.cpp | 2 +- src/hotspot/os/windows/os_windows.cpp | 20 ++++++------- src/hotspot/os/windows/perfMemory_windows.cpp | 2 +- src/hotspot/share/cds/archiveBuilder.cpp | 3 +- src/hotspot/share/cds/filemap.cpp | 10 +++---- src/hotspot/share/cds/metaspaceShared.cpp | 12 +++----- .../share/classfile/compactHashtable.cpp | 2 +- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 3 +- .../share/gc/parallel/parMarkBitMap.cpp | 3 +- .../share/gc/parallel/psParallelCompact.cpp | 3 +- src/hotspot/share/gc/shared/cardTable.cpp | 2 +- .../gc/shenandoah/shenandoahCardTable.cpp | 4 +-- .../share/gc/shenandoah/shenandoahHeap.cpp | 6 ++-- .../jfr/recorder/storage/jfrVirtualMemory.cpp | 3 +- .../share/memory/allocation.inline.hpp | 4 +-- src/hotspot/share/memory/memoryReserver.cpp | 8 +++--- src/hotspot/share/memory/memoryReserver.hpp | 4 +-- src/hotspot/share/memory/metaspace.cpp | 5 ++-- .../share/memory/metaspace/testHelpers.cpp | 3 +- .../memory/metaspace/virtualSpaceNode.cpp | 2 +- src/hotspot/share/nmt/memReporter.cpp | 2 +- src/hotspot/share/nmt/memReporter.hpp | 2 +- src/hotspot/share/nmt/memTracker.hpp | 4 +-- .../share/nmt/virtualMemoryTracker.hpp | 4 +-- src/hotspot/share/prims/jni.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 6 ++-- src/hotspot/share/runtime/os.cpp | 12 ++++---- src/hotspot/share/runtime/os.hpp | 16 +++++------ .../share/runtime/safepointMechanism.cpp | 2 +- src/hotspot/share/utilities/debug.cpp | 2 +- .../gtest/gc/g1/test_stressCommitUncommit.cpp | 10 +++---- test/hotspot/gtest/gc/z/test_zForwarding.cpp | 2 +- .../gtest/memory/test_virtualspace.cpp | 24 ++++++---------- .../gtest/nmt/test_nmt_locationprinting.cpp | 2 +- .../runtime/test_committed_virtualmemory.cpp | 6 ++-- test/hotspot/gtest/runtime/test_os.cpp | 28 +++++++++---------- test/hotspot/gtest/runtime/test_os_aix.cpp | 4 +-- test/hotspot/gtest/runtime/test_os_linux.cpp | 2 +- .../gtest/runtime/test_os_reserve_between.cpp | 6 ++-- .../runtime/NMT/MallocRoundingReportTest.java | 4 +-- .../jtreg/runtime/NMT/MallocTestType.java | 6 ++-- .../runtime/NMT/MallocTrackingVerify.java | 4 +-- .../runtime/NMT/ThreadedMallocTestType.java | 4 +-- 47 files changed, 126 insertions(+), 143 deletions(-) diff --git a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp index 3874c8cd54ef9..0c2d9a32c8c13 100644 --- a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp @@ -70,7 +70,7 @@ static char* reserve_at_eor_compatible_address(size_t size, bool aslr) { const uint64_t immediate = ((uint64_t)immediates[index]) << 32; assert(immediate > 0 && Assembler::operand_valid_for_logical_immediate(/*is32*/false, immediate), "Invalid immediate %d " UINT64_FORMAT, index, immediate); - result = os::attempt_reserve_memory_at((char*)immediate, size, mtNone); + result = os::attempt_reserve_memory_at((char*)immediate, size, false); if (result == nullptr) { log_trace(metaspace, map)("Failed to attach at " UINT64_FORMAT_X, immediate); } @@ -114,7 +114,7 @@ char* CompressedKlassPointers::reserve_address_space_for_compressed_classes(size if (result == nullptr) { constexpr size_t alignment = nth_bit(32); log_debug(metaspace, map)("Trying to reserve at a 32-bit-aligned address"); - result = os::reserve_memory_aligned(size, alignment, mtNone); + result = os::reserve_memory_aligned(size, alignment, false); } return result; diff --git a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp index 861fda7a71d7a..86549e878cb74 100644 --- a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp +++ b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp @@ -77,7 +77,7 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity) _initialized(false) { // Reserve address space for backing memory - _base = (uintptr_t)os::reserve_memory(max_capacity, mtJavaHeap); + _base = (uintptr_t)os::reserve_memory(max_capacity, false, mtJavaHeap); if (_base == 0) { // Failed ZInitialize::error("Failed to reserve address space for backing memory"); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index a8dce39ce5d53..4e26797cd5b3a 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4577,7 +4577,7 @@ static void workaround_expand_exec_shield_cs_limit() { */ char* hint = (char*)(os::Linux::initial_thread_stack_bottom() - (StackOverflow::stack_guard_zone_size() + page_size)); - char* codebuf = os::attempt_reserve_memory_at(hint, page_size, mtThread); + char* codebuf = os::attempt_reserve_memory_at(hint, page_size, false, mtThread); if (codebuf == nullptr) { // JDK-8197429: There may be a stack gap of one megabyte between @@ -4585,7 +4585,7 @@ static void workaround_expand_exec_shield_cs_limit() { // Linux kernel workaround for CVE-2017-1000364. If we failed to // map our codebuf, try again at an address one megabyte lower. hint -= 1 * M; - codebuf = os::attempt_reserve_memory_at(hint, page_size, mtThread); + codebuf = os::attempt_reserve_memory_at(hint, page_size, false, mtThread); } if ((codebuf == nullptr) || (!os::commit_memory(codebuf, page_size, true))) { diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 8df488768be8e..a36d6b87641e5 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -491,9 +491,9 @@ static char* chop_extra_memory(size_t size, size_t alignment, char* extra_base, // Multiple threads can race in this code, and can remap over each other with MAP_FIXED, // so on posix, unmap the section at the start and at the end of the chunk that we mapped // rather than unmapping and remapping the whole chunk to get requested alignment. -char* os::reserve_memory_aligned(size_t size, size_t alignment, MemTag mem_tag, bool exec) { +char* os::reserve_memory_aligned(size_t size, size_t alignment, bool exec) { size_t extra_size = calculate_aligned_extra_size(size, alignment); - char* extra_base = os::reserve_memory(extra_size, mem_tag, exec); + char* extra_base = os::reserve_memory(extra_size, exec); if (extra_base == nullptr) { return nullptr; } diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index cbbecea3a6a0a..4d6fc1e4b8c9e 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -64,7 +64,7 @@ static char* backing_store_file_name = nullptr; // name of the backing store static char* create_standard_memory(size_t size) { // allocate an aligned chuck of memory - char* mapAddress = os::reserve_memory(size, mtInternal); + char* mapAddress = os::reserve_memory(size); if (mapAddress == nullptr) { return nullptr; diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 843272f57b584..84e89334feb63 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -3019,7 +3019,7 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, PAGE_READWRITE); // If reservation failed, return null if (p_buf == nullptr) return nullptr; - MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC, mtNone); + MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC); os::release_memory(p_buf, bytes + chunk_size); // we still need to round up to a page boundary (in case we are using large pages) @@ -3080,7 +3080,7 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, // need to create a dummy 'reserve' record to match // the release. MemTracker::record_virtual_memory_reserve((address)p_buf, - bytes_to_release, CALLER_PC, mtNone); + bytes_to_release, CALLER_PC); os::release_memory(p_buf, bytes_to_release); } #ifdef ASSERT @@ -3098,9 +3098,9 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, // Although the memory is allocated individually, it is returned as one. // NMT records it as one block. if ((flags & MEM_COMMIT) != 0) { - MemTracker::record_virtual_memory_reserve_and_commit((address)p_buf, bytes, CALLER_PC, mtNone); + MemTracker::record_virtual_memory_reserve_and_commit((address)p_buf, bytes, CALLER_PC); } else { - MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, CALLER_PC, mtNone); + MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, CALLER_PC); } // made it this far, success @@ -3240,7 +3240,7 @@ char* os::replace_existing_mapping_with_file_mapping(char* base, size_t size, in // Multiple threads can race in this code but it's not possible to unmap small sections of // virtual space to get requested alignment, like posix-like os's. // Windows prevents multiple thread from remapping over each other so this loop is thread-safe. -static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int file_desc, MemTag mem_tag) { +static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int file_desc, MemTag mem_tag = mtNone) { assert(is_aligned(alignment, os::vm_allocation_granularity()), "Alignment must be a multiple of allocation granularity (page size)"); assert(is_aligned(size, os::vm_allocation_granularity()), @@ -3254,7 +3254,7 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi for (int attempt = 0; attempt < max_attempts && aligned_base == nullptr; attempt ++) { char* extra_base = file_desc != -1 ? os::map_memory_to_file(extra_size, file_desc, mem_tag) : - os::reserve_memory(extra_size, mem_tag); + os::reserve_memory(extra_size, false, mem_tag); if (extra_base == nullptr) { return nullptr; } @@ -3271,7 +3271,7 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi // Attempt to map, into the just vacated space, the slightly smaller aligned area. // Which may fail, hence the loop. aligned_base = file_desc != -1 ? os::attempt_map_memory_to_file_at(aligned_base, size, file_desc, mem_tag) : - os::attempt_reserve_memory_at(aligned_base, size, mem_tag); + os::attempt_reserve_memory_at(aligned_base, size, false, mem_tag); } assert(aligned_base != nullptr, @@ -3280,9 +3280,9 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi return aligned_base; } -char* os::reserve_memory_aligned(size_t size, size_t alignment, MemTag mem_tag, bool exec) { +char* os::reserve_memory_aligned(size_t size, size_t alignment, bool exec) { // exec can be ignored - return map_or_reserve_memory_aligned(size, alignment, -1/* file_desc */, mem_tag); + return map_or_reserve_memory_aligned(size, alignment, -1 /* file_desc */); } char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int fd, MemTag mem_tag) { @@ -5187,7 +5187,7 @@ char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, } // Record virtual memory allocation - MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, CALLER_PC, mtNone); + MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, CALLER_PC); DWORD bytes_read; OVERLAPPED overlapped; diff --git a/src/hotspot/os/windows/perfMemory_windows.cpp b/src/hotspot/os/windows/perfMemory_windows.cpp index 322b844f413a2..dda0acde79346 100644 --- a/src/hotspot/os/windows/perfMemory_windows.cpp +++ b/src/hotspot/os/windows/perfMemory_windows.cpp @@ -54,7 +54,7 @@ typedef BOOL (WINAPI *SetSecurityDescriptorControlFnPtr)( static char* create_standard_memory(size_t size) { // allocate an aligned chuck of memory - char* mapAddress = os::reserve_memory(size, mtInternal); + char* mapAddress = os::reserve_memory(size); if (mapAddress == nullptr) { return nullptr; diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index fa65d7d27bf95..c309de17b4cad 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -309,8 +309,7 @@ address ArchiveBuilder::reserve_buffer() { size_t buffer_size = LP64_ONLY(CompressedClassSpaceSize) NOT_LP64(256 * M); ReservedSpace rs = MemoryReserver::reserve(buffer_size, MetaspaceShared::core_region_alignment(), - os::vm_page_size(), - mtClassShared); + os::vm_page_size()); if (!rs.is_reserved()) { log_error(cds)("Failed to reserve %zu bytes of output buffer.", buffer_size); MetaspaceShared::unrecoverable_writing_error(); diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 1b5d455485c63..580699b60b583 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -1066,10 +1066,10 @@ void FileMapInfo::close() { */ static char* map_memory(int fd, const char* file_name, size_t file_offset, char *addr, size_t bytes, bool read_only, - bool allow_exec, MemTag mem_tag) { + bool allow_exec, MemTag mem_tag = mtNone) { char* mem = os::map_memory(fd, file_name, file_offset, addr, bytes, - mem_tag, AlwaysPreTouch ? false : read_only, - allow_exec); + AlwaysPreTouch ? false : read_only, + allow_exec, mem_tag); if (mem != nullptr && AlwaysPreTouch) { os::pretouch_memory(mem, mem + bytes); } @@ -1094,7 +1094,7 @@ bool FileMapInfo::remap_shared_readonly_as_readwrite() { assert(WINDOWS_ONLY(false) NOT_WINDOWS(true), "Don't call on Windows"); // Replace old mapping with new one that is writable. char *base = os::map_memory(_fd, _full_path, r->file_offset(), - addr, size, mtNone, false /* !read_only */, + addr, size, false /* !read_only */, r->allow_exec()); close(); // These have to be errors because the shared region is now unmapped. @@ -1620,7 +1620,7 @@ bool FileMapInfo::map_heap_region_impl() { } else { base = map_memory(_fd, _full_path, r->file_offset(), addr, _mapped_heap_memregion.byte_size(), r->read_only(), - r->allow_exec(), mtJavaHeap); + r->allow_exec()); if (base == nullptr || base != addr) { dealloc_heap_region(); log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap. " diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 3ca1985843033..ef2a6dcb8e63c 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -1537,8 +1537,7 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma archive_space_rs = MemoryReserver::reserve((char*)base_address, archive_space_size, archive_space_alignment, - os::vm_page_size(), - mtNone); + os::vm_page_size()); if (archive_space_rs.is_reserved()) { assert(base_address == nullptr || (address)archive_space_rs.base() == base_address, "Sanity"); @@ -1606,13 +1605,11 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma archive_space_rs = MemoryReserver::reserve((char*)base_address, archive_space_size, archive_space_alignment, - os::vm_page_size(), - mtNone); + os::vm_page_size()); class_space_rs = MemoryReserver::reserve((char*)ccs_base, class_space_size, class_space_alignment, - os::vm_page_size(), - mtNone); + os::vm_page_size()); } if (!archive_space_rs.is_reserved() || !class_space_rs.is_reserved()) { release_reserved_spaces(total_space_rs, archive_space_rs, class_space_rs); @@ -1625,8 +1622,7 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma total_space_rs = MemoryReserver::reserve((char*) base_address, total_range_size, base_address_alignment, - os::vm_page_size(), - mtNone); + os::vm_page_size()); } else { // We did not manage to reserve at the preferred address, or were instructed to relocate. In that // case we reserve wherever possible, but the start address needs to be encodable as narrow Klass diff --git a/src/hotspot/share/classfile/compactHashtable.cpp b/src/hotspot/share/classfile/compactHashtable.cpp index 15ae5ba8013e0..8d50e8136a3be 100644 --- a/src/hotspot/share/classfile/compactHashtable.cpp +++ b/src/hotspot/share/classfile/compactHashtable.cpp @@ -226,7 +226,7 @@ HashtableTextDump::HashtableTextDump(const char* filename) : _fd(-1) { if (_fd < 0) { quit("Unable to open hashtable dump file", filename); } - _base = os::map_memory(_fd, filename, 0, nullptr, _size, mtNone, true, false); + _base = os::map_memory(_fd, filename, 0, nullptr, _size, true, false); if (_base == nullptr) { quit("Unable to map hashtable dump file", filename); } diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 44fb790f7055f..31f0cc12aa5ee 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -1230,8 +1230,7 @@ G1RegionToSpaceMapper* G1CollectedHeap::create_aux_memory_mapper(const char* des // Allocate a new reserved space, preferring to use large pages. ReservedSpace rs = MemoryReserver::reserve(size, alignment, - preferred_page_size, - mtGC); + preferred_page_size); size_t page_size = rs.page_size(); G1RegionToSpaceMapper* result = diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp index d2d168cc2c0db..f33d7f93f1db6 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp @@ -48,8 +48,7 @@ ParMarkBitMap::initialize(MemRegion covered_region) ReservedSpace rs = MemoryReserver::reserve(_reserved_byte_size, rs_align, - page_sz, - mtGC); + page_sz); if (!rs.is_reserved()) { // Failed to reserve memory for the bitmap, diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 84ed77986910f..99b975c282a91 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -246,8 +246,7 @@ ParallelCompactData::create_vspace(size_t count, size_t element_size) ReservedSpace rs = MemoryReserver::reserve(_reserved_byte_size, rs_align, - page_sz, - mtGC); + page_sz); if (!rs.is_reserved()) { // Failed to reserve memory. diff --git a/src/hotspot/share/gc/shared/cardTable.cpp b/src/hotspot/share/gc/shared/cardTable.cpp index 24546618edbcc..3236d73933c49 100644 --- a/src/hotspot/share/gc/shared/cardTable.cpp +++ b/src/hotspot/share/gc/shared/cardTable.cpp @@ -80,7 +80,7 @@ void CardTable::initialize(void* region0_start, void* region1_start) { HeapWord* high_bound = _whole_heap.end(); const size_t rs_align = MAX2(_page_size, os::vm_allocation_granularity()); - ReservedSpace rs = MemoryReserver::reserve(_byte_map_size, rs_align, _page_size, mtGC); + ReservedSpace rs = MemoryReserver::reserve(_byte_map_size, rs_align, _page_size); if (!rs.is_reserved()) { vm_exit_during_initialization("Could not reserve enough space for the " diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCardTable.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCardTable.cpp index e9e52475fb92b..00f119384895b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCardTable.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCardTable.cpp @@ -45,7 +45,7 @@ void ShenandoahCardTable::initialize() { // ReservedSpace constructor would assert rs_align >= os::vm_page_size(). const size_t rs_align = MAX2(_page_size, granularity); - ReservedSpace write_space = MemoryReserver::reserve(_byte_map_size, rs_align, _page_size, mtGC); + ReservedSpace write_space = MemoryReserver::reserve(_byte_map_size, rs_align, _page_size); initialize(write_space); // The assembler store_check code will do an unsigned shift of the oop, @@ -60,7 +60,7 @@ void ShenandoahCardTable::initialize() { _write_byte_map = _byte_map; _write_byte_map_base = _byte_map_base; - ReservedSpace read_space = MemoryReserver::reserve(_byte_map_size, rs_align, _page_size, mtGC); + ReservedSpace read_space = MemoryReserver::reserve(_byte_map_size, rs_align, _page_size); initialize(read_space); _read_byte_map = (CardValue*) read_space.base(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index ce4b9fc2406e4..045f485090d2c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -166,7 +166,7 @@ static ReservedSpace reserve(size_t size, size_t preferred_page_size) { size = align_up(size, alignment); } - const ReservedSpace reserved = MemoryReserver::reserve(size, alignment, preferred_page_size, mtGC); + const ReservedSpace reserved = MemoryReserver::reserve(size, alignment, preferred_page_size); if (!reserved.is_reserved()) { vm_exit_during_initialization("Could not reserve space"); } @@ -380,7 +380,7 @@ jint ShenandoahHeap::initialize() { for (uintptr_t addr = min; addr <= max; addr <<= 1u) { char* req_addr = (char*)addr; assert(is_aligned(req_addr, cset_align), "Should be aligned"); - cset_rs = MemoryReserver::reserve(req_addr, cset_size, cset_align, cset_page_size, mtGC); + cset_rs = MemoryReserver::reserve(req_addr, cset_size, cset_align, cset_page_size); if (cset_rs.is_reserved()) { assert(cset_rs.base() == req_addr, "Allocated where requested: " PTR_FORMAT ", " PTR_FORMAT, p2i(cset_rs.base()), addr); _collection_set = new ShenandoahCollectionSet(this, cset_rs, sh_rs.base()); @@ -389,7 +389,7 @@ jint ShenandoahHeap::initialize() { } if (_collection_set == nullptr) { - cset_rs = MemoryReserver::reserve(cset_size, cset_align, os::vm_page_size(), mtGC); + cset_rs = MemoryReserver::reserve(cset_size, cset_align, os::vm_page_size()); if (!cset_rs.is_reserved()) { vm_exit_during_initialization("Cannot reserve memory for collection set"); } diff --git a/src/hotspot/share/jfr/recorder/storage/jfrVirtualMemory.cpp b/src/hotspot/share/jfr/recorder/storage/jfrVirtualMemory.cpp index 0ba54fc79bed3..97f2b8a1990b0 100644 --- a/src/hotspot/share/jfr/recorder/storage/jfrVirtualMemory.cpp +++ b/src/hotspot/share/jfr/recorder/storage/jfrVirtualMemory.cpp @@ -106,8 +106,7 @@ bool JfrVirtualMemorySegment::initialize(size_t reservation_size_request_bytes) assert(is_aligned(reservation_size_request_bytes, os::vm_allocation_granularity()), "invariant"); _rs = MemoryReserver::reserve(reservation_size_request_bytes, os::vm_allocation_granularity(), - os::vm_page_size(), - mtTracing); + os::vm_page_size()); if (!_rs.is_reserved()) { return false; } diff --git a/src/hotspot/share/memory/allocation.inline.hpp b/src/hotspot/share/memory/allocation.inline.hpp index 01af1616ce18f..8d531c6dd2318 100644 --- a/src/hotspot/share/memory/allocation.inline.hpp +++ b/src/hotspot/share/memory/allocation.inline.hpp @@ -58,7 +58,7 @@ template E* MmapArrayAllocator::allocate_or_null(size_t length, MemTag mem_tag) { size_t size = size_for(length); - char* addr = os::reserve_memory(size, mem_tag); + char* addr = os::reserve_memory(size, !ExecMem, mem_tag); if (addr == nullptr) { return nullptr; } @@ -75,7 +75,7 @@ template E* MmapArrayAllocator::allocate(size_t length, MemTag mem_tag) { size_t size = size_for(length); - char* addr = os::reserve_memory(size, mem_tag); + char* addr = os::reserve_memory(size, !ExecMem, mem_tag); if (addr == nullptr) { vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "Allocator (reserve)"); } diff --git a/src/hotspot/share/memory/memoryReserver.cpp b/src/hotspot/share/memory/memoryReserver.cpp index 457818139cda9..43cc71355ffce 100644 --- a/src/hotspot/share/memory/memoryReserver.cpp +++ b/src/hotspot/share/memory/memoryReserver.cpp @@ -90,13 +90,13 @@ static char* reserve_memory_inner(char* requested_address, assert(is_aligned(requested_address, alignment), "Requested address " PTR_FORMAT " must be aligned to %zu", p2i(requested_address), alignment); - return os::attempt_reserve_memory_at(requested_address, size, mem_tag, exec); + return os::attempt_reserve_memory_at(requested_address, size, exec, mem_tag); } // Optimistically assume that the OS returns an aligned base pointer. // When reserving a large address range, most OSes seem to align to at // least 64K. - char* base = os::reserve_memory(size, mem_tag, exec); + char* base = os::reserve_memory(size, exec, mem_tag); if (is_aligned(base, alignment)) { return base; } @@ -107,7 +107,7 @@ static char* reserve_memory_inner(char* requested_address, } // Map using the requested alignment. - return os::reserve_memory_aligned(size, alignment, mem_tag, exec); + return os::reserve_memory_aligned(size, alignment, exec); } ReservedSpace MemoryReserver::reserve_memory(char* requested_address, @@ -261,7 +261,7 @@ static char* map_memory_to_file(char* requested_address, // Optimistically assume that the OS returns an aligned base pointer. // When reserving a large address range, most OSes seem to align to at // least 64K. - char* base = os::map_memory_to_file(size, fd, mem_tag); + char* base = os::map_memory_to_file(size, fd); if (is_aligned(base, alignment)) { return base; } diff --git a/src/hotspot/share/memory/memoryReserver.hpp b/src/hotspot/share/memory/memoryReserver.hpp index f8f642cca9537..1e16ec252a9de 100644 --- a/src/hotspot/share/memory/memoryReserver.hpp +++ b/src/hotspot/share/memory/memoryReserver.hpp @@ -58,12 +58,12 @@ class MemoryReserver : AllStatic { size_t size, size_t alignment, size_t page_size, - MemTag mem_tag); + MemTag mem_tag = mtNone); static ReservedSpace reserve(size_t size, size_t alignment, size_t page_size, - MemTag mem_tag); + MemTag mem_tag = mtNone); static ReservedSpace reserve(size_t size, MemTag mem_tag); diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index 33cd4a75d7e5d..04e5d807f3244 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -594,7 +594,7 @@ ReservedSpace Metaspace::reserve_address_space_for_compressed_classes(size_t siz if (result == nullptr) { // Fallback: reserve anywhere log_debug(metaspace, map)("Trying anywhere..."); - result = os::reserve_memory_aligned(size, Metaspace::reserve_alignment(), mtClass); + result = os::reserve_memory_aligned(size, Metaspace::reserve_alignment(), false); } // Wrap resulting range in ReservedSpace @@ -767,8 +767,7 @@ void Metaspace::global_initialize() { rs = MemoryReserver::reserve((char*)base, size, Metaspace::reserve_alignment(), - os::vm_page_size(), - mtClass); + os::vm_page_size()); if (rs.is_reserved()) { log_info(metaspace)("Successfully forced class space address to " PTR_FORMAT, p2i(base)); diff --git a/src/hotspot/share/memory/metaspace/testHelpers.cpp b/src/hotspot/share/memory/metaspace/testHelpers.cpp index f06f6c855bed5..76fa1e36c4523 100644 --- a/src/hotspot/share/memory/metaspace/testHelpers.cpp +++ b/src/hotspot/share/memory/metaspace/testHelpers.cpp @@ -82,7 +82,7 @@ MetaspaceTestContext::MetaspaceTestContext(const char* name, size_t commit_limit reserve_limit, Metaspace::reserve_alignment_words()); if (reserve_limit > 0) { // have reserve limit -> non-expandable context - _rs = MemoryReserver::reserve(reserve_limit * BytesPerWord, Metaspace::reserve_alignment(), os::vm_page_size(), mtTest); + _rs = MemoryReserver::reserve(reserve_limit * BytesPerWord, Metaspace::reserve_alignment(), os::vm_page_size()); _context = MetaspaceContext::create_nonexpandable_context(name, _rs, &_commit_limiter); } else { // no reserve limit -> expandable vslist @@ -142,3 +142,4 @@ size_t MetaspaceTestContext::reserved_words() const { } } // namespace metaspace + diff --git a/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp b/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp index bb59192cf16cb..66644c805a938 100644 --- a/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp +++ b/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp @@ -256,7 +256,7 @@ VirtualSpaceNode* VirtualSpaceNode::create_node(size_t word_size, ReservedSpace rs = MemoryReserver::reserve(word_size * BytesPerWord, Settings::virtual_space_node_reserve_alignment_words() * BytesPerWord, - os::vm_page_size(), mtMetaspace); + os::vm_page_size()); if (!rs.is_reserved()) { vm_exit_out_of_memory(word_size * BytesPerWord, OOM_MMAP_ERROR, "Failed to reserve memory for metaspace"); } diff --git a/src/hotspot/share/nmt/memReporter.cpp b/src/hotspot/share/nmt/memReporter.cpp index 512e197592962..c7327782a4ad7 100644 --- a/src/hotspot/share/nmt/memReporter.cpp +++ b/src/hotspot/share/nmt/memReporter.cpp @@ -249,7 +249,7 @@ void MemSummaryReporter::report_summary_of_tag(MemTag mem_tag, // report malloc'd memory if (amount_in_current_scale(MAX2(malloc_memory->malloc_size(), pk_malloc)) > 0) { - print_malloc(malloc_memory->malloc_counter(), mem_tag); + print_malloc(malloc_memory->malloc_counter()); out->cr(); } diff --git a/src/hotspot/share/nmt/memReporter.hpp b/src/hotspot/share/nmt/memReporter.hpp index 2238d42f15fbd..05b1588f38b34 100644 --- a/src/hotspot/share/nmt/memReporter.hpp +++ b/src/hotspot/share/nmt/memReporter.hpp @@ -108,7 +108,7 @@ class MemReporterBase : public StackObj { // Print summary total, malloc and virtual memory void print_total(size_t reserved, size_t committed, size_t peak = 0) const; - void print_malloc(const MemoryCounter* c, MemTag mem_tag) const; + void print_malloc(const MemoryCounter* c, MemTag mem_tag = mtNone) const; void print_virtual_memory(size_t reserved, size_t committed, size_t peak) const; void print_arena(const MemoryCounter* c) const; diff --git a/src/hotspot/share/nmt/memTracker.hpp b/src/hotspot/share/nmt/memTracker.hpp index 3918e81dab72b..981e991a41ef4 100644 --- a/src/hotspot/share/nmt/memTracker.hpp +++ b/src/hotspot/share/nmt/memTracker.hpp @@ -127,7 +127,7 @@ class MemTracker : AllStatic { // (we do not do any reservations before that). static inline void record_virtual_memory_reserve(void* addr, size_t size, const NativeCallStack& stack, - MemTag mem_tag) { + MemTag mem_tag = mtNone) { assert_post_init(); if (!enabled()) return; if (addr != nullptr) { @@ -153,7 +153,7 @@ class MemTracker : AllStatic { } static inline void record_virtual_memory_reserve_and_commit(void* addr, size_t size, - const NativeCallStack& stack, MemTag mem_tag) { + const NativeCallStack& stack, MemTag mem_tag = mtNone) { assert_post_init(); if (!enabled()) return; if (addr != nullptr) { diff --git a/src/hotspot/share/nmt/virtualMemoryTracker.hpp b/src/hotspot/share/nmt/virtualMemoryTracker.hpp index 2b3b572257114..74d299e6637f6 100644 --- a/src/hotspot/share/nmt/virtualMemoryTracker.hpp +++ b/src/hotspot/share/nmt/virtualMemoryTracker.hpp @@ -297,7 +297,7 @@ class ReservedMemoryRegion : public VirtualMemoryRegion { public: ReservedMemoryRegion(address base, size_t size, const NativeCallStack& stack, - MemTag mem_tag) : + MemTag mem_tag = mtNone) : VirtualMemoryRegion(base, size), _stack(stack), _mem_tag(mem_tag) { } @@ -380,7 +380,7 @@ class VirtualMemoryTracker : AllStatic { public: static bool initialize(NMT_TrackingLevel level); - static bool add_reserved_region (address base_addr, size_t size, const NativeCallStack& stack, MemTag mem_tag); + static bool add_reserved_region (address base_addr, size_t size, const NativeCallStack& stack, MemTag mem_tag = mtNone); static bool add_committed_region (address base_addr, size_t size, const NativeCallStack& stack); static bool remove_uncommitted_region (address base_addr, size_t size); diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index c988745f7b628..d2916fad1850d 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -2400,7 +2400,7 @@ static char* get_bad_address() { static char* bad_address = nullptr; if (bad_address == nullptr) { size_t size = os::vm_allocation_granularity(); - bad_address = os::reserve_memory(size, mtInternal); + bad_address = os::reserve_memory(size, false, mtInternal); if (bad_address != nullptr) { os::protect_memory(bad_address, size, os::MEM_PROT_READ, /*is_committed*/false); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 884fbf981382a..e08a5ba5ebd12 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -728,11 +728,11 @@ WB_ENTRY(void, WB_NMTFree(JNIEnv* env, jobject o, jlong mem)) WB_END WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size)) - return (jlong)(uintptr_t)os::reserve_memory(size, mtTest); + return (jlong)(uintptr_t)os::reserve_memory(size, false, mtTest); WB_END WB_ENTRY(jlong, WB_NMTAttemptReserveMemoryAt(JNIEnv* env, jobject o, jlong addr, jlong size)) - return (jlong)(uintptr_t)os::attempt_reserve_memory_at((char*)(uintptr_t)addr, (size_t)size, mtTest); + return (jlong)(uintptr_t)os::attempt_reserve_memory_at((char*)(uintptr_t)addr, (size_t)size, false, mtTest); WB_END WB_ENTRY(void, WB_NMTCommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size)) @@ -1524,7 +1524,7 @@ WB_ENTRY(void, WB_ReadReservedMemory(JNIEnv* env, jobject o)) static char c; static volatile char* p; - p = os::reserve_memory(os::vm_allocation_granularity(), mtTest); + p = os::reserve_memory(os::vm_allocation_granularity()); if (p == nullptr) { THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "Failed to reserve memory"); } diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 7695fed564dbe..cbe40ca214bba 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1916,7 +1916,7 @@ bool os::create_stack_guard_pages(char* addr, size_t bytes) { return os::pd_create_stack_guard_pages(addr, bytes); } -char* os::reserve_memory(size_t bytes, MemTag mem_tag, bool executable) { +char* os::reserve_memory(size_t bytes, bool executable, MemTag mem_tag) { char* result = pd_reserve_memory(bytes, executable); if (result != nullptr) { MemTracker::record_virtual_memory_reserve(result, bytes, CALLER_PC, mem_tag); @@ -1927,7 +1927,7 @@ char* os::reserve_memory(size_t bytes, MemTag mem_tag, bool executable) { return result; } -char* os::attempt_reserve_memory_at(char* addr, size_t bytes, MemTag mem_tag, bool executable) { +char* os::attempt_reserve_memory_at(char* addr, size_t bytes, bool executable, MemTag mem_tag) { char* result = SimulateFullAddressSpace ? nullptr : pd_attempt_reserve_memory_at(addr, bytes, executable); if (result != nullptr) { MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC, mem_tag); @@ -2133,7 +2133,7 @@ char* os::attempt_reserve_memory_between(char* min, char* max, size_t bytes, siz assert(is_aligned(result, alignment), "alignment invalid (" ERRFMT ")", ERRFMTARGS); log_trace(os, map)(ERRFMT, ERRFMTARGS); log_debug(os, map)("successfully attached at " PTR_FORMAT, p2i(result)); - MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC, mtNone); + MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); } else { log_debug(os, map)("failed to attach anywhere in [" PTR_FORMAT "-" PTR_FORMAT ")", p2i(min), p2i(max)); } @@ -2300,8 +2300,8 @@ char* os::attempt_map_memory_to_file_at(char* addr, size_t bytes, int file_desc, } char* os::map_memory(int fd, const char* file_name, size_t file_offset, - char *addr, size_t bytes, MemTag mem_tag, - bool read_only, bool allow_exec) { + char *addr, size_t bytes, bool read_only, + bool allow_exec, MemTag mem_tag) { char* result = pd_map_memory(fd, file_name, file_offset, addr, bytes, read_only, allow_exec); if (result != nullptr) { MemTracker::record_virtual_memory_reserve_and_commit((address)result, bytes, CALLER_PC, mem_tag); @@ -2339,7 +2339,7 @@ char* os::reserve_memory_special(size_t size, size_t alignment, size_t page_size char* result = pd_reserve_memory_special(size, alignment, page_size, addr, executable); if (result != nullptr) { // The memory is committed - MemTracker::record_virtual_memory_reserve_and_commit((address)result, size, CALLER_PC, mtNone); + MemTracker::record_virtual_memory_reserve_and_commit((address)result, size, CALLER_PC); log_debug(os, map)("Reserved and committed " RANGEFMT, RANGEFMTARGS(result, size)); } else { log_info(os, map)("Reserve and commit failed (%zu bytes)", size); diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index b9a3bf564f7e4..242959034afb1 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -457,14 +457,14 @@ class os: AllStatic { inline static size_t cds_core_region_alignment(); // Reserves virtual memory. - static char* reserve_memory(size_t bytes, MemTag mem_tag, bool executable = false); + static char* reserve_memory(size_t bytes, bool executable = false, MemTag mem_tag = mtNone); // Reserves virtual memory that starts at an address that is aligned to 'alignment'. - static char* reserve_memory_aligned(size_t size, size_t alignment, MemTag mem_tag, bool executable = false); + static char* reserve_memory_aligned(size_t size, size_t alignment, bool executable = false); // Attempts to reserve the virtual memory at [addr, addr + bytes). // Does not overwrite existing mappings. - static char* attempt_reserve_memory_at(char* addr, size_t bytes, MemTag mem_tag, bool executable = false); + static char* attempt_reserve_memory_at(char* addr, size_t bytes, bool executable = false, MemTag mem_tag = mtNone); // Given an address range [min, max), attempts to reserve memory within this area, with the given alignment. // If randomize is true, the location will be randomized. @@ -516,16 +516,16 @@ class os: AllStatic { static int create_file_for_heap(const char* dir); // Map memory to the file referred by fd. This function is slightly different from map_memory() // and is added to be used for implementation of -XX:AllocateHeapAt - static char* map_memory_to_file(size_t size, int fd, MemTag mem_tag); - static char* map_memory_to_file_aligned(size_t size, size_t alignment, int fd, MemTag mem_tag); + static char* map_memory_to_file(size_t size, int fd, MemTag mem_tag = mtNone); + static char* map_memory_to_file_aligned(size_t size, size_t alignment, int fd, MemTag mem_tag = mtNone); static char* map_memory_to_file(char* base, size_t size, int fd); - static char* attempt_map_memory_to_file_at(char* base, size_t size, int fd, MemTag mem_tag); + static char* attempt_map_memory_to_file_at(char* base, size_t size, int fd, MemTag mem_tag = mtNone); // Replace existing reserved memory with file mapping static char* replace_existing_mapping_with_file_mapping(char* base, size_t size, int fd); static char* map_memory(int fd, const char* file_name, size_t file_offset, - char *addr, size_t bytes, MemTag mem_tag, bool read_only = false, - bool allow_exec = false); + char *addr, size_t bytes, bool read_only = false, + bool allow_exec = false, MemTag mem_tag = mtNone); static bool unmap_memory(char *addr, size_t bytes); static void disclaim_memory(char *addr, size_t bytes); static void realign_memory(char *addr, size_t bytes, size_t alignment_hint); diff --git a/src/hotspot/share/runtime/safepointMechanism.cpp b/src/hotspot/share/runtime/safepointMechanism.cpp index 71224bbff4c88..51038d764bb63 100644 --- a/src/hotspot/share/runtime/safepointMechanism.cpp +++ b/src/hotspot/share/runtime/safepointMechanism.cpp @@ -57,7 +57,7 @@ void SafepointMechanism::default_initialize() { // Polling page const size_t page_size = os::vm_page_size(); const size_t allocation_size = 2 * page_size; - char* polling_page = os::reserve_memory(allocation_size, mtSafepoint); + char* polling_page = os::reserve_memory(allocation_size, !ExecMem, mtSafepoint); os::commit_memory_or_exit(polling_page, allocation_size, !ExecMem, "Unable to commit Safepoint polling page"); char* bad_page = polling_page; diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp index abe3d6757b5fb..9413f1f72d7a9 100644 --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -712,7 +712,7 @@ struct TestMultipleStaticAssertFormsInClassScope { // Support for showing register content on asserts/guarantees. #ifdef CAN_SHOW_REGISTERS_ON_ASSERT void initialize_assert_poison() { - char* page = os::reserve_memory(os::vm_page_size(), mtInternal); + char* page = os::reserve_memory(os::vm_page_size(), !ExecMem, mtInternal); if (page) { if (os::commit_memory(page, os::vm_page_size(), !ExecMem) && os::protect_memory(page, os::vm_page_size(), os::MEM_PROT_NONE)) { diff --git a/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp b/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp index 45da22ce116be..bc0ed0f3c597f 100644 --- a/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp +++ b/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp @@ -82,8 +82,7 @@ TEST_VM(G1RegionToSpaceMapper, smallStressAdjacent) { ReservedSpace rs = MemoryReserver::reserve(size, os::vm_allocation_granularity(), - os::vm_page_size(), - mtTest); + os::vm_page_size()); G1RegionToSpaceMapper* small_mapper = G1RegionToSpaceMapper::create_mapper(rs, @@ -91,7 +90,7 @@ TEST_VM(G1RegionToSpaceMapper, smallStressAdjacent) { page_size, region_size, G1BlockOffsetTable::heap_map_factor(), - mtTest); + mtGC); @@ -109,15 +108,14 @@ TEST_VM(G1RegionToSpaceMapper, largeStressAdjacent) { ReservedSpace rs = MemoryReserver::reserve(size, os::vm_allocation_granularity(), - os::vm_page_size(), - mtTest); + os::vm_page_size()); G1RegionToSpaceMapper* large_mapper = G1RegionToSpaceMapper::create_mapper(rs, size, page_size, region_size, G1BlockOffsetTable::heap_map_factor(), - mtTest); + mtGC); G1TestCommitUncommit task(large_mapper); G1MapperWorkers::run_task(&task); diff --git a/test/hotspot/gtest/gc/z/test_zForwarding.cpp b/test/hotspot/gtest/gc/z/test_zForwarding.cpp index f22eef5085827..71fb83827c747 100644 --- a/test/hotspot/gtest/gc/z/test_zForwarding.cpp +++ b/test/hotspot/gtest/gc/z/test_zForwarding.cpp @@ -56,7 +56,7 @@ class ZForwardingTest : public Test { const size_t increment = MAX2(align_up(unused / 100, ZGranuleSize), ZGranuleSize); for (uintptr_t start = 0; start + ZGranuleSize <= ZAddressOffsetMax; start += increment) { - char* const reserved = os::attempt_reserve_memory_at((char*)ZAddressHeapBase + start, ZGranuleSize, mtTest); + char* const reserved = os::attempt_reserve_memory_at((char*)ZAddressHeapBase + start, ZGranuleSize, false /* executable */); if (reserved != nullptr) { // Success return reserved; diff --git a/test/hotspot/gtest/memory/test_virtualspace.cpp b/test/hotspot/gtest/memory/test_virtualspace.cpp index d2f8927ba28f7..d3fed31da0bfc 100644 --- a/test/hotspot/gtest/memory/test_virtualspace.cpp +++ b/test/hotspot/gtest/memory/test_virtualspace.cpp @@ -73,7 +73,7 @@ namespace { static void test_reserved_size_alignment(size_t size, size_t alignment) { ASSERT_PRED2(is_size_aligned, size, alignment) << "Incorrect input parameters"; size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); - ReservedSpace rs = MemoryReserver::reserve(size, alignment, page_size, mtTest); + ReservedSpace rs = MemoryReserver::reserve(size, alignment, page_size); ASSERT_TRUE(rs.base() != nullptr) << "rs.special = " << rs.special(); ASSERT_EQ(size, rs.size()) << "rs.special = " << rs.special(); @@ -101,7 +101,7 @@ namespace { bool large = maybe_large && UseLargePages && size >= os::large_page_size(); size_t page_size = large ? os::large_page_size() : os::vm_page_size(); - ReservedSpace rs = MemoryReserver::reserve(size, alignment, page_size, mtTest); + ReservedSpace rs = MemoryReserver::reserve(size, alignment, page_size); MemoryReleaser releaser(&rs); EXPECT_TRUE(rs.base() != nullptr) << "rs.special: " << rs.special(); @@ -217,8 +217,7 @@ namespace { case Commit: return MemoryReserver::reserve(reserve_size_aligned, os::vm_allocation_granularity(), - os::vm_page_size(), - mtTest); + os::vm_page_size()); } } @@ -297,7 +296,7 @@ TEST_VM(VirtualSpace, actual_committed_space_one_large_page) { size_t large_page_size = os::large_page_size(); - ReservedSpace reserved = MemoryReserver::reserve(large_page_size, large_page_size, large_page_size, mtTest); + ReservedSpace reserved = MemoryReserver::reserve(large_page_size, large_page_size, large_page_size); ReservedSpaceReleaser releaser(&reserved); ASSERT_TRUE(reserved.is_reserved()); @@ -366,8 +365,7 @@ class TestReservedSpace : AllStatic { size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); ReservedSpace rs = MemoryReserver::reserve(size, alignment, - page_size, - mtTest); + page_size); EXPECT_TRUE(rs.base() != nullptr); EXPECT_EQ(rs.size(), size) << "rs.size: " << rs.size(); @@ -412,8 +410,7 @@ class TestReservedSpace : AllStatic { ReservedSpace rs = MemoryReserver::reserve(size, alignment, - page_size, - mtTest); + page_size); EXPECT_TRUE(rs.base() != nullptr); EXPECT_EQ(rs.size(), size) << "rs.size: " << rs.size(); @@ -517,14 +514,12 @@ class TestVirtualSpace : AllStatic { default: case Default: case Reserve: - return MemoryReserver::reserve(reserve_size_aligned, - mtTest); + return MemoryReserver::reserve(reserve_size_aligned, mtTest); case Disable: case Commit: return MemoryReserver::reserve(reserve_size_aligned, os::vm_allocation_granularity(), - os::vm_page_size(), - mtTest); + os::vm_page_size()); } } @@ -581,8 +576,7 @@ class TestVirtualSpace : AllStatic { ReservedSpace reserved = MemoryReserver::reserve(large_page_size, large_page_size, - large_page_size, - mtTest); + large_page_size); ASSERT_TRUE(reserved.is_reserved()); diff --git a/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp b/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp index c8711004f1052..e0e3c28910225 100644 --- a/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp @@ -113,7 +113,7 @@ TEST_VM(NMT, DISABLED_location_printing_cheap_dead_7) { test_for_dead_c_heap_blo #endif static void test_for_mmap(size_t sz, ssize_t offset) { - char* addr = os::reserve_memory(sz, mtTest); + char* addr = os::reserve_memory(sz, false, mtTest); if (MemTracker::enabled()) { test_pointer(addr + offset, true, "in mmap'd memory region"); } else { diff --git a/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp index f07b45bc32d6b..de63e1807c13f 100644 --- a/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp +++ b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp @@ -91,7 +91,7 @@ class CommittedVirtualMemoryTest { static void test_committed_region_impl(size_t num_pages, size_t touch_pages, int* page_num) { const size_t page_sz = os::vm_page_size(); const size_t size = num_pages * page_sz; - char* base = os::reserve_memory(size, mtThreadStack); + char* base = os::reserve_memory(size, !ExecMem, mtThreadStack); bool result = os::commit_memory(base, size, !ExecMem); size_t index; ASSERT_NE(base, (char*)nullptr); @@ -159,7 +159,7 @@ class CommittedVirtualMemoryTest { const size_t page_sz = os::vm_page_size(); const size_t num_pages = 4; const size_t size = num_pages * page_sz; - char* base = os::reserve_memory(size, mtTest); + char* base = os::reserve_memory(size, !ExecMem, mtTest); ASSERT_NE(base, (char*)nullptr); result = os::commit_memory(base, size, !ExecMem); @@ -205,7 +205,7 @@ class CommittedVirtualMemoryTest { const size_t page_sz = os::vm_page_size(); const size_t size = num_pages * page_sz; - char* base = os::reserve_memory(size, mtTest); + char* base = os::reserve_memory(size, !ExecMem, mtTest); ASSERT_NE(base, (char*)nullptr); result = os::commit_memory(base, size, !ExecMem); diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 6b7653f5eecfd..ee6d1427d0b8b 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -258,7 +258,7 @@ TEST_VM(os, test_print_hex_dump) { // two pages, first one protected. const size_t ps = os::vm_page_size(); - char* two_pages = os::reserve_memory(ps * 2, mtTest); + char* two_pages = os::reserve_memory(ps * 2, false, mtTest); os::commit_memory(two_pages, ps * 2, false); os::protect_memory(two_pages, ps, os::MEM_PROT_NONE, true); @@ -492,7 +492,7 @@ TEST_VM(os, realpath) { static inline bool can_reserve_executable_memory(void) { bool executable = true; size_t len = 128; - char* p = os::reserve_memory(len, mtTest, executable); + char* p = os::reserve_memory(len, executable); bool exec_supported = (p != nullptr); if (exec_supported) { os::release_memory(p, len); @@ -530,7 +530,7 @@ static address reserve_multiple(int num_stripes, size_t stripe_len) { for (int tries = 0; tries < 256 && p == nullptr; tries ++) { size_t total_range_len = num_stripes * stripe_len; // Reserve a large contiguous area to get the address space... - p = (address)os::reserve_memory(total_range_len, mtTest); + p = (address)os::reserve_memory(total_range_len); EXPECT_NE(p, (address)nullptr); // .. release it... EXPECT_TRUE(os::release_memory((char*)p, total_range_len)); @@ -544,7 +544,7 @@ static address reserve_multiple(int num_stripes, size_t stripe_len) { #else const bool executable = stripe % 2 == 0; #endif - q = (address)os::attempt_reserve_memory_at((char*)q, stripe_len, mtTest, executable); + q = (address)os::attempt_reserve_memory_at((char*)q, stripe_len, executable); if (q == nullptr) { // Someone grabbed that area concurrently. Cleanup, then retry. tty->print_cr("reserve_multiple: retry (%d)...", stripe); @@ -564,7 +564,7 @@ static address reserve_multiple(int num_stripes, size_t stripe_len) { static address reserve_one_commit_multiple(int num_stripes, size_t stripe_len) { assert(is_aligned(stripe_len, os::vm_allocation_granularity()), "Sanity"); size_t total_range_len = num_stripes * stripe_len; - address p = (address)os::reserve_memory(total_range_len, mtTest); + address p = (address)os::reserve_memory(total_range_len); EXPECT_NE(p, (address)nullptr); for (int stripe = 0; stripe < num_stripes; stripe++) { address q = p + (stripe * stripe_len); @@ -631,7 +631,7 @@ TEST_VM(os, release_multi_mappings) { PRINT_MAPPINGS("B"); // ...re-reserve the middle stripes. This should work unless release silently failed. - address p2 = (address)os::attempt_reserve_memory_at((char*)p_middle_stripes, middle_stripe_len, mtTest); + address p2 = (address)os::attempt_reserve_memory_at((char*)p_middle_stripes, middle_stripe_len); ASSERT_EQ(p2, p_middle_stripes); @@ -654,7 +654,7 @@ TEST_VM_ASSERT_MSG(os, release_bad_ranges, ".*bad release") { #else TEST_VM(os, release_bad_ranges) { #endif - char* p = os::reserve_memory(4 * M, mtTest); + char* p = os::reserve_memory(4 * M); ASSERT_NE(p, (char*)nullptr); // Release part of range ASSERT_FALSE(os::release_memory(p, M)); @@ -689,7 +689,7 @@ TEST_VM(os, release_one_mapping_multi_commits) { // // make things even more difficult by trying to reserve at the border of the region address border = p + num_stripes * stripe_len; - address p2 = (address)os::attempt_reserve_memory_at((char*)border, stripe_len, mtTest); + address p2 = (address)os::attempt_reserve_memory_at((char*)border, stripe_len); PRINT_MAPPINGS("B"); ASSERT_TRUE(p2 == nullptr || p2 == border); @@ -730,7 +730,7 @@ TEST_VM(os, show_mappings_small_range) { TEST_VM(os, show_mappings_full_range) { // Reserve a small range and fill it with a marker string, should show up // on implementations displaying range snippets - char* p = os::reserve_memory(1 * M, mtTest); + char* p = os::reserve_memory(1 * M, false, mtInternal); if (p != nullptr) { if (os::commit_memory(p, 1 * M, false)) { strcpy(p, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); @@ -754,7 +754,7 @@ TEST_VM(os, find_mapping_simple) { // A simple allocation { - address p = (address)os::reserve_memory(total_range_len, mtTest); + address p = (address)os::reserve_memory(total_range_len); ASSERT_NE(p, (address)nullptr); PRINT_MAPPINGS("A"); for (size_t offset = 0; offset < total_range_len; offset += 4711) { @@ -1059,9 +1059,9 @@ TEST_VM(os, open_O_CLOEXEC) { } TEST_VM(os, reserve_at_wish_address_shall_not_replace_mappings_smallpages) { - char* p1 = os::reserve_memory(M, mtTest); + char* p1 = os::reserve_memory(M, false, mtTest); ASSERT_NE(p1, nullptr); - char* p2 = os::attempt_reserve_memory_at(p1, M, mtTest); + char* p2 = os::attempt_reserve_memory_at(p1, M); ASSERT_EQ(p2, nullptr); // should have failed os::release_memory(p1, M); } @@ -1069,7 +1069,7 @@ TEST_VM(os, reserve_at_wish_address_shall_not_replace_mappings_smallpages) { TEST_VM(os, reserve_at_wish_address_shall_not_replace_mappings_largepages) { if (UseLargePages && !os::can_commit_large_page_memory()) { // aka special const size_t lpsz = os::large_page_size(); - char* p1 = os::reserve_memory_aligned(lpsz, lpsz, mtTest); + char* p1 = os::reserve_memory_aligned(lpsz, lpsz, false); ASSERT_NE(p1, nullptr); char* p2 = os::reserve_memory_special(lpsz, lpsz, lpsz, p1, false); ASSERT_EQ(p2, nullptr); // should have failed @@ -1095,7 +1095,7 @@ TEST_VM(os, free_without_uncommit) { const size_t pages = 64; const size_t size = pages * page_sz; - char* base = os::reserve_memory(size, mtTest); + char* base = os::reserve_memory(size, false, mtTest); ASSERT_NE(base, (char*) nullptr); ASSERT_TRUE(os::commit_memory(base, size, false)); diff --git a/test/hotspot/gtest/runtime/test_os_aix.cpp b/test/hotspot/gtest/runtime/test_os_aix.cpp index 73ed55dc3ce74..9fcb2f9c691a9 100644 --- a/test/hotspot/gtest/runtime/test_os_aix.cpp +++ b/test/hotspot/gtest/runtime/test_os_aix.cpp @@ -34,9 +34,9 @@ TEST_VM(os_aix, aix_reserve_at_non_shmlba_aligned_address) { if (os::vm_page_size() != 4*K && !os::Aix::supports_64K_mmap_pages()) { // With this condition true shmget() is used inside - char* p = os::attempt_reserve_memory_at((char*)0x1f00000, M, mtTest); + char* p = os::attempt_reserve_memory_at((char*)0x1f00000, M); ASSERT_EQ(p, nullptr); // should have failed - p = os::attempt_reserve_memory_at((char*)((64 * G) + M), M, mtTest); + p = os::attempt_reserve_memory_at((char*)((64 * G) + M), M); ASSERT_EQ(p, nullptr); // should have failed } } diff --git a/test/hotspot/gtest/runtime/test_os_linux.cpp b/test/hotspot/gtest/runtime/test_os_linux.cpp index 21133788a3668..caa227c5e35aa 100644 --- a/test/hotspot/gtest/runtime/test_os_linux.cpp +++ b/test/hotspot/gtest/runtime/test_os_linux.cpp @@ -354,7 +354,7 @@ TEST_VM(os_linux, pretouch_thp_and_use_concurrent) { const size_t size = 1 * G; const bool useThp = UseTransparentHugePages; UseTransparentHugePages = true; - char* const heap = os::reserve_memory(size, mtTest); + char* const heap = os::reserve_memory(size, false, mtInternal); EXPECT_NE(heap, nullptr); EXPECT_TRUE(os::commit_memory(heap, size, false)); diff --git a/test/hotspot/gtest/runtime/test_os_reserve_between.cpp b/test/hotspot/gtest/runtime/test_os_reserve_between.cpp index ee91ff49ded52..34dd26dcf1769 100644 --- a/test/hotspot/gtest/runtime/test_os_reserve_between.cpp +++ b/test/hotspot/gtest/runtime/test_os_reserve_between.cpp @@ -157,7 +157,7 @@ struct SpaceWithHole { // the hole. const uintptr_t candidate = nth_bit(i); if ((candidate + _len) <= ARMB_constants::absolute_max) { - _base = os::attempt_reserve_memory_at((char*)candidate, _len, mtTest); + _base = os::attempt_reserve_memory_at((char*)candidate, _len); } } if (_base == nullptr) { @@ -165,8 +165,8 @@ struct SpaceWithHole { } // Release total mapping, remap the individual non-holy parts os::release_memory(_base, _len); - _p1 = os::attempt_reserve_memory_at(_base + _p1_offset, _p1_size, mtTest); - _p2 = os::attempt_reserve_memory_at(_base + _p2_offset, _p2_size, mtTest); + _p1 = os::attempt_reserve_memory_at(_base + _p1_offset, _p1_size); + _p2 = os::attempt_reserve_memory_at(_base + _p2_offset, _p2_size); if (_p1 == nullptr || _p2 == nullptr) { return false; } diff --git a/test/hotspot/jtreg/runtime/NMT/MallocRoundingReportTest.java b/test/hotspot/jtreg/runtime/NMT/MallocRoundingReportTest.java index a0c14d7083132..30a03f973bf21 100644 --- a/test/hotspot/jtreg/runtime/NMT/MallocRoundingReportTest.java +++ b/test/hotspot/jtreg/runtime/NMT/MallocRoundingReportTest.java @@ -57,7 +57,7 @@ public static void main(String args[]) throws Exception { // NMT does not track memory allocations less than 1KB, and rounds to the nearest KB NMTTestUtils.runJcmdSummaryReportAndCheckOutput( "Test (reserved=" + numKB + "KB, committed=" + numKB + "KB)", - "(malloc=" + numKB + "KB tag=Test #1) (at peak)" // (malloc=1KB tag=Test #1) (at peak) + "(malloc=" + numKB + "KB #1) (at peak)" ); wb.NMTFree(mallocd_total); @@ -65,7 +65,7 @@ public static void main(String args[]) throws Exception { // Run 'jcmd VM.native_memory summary', check for expected output NMTTestUtils.runJcmdSummaryReportAndCheckOutput( "Test (reserved=0KB, committed=0KB)", - "(malloc=0KB tag=Test) (peak=" + numKB + "KB #1)" + "(malloc=0KB) (peak=" + numKB + "KB #1)" ); } } diff --git a/test/hotspot/jtreg/runtime/NMT/MallocTestType.java b/test/hotspot/jtreg/runtime/NMT/MallocTestType.java index 1612cbd81c0a3..67df864e7b41c 100644 --- a/test/hotspot/jtreg/runtime/NMT/MallocTestType.java +++ b/test/hotspot/jtreg/runtime/NMT/MallocTestType.java @@ -46,7 +46,7 @@ public static void main(String args[]) throws Exception { NMTTestUtils.runJcmdSummaryReportAndCheckOutput( new String[]{"Test (reserved=384KB, committed=384KB)", - "(malloc=384KB tag=Test #2) (at peak)"}); + "(malloc=384KB #2) (at peak)"}); wb.NMTFree(memAlloc3); // current +256K #1 peak +384K #2 long memAlloc1 = wb.NMTMalloc(512 * 1024); // current +768K #2 peak +768K #2 @@ -54,13 +54,13 @@ public static void main(String args[]) throws Exception { NMTTestUtils.runJcmdSummaryReportAndCheckOutput( new String[]{"Test (reserved=512KB, committed=512KB)", - "(malloc=512KB tag=Test #1) (peak=768KB #2)"}); + "(malloc=512KB #1) (peak=768KB #2)"}); // Free the memory allocated by NMTAllocTest wb.NMTFree(memAlloc1); // current 0K #0 peak +768K #2 NMTTestUtils.runJcmdSummaryReportAndCheckOutput( new String[]{"Test (reserved=0KB, committed=0KB)", - "(malloc=0KB tag=Test) (peak=768KB #2)"}); + "(malloc=0KB) (peak=768KB #2)"}); } } diff --git a/test/hotspot/jtreg/runtime/NMT/MallocTrackingVerify.java b/test/hotspot/jtreg/runtime/NMT/MallocTrackingVerify.java index 141ef9f2ac3fe..0c08e07fd2588 100644 --- a/test/hotspot/jtreg/runtime/NMT/MallocTrackingVerify.java +++ b/test/hotspot/jtreg/runtime/NMT/MallocTrackingVerify.java @@ -72,7 +72,7 @@ public static void main(String args[]) throws Exception { NMTTestUtils.runJcmdSummaryReportAndCheckOutput( "Test (reserved=4KB, committed=4KB)", - "(malloc=4KB tag=Test #" + mallocd_memory.size() + ") (at peak)" + "(malloc=4KB #" + mallocd_memory.size() + ") (at peak)" ); // Free @@ -83,7 +83,7 @@ public static void main(String args[]) throws Exception { // Run 'jcmd VM.native_memory summary', check for expected output NMTTestUtils.runJcmdSummaryReportAndCheckOutput( "Test (reserved=0KB, committed=0KB)", - "(malloc=0KB tag=Test) (peak=4KB #" + + mallocd_memory.size() + ")" + "(malloc=0KB) (peak=4KB #" + + mallocd_memory.size() + ")" ); } diff --git a/test/hotspot/jtreg/runtime/NMT/ThreadedMallocTestType.java b/test/hotspot/jtreg/runtime/NMT/ThreadedMallocTestType.java index f6b0f3baf041a..290984c41854f 100644 --- a/test/hotspot/jtreg/runtime/NMT/ThreadedMallocTestType.java +++ b/test/hotspot/jtreg/runtime/NMT/ThreadedMallocTestType.java @@ -61,7 +61,7 @@ public void run() { // Run 'jcmd VM.native_memory summary' NMTTestUtils.runJcmdSummaryReportAndCheckOutput( "Test (reserved=896KB, committed=896KB)", - "(malloc=896KB tag=Test #3) (at peak)" + "(malloc=896KB #3) (at peak)" ); Thread freeThread = new Thread() { @@ -78,7 +78,7 @@ public void run() { NMTTestUtils.runJcmdSummaryReportAndCheckOutput( "Test (reserved=0KB, committed=0KB)", - "(malloc=0KB tag=Test) (peak=896KB #3)" + "(malloc=0KB) (peak=896KB #3)" ); } } From f6d8c8cb0c6b226d68791ffd126908d3fea11473 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Mon, 14 Apr 2025 19:16:17 +0000 Subject: [PATCH 0575/1101] 8351339: WebSocket::sendBinary assume that user supplied buffers are BIG_ENDIAN Reviewed-by: michaelm, dfuchs --- .../internal/net/http/websocket/Frame.java | 86 +-- .../net/http/websocket/MessageDecoder.java | 4 +- .../net/http/websocket/MessageEncoder.java | 6 +- .../httpclient/websocket/AutomaticPong.java | 7 +- .../websocket/DummyWebSocketServer.java | 88 +++- .../java/net/httpclient/websocket/Frame.java | 497 ------------------ .../net/httpclient/websocket/TEST.properties | 5 + .../websocket/WebSocketBuilderTest.java | 4 +- .../websocket/WebSocketEndiannessTest.java | 178 +++++++ .../websocket/WebSocketExtendedTest.java | 127 +---- .../net/http/websocket/MaskerTest.java | 12 +- 11 files changed, 359 insertions(+), 655 deletions(-) delete mode 100644 test/jdk/java/net/httpclient/websocket/Frame.java create mode 100644 test/jdk/java/net/httpclient/websocket/TEST.properties create mode 100644 test/jdk/java/net/httpclient/websocket/WebSocketEndiannessTest.java diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/websocket/Frame.java b/src/java.net.http/share/classes/jdk/internal/net/http/websocket/Frame.java index 838e7c6a26b82..0827d64a28d11 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/websocket/Frame.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/websocket/Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package jdk.internal.net.http.websocket; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import static jdk.internal.net.http.common.Utils.dump; import static jdk.internal.net.http.websocket.Frame.Opcode.ofCode; @@ -33,14 +34,14 @@ /* * A collection of utilities for reading, writing, and masking frames. */ -final class Frame { +public final class Frame { private Frame() { } static final int MAX_HEADER_SIZE_BYTES = 2 + 8 + 4; - static final int MAX_CONTROL_FRAME_PAYLOAD_LENGTH = 125; + public static final int MAX_CONTROL_FRAME_PAYLOAD_LENGTH = 125; - enum Opcode { + public enum Opcode { CONTINUATION (0x0), TEXT (0x1), @@ -87,13 +88,13 @@ static Opcode ofCode(int code) { /* * A utility for masking frame payload data. */ - static final class Masker { + public static final class Masker { - // Exploiting ByteBuffer's ability to read/write multi-byte integers private final ByteBuffer acc = ByteBuffer.allocate(8); - private final int[] maskBytes = new int[4]; + private final byte[] maskBytes = new byte[4]; private int offset; - private long maskLong; + private long maskLongBe; + private long maskLongLe; /* * Reads all remaining bytes from the given input buffer, masks them @@ -102,11 +103,11 @@ static final class Masker { * * The source and the destination buffers may be the same instance. */ - static void transferMasking(ByteBuffer src, ByteBuffer dst, int mask) { + static void applyMask(ByteBuffer src, ByteBuffer dst, int mask) { if (src.remaining() > dst.remaining()) { throw new IllegalArgumentException(dump(src, dst)); } - new Masker().mask(mask).transferMasking(src, dst); + new Masker().setMask(mask).applyMask(src, dst); } /* @@ -114,13 +115,14 @@ static void transferMasking(ByteBuffer src, ByteBuffer dst, int mask) { * * The behaviour is as if the mask was set on a newly created instance. */ - Masker mask(int value) { - acc.clear().putInt(value).putInt(value).flip(); + public Masker setMask(int mask) { + acc.clear().putInt(mask).putInt(mask).flip(); for (int i = 0; i < maskBytes.length; i++) { maskBytes[i] = acc.get(i); } offset = 0; - maskLong = acc.getLong(0); + maskLongBe = acc.getLong(0); + maskLongLe = Long.reverseBytes(maskLongBe); return this; } @@ -132,18 +134,25 @@ Masker mask(int value) { * The source and the destination buffers may be the same instance. If * the mask hasn't been previously set it is assumed to be 0. */ - Masker transferMasking(ByteBuffer src, ByteBuffer dst) { - begin(src, dst); - loop(src, dst); - end(src, dst); - return this; + public void applyMask(ByteBuffer src, ByteBuffer dst) { + if (canVectorMask(src, dst)) { + initVectorMask(src, dst); + applyVectorMask(src, dst); + } + applyPlainMask(src, dst); } - /* - * Applies up to 3 remaining from the previous pass bytes of the mask. + private static boolean canVectorMask(ByteBuffer src, ByteBuffer dst) { + return src.order() == dst.order() && Math.min(src.remaining(), dst.remaining()) >= 8; + } + + /** + * Positions the {@link #offset} at 0, which is needed for vectorized + * masking, by masking up to 3 remaining bytes from the previous pass. */ - private void begin(ByteBuffer src, ByteBuffer dst) { - if (offset == 0) { // No partially applied mask from the previous invocation + private void initVectorMask(ByteBuffer src, ByteBuffer dst) { + assert src.order() == dst.order() : "vectorized masking is only allowed on matching byte orders"; + if (offset == 0) { return; } int i = src.position(), j = dst.position(); @@ -158,12 +167,16 @@ private void begin(ByteBuffer src, ByteBuffer dst) { } /* - * Gallops one long (mask + mask) at a time. + * Masks one {@code long} (mask + mask) at a time. */ - private void loop(ByteBuffer src, ByteBuffer dst) { + private void applyVectorMask(ByteBuffer src, ByteBuffer dst) { + assert src.order() == dst.order() : "vectorized masking is only allowed on matching byte orders"; + long maskLong = ByteOrder.LITTLE_ENDIAN == src.order() ? maskLongLe : maskLongBe; int i = src.position(); int j = dst.position(); final int srcLongLim = src.limit() - 7, dstLongLim = dst.limit() - 7; + assert !(i < srcLongLim && j < dstLongLim) || // That is, if loop will run at least once + offset == 0 : "offset must have been positioned at 0"; for (; i < srcLongLim && j < dstLongLim; i += 8, j += 8) { dst.putLong(j, src.getLong(i) ^ maskLong); } @@ -180,11 +193,9 @@ private void loop(ByteBuffer src, ByteBuffer dst) { } /* - * Applies up to 7 remaining from the "galloping" phase bytes of the - * mask. + * Masks one {@code byte} at a time. */ - private void end(ByteBuffer src, ByteBuffer dst) { - assert Math.min(src.remaining(), dst.remaining()) < 8; + private void applyPlainMask(ByteBuffer src, ByteBuffer dst) { final int srcLim = src.limit(), dstLim = dst.limit(); int i = src.position(), j = dst.position(); for (; i < srcLim && j < dstLim; @@ -195,6 +206,7 @@ private void end(ByteBuffer src, ByteBuffer dst) { src.position(i); dst.position(j); } + } /* @@ -204,14 +216,14 @@ private void end(ByteBuffer src, ByteBuffer dst) { * header structure to the given buffer. The order of calls to intermediate * methods is NOT significant. */ - static final class HeaderWriter { + public static final class HeaderWriter { private char firstChar; private long payloadLen; private int maskingKey; private boolean mask; - HeaderWriter fin(boolean value) { + public HeaderWriter fin(boolean value) { if (value) { firstChar |= 0b10000000_00000000; } else { @@ -254,12 +266,12 @@ HeaderWriter rsv3(boolean value) { return this; } - HeaderWriter opcode(Opcode value) { + public HeaderWriter opcode(Opcode value) { firstChar = (char) ((firstChar & 0xF0FF) | (value.code << 8)); return this; } - HeaderWriter payloadLen(long value) { + public HeaderWriter payloadLen(long value) { if (value < 0) { throw new IllegalArgumentException("Negative: " + value); } @@ -282,7 +294,7 @@ HeaderWriter mask(int value) { return this; } - HeaderWriter noMask() { + public HeaderWriter noMask() { // Explicit cast required: see fin() above firstChar &= (char) ~0b00000000_10000000; mask = false; @@ -295,7 +307,7 @@ HeaderWriter noMask() { * The buffer must have at least MAX_HEADER_SIZE_BYTES remaining. The * buffer's position is incremented by the number of bytes written. */ - void write(ByteBuffer buffer) { + public void write(ByteBuffer buffer) { buffer.putChar(firstChar); if (payloadLen >= 126) { if (payloadLen < 65536) { @@ -317,7 +329,7 @@ void write(ByteBuffer buffer) { * * fin rsv1 rsv2 rsv3 opcode mask payloadLength maskingKey? payloadData+ endFrame */ - interface Consumer { + public interface Consumer { void fin(boolean value); @@ -358,7 +370,7 @@ interface Consumer { * * No protocol-level rules are checked. */ - static final class Reader { + public static final class Reader { private static final int AWAITING_FIRST_BYTE = 1; private static final int AWAITING_SECOND_BYTE = 2; @@ -382,7 +394,7 @@ static final class Reader { * * Throws FailWebSocketException if detects the frame is malformed. */ - void readFrame(ByteBuffer input, Consumer consumer) { + public void readFrame(ByteBuffer input, Consumer consumer) { loop: while (true) { byte b; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/websocket/MessageDecoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/websocket/MessageDecoder.java index 9e66327b7c88b..e8923188489e3 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/websocket/MessageDecoder.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/websocket/MessageDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -248,7 +248,7 @@ private void unMask(ByteBuffer src) { int pos = src.position(); int size = src.remaining(); ByteBuffer temp = ByteBuffer.allocate(size); - Frame.Masker.transferMasking(src, temp, maskingKey); + Frame.Masker.applyMask(src, temp, maskingKey); temp.flip(); src.position(pos); src.put(temp); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/websocket/MessageEncoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/websocket/MessageEncoder.java index 0dd03e8f4c3ff..b8d17ce12ba16 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/websocket/MessageEncoder.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/websocket/MessageEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -257,7 +257,7 @@ public boolean encodeBinary(ByteBuffer src, boolean last, ByteBuffer dst) private int maskAvailable(ByteBuffer src, ByteBuffer dst) { int r0 = dst.remaining(); - payloadMasker.transferMasking(src, dst); + payloadMasker.applyMask(src, dst); int masked = r0 - dst.remaining(); return src.hasRemaining() ? -masked : masked; } @@ -393,6 +393,6 @@ private void setupHeader(Opcode opcode, boolean fin, long payloadLen) { .write(headerBuffer); } headerBuffer.flip(); - payloadMasker.mask(mask); + payloadMasker.setMask(mask); } } diff --git a/test/jdk/java/net/httpclient/websocket/AutomaticPong.java b/test/jdk/java/net/httpclient/websocket/AutomaticPong.java index e6e760dba4353..1999781b82ffb 100644 --- a/test/jdk/java/net/httpclient/websocket/AutomaticPong.java +++ b/test/jdk/java/net/httpclient/websocket/AutomaticPong.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ * -Djdk.internal.httpclient.websocket.debug=true * AutomaticPong */ +import jdk.internal.net.http.websocket.Frame; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -186,12 +187,12 @@ public void payloadLen(long value) { @Override public void maskingKey(int value) { - masker.mask(value); + masker.setMask(value); } @Override public void payloadData(ByteBuffer src) { - masker.transferMasking(src, number); + masker.applyMask(src, number); if (closed) { return; } diff --git a/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java b/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java index 176634d690777..9034cf9f28add 100644 --- a/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java +++ b/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,6 +21,8 @@ * questions. */ +import jdk.internal.net.http.websocket.Frame; + import java.io.Closeable; import java.io.IOException; import java.io.UncheckedIOException; @@ -217,6 +219,90 @@ protected final void serve(SocketChannel channel) } } + public List readFrames() throws InterruptedException { + ByteBuffer buffer = read(); + Frame.Reader reader = new Frame.Reader(); + DecodedFrameCollector consumer = new DecodedFrameCollector(); + while (buffer.hasRemaining()) { + reader.readFrame(buffer, consumer); + } + return consumer.frames; + } + + private static final class DecodedFrameCollector implements Frame.Consumer { + + private final Frame.Masker masker = new Frame.Masker(); + + private final List frames = new ArrayList<>(); + + private ByteBuffer data; + + private Frame.Opcode opcode; + + private boolean last; + + @Override + public void fin(boolean value) { + last = value; + } + + @Override + public void rsv1(boolean value) { + if (value) { + throw new AssertionError(); + } + } + + @Override + public void rsv2(boolean value) { + if (value) { + throw new AssertionError(); + } + } + + @Override + public void rsv3(boolean value) { + if (value) { + throw new AssertionError(); + } + } + + @Override + public void opcode(Frame.Opcode value) { + opcode = value; + } + + @Override + public void mask(boolean value) { + if (!value) { // Frames from the client MUST be masked + throw new AssertionError(); + } + } + + @Override + public void payloadLen(long value) { + data = ByteBuffer.allocate((int) value); + } + + @Override + public void maskingKey(int value) { + masker.setMask(value); + } + + @Override + public void payloadData(ByteBuffer data) { + masker.applyMask(data, this.data); + } + + @Override + public void endFrame() { + frames.add(new DecodedFrame(opcode, this.data.flip(), last)); + } + + } + + public record DecodedFrame(Frame.Opcode opcode, ByteBuffer data, boolean last) {} + public ByteBuffer read() throws InterruptedException { readReady.await(); return read.duplicate().asReadOnlyBuffer().flip(); diff --git a/test/jdk/java/net/httpclient/websocket/Frame.java b/test/jdk/java/net/httpclient/websocket/Frame.java deleted file mode 100644 index 99c7f4ac65cb0..0000000000000 --- a/test/jdk/java/net/httpclient/websocket/Frame.java +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Copyright (c) 2016, 2018, 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. - */ - -import java.nio.ByteBuffer; - -/* Copied from jdk.internal.net.http.websocket.Frame */ -final class Frame { - - final Opcode opcode; - final ByteBuffer data; - final boolean last; - - public Frame(Opcode opcode, ByteBuffer data, boolean last) { - this.opcode = opcode; - /* copy */ - this.data = ByteBuffer.allocate(data.remaining()).put(data.slice()).flip(); - this.last = last; - } - - static final int MAX_HEADER_SIZE_BYTES = 2 + 8 + 4; - static final int MAX_CONTROL_FRAME_PAYLOAD_SIZE = 125; - - enum Opcode { - - CONTINUATION (0x0), - TEXT (0x1), - BINARY (0x2), - NON_CONTROL_0x3(0x3), - NON_CONTROL_0x4(0x4), - NON_CONTROL_0x5(0x5), - NON_CONTROL_0x6(0x6), - NON_CONTROL_0x7(0x7), - CLOSE (0x8), - PING (0x9), - PONG (0xA), - CONTROL_0xB (0xB), - CONTROL_0xC (0xC), - CONTROL_0xD (0xD), - CONTROL_0xE (0xE), - CONTROL_0xF (0xF); - - private static final Opcode[] opcodes; - - static { - Opcode[] values = values(); - opcodes = new Opcode[values.length]; - for (Opcode c : values) { - opcodes[c.code] = c; - } - } - - private final byte code; - - Opcode(int code) { - this.code = (byte) code; - } - - boolean isControl() { - return (code & 0x8) != 0; - } - - static Opcode ofCode(int code) { - return opcodes[code & 0xF]; - } - } - - /* - * A utility for masking frame payload data. - */ - static final class Masker { - - // Exploiting ByteBuffer's ability to read/write multi-byte integers - private final ByteBuffer acc = ByteBuffer.allocate(8); - private final int[] maskBytes = new int[4]; - private int offset; - private long maskLong; - - /* - * Reads all remaining bytes from the given input buffer, masks them - * with the supplied mask and writes the resulting bytes to the given - * output buffer. - * - * The source and the destination buffers may be the same instance. - */ - static void transferMasking(ByteBuffer src, ByteBuffer dst, int mask) { - if (src.remaining() > dst.remaining()) { - throw new IllegalArgumentException(); - } - new Masker().mask(mask).transferMasking(src, dst); - } - - /* - * Clears this instance's state and sets the mask. - * - * The behaviour is as if the mask was set on a newly created instance. - */ - Masker mask(int value) { - acc.clear().putInt(value).putInt(value).flip(); - for (int i = 0; i < maskBytes.length; i++) { - maskBytes[i] = acc.get(i); - } - offset = 0; - maskLong = acc.getLong(0); - return this; - } - - /* - * Reads as many remaining bytes as possible from the given input - * buffer, masks them with the previously set mask and writes the - * resulting bytes to the given output buffer. - * - * The source and the destination buffers may be the same instance. If - * the mask hasn't been previously set it is assumed to be 0. - */ - Masker transferMasking(ByteBuffer src, ByteBuffer dst) { - begin(src, dst); - loop(src, dst); - end(src, dst); - return this; - } - - /* - * Applies up to 3 remaining from the previous pass bytes of the mask. - */ - private void begin(ByteBuffer src, ByteBuffer dst) { - if (offset == 0) { // No partially applied mask from the previous invocation - return; - } - int i = src.position(), j = dst.position(); - final int srcLim = src.limit(), dstLim = dst.limit(); - for (; offset < 4 && i < srcLim && j < dstLim; i++, j++, offset++) - { - dst.put(j, (byte) (src.get(i) ^ maskBytes[offset])); - } - offset &= 3; // Will become 0 if the mask has been fully applied - src.position(i); - dst.position(j); - } - - /* - * Gallops one long (mask + mask) at a time. - */ - private void loop(ByteBuffer src, ByteBuffer dst) { - int i = src.position(); - int j = dst.position(); - final int srcLongLim = src.limit() - 7, dstLongLim = dst.limit() - 7; - for (; i < srcLongLim && j < dstLongLim; i += 8, j += 8) { - dst.putLong(j, src.getLong(i) ^ maskLong); - } - if (i > src.limit()) { - src.position(i - 8); - } else { - src.position(i); - } - if (j > dst.limit()) { - dst.position(j - 8); - } else { - dst.position(j); - } - } - - /* - * Applies up to 7 remaining from the "galloping" phase bytes of the - * mask. - */ - private void end(ByteBuffer src, ByteBuffer dst) { - assert Math.min(src.remaining(), dst.remaining()) < 8; - final int srcLim = src.limit(), dstLim = dst.limit(); - int i = src.position(), j = dst.position(); - for (; i < srcLim && j < dstLim; - i++, j++, offset = (offset + 1) & 3) // offset cycles through 0..3 - { - dst.put(j, (byte) (src.get(i) ^ maskBytes[offset])); - } - src.position(i); - dst.position(j); - } - } - - /* - * A builder-style writer of frame headers. - * - * The writer does not enforce any protocol-level rules, it simply writes a - * header structure to the given buffer. The order of calls to intermediate - * methods is NOT significant. - */ - static final class HeaderWriter { - - private char firstChar; - private long payloadLen; - private int maskingKey; - private boolean mask; - - HeaderWriter fin(boolean value) { - if (value) { - firstChar |= 0b10000000_00000000; - } else { - firstChar &= ~0b10000000_00000000; - } - return this; - } - - HeaderWriter rsv1(boolean value) { - if (value) { - firstChar |= 0b01000000_00000000; - } else { - firstChar &= ~0b01000000_00000000; - } - return this; - } - - HeaderWriter rsv2(boolean value) { - if (value) { - firstChar |= 0b00100000_00000000; - } else { - firstChar &= ~0b00100000_00000000; - } - return this; - } - - HeaderWriter rsv3(boolean value) { - if (value) { - firstChar |= 0b00010000_00000000; - } else { - firstChar &= ~0b00010000_00000000; - } - return this; - } - - HeaderWriter opcode(Opcode value) { - firstChar = (char) ((firstChar & 0xF0FF) | (value.code << 8)); - return this; - } - - HeaderWriter payloadLen(long value) { - if (value < 0) { - throw new IllegalArgumentException("Negative: " + value); - } - payloadLen = value; - firstChar &= 0b11111111_10000000; // Clear previous payload length leftovers - if (payloadLen < 126) { - firstChar |= payloadLen; - } else if (payloadLen < 65536) { - firstChar |= 126; - } else { - firstChar |= 127; - } - return this; - } - - HeaderWriter mask(int value) { - firstChar |= 0b00000000_10000000; - maskingKey = value; - mask = true; - return this; - } - - HeaderWriter noMask() { - firstChar &= ~0b00000000_10000000; - mask = false; - return this; - } - - /* - * Writes the header to the given buffer. - * - * The buffer must have at least MAX_HEADER_SIZE_BYTES remaining. The - * buffer's position is incremented by the number of bytes written. - */ - void write(ByteBuffer buffer) { - buffer.putChar(firstChar); - if (payloadLen >= 126) { - if (payloadLen < 65536) { - buffer.putChar((char) payloadLen); - } else { - buffer.putLong(payloadLen); - } - } - if (mask) { - buffer.putInt(maskingKey); - } - } - } - - /* - * A consumer of frame parts. - * - * Frame.Reader invokes the consumer's methods in the following order: - * - * fin rsv1 rsv2 rsv3 opcode mask payloadLength maskingKey? payloadData+ endFrame - */ - interface Consumer { - - void fin(boolean value); - - void rsv1(boolean value); - - void rsv2(boolean value); - - void rsv3(boolean value); - - void opcode(Opcode value); - - void mask(boolean value); - - void payloadLen(long value); - - void maskingKey(int value); - - /* - * Called by the Frame.Reader when a part of the (or a complete) payload - * is ready to be consumed. - * - * The sum of numbers of bytes consumed in each invocation of this - * method corresponding to the given frame WILL be equal to - * 'payloadLen', reported to `void payloadLen(long value)` before that. - * - * In particular, if `payloadLen` is 0, then there WILL be a single - * invocation to this method. - * - * No unmasking is done. - */ - void payloadData(ByteBuffer data); - - void endFrame(); - } - - /* - * A Reader of frames. - * - * No protocol-level rules are checked. - */ - static final class Reader { - - private static final int AWAITING_FIRST_BYTE = 1; - private static final int AWAITING_SECOND_BYTE = 2; - private static final int READING_16_LENGTH = 4; - private static final int READING_64_LENGTH = 8; - private static final int READING_MASK = 16; - private static final int READING_PAYLOAD = 32; - - // Exploiting ByteBuffer's ability to read multi-byte integers - private final ByteBuffer accumulator = ByteBuffer.allocate(8); - private int state = AWAITING_FIRST_BYTE; - private boolean mask; - private long remainingPayloadLength; - - /* - * Reads at most one frame from the given buffer invoking the consumer's - * methods corresponding to the frame parts found. - * - * As much of the frame's payload, if any, is read. The buffer's - * position is updated to reflect the number of bytes read. - * - * Throws FailWebSocketException if detects the frame is malformed. - */ - void readFrame(ByteBuffer input, Consumer consumer) { - loop: - while (true) { - byte b; - switch (state) { - case AWAITING_FIRST_BYTE: - if (!input.hasRemaining()) { - break loop; - } - b = input.get(); - consumer.fin( (b & 0b10000000) != 0); - consumer.rsv1((b & 0b01000000) != 0); - consumer.rsv2((b & 0b00100000) != 0); - consumer.rsv3((b & 0b00010000) != 0); - consumer.opcode(Opcode.ofCode(b)); - state = AWAITING_SECOND_BYTE; - continue loop; - case AWAITING_SECOND_BYTE: - if (!input.hasRemaining()) { - break loop; - } - b = input.get(); - consumer.mask(mask = (b & 0b10000000) != 0); - byte p1 = (byte) (b & 0b01111111); - if (p1 < 126) { - assert p1 >= 0 : p1; - consumer.payloadLen(remainingPayloadLength = p1); - state = mask ? READING_MASK : READING_PAYLOAD; - } else if (p1 < 127) { - state = READING_16_LENGTH; - } else { - state = READING_64_LENGTH; - } - continue loop; - case READING_16_LENGTH: - if (!input.hasRemaining()) { - break loop; - } - b = input.get(); - if (accumulator.put(b).position() < 2) { - continue loop; - } - remainingPayloadLength = accumulator.flip().getChar(); - if (remainingPayloadLength < 126) { - throw notMinimalEncoding(remainingPayloadLength); - } - consumer.payloadLen(remainingPayloadLength); - accumulator.clear(); - state = mask ? READING_MASK : READING_PAYLOAD; - continue loop; - case READING_64_LENGTH: - if (!input.hasRemaining()) { - break loop; - } - b = input.get(); - if (accumulator.put(b).position() < 8) { - continue loop; - } - remainingPayloadLength = accumulator.flip().getLong(); - if (remainingPayloadLength < 0) { - throw negativePayload(remainingPayloadLength); - } else if (remainingPayloadLength < 65536) { - throw notMinimalEncoding(remainingPayloadLength); - } - consumer.payloadLen(remainingPayloadLength); - accumulator.clear(); - state = mask ? READING_MASK : READING_PAYLOAD; - continue loop; - case READING_MASK: - if (!input.hasRemaining()) { - break loop; - } - b = input.get(); - if (accumulator.put(b).position() != 4) { - continue loop; - } - consumer.maskingKey(accumulator.flip().getInt()); - accumulator.clear(); - state = READING_PAYLOAD; - continue loop; - case READING_PAYLOAD: - // This state does not require any bytes to be available - // in the input buffer in order to proceed - int deliverable = (int) Math.min(remainingPayloadLength, - input.remaining()); - int oldLimit = input.limit(); - input.limit(input.position() + deliverable); - if (deliverable != 0 || remainingPayloadLength == 0) { - consumer.payloadData(input); - } - int consumed = deliverable - input.remaining(); - if (consumed < 0) { - // Consumer cannot consume more than there was available - throw new InternalError(); - } - input.limit(oldLimit); - remainingPayloadLength -= consumed; - if (remainingPayloadLength == 0) { - consumer.endFrame(); - state = AWAITING_FIRST_BYTE; - } - break loop; - default: - throw new InternalError(String.valueOf(state)); - } - } - } - - private static IllegalArgumentException negativePayload(long payloadLength) - { - return new IllegalArgumentException("Negative payload length: " - + payloadLength); - } - - private static IllegalArgumentException notMinimalEncoding(long payloadLength) - { - return new IllegalArgumentException("Not minimally-encoded payload length:" - + payloadLength); - } - } -} diff --git a/test/jdk/java/net/httpclient/websocket/TEST.properties b/test/jdk/java/net/httpclient/websocket/TEST.properties new file mode 100644 index 0000000000000..685dab026271b --- /dev/null +++ b/test/jdk/java/net/httpclient/websocket/TEST.properties @@ -0,0 +1,5 @@ +modules=java.net.http/jdk.internal.net.http.common \ + java.net.http/jdk.internal.net.http.frame \ + java.net.http/jdk.internal.net.http.hpack \ + java.net.http/jdk.internal.net.http.websocket +maxOutputSize = 2500000 diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketBuilderTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketBuilderTest.java index 6fb94a9fa2ea7..b28b8f59875a1 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketBuilderTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketBuilderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,8 @@ /* * @test * @bug 8159053 + * @build DummyWebSocketServer + * Support * @run testng/othervm WebSocketBuilderTest */ diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketEndiannessTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketEndiannessTest.java new file mode 100644 index 0000000000000..0d532669a10d8 --- /dev/null +++ b/test/jdk/java/net/httpclient/websocket/WebSocketEndiannessTest.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8351339 + * @summary Verify the intact transmission of the binary payload regardless of its endianness + * @modules java.net.http/jdk.internal.net.http.websocket + * @library /test/lib + * @build DummyWebSocketServer + * jdk.test.lib.Asserts + * @run main WebSocketEndiannessTest + */ + +import jdk.internal.net.http.websocket.Frame; + +import java.net.http.HttpClient; +import java.net.http.WebSocket; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.List; +import java.util.function.Supplier; + +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.nio.ByteOrder.BIG_ENDIAN; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static jdk.test.lib.Asserts.assertEquals; +import static jdk.test.lib.Asserts.assertEqualsByteArray; +import static jdk.test.lib.Asserts.assertTrue; + +public class WebSocketEndiannessTest { + + public static void main(String[] args) throws Exception { + assertEndiannessAgnosticTransfer(); + assertSuccessfulMasking(); + } + + private static void assertEndiannessAgnosticTransfer() throws Exception { + Supplier bufferSupplier = () -> ByteBuffer + .wrap(new byte[]{ + // 4-byte words + 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, + // 2-byte words + 0x10, 0x11, + 0x12, 0x13, + 0x14, 0x15, + 0x16, 0x17, + 0x18, 0x19, + 0x1a, 0x1b, + 0x1c, 0x1d, + 0x1e, 0x1f, + // negative ones + -1, -2, -3, 4, + -5, -6 + }); + assertEndiannessAgnosticTransfer(bufferSupplier.get().order(LITTLE_ENDIAN)); + assertEndiannessAgnosticTransfer(bufferSupplier.get().order(BIG_ENDIAN)); + } + + private static void assertEndiannessAgnosticTransfer(ByteBuffer data) throws Exception { + List frames = sendDataAndReadFrames(data); + assertEquals(frames.size(), 1); + DummyWebSocketServer.DecodedFrame frame = frames.getFirst(); + assertEquals(frame.opcode(), Frame.Opcode.BINARY); + assertTrue(frame.last()); + assertEqualsByteArray(data.array(), frame.data().array()); + } + + private static List sendDataAndReadFrames(ByteBuffer data) throws Exception { + try (var server = new DummyWebSocketServer(); + var client = HttpClient.newBuilder().proxy(NO_PROXY).build()) { + server.open(); + WebSocket webSocket = client + .newWebSocketBuilder() + .buildAsync(server.getURI(), new WebSocket.Listener() {}) + .join(); + try { + webSocket.sendBinary(data, true).join(); + } finally { + webSocket.abort(); + } + return server.readFrames(); + } + } + + private static void assertSuccessfulMasking() { + assertSuccessfulMasking(LITTLE_ENDIAN, LITTLE_ENDIAN); + assertSuccessfulMasking(LITTLE_ENDIAN, BIG_ENDIAN); + assertSuccessfulMasking(BIG_ENDIAN, LITTLE_ENDIAN); + assertSuccessfulMasking(BIG_ENDIAN, BIG_ENDIAN); + } + + private static void assertSuccessfulMasking(ByteOrder srcOrder, ByteOrder dstOrder) { + + // Create the masker + Frame.Masker masker = new Frame.Masker() + // `0xB0` and `0xD0` is used instead of `0x0B` and `0x0D` to cover the negative `byte` range: + // + // (byte) 0x0A -> 10 + // (byte) 0xB0 -> -80 + // (byte) 0x0C -> 12 + // (byte) 0xD0 -> -48 + .setMask(0x0AB00CD0); + + // Perform dummy masking to advance `Frame::offset` 1 byte, and effectively make it non-zero. + // A non-zero `Frame::offset` will trigger `Frame::initVectorMask` invocation. + masker.applyMask(ByteBuffer.wrap(new byte[1]), ByteBuffer.wrap(new byte[1])); + + // Perform the actual masking + ByteBuffer src = ByteBuffer + .wrap(new byte[]{ + // `initVectorMask` will mask 3 bytes to position the `offset` back to 0. + // It is 3 bytes, because of the 1 byte dummy advancement above. + -0x1, -0x2, 0x3, + // `applyVectorMask` will make a single 8-byte pass + 0x1, 0x2, 0x3, 0x4, -0x5, 0x6, -0x7, -0x8, + // `applyPlainMask` will mask 3 bytes + 0x1, -0x2, -0x3 + // Note minus signs sprinkled above to cover the negative `byte` range in a certain structure: + // Some will get masked with a positive number, some with a negative. + // For instance, for `applyPlainMask`: + // - `0x1` will be masked with `0xA` + // - `-0x2` will be masked with `0xB0` + }) + .order(srcOrder); + ByteBuffer dst = ByteBuffer.allocate(src.capacity()).order(dstOrder); + masker.applyMask(src, dst); + + // Verify the masking + assertEqualsByteArray( + new byte[]{ + // 3 bytes for `initVectorMask`. + // Remember 0xA is consumed by the initial dummy masking. + (byte) (-0x1 ^ 0xB0), + -0x2 ^ 0xC, + (byte) (0x3 ^ 0xD0), + // 8 bytes for `applyVectorMask` + 0x1 ^ 0xA, + (byte) (0x2 ^ 0xB0), + 0x3 ^ 0xC, + (byte) (0x4 ^ 0xD0), + -0x5 ^ 0xA, + (byte) (0x6 ^ 0xB0), + -0x7 ^ 0xC, + (byte) (-0x8 ^ 0xD0), + // 3 bytes for `applyPlainMask` + 0x1 ^ 0xA, + (byte) (-0x2 ^ 0xB0), + -0x3 ^ 0xC + }, + dst.array()); + + } + +} diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java index e739c5ef7951e..0099104e87291 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,6 @@ /* * @test * @bug 8159053 - * - * * @run testng/othervm * -Djdk.internal.httpclient.websocket.debug=true * -Djdk.internal.httpclient.debug=true @@ -33,6 +31,7 @@ * -Djdk.httpclient.websocket.intermediateBufferSize=2048 WebSocketExtendedTest */ +import jdk.internal.net.http.websocket.Frame; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -40,7 +39,6 @@ import java.net.http.WebSocket; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.List; import java.util.Random; import static java.net.http.HttpClient.Builder.NO_PROXY; @@ -77,91 +75,15 @@ public void binary(ByteBuffer expected) throws IOException, InterruptedException .join(); ws.sendBinary(expected.duplicate(), true).join(); ws.abort(); - ByteBuffer data = server.read(); - List frames = readFrames(data); + List frames = server.readFrames(); assertEquals(frames.size(), 1); - Frame f = frames.get(0); - assertTrue(f.last); - assertEquals(f.opcode, Frame.Opcode.BINARY); - assertEquals(f.data, expected); + DummyWebSocketServer.DecodedFrame f = frames.get(0); + assertTrue(f.last()); + assertEquals(f.opcode(), Frame.Opcode.BINARY); + assertEquals(f.data(), expected); } } - private static List readFrames(ByteBuffer src) { - List frames = new ArrayList<>(); - Frame.Consumer consumer = new Frame.Consumer() { - - ByteBuffer data; - Frame.Opcode opcode; - Frame.Masker masker = new Frame.Masker(); - boolean last; - - @Override - public void fin(boolean value) { - last = value; - } - - @Override - public void rsv1(boolean value) { - if (value) { - throw new AssertionError(); - } - } - - @Override - public void rsv2(boolean value) { - if (value) { - throw new AssertionError(); - } - } - - @Override - public void rsv3(boolean value) { - if (value) { - throw new AssertionError(); - } - } - - @Override - public void opcode(Frame.Opcode value) { - opcode = value; - } - - @Override - public void mask(boolean value) { - if (!value) { // Frames from the client MUST be masked - throw new AssertionError(); - } - } - - @Override - public void payloadLen(long value) { - data = ByteBuffer.allocate((int) value); - } - - @Override - public void maskingKey(int value) { - masker.mask(value); - } - - @Override - public void payloadData(ByteBuffer data) { - masker.transferMasking(data, this.data); - } - - @Override - public void endFrame() { - frames.add(new Frame(opcode, this.data.flip(), last)); - } - }; - - Frame.Reader r = new Frame.Reader(); - while (src.hasRemaining()) { - r.readFrame(src, consumer); - } - return frames; - } - @Test(dataProvider = "pingPong") public void ping(ByteBuffer expected) throws Exception { try (DummyWebSocketServer server = new DummyWebSocketServer()) { @@ -172,13 +94,12 @@ public void ping(ByteBuffer expected) throws Exception { .join(); ws.sendPing(expected.duplicate()).join(); ws.abort(); - ByteBuffer data = server.read(); - List frames = readFrames(data); + List frames = server.readFrames(); assertEquals(frames.size(), 1); - Frame f = frames.get(0); - assertEquals(f.opcode, Frame.Opcode.PING); + DummyWebSocketServer.DecodedFrame f = frames.get(0); + assertEquals(f.opcode(), Frame.Opcode.PING); ByteBuffer actual = ByteBuffer.allocate(expected.remaining()); - actual.put(f.data); + actual.put(f.data()); actual.flip(); assertEquals(actual, expected); } @@ -194,13 +115,12 @@ public void pong(ByteBuffer expected) throws Exception { .join(); ws.sendPong(expected.duplicate()).join(); ws.abort(); - ByteBuffer data = server.read(); - List frames = readFrames(data); + List frames = server.readFrames(); assertEquals(frames.size(), 1); - Frame f = frames.get(0); - assertEquals(f.opcode, Frame.Opcode.PONG); + DummyWebSocketServer.DecodedFrame f = frames.get(0); + assertEquals(f.opcode(), Frame.Opcode.PONG); ByteBuffer actual = ByteBuffer.allocate(expected.remaining()); - actual.put(f.data); + actual.put(f.data()); actual.flip(); assertEquals(actual, expected); } @@ -216,13 +136,12 @@ public void close(int statusCode, String reason) throws Exception { .join(); ws.sendClose(statusCode, reason).join(); ws.abort(); - ByteBuffer data = server.read(); - List frames = readFrames(data); + List frames = server.readFrames(); assertEquals(frames.size(), 1); - Frame f = frames.get(0); - assertEquals(f.opcode, Frame.Opcode.CLOSE); - ByteBuffer actual = ByteBuffer.allocate(Frame.MAX_CONTROL_FRAME_PAYLOAD_SIZE); - actual.put(f.data); + DummyWebSocketServer.DecodedFrame f = frames.get(0); + assertEquals(f.opcode(), Frame.Opcode.CLOSE); + ByteBuffer actual = ByteBuffer.allocate(Frame.MAX_CONTROL_FRAME_PAYLOAD_LENGTH); + actual.put(f.data()); actual.flip(); assertEquals(actual.getChar(), statusCode); assertEquals(StandardCharsets.UTF_8.decode(actual).toString(), reason); @@ -239,12 +158,10 @@ public void text(String expected) throws Exception { .join(); ws.sendText(expected, true).join(); ws.abort(); - ByteBuffer data = server.read(); - List frames = readFrames(data); - + List frames = server.readFrames(); int maxBytes = (int) StandardCharsets.UTF_8.newEncoder().maxBytesPerChar() * expected.length(); ByteBuffer actual = ByteBuffer.allocate(maxBytes); - frames.stream().forEachOrdered(f -> actual.put(f.data)); + frames.stream().forEachOrdered(f -> actual.put(f.data())); actual.flip(); assertEquals(StandardCharsets.UTF_8.decode(actual).toString(), expected); } diff --git a/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/MaskerTest.java b/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/MaskerTest.java index 35270203773cf..7eb892f12ea02 100644 --- a/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/MaskerTest.java +++ b/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/MaskerTest.java @@ -30,7 +30,7 @@ import java.util.stream.IntStream; import static org.testng.Assert.assertEquals; -import static jdk.internal.net.http.websocket.Frame.Masker.transferMasking; +import static jdk.internal.net.http.websocket.Frame.Masker.applyMask; import static jdk.internal.net.http.websocket.TestSupport.forEachBufferPartition; import static jdk.internal.net.http.websocket.TestSupport.fullCopy; @@ -46,7 +46,7 @@ public void stateless() { ByteBuffer src = createSourceBuffer(r); ByteBuffer dst = createDestinationBuffer(r); verify(src, dst, maskArray(m), 0, - () -> transferMasking(src, dst, m)); + () -> applyMask(src, dst, m)); }); } @@ -67,11 +67,11 @@ public void stateful0() { forEachBufferPartition(src, buffers -> { int offset = 0; - masker.mask(mask); + masker.setMask(mask); int[] maskBytes = maskArray(mask); for (ByteBuffer s : buffers) { offset = verify(s, dst, maskBytes, offset, - () -> masker.transferMasking(s, dst)); + () -> masker.applyMask(s, dst)); } }); } @@ -79,11 +79,11 @@ public void stateful0() { @Test public void stateful1() { int m = random.nextInt(); - masker.mask(m); + masker.setMask(m); ByteBuffer src = ByteBuffer.allocate(0); ByteBuffer dst = ByteBuffer.allocate(16); verify(src, dst, maskArray(m), 0, - () -> masker.transferMasking(src, dst)); + () -> masker.applyMask(src, dst)); } private static int verify(ByteBuffer src, From 9e7763d44274ad1ac633120553d5c67f494bf3ef Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Mon, 14 Apr 2025 19:27:16 +0000 Subject: [PATCH 0576/1101] 8354536: Problem-list java/util/logging/LoggingDeadlock5.java due to JDK-8354424 Reviewed-by: smarks --- test/jdk/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index b85e5bb21db5e..4ff6ea1fe74fd 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -727,6 +727,7 @@ com/sun/jdi/InvokeHangTest.java 8218463 linux-al # jdk_util java/util/zip/CloseInflaterDeflaterTest.java 8339216 linux-s390x +java/util/logging/LoggingDeadlock5.java 8354424 generic-all ############################################################################ From 5280b7b031bb3dc44fb923c3be7ae04ec22fd364 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Mon, 14 Apr 2025 22:07:26 +0000 Subject: [PATCH 0577/1101] 8353592: Open source several scrollbar tests Reviewed-by: psadhukhan, honkar --- .../java/awt/Scrollbar/ListScrollbarTest.java | 139 ++++++++++++++++++ .../awt/Scrollbar/ScrollbarCtrlClickTest.java | 114 ++++++++++++++ .../java/awt/Scrollbar/UnitIncrementTest.java | 129 ++++++++++++++++ 3 files changed, 382 insertions(+) create mode 100644 test/jdk/java/awt/Scrollbar/ListScrollbarTest.java create mode 100644 test/jdk/java/awt/Scrollbar/ScrollbarCtrlClickTest.java create mode 100644 test/jdk/java/awt/Scrollbar/UnitIncrementTest.java diff --git a/test/jdk/java/awt/Scrollbar/ListScrollbarTest.java b/test/jdk/java/awt/Scrollbar/ListScrollbarTest.java new file mode 100644 index 0000000000000..fb441fe44ba1c --- /dev/null +++ b/test/jdk/java/awt/Scrollbar/ListScrollbarTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4029465 + * @summary Win95 Multiselect List doesn't display scrollbar + * @key headful + * @run main ListScrollbarTest + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.List; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; + +public class ListScrollbarTest { + + private static final Color BG_COLOR = Color.RED; + private static Robot robot; + private static Frame frame; + private static List list; + private static int counter = 0; + private static volatile Rectangle listBounds; + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(ListScrollbarTest::createAndShowUI); + test(); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void test() throws Exception { + robot = new Robot(); + robot.waitForIdle(); + robot.delay(500); + + EventQueue.invokeAndWait(() -> { + Point locationOnScreen = list.getLocationOnScreen(); + Dimension size = list.getSize(); + listBounds = new Rectangle(locationOnScreen, size); + }); + + Point point = new Point(listBounds.x + listBounds.width - 5, + listBounds.y + listBounds.height / 2); + + + for (int i = 0; i < 4; i++) { + scrollbarCheck(point, false); + addListItem(); + } + scrollbarCheck(point, true); + } + + public static boolean areColorsSimilar(Color c1, Color c2, int tolerance) { + return Math.abs(c1.getRed() - c2.getRed()) <= tolerance + && Math.abs(c1.getGreen() - c2.getGreen()) <= tolerance + && Math.abs(c1.getBlue() - c2.getBlue()) <= tolerance; + } + + private static void scrollbarCheck(Point point, boolean isScrollbarExpected) { + Color pixelColor = robot.getPixelColor(point.x, point.y); + boolean areColorsSimilar = areColorsSimilar(BG_COLOR, pixelColor, 5); + + if (isScrollbarExpected && areColorsSimilar) { + throw new RuntimeException((""" + Scrollbar is expected, but pixel color \ + is similar to the background color + %s pixel color + %s bg color""") + .formatted(pixelColor, BG_COLOR)); + } + + if (!isScrollbarExpected && !areColorsSimilar) { + throw new RuntimeException((""" + Scrollbar is not expected, but pixel color \ + is not similar to the background color + %s pixel color + %s bg color""") + .formatted(pixelColor, BG_COLOR)); + } + } + + private static void addListItem() throws Exception { + EventQueue.invokeAndWait(() -> { + counter++; + System.out.println("Adding list item " + counter); + list.add("List Item " + counter); + frame.validate(); + }); + robot.waitForIdle(); + robot.delay(150); + } + + private static void createAndShowUI() { + frame = new Frame("ListScrollbarTest"); + list = new List(3, true); + list.setBackground(BG_COLOR); + + // do not draw border around items, it can affect screen capture + list.setFocusable(false); + + frame.add(list); + + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } +} diff --git a/test/jdk/java/awt/Scrollbar/ScrollbarCtrlClickTest.java b/test/jdk/java/awt/Scrollbar/ScrollbarCtrlClickTest.java new file mode 100644 index 0000000000000..3b5a24008fd8c --- /dev/null +++ b/test/jdk/java/awt/Scrollbar/ScrollbarCtrlClickTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4075950 + * @summary Test for functionality of Control Click on Scrollbar + * @key headful + * @run main ScrollbarCtrlClickTest + */ + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class ScrollbarCtrlClickTest { + private static Frame frame; + private static TextArea ta; + private static Scrollbar scrollbar; + private static final CountDownLatch latch = new CountDownLatch(1); + private static volatile Rectangle sbBounds; + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(ScrollbarCtrlClickTest::initAndShowGUI); + test(); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void initAndShowGUI() { + frame = new Frame("ScrollbarDimensionTest"); + ta = new TextArea("", 30, 100); + + + scrollbar = new Scrollbar(Scrollbar.VERTICAL, + 0, 10, 0, 20); + + // Just setting layout so scrollbar thumb will be big enough to use + frame.setLayout(new BorderLayout()); + frame.add("East", scrollbar); + frame.add("West", ta); + + scrollbar.addAdjustmentListener(e -> { + System.out.println(e.paramString()); + ta.append(e.paramString() + "\n"); + latch.countDown(); + }); + + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void test() throws Exception { + Robot robot = new Robot(); + robot.waitForIdle(); + robot.setAutoDelay(25); + robot.delay(500); + + EventQueue.invokeAndWait(() -> { + Point locationOnScreen = scrollbar.getLocationOnScreen(); + Dimension size = scrollbar.getSize(); + sbBounds = new Rectangle(locationOnScreen, size); + }); + + robot.mouseMove(sbBounds.x + sbBounds.width / 2, + sbBounds.y + sbBounds.height - 50); + + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + + if (!latch.await(1, TimeUnit.SECONDS)) { + throw new RuntimeException("Timed out waiting for latch"); + } + } +} diff --git a/test/jdk/java/awt/Scrollbar/UnitIncrementTest.java b/test/jdk/java/awt/Scrollbar/UnitIncrementTest.java new file mode 100644 index 0000000000000..03dba0f3a994b --- /dev/null +++ b/test/jdk/java/awt/Scrollbar/UnitIncrementTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4169461 + * @summary Test for Motif Scrollbar unit increment + * @key headful + * @run main UnitIncrementTest + */ + +import javax.swing.UIManager; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Scrollbar; +import java.awt.event.AdjustmentEvent; +import java.awt.event.MouseEvent; +import java.util.ArrayList; + +public class UnitIncrementTest { + private static Frame frame; + private static Scrollbar scrollbar; + private static final java.util.List eventsList = new ArrayList<>(); + private static final int UNIT_INCREMENT_VALUE = 5; + private static final int INCREMENTS_COUNT = 10; + private static volatile Rectangle scrollbarBounds; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); + + try { + EventQueue.invokeAndWait(UnitIncrementTest::createAndShowUI); + test(); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createAndShowUI() { + frame = new Frame("UnitIncrementTest"); + + scrollbar = new Scrollbar(Scrollbar.HORIZONTAL); + + scrollbar.setUnitIncrement(UNIT_INCREMENT_VALUE); + scrollbar.setBlockIncrement(20); + + scrollbar.addAdjustmentListener(e -> { + eventsList.add(e); + System.out.println(e); + }); + + frame.add(scrollbar); + + frame.setSize(300, 100); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void test() throws Exception { + Robot robot = new Robot(); + robot.waitForIdle(); + robot.setAutoDelay(25); + robot.delay(500); + + EventQueue.invokeAndWait(() -> { + Point locationOnScreen = scrollbar.getLocationOnScreen(); + Dimension size = scrollbar.getSize(); + scrollbarBounds = new Rectangle(locationOnScreen, size); + }); + + robot.mouseMove(scrollbarBounds.x + scrollbarBounds.width - 10, + scrollbarBounds.y + scrollbarBounds.height / 2); + + for (int i = 0; i < INCREMENTS_COUNT; i++) { + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); + robot.delay(150); + } + + robot.waitForIdle(); + robot.delay(250); + + if (eventsList.size() != INCREMENTS_COUNT) { + throw new RuntimeException("Wrong number of events: " + eventsList.size()); + } + + int oldValue = 0; + for (AdjustmentEvent event : eventsList) { + System.out.println("\nChecking event " + event); + + int diff = event.getValue() - oldValue; + System.out.printf("diff: %d - %d = %d\n", event.getValue(), oldValue, diff); + + if (diff != UNIT_INCREMENT_VALUE) { + throw new RuntimeException("Unexpected adjustment value: %d".formatted(diff)); + } + + oldValue = event.getValue(); + } + } +} From 92e52fe1df84efd94d713afed5acd9c7281a77d7 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 15 Apr 2025 02:00:49 +0000 Subject: [PATCH 0578/1101] 8353946: Incorrect WINDOWS ifdef in os::build_agent_function_name Reviewed-by: kbarrett --- src/hotspot/share/runtime/os.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index cbe40ca214bba..99559cee2879e 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -2535,7 +2535,7 @@ char* os::build_agent_function_name(const char *sym_name, const char *lib_name, if ((start = strrchr(lib_name, *os::file_separator())) != nullptr) { lib_name = ++start; } -#ifdef WINDOWS +#ifdef _WINDOWS else { // Need to check for drive prefix e.g. C:L.dll if ((start = strchr(lib_name, ':')) != nullptr) { lib_name = ++start; From c7b70a138ff592fdf1cd4f1d063103491a8aa7db Mon Sep 17 00:00:00 2001 From: "Dr Heinz M. Kabutz" Date: Tue, 15 Apr 2025 02:48:32 +0000 Subject: [PATCH 0579/1101] 8354111: JavaDoc states that Iterator.remove() is linear in the LinkedBlockingDeque Reviewed-by: liach, smarks --- .../classes/java/util/concurrent/LinkedBlockingDeque.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java b/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java index 7c112eb80081b..8d0bc7ccdde62 100644 --- a/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java +++ b/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java @@ -61,8 +61,8 @@ * blocking). Exceptions include {@link #remove(Object) remove}, * {@link #removeFirstOccurrence removeFirstOccurrence}, {@link * #removeLastOccurrence removeLastOccurrence}, {@link #contains - * contains}, {@link #iterator iterator.remove()}, and the bulk - * operations, all of which run in linear time. + * contains}, and the bulk operations, all of which run in linear + * time. * *

This class and its iterator implement all of the optional * methods of the {@link Collection} and {@link Iterator} interfaces. From 76ff97811abf5a4eaede6303e25ff9582302e436 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 15 Apr 2025 05:11:40 +0000 Subject: [PATCH 0580/1101] 8354510: Skipped gtest cause test failure Reviewed-by: rehn, erikj --- make/RunTests.gmk | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 7aa0082e0ae81..80c1ff99b2e40 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -534,22 +534,21 @@ define SetupRunGtestTestBody $$(eval $1_PASSED := $$(shell $$(AWK) '/\[ PASSED \] .* tests?./ \ { print $$$$4 }' $$($1_RESULT_FILE))) \ $$(if $$($1_PASSED), , $$(eval $1_PASSED := 0)) \ - $$(eval $1_SKIPPED := $$(shell $$(AWK) \ - '/YOU HAVE [0-9]+ DISABLED TEST/ { \ - if (match($$$$0, /[0-9]+/, arr)) { \ - print arr[0]; \ - found=1; \ - } \ - } \ - END { if (!found) print 0; }' \ - $$($1_RESULT_FILE))) \ + $$(eval $1_GTEST_DISABLED := $$(shell $$(AWK) '/YOU HAVE .* DISABLED TEST/ \ + { print $$$$3 }' $$($1_RESULT_FILE))) \ + $$(if $$($1_GTEST_DISABLED), , $$(eval $1_GTEST_DISABLED := 0)) \ + $$(eval $1_GTEST_SKIPPED := $$(shell $$(AWK) '/\[ SKIPPED \] .* tests?.*/ \ + { print $$$$4 }' $$($1_RESULT_FILE))) \ + $$(if $$($1_GTEST_SKIPPED), , $$(eval $1_GTEST_SKIPPED := 0)) \ + $$(eval $1_SKIPPED := $$(shell \ + $$(EXPR) $$($1_GTEST_DISABLED) + $$($1_GTEST_SKIPPED))) \ $$(eval $1_FAILED := $$(shell $$(AWK) '/\[ FAILED \] .* tests?, \ listed below/ { print $$$$4 }' $$($1_RESULT_FILE))) \ $$(if $$($1_FAILED), , $$(eval $1_FAILED := 0)) \ $$(eval $1_ERROR := $$(shell \ - $$(EXPR) $$($1_RUN) - $$($1_PASSED) - $$($1_FAILED))) \ + $$(EXPR) $$($1_RUN) - $$($1_PASSED) - $$($1_FAILED) - $$($1_GTEST_SKIPPED))) \ $$(eval $1_TOTAL := $$(shell \ - $$(EXPR) $$($1_RUN) + $$($1_SKIPPED))) \ + $$(EXPR) $$($1_RUN) + $$($1_GTEST_DISABLED))) \ , \ $$(eval $1_PASSED := 0) \ $$(eval $1_FAILED := 0) \ From 3090e2187c2cbbbc08f27305d152664a83736dfa Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 15 Apr 2025 06:03:50 +0000 Subject: [PATCH 0581/1101] 8353572: x86: AMD platforms miss the check for CLWB feature flag Reviewed-by: vlivanov, kvn --- src/hotspot/cpu/x86/vm_version_x86.cpp | 38 ++++++++++---------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index f7c9ebef3efe6..32e6e33d13380 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -3062,6 +3062,10 @@ uint64_t VM_Version::CpuidInfo::feature_flags() const { result |= CPU_TSCINV_BIT; if (std_cpuid1_ecx.bits.aes != 0) result |= CPU_AES; + if (ext_cpuid1_ecx.bits.lzcnt != 0) + result |= CPU_LZCNT; + if (ext_cpuid1_ecx.bits.prefetchw != 0) + result |= CPU_3DNOW_PREFETCH; if (sef_cpuid7_ebx.bits.erms != 0) result |= CPU_ERMS; if (sef_cpuid7_edx.bits.fast_short_rep_mov != 0) @@ -3080,48 +3084,36 @@ uint64_t VM_Version::CpuidInfo::feature_flags() const { result |= CPU_FMA; if (sef_cpuid7_ebx.bits.clflushopt != 0) result |= CPU_FLUSHOPT; + if (sef_cpuid7_ebx.bits.clwb != 0) + result |= CPU_CLWB; if (ext_cpuid1_edx.bits.rdtscp != 0) result |= CPU_RDTSCP; if (sef_cpuid7_ecx.bits.rdpid != 0) result |= CPU_RDPID; - // AMD|Hygon features. + // AMD|Hygon additional features. if (is_amd_family()) { - if ((ext_cpuid1_edx.bits.tdnow != 0) || - (ext_cpuid1_ecx.bits.prefetchw != 0)) + // PREFETCHW was checked above, check TDNOW here. + if ((ext_cpuid1_edx.bits.tdnow != 0)) result |= CPU_3DNOW_PREFETCH; - if (ext_cpuid1_ecx.bits.lzcnt != 0) - result |= CPU_LZCNT; if (ext_cpuid1_ecx.bits.sse4a != 0) result |= CPU_SSE4A; } - // Intel features. + // Intel additional features. if (is_intel()) { - if (ext_cpuid1_ecx.bits.lzcnt != 0) { - result |= CPU_LZCNT; - } - if (ext_cpuid1_ecx.bits.prefetchw != 0) { - result |= CPU_3DNOW_PREFETCH; - } - if (sef_cpuid7_ebx.bits.clwb != 0) { - result |= CPU_CLWB; - } if (sef_cpuid7_edx.bits.serialize != 0) result |= CPU_SERIALIZE; - if (_cpuid_info.sef_cpuid7_edx.bits.avx512_fp16 != 0) result |= CPU_AVX512_FP16; } - // ZX features. + // ZX additional features. if (is_zx()) { - if (ext_cpuid1_ecx.bits.lzcnt != 0) { - result |= CPU_LZCNT; - } - if (ext_cpuid1_ecx.bits.prefetchw != 0) { - result |= CPU_3DNOW_PREFETCH; - } + // We do not know if these are supported by ZX, so we cannot trust + // common CPUID bit for them. + assert((result & CPU_CLWB) == 0, "Check if it is supported?"); + result &= ~CPU_CLWB; } // Protection key features. From b78378437cf911a527331e6aaf36f968169c0574 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Tue, 15 Apr 2025 08:41:37 +0000 Subject: [PATCH 0582/1101] 8354163: Open source Swing tests Batch 1 Reviewed-by: psadhukhan --- .../swing/AbstractButton/bug4133768.java | 162 +++++++++++++++++ .../swing/AbstractButton/bug4391622.java | 142 +++++++++++++++ test/jdk/javax/swing/JList/bug4183379.java | 85 +++++++++ test/jdk/javax/swing/JList/bug4251306.java | 115 ++++++++++++ test/jdk/javax/swing/JMenu/bug4624845.java | 164 ++++++++++++++++++ 5 files changed, 668 insertions(+) create mode 100644 test/jdk/javax/swing/AbstractButton/bug4133768.java create mode 100644 test/jdk/javax/swing/AbstractButton/bug4391622.java create mode 100644 test/jdk/javax/swing/JList/bug4183379.java create mode 100644 test/jdk/javax/swing/JList/bug4251306.java create mode 100644 test/jdk/javax/swing/JMenu/bug4624845.java diff --git a/test/jdk/javax/swing/AbstractButton/bug4133768.java b/test/jdk/javax/swing/AbstractButton/bug4133768.java new file mode 100644 index 0000000000000..ad5f56c014984 --- /dev/null +++ b/test/jdk/javax/swing/AbstractButton/bug4133768.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4133768 4363569 + * @summary Tests how button displays its icons + * @key headful + * @run main bug4133768 + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.Point; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.io.IOException; +import javax.swing.AbstractButton; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JToggleButton; +import javax.swing.SwingUtilities; + +public class bug4133768 { + private static Icon RED, GREEN; + private static JFrame f; + private static AbstractButton[] buttons; + private static volatile Point buttonLocation; + private static volatile int buttonWidth; + private static volatile int buttonHeight; + private static Robot robot; + + public static void main(String[] args) throws Exception { + try { + createTestImages(); + createUI(); + robot = new Robot(); + robot.delay(1000); + for (AbstractButton b : buttons) { + testEnabledButton(b); + } + for (AbstractButton b : buttons) { + b.setEnabled(false); + robot.delay(1000); + testDisabledButton(b); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private static void createTestImages() throws IOException { + int imageWidth = 32; + int imageHeight = 32; + BufferedImage redImg = new BufferedImage(imageWidth, imageHeight, + BufferedImage.TYPE_INT_RGB); + Graphics2D g = redImg.createGraphics(); + g.setColor(Color.RED); + g.fillRect(0, 0, imageWidth, imageHeight); + g.dispose(); + RED = new ImageIcon(redImg); + BufferedImage greenImg = new BufferedImage(imageWidth, imageHeight, + BufferedImage.TYPE_INT_RGB); + g = greenImg.createGraphics(); + g.setColor(Color.GREEN); + g.fillRect(0, 0, imageWidth, imageHeight); + g.dispose(); + GREEN = new ImageIcon(greenImg); + } + + private static void createUI() throws Exception { + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("ButtonIconsTest"); + buttons = new AbstractButton[] { + new JToggleButton(), + new JRadioButton(), + new JCheckBox() + }; + + JPanel buttonPanel = new JPanel(); + for (int i = 0; i < buttons.length; i++) { + AbstractButton b = buttons[i]; + b.setIcon(RED); + b.setSelected(true); + b.setRolloverSelectedIcon(GREEN); + buttonPanel.add(b); + } + f.setLayout(new GridLayout(2, 1)); + f.add(buttonPanel); + f.pack(); + f.setLocationRelativeTo(null); + f.setAlwaysOnTop(true); + f.setVisible(true); + }); + } + + private static void testEnabledButton(AbstractButton button) throws Exception { + robot.waitForIdle(); + SwingUtilities.invokeAndWait(() -> { + buttonLocation = button.getLocationOnScreen(); + buttonWidth = button.getWidth(); + buttonHeight = button.getHeight(); + }); + robot.mouseMove(buttonLocation.x + buttonWidth / 2, + buttonLocation.y + buttonHeight / 2 ); + robot.delay(1000); + Color buttonColor = robot.getPixelColor(buttonLocation.x + + buttonWidth / 2, buttonLocation.y + buttonHeight / 2); + if (!buttonColor.equals(Color.GREEN)) { + throw new RuntimeException("Button roll over color is : " + + buttonColor + " but it should be : " + Color.GREEN); + } + } + + private static void testDisabledButton(AbstractButton button) throws Exception { + robot.waitForIdle(); + SwingUtilities.invokeAndWait(() -> { + buttonLocation = button.getLocationOnScreen(); + buttonWidth = button.getWidth(); + buttonHeight = button.getHeight(); + }); + robot.mouseMove(buttonLocation.x + buttonWidth / 2, + buttonLocation.y + buttonHeight / 2 ); + robot.delay(1000); + Color buttonColor = robot.getPixelColor(buttonLocation.x + + buttonWidth / 2, buttonLocation.y + buttonHeight / 2); + if (buttonColor.equals(Color.GREEN) || + buttonColor.equals(Color.RED)) { + throw new RuntimeException("Disabled button color should not be : " + + buttonColor); + } + } +} diff --git a/test/jdk/javax/swing/AbstractButton/bug4391622.java b/test/jdk/javax/swing/AbstractButton/bug4391622.java new file mode 100644 index 0000000000000..7d3e8588f1755 --- /dev/null +++ b/test/jdk/javax/swing/AbstractButton/bug4391622.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.image.BufferedImage; +import java.io.IOException; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JToolBar; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4391622 + * @summary The toolbar's button which is added as action should ignore text + * @key headful + * @run main bug4391622 + */ + +public class bug4391622 { + private static Icon RED, GREEN; + private static JButton bt; + private static JFrame f; + private static volatile Point buttonLocation; + private static volatile int buttonWidth; + private static volatile int buttonHeight; + + public static void main(String[] args) throws Exception { + try { + createTestImages(); + createUI(); + runTest(); + verifyTest(); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private static void createTestImages() throws IOException { + int imageWidth = 32; + int imageHeight = 32; + BufferedImage redImg = new BufferedImage(imageWidth, imageHeight, + BufferedImage.TYPE_INT_RGB); + Graphics2D g = redImg.createGraphics(); + g.setColor(Color.RED); + g.fillRect(0, 0, imageWidth, imageHeight); + g.dispose(); + RED = new ImageIcon(redImg); + BufferedImage greenImg = new BufferedImage(imageWidth, imageHeight, + BufferedImage.TYPE_INT_RGB); + g = greenImg.createGraphics(); + g.setColor(Color.GREEN); + g.fillRect(0, 0, imageWidth, imageHeight); + g.dispose(); + GREEN = new ImageIcon(greenImg); + } + + private static void createUI() throws Exception { + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("bug4391622"); + Action changeIt = new ChangeIt(); + + JToolBar toolbar = new JToolBar(); + bt = toolbar.add(changeIt); + f.add(bt); + f.pack(); + f.setLocationRelativeTo(null); + f.setVisible(true); + }); + } + + private static void runTest() throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(500); + robot.waitForIdle(); + SwingUtilities.invokeAndWait(() -> { + buttonLocation = bt.getLocationOnScreen(); + buttonWidth = bt.getWidth(); + buttonHeight = bt.getHeight(); + }); + robot.mouseMove(buttonLocation.x + buttonWidth / 2, + buttonLocation.y + buttonHeight / 2 ); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + } + + private static void verifyTest() { + if (bt.getText() != null) { + throw new RuntimeException("The toolbar's button shouldn't" + + " have any text."); + } + } + + public static class ChangeIt extends AbstractAction { + private boolean c = true; + + public ChangeIt() { + putValue(Action.NAME, "Red"); + putValue(Action.SMALL_ICON, RED); + } + + public void actionPerformed(ActionEvent event) { + c = !c; + putValue(Action.NAME, c ? "Red" : "Green"); + putValue(Action.SMALL_ICON, c ? RED : GREEN); + } + } +} diff --git a/test/jdk/javax/swing/JList/bug4183379.java b/test/jdk/javax/swing/JList/bug4183379.java new file mode 100644 index 0000000000000..784b92a6f16f9 --- /dev/null +++ b/test/jdk/javax/swing/JList/bug4183379.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4183379 + * @summary JList has wrong scrolling behavior when you click in the "troth" + * of a scrollbar, in a scrollpane. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4183379 + */ + +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JScrollPane; + +public class bug4183379 { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Click mouse several times in the "troth" of a scrollbars + in a scrollpane containing a list. + The list should scrolls by one block, i.e.: + + For vertical scrolling: + - if scrolling down the last visible element should become the + first completely visible element + - if scrolling up, the first visible element should become the + last completely visible element + + For horizontal scrolling: + - for scrolling left if the beginning of the first column is not + visible it should become visible, otherwise the beginning of the + previous column should become visible; + - for scrolling right the next colunm after first visible column + should become visible. + """; + PassFailJFrame.builder() + .title("bug4183379 Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(bug4183379::initialize) + .build() + .awaitAndCheck(); + } + + private static JFrame initialize() { + JFrame fr = new JFrame("bug4183379"); + + String[] data = new String[90]; + for (int i=0; i<90; i++) { + data[i] = "item number "+i; + } + + JList lst = new JList(data); + lst.setLayoutOrientation(JList.VERTICAL_WRAP); + lst.setVisibleRowCount(20); + + JScrollPane jsp = new JScrollPane(lst); + fr.add(jsp); + fr.setSize(210,200); + fr.setAlwaysOnTop(true); + return fr; + } +} diff --git a/test/jdk/javax/swing/JList/bug4251306.java b/test/jdk/javax/swing/JList/bug4251306.java new file mode 100644 index 0000000000000..ec53094608859 --- /dev/null +++ b/test/jdk/javax/swing/JList/bug4251306.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4251306 + * @summary Test that Shift-Space keybinding works properly in JList. + * @key headful + * @run main bug4251306 + */ + +import java.awt.Robot; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; + +public class bug4251306 { + private static JFrame f; + private static JList lst; + private static CountDownLatch listGainedFocusLatch; + private static volatile boolean failed; + public static void main(String[] args) throws Exception { + try { + listGainedFocusLatch = new CountDownLatch(1); + createUI(); + runTest(); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private static void createUI() throws Exception { + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("bug4251306"); + lst = new JList<>(new String[]{"anaheim", "bill", + "chicago", "dingo"}); + lst.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + listGainedFocusLatch.countDown(); + } + }); + JScrollPane sp = new JScrollPane(lst); + f.add(sp); + f.pack(); + f.setLocationRelativeTo(null); + f.setAlwaysOnTop(true); + f.setVisible(true); + }); + } + + private static void runTest() throws Exception { + if (!listGainedFocusLatch.await(3, TimeUnit.SECONDS)) { + throw new RuntimeException("Waited too long, but can't gain focus for list"); + } + Robot robot = new Robot(); + robot.setAutoDelay(500); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_A); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_SPACE); + robot.keyPress(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_DOWN); + robot.keyPress(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_DOWN); + robot.keyPress(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_SPACE); + robot.keyRelease(KeyEvent.VK_SHIFT); + + SwingUtilities.invokeAndWait(() -> { + if (!lst.isSelectedIndex(0) || + !lst.isSelectedIndex(1) || + !lst.isSelectedIndex(2) || + !lst.isSelectedIndex(3)) { + failed = true; + } + }); + if (failed) { + throw new RuntimeException("Required list items are not selected"); + } + } +} diff --git a/test/jdk/javax/swing/JMenu/bug4624845.java b/test/jdk/javax/swing/JMenu/bug4624845.java new file mode 100644 index 0000000000000..54524b7a42e7e --- /dev/null +++ b/test/jdk/javax/swing/JMenu/bug4624845.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4624845 + * @requires (os.family == "windows") + * @summary Tests how submenus in WinLAF are painted + * @key headful + * @run main bug4624845 + */ + +import java.awt.Color; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class bug4624845 { + private static JFrame f; + private static JMenu menu, subMenu; + private static JMenuItem menuItem; + private static volatile Point menuLocation; + private static volatile Point subMenuLocation; + private static volatile Point menuItemLocation; + private static volatile int menuWidth; + private static volatile int menuHeight; + private static volatile int subMenuWidth; + private static volatile int subMenuHeight; + private static volatile int menuItemWidth; + private static volatile int menuItemHeight; + private static Color menuItemColor; + private static Color subMenuColor; + private static boolean passed; + private final static int OFFSET = 2; + private static final int COLOR_TOLERANCE = 10; + + public static void main(String[] args) throws Exception { + try { + UIManager.setLookAndFeel + ("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + } catch (Exception e) { + throw new RuntimeException("Failed to set Windows LAF"); + } + try { + bug4624845 test = new bug4624845(); + SwingUtilities.invokeAndWait(() -> test.createUI()); + runTest(); + verifyColor(); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + if (!passed) { + throw new RuntimeException("Nested MenuItem color : " + + menuItemColor + " is not similar to sub Menu color : " + + subMenuColor); + } + } + private void createUI() { + f = new JFrame("bug4624845"); + menu = new JMenu("Menu"); + menu.add(new JMenuItem("Item 1")); + + subMenu = new JMenu("Submenu"); + menuItem = new JMenuItem("This"); + subMenu.add(menuItem); + subMenu.add(new JMenuItem("That")); + menu.add(subMenu); + + JMenuBar mBar = new JMenuBar(); + mBar.add(menu); + f.add(mBar); + f.pack(); + f.setLocationRelativeTo(null); + f.setVisible(true); + } + + private static void runTest() throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(200); + robot.waitForIdle(); + SwingUtilities.invokeAndWait(() -> { + menuLocation = menu.getLocationOnScreen(); + menuWidth = menu.getWidth(); + menuHeight = menu.getHeight(); + }); + robot.mouseMove(menuLocation.x + menuWidth / 2, + menuLocation.y + menuHeight / 2 ); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + SwingUtilities.invokeAndWait(() -> { + subMenuLocation = subMenu.getLocationOnScreen(); + subMenuWidth = subMenu.getWidth(); + subMenuHeight = subMenu.getHeight(); + }); + robot.mouseMove(subMenuLocation.x + subMenuWidth / 2, + subMenuLocation.y + subMenuHeight / 2 ); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + subMenuColor = robot. + getPixelColor(subMenuLocation.x + OFFSET, + subMenuLocation.y + OFFSET); + SwingUtilities.invokeAndWait(() -> { + menuItemLocation = menuItem.getLocationOnScreen(); + menuItemWidth = subMenu.getWidth(); + menuItemHeight = subMenu.getHeight(); + }); + robot.mouseMove(menuItemLocation.x + menuItemWidth / 2, + menuItemLocation.y + menuItemHeight / 2 ); + robot.waitForIdle(); + menuItemColor = robot. + getPixelColor(menuItemLocation.x + OFFSET, + menuItemLocation.y + OFFSET); + } + + private static void verifyColor() { + + int red1 = subMenuColor.getRed(); + int blue1 = subMenuColor.getBlue(); + int green1 = subMenuColor.getGreen(); + + int red2 = menuItemColor.getRed(); + int blue2 = menuItemColor.getBlue(); + int green2 = menuItemColor.getGreen(); + + passed = true; + if ((Math.abs(red1 - red2) > COLOR_TOLERANCE) + || (Math.abs(green1 - green2) > COLOR_TOLERANCE) + || (Math.abs(blue1 - blue2) > COLOR_TOLERANCE)) { + passed = false; + } + } +} From 24be888d655a5227cfb9fc22f36d6ba30d732b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Lund=C3=A9n?= Date: Tue, 15 Apr 2025 08:58:02 +0000 Subject: [PATCH 0583/1101] 8351833: Unexpected increase in live nodes when splitting Phis through MergeMems in PhiNode::Ideal Reviewed-by: chagedorn, rcastanedalo, kvn --- src/hotspot/share/opto/cfgnode.cpp | 22 ++---- src/hotspot/share/opto/phaseX.cpp | 20 +++++- test/hotspot/jtreg/TEST.groups | 1 + .../igvn/TestSplitPhiThroughMergeMem.java | 70 +++++++++++++++++++ 4 files changed, 95 insertions(+), 18 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/igvn/TestSplitPhiThroughMergeMem.java diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 4cf080a2e196a..5bf0d6facc13b 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -2530,11 +2530,9 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { // MergeMem(Phi(...m0...), Phi:AT1(...m1...), Phi:AT2(...m2...)) PhaseIterGVN* igvn = phase->is_IterGVN(); assert(igvn != nullptr, "sanity check"); - Node* hook = new Node(1); PhiNode* new_base = (PhiNode*) clone(); // Must eagerly register phis, since they participate in loops. igvn->register_new_node_with_optimizer(new_base); - hook->add_req(new_base); MergeMemNode* result = MergeMemNode::make(new_base); for (uint i = 1; i < req(); ++i) { @@ -2548,7 +2546,6 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node* new_phi = new_base->slice_memory(mms.adr_type(phase->C)); made_new_phi = true; igvn->register_new_node_with_optimizer(new_phi); - hook->add_req(new_phi); mms.set_memory(new_phi); } Node* phi = mms.memory(); @@ -2566,19 +2563,12 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { } } } - // Already replace this phi node to cut it off from the graph to not interfere in dead loop checks during the - // transformations of the new phi nodes below. Otherwise, we could wrongly conclude that there is no dead loop - // because we are finding this phi node again. Also set the type of the new MergeMem node in case we are also - // visiting it in the transformations below. - igvn->replace_node(this, result); - igvn->set_type(result, result->bottom_type()); - - // now transform the new nodes, and return the mergemem - for (MergeMemStream mms(result); mms.next_non_empty(); ) { - Node* phi = mms.memory(); - mms.set_memory(phase->transform(phi)); - } - hook->destruct(igvn); + + // We could immediately transform the new Phi nodes here, but that can + // result in creating an excessive number of new nodes within a single + // IGVN iteration. We have put the Phi nodes on the IGVN worklist, so + // they are transformed later on in any case. + // Replace self with the result. return result; } diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 90bc923187354..f0c8f9d76494f 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1024,11 +1024,18 @@ void PhaseIterGVN::optimize() { shuffle_worklist(); } + // The node count check in the loop below (check_node_count) assumes that we + // increase the live node count with at most + // max_live_nodes_increase_per_iteration in between checks. If this + // assumption does not hold, there is a risk that we exceed the max node + // limit in between checks and trigger an assert during node creation. + const int max_live_nodes_increase_per_iteration = NodeLimitFudgeFactor * 2; + uint loop_count = 0; // Pull from worklist and transform the node. If the node has changed, // update edge info and put uses on worklist. - while(_worklist.size()) { - if (C->check_node_count(NodeLimitFudgeFactor * 2, "Out of nodes")) { + while (_worklist.size() > 0) { + if (C->check_node_count(max_live_nodes_increase_per_iteration, "Out of nodes")) { C->print_method(PHASE_AFTER_ITER_GVN, 3); return; } @@ -1043,7 +1050,16 @@ void PhaseIterGVN::optimize() { if (n->outcnt() != 0) { NOT_PRODUCT(const Type* oldtype = type_or_null(n)); // Do the transformation + DEBUG_ONLY(int live_nodes_before = C->live_nodes();) Node* nn = transform_old(n); + DEBUG_ONLY(int live_nodes_after = C->live_nodes();) + // Ensure we did not increase the live node count with more than + // max_live_nodes_increase_per_iteration during the call to transform_old + DEBUG_ONLY(int increase = live_nodes_after - live_nodes_before;) + assert(increase < max_live_nodes_increase_per_iteration, + "excessive live node increase in single iteration of IGVN: %d " + "(should be at most %d)", + increase, max_live_nodes_increase_per_iteration); NOT_PRODUCT(trace_PhaseIterGVN(n, nn, oldtype);) } else if (!n->is_top()) { remove_dead_node(n); diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index eb80d74e5f094..4624d74f5577b 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -185,6 +185,7 @@ tier1_compiler_2 = \ compiler/integerArithmetic/ \ compiler/interpreter/ \ compiler/jvmci/ \ + compiler/igvn/ \ -compiler/classUnloading/methodUnloading/TestOverloadCompileQueues.java \ -compiler/codecache/stress \ -compiler/codegen/aes \ diff --git a/test/hotspot/jtreg/compiler/igvn/TestSplitPhiThroughMergeMem.java b/test/hotspot/jtreg/compiler/igvn/TestSplitPhiThroughMergeMem.java new file mode 100644 index 0000000000000..5c999dd61c2fe --- /dev/null +++ b/test/hotspot/jtreg/compiler/igvn/TestSplitPhiThroughMergeMem.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8351833 + * @summary Splitting Phi memory nodes through MergeMem nodes in PhiNode::Ideal + * could sometimes result in a too large number of added nodes within + * a single iteration of the main loop in PhaseIterGVN::optimize. This + * test, reduced from TestScalarReplacementMaxLiveNodes, triggers an + * assert added as part of the fix for the linked bug/issue (the + * assert naturally triggers only before the fix). The test's ability + * to trigger the issue is quite sensitive to the specific String + * constants used. The current set of chosen String constants happened + * to work particularly well. + * @run main/othervm -Xbatch + * -XX:CompileCommand=CompileOnly,compiler.igvn.TestSplitPhiThroughMergeMem::test + * compiler.igvn.TestSplitPhiThroughMergeMem + * @run main compiler.igvn.TestSplitPhiThroughMergeMem + */ + +package compiler.igvn; + +public class TestSplitPhiThroughMergeMem { + + public static void main(String[] args) { + for (int i = 0; i < 10_000; i++) { + int val = i % 50; + test(val == 0, val % 10, val % 20); + } + } + + static void test(boolean flag, int param1, int param2) { + if (flag) { + new String("tenth" + param1); + new String("eleventh" + param2); + new String("fifteenth" + param2); + new String("sixteenth" + param1); + new String("seventeenth" + param1); + new String("nineteenth" + param2); + new String("tweenth" + param1); + new String("nineth" + param1); + new String("nineth" + param1); + new String("eighteenth" + param1); + new String("abcdef" + param2); + new String("ghijklmn" + param1); + new String("ghijklmn" + param1); + } + } +} From 81d4c80742305b72c73a59cf6a596b49bc68bab9 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 15 Apr 2025 09:02:41 +0000 Subject: [PATCH 0584/1101] 8354507: [ubsan] subnode.cpp:406:36: runtime error: negation of -9223372036854775808 cannot be represented in type 'long int' Reviewed-by: mdoerr, thartmann --- src/hotspot/share/opto/subnode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index 24d1f820ffbc0..d138438410151 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -403,7 +403,7 @@ Node *SubLNode::Ideal(PhaseGVN *phase, bool can_reshape) { return new SubLNode(sub2, in21); } else { Node* sub2 = phase->transform(new SubLNode(in1, in21)); - Node* neg_c0 = phase->longcon(-c0); + Node* neg_c0 = phase->longcon(java_negate(c0)); return new AddLNode(sub2, neg_c0); } } From d7676c39b648bd55f72a50494432b02862a4e111 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Tue, 15 Apr 2025 09:48:11 +0000 Subject: [PATCH 0585/1101] 8354508: JFR: Strengthen metadata checks for labels Reviewed-by: shade --- src/hotspot/share/jfr/metadata/metadata.xml | 18 ++-- .../jfr/event/metadata/TestEventMetadata.java | 85 ++++++++++++++----- 2 files changed, 72 insertions(+), 31 deletions(-) diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 2b04b433c29f2..644abcc324c5a 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -453,10 +453,10 @@ - - - - + + + + - + @@ -1007,7 +1007,7 @@ - + @@ -1030,10 +1030,10 @@ - + - - + + diff --git a/test/jdk/jdk/jfr/event/metadata/TestEventMetadata.java b/test/jdk/jdk/jfr/event/metadata/TestEventMetadata.java index e3255909fccb7..78a92d9a2d9ad 100644 --- a/test/jdk/jdk/jfr/event/metadata/TestEventMetadata.java +++ b/test/jdk/jdk/jfr/event/metadata/TestEventMetadata.java @@ -23,6 +23,7 @@ package jdk.jfr.event.metadata; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -51,7 +52,7 @@ public class TestEventMetadata { * ---- * * Symbolic name that is used to identify an event, or a field. Referred to - * as "id" and "field" in trace.xml-files and @Name in the Java API. If it is + * as "name" in metadata.xml and @Name in the Java API. If it is * the name of an event, the name should be prefixed "jdk.", which * happens automatically for native events. * @@ -61,10 +62,10 @@ public class TestEventMetadata { * "allocationRate" for a field. Do not use "_" and don't add the word * "Event" to the event name. * - * Abbreviations should be avoided, but may be acceptable if the name - * becomes long, or if it is a well established acronym. Write whole words, - * i.e. "allocation" instead of "alloc". The name should not be a reserved - * Java keyword, i.e "void" or "class". + * Abbreviations, such as info, alloc, num, gen, conf, stat, and evac, should + * be avoided. For example, use "allocation" instead of "alloc". Acronyms should be + * avoided unless they are well-established. The name should not be a reserved + * Java keyword, such as "void" or "class". * * Label * ----- @@ -84,8 +85,8 @@ public class TestEventMetadata { * period should not be included. * * - * Do not forget to set proper units for fields, i.e "NANOS", "MILLS", - * "TICKSPAN" ,"BYETS", "PECENTAGE" etc. in native and @Timespan, @Timespan + * Do not forget to set proper units for fields, such as "NANOS", "MILLIS", + * "TICKSPAN", "BYTES", and "PERCENTAGE", in native and @Timespan, @Timespan * etc. in Java. */ public static void main(String[] args) throws Exception { @@ -161,18 +162,63 @@ private static void verifyName(String name) { } private static void verifyLabel(String label) { + System.out.println("Verifying label: " + label); Asserts.assertNotEquals(label, null, "Label not allowed to be null"); - Asserts.assertTrue(label.length() > 1, "Name must be at least two characters"); - Asserts.assertTrue(label.length() < 45, "Label should not exceed 45 characters, use description to explain " + label); - Asserts.assertTrue(label.length() == label.trim().length(), "Label should not have trim character at start and end"); - Asserts.assertTrue(Character.isUpperCase(label.charAt(0)), "Label should start with upper case letter"); - for (int i = 0; i < label.length(); i++) { - char c = label.charAt(i); - Asserts.assertTrue(Character.isDigit(c) || Character.isAlphabetic(label.charAt(i)) || c == ' ' || c == '(' || c == ')' || c == '-', "Label should only consist of letters or space, found '" + label.charAt(i) - + "'"); + Asserts.assertTrue(label.length() > 1, "Label must be at least two characters"); + Asserts.assertTrue(label.length() <= 45, "Label should not exceed 45 characters, use description to explain"); + Asserts.assertTrue(label.length() == label.trim().length(), "Label should not have superfluous whitespace at start or end"); + + String[] words = label.split(" "); + String[] middleWords = words.length > 2 ? Arrays.copyOfRange(words, 1, words.length - 1) : new String[0]; + String firstWord = words[0]; + String lastWord = words[words.length - 1]; + Asserts.assertTrue(isCapitalized(firstWord), "Label should capitalize first word"); + + // The isNumeric check is a workaround so "GC Phase Pause Level 1" doesn't fail. + if (!isNumeric(lastWord)) { + Asserts.assertTrue(isCapitalized(lastWord), "Label should capitalize last word"); + } + for (String word : words) { + Asserts.assertFalse(word.endsWith("-") || word.startsWith("-"), "Word in label should not start or end with hyphen"); + Asserts.assertTrue(word.length() != 0, "Label should not contain superfluous whitespace"); + if (isCapitalized(word)) { + for (String w : word.split("-")) { + Asserts.assertTrue(isCapitalized(w), "Label should capitalize all words in a hyphenated word"); + } + } + } + for (String word : middleWords) { + if (isShortCommonPreposition(word)) { + Asserts.assertFalse(isCapitalized(word), "Preposition in label should be lower case, unless first and last word"); + } + } + for (char c : label.toCharArray()) { + Asserts.assertTrue(isAllowedCharacter(c), "Label should only consist of letters, numbers, hyphens, parentheses or whitespace, found '" + c + "'"); } } + private static boolean isAllowedCharacter(char c) { + return Character.isDigit(c) || Character.isAlphabetic(c) || c == ' ' || c == '(' || c == ')' || c == '-'; + } + + private static boolean isCapitalized(String word) { + String w = word.replace("(", "").replace(")", ""); + return !w.isEmpty() && Character.isUpperCase(w.charAt(0)); + } + + private static boolean isNumeric(String word) { + return word.chars().allMatch(Character::isDigit); + } + + private static boolean isShortCommonPreposition(String word) { + String[] prepositions = { "in", "on", "at", "by", "to", "of" }; + return containsWord(prepositions, word); + } + + private static boolean containsWord(String[] words, String match) { + return Arrays.asList(words).contains(match); + } + private static void verifyEventType(EventType eventType) { System.out.println("Verifying event: " + eventType.getName()); verifyDescription(eventType.getDescription()); @@ -182,7 +228,7 @@ private static void verifyEventType(EventType eventType) { String name = eventType.getName().substring(EventNames.PREFIX.length()); Asserts.assertFalse(isReservedKeyword(name),"Name must not be reserved keyword in the Java language (" + name + ")"); checkCommonAbbreviations(name); - char firstChar = name.charAt(0); + char firstChar = name.charAt(0); Asserts.assertFalse(name.contains("ID"), "'ID' should not be used in name, consider using 'Id'"); Asserts.assertTrue(Character.isAlphabetic(firstChar), "Name " + name + " must start with a character"); Asserts.assertTrue(Character.isUpperCase(firstChar), "Name " + name + " must start with upper case letter"); @@ -198,12 +244,7 @@ static boolean isReservedKeyword(String s) { "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum", "extends", "false", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "void", "volatile", "while" }; - for (int i = 0; i < keywords.length; i++) { - if (s.equals(keywords[i])) { - return true; - } - } - return false; + return containsWord(keywords, s); } private static void checkCommonAbbreviations(String name) { From 4e24dc003c2304041b342371adf430b120a9fec8 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Tue, 15 Apr 2025 10:16:31 +0000 Subject: [PATCH 0586/1101] 8353185: Introduce the concept of upgradeable files in context of JEP 493 Reviewed-by: clanger, ihse, alanb --- make/modules/jdk.jlink/Java.gmk | 32 ++++ .../jdk/tools/jlink/internal/JRTArchive.java | 22 ++- .../jlink/internal/LinkableRuntimeImage.java | 47 +++++- .../runtimelink/upgrade_files_java.base.conf | 4 + .../UpgradeableFileCacertsTest.java | 153 ++++++++++++++++++ 5 files changed, 254 insertions(+), 4 deletions(-) create mode 100644 make/modules/jdk.jlink/Java.gmk create mode 100644 src/jdk.jlink/share/classes/jdk/tools/jlink/internal/runtimelink/upgrade_files_java.base.conf create mode 100644 test/jdk/tools/jlink/runtimeImage/UpgradeableFileCacertsTest.java diff --git a/make/modules/jdk.jlink/Java.gmk b/make/modules/jdk.jlink/Java.gmk new file mode 100644 index 0000000000000..4ddd1eab03d92 --- /dev/null +++ b/make/modules/jdk.jlink/Java.gmk @@ -0,0 +1,32 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +################################################################################ + +# Instruct SetupJavaCompilation for the jdk.jlink module to include +# upgrade_files_.conf files +COPY += .conf + +################################################################################ diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JRTArchive.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JRTArchive.java index df7d35ac777ea..aac220e5b943e 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JRTArchive.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JRTArchive.java @@ -45,6 +45,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -76,6 +77,7 @@ public class JRTArchive implements Archive { private final Map resDiff; private final boolean errorOnModifiedFile; private final TaskHelper taskHelper; + private final Set upgradeableFiles; /** * JRTArchive constructor @@ -86,12 +88,15 @@ public class JRTArchive implements Archive { * install aborts the link. * @param perModDiff The lib/modules (a.k.a jimage) diff for this module, * possibly an empty list if there are no differences. + * @param taskHelper The task helper instance. + * @param upgradeableFiles The set of files that are allowed for upgrades. */ JRTArchive(String module, Path path, boolean errorOnModifiedFile, List perModDiff, - TaskHelper taskHelper) { + TaskHelper taskHelper, + Set upgradeableFiles) { this.module = module; this.path = path; this.ref = ModuleFinder.ofSystem() @@ -105,6 +110,7 @@ public class JRTArchive implements Archive { this.resDiff = Objects.requireNonNull(perModDiff).stream() .collect(Collectors.toMap(ResourceDiff::getName, Function.identity())); this.taskHelper = taskHelper; + this.upgradeableFiles = upgradeableFiles; } @Override @@ -217,7 +223,8 @@ private void addNonClassResources() { // Read from the base JDK image. Path path = BASE.resolve(m.resPath); - if (shaSumMismatch(path, m.hashOrTarget, m.symlink)) { + if (!isUpgradeableFile(m.resPath) && + shaSumMismatch(path, m.hashOrTarget, m.symlink)) { if (errorOnModifiedFile) { String msg = taskHelper.getMessage("err.runtime.link.modified.file", path.toString()); IOException cause = new IOException(msg); @@ -239,6 +246,17 @@ private void addNonClassResources() { } } + /** + * Certain files in a module are considered upgradeable. That is, + * their hash sums aren't checked. + * + * @param resPath The resource path of the file to check for upgradeability. + * @return {@code true} if the file is upgradeable. {@code false} otherwise. + */ + private boolean isUpgradeableFile(String resPath) { + return upgradeableFiles.contains(resPath); + } + static boolean shaSumMismatch(Path res, String expectedSha, boolean isSymlink) { if (isSymlink) { return false; diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/LinkableRuntimeImage.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/LinkableRuntimeImage.java index 935af4585ad7a..d564ed0bad8d8 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/LinkableRuntimeImage.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/LinkableRuntimeImage.java @@ -28,7 +28,10 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; +import java.util.HashSet; import java.util.List; +import java.util.Scanner; +import java.util.Set; import jdk.tools.jlink.internal.runtimelink.ResourceDiff; @@ -42,6 +45,9 @@ public class LinkableRuntimeImage { public static final String RESPATH_PATTERN = "jdk/tools/jlink/internal/runtimelink/fs_%s_files"; // The diff files per module for supporting linking from the run-time image public static final String DIFF_PATTERN = "jdk/tools/jlink/internal/runtimelink/diff_%s"; + // meta data for upgradable files + private static final String UPGRADEABLE_FILES_PATTERN = "jdk/tools/jlink/internal/runtimelink/upgrade_files_%s.conf"; + private static final Module JDK_JLINK_MOD = LinkableRuntimeImage.class.getModule(); /** * In order to be able to show whether or not a runtime is capable of @@ -62,7 +68,38 @@ public static boolean isLinkableRuntime() { private static InputStream getDiffInputStream(String module) throws IOException { String resourceName = String.format(DIFF_PATTERN, module); - return LinkableRuntimeImage.class.getModule().getResourceAsStream(resourceName); + return JDK_JLINK_MOD.getResourceAsStream(resourceName); + } + + private static Set upgradeableFiles(String module) { + String resourceName = String.format(UPGRADEABLE_FILES_PATTERN, module); + InputStream filesIn = null; + try { + filesIn = JDK_JLINK_MOD.getResourceAsStream(resourceName); + } catch (IOException e) { + throw new AssertionError("Unexpected IO error getting res stream"); + } + if (filesIn == null) { + // no upgradeable files + return Set.of(); + } + Set upgradeableFiles = new HashSet<>(); + final InputStream in = filesIn; + try (in; + Scanner scanner = new Scanner(filesIn)) { + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (line.trim().startsWith("#")) { + // Skip comments + continue; + } + upgradeableFiles.add(scanner.nextLine()); + } + } catch (IOException e) { + throw new AssertionError("Failure to retrieve upgradeable files for " + + "module " + module, e); + } + return upgradeableFiles; } public static Archive newArchive(String module, @@ -81,7 +118,13 @@ public static Archive newArchive(String module, throw new AssertionError("Failure to retrieve resource diff for " + "module " + module, e); } - return new JRTArchive(module, path, !ignoreModifiedRuntime, perModuleDiff, taskHelper); + Set upgradeableFiles = upgradeableFiles(module); + return new JRTArchive(module, + path, + !ignoreModifiedRuntime, + perModuleDiff, + taskHelper, + upgradeableFiles); } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/runtimelink/upgrade_files_java.base.conf b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/runtimelink/upgrade_files_java.base.conf new file mode 100644 index 0000000000000..df2ca809f089c --- /dev/null +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/runtimelink/upgrade_files_java.base.conf @@ -0,0 +1,4 @@ +# Configuration for resource paths of files allowed to be +# upgraded (in java.base) +lib/tzdb.dat +lib/security/cacerts diff --git a/test/jdk/tools/jlink/runtimeImage/UpgradeableFileCacertsTest.java b/test/jdk/tools/jlink/runtimeImage/UpgradeableFileCacertsTest.java new file mode 100644 index 0000000000000..86e0f8cefd5a9 --- /dev/null +++ b/test/jdk/tools/jlink/runtimeImage/UpgradeableFileCacertsTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2025, Red Hat, Inc. + * 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. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.security.KeyStore; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import jdk.test.lib.process.OutputAnalyzer; +import tests.Helper; + +/* + * @test + * @summary Verify that no errors are reported for files that have been + * upgraded when linking from the run-time image + * @requires (vm.compMode != "Xcomp" & os.maxMemory >= 2g) + * @library ../../lib /test/lib + * @modules java.base/jdk.internal.jimage + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.plugin + * jdk.jlink/jdk.tools.jimage + * @build tests.* jdk.test.lib.process.OutputAnalyzer + * jdk.test.lib.process.ProcessTools + * @run main/othervm -Xmx1g UpgradeableFileCacertsTest + */ +public class UpgradeableFileCacertsTest extends ModifiedFilesTest { + + /* + * Generated with: + * $ rm -f server.keystore && keytool -genkey -alias jlink-upgrade-test \ + * -keyalg RSA -dname CN=jlink-upgrade-test \ + * -storepass changeit -keysize 3072 -sigalg SHA512withRSA \ + * -validity 7300 -keystore server.keystore + * $ keytool -export -alias jlink-upgrade-test -storepass changeit \ + * -keystore server.keystore -rfc + */ + private static final String CERT = """ + -----BEGIN CERTIFICATE----- + MIID3jCCAkagAwIBAgIJALiT/+HXBkSIMA0GCSqGSIb3DQEBDQUAMB0xGzAZBgNV + BAMTEmpsaW5rLXVwZ3JhZGUtdGVzdDAeFw0yNTA0MDQxMjA3MjJaFw00NTAzMzAx + MjA3MjJaMB0xGzAZBgNVBAMTEmpsaW5rLXVwZ3JhZGUtdGVzdDCCAaIwDQYJKoZI + hvcNAQEBBQADggGPADCCAYoCggGBANmrnCDKqSXEJRIiSi4yHWN97ILls3RqYjED + la3AZTeXnZrrEIgSjVFUMxCztYqbWoVzKa2lov42Vue2BXVYffcQ8TKc2EJDNO+2 + uRKQZpsN7RI4QoVBR2Rq8emrO8CrdOQT7Hh4agxkN9AOvGKMFdt+fXeCIPIuflKP + f+RfvhLfC2A70Y+Uu74C5uWgLloA/HF0SsVxf9KmqS9fZBQaiTYhKyoDghCRlWpa + nPIHB1XVaRdw8aSpCuzIOQzSCTTlLcammJkBjbFwMZdQG7eglTWzIYryZwe/cyY2 + xctLVW3xhUHvnMFG+MajeFny2mxNu163Rxf/rBu4e7jRC/LGSU784nJGapq5K170 + WbaeceKp+YORJBviFFORrmkPIwIgE+iGCD6PD6Xwu8vcpeuTVDgsSWMlfgCL3NoI + GXmdGiI2Xc/hQX7uzu3UBF6IcPDMTcYr2JKYbgu3v2/vDlJu3qO2ycUeePo5jhuG + X2WgcHkb6uOU4W5qdbCA+wFPVZBuwQIDAQABoyEwHzAdBgNVHQ4EFgQUtMJM0+ct + ssKqryRckk4YEWdYAZkwDQYJKoZIhvcNAQENBQADggGBAI8A6gJQ8wDx12sy2ZI4 + 1q9b+WG6w3LcFEF6Fko5NBizhtfmVycQv4mBa/NJgx4DZmd+5d60gJcTp/hJXGY0 + LZyFilm/AgxsLNUUQLbHAV6TWqd3ODWwswAuew9sFU6izl286a9W65tbMWL5r1EA + t34ZYVWZYbCS9+czU98WomH4uarRAOlzcEUui3ZX6ZcQxWbz/R2wtKcUPUAYnsqH + JPivpE25G5xW2Dp/yeQTrlffq9OLgZWVz0jtOguBUMnsUsgCcpQZtqZX08//wtpz + ohLHFGvpXTPbRumRasWWtnRR/QqGRT66tYDqybXXz37UtKZ8VKW0sv2ypVbmAEs5 + pLkA/3XiXlstJuCD6cW0Gfbpb5rrPPD46O3FDVlmqlTH3b/MsiQREdydqGzqY7uG + AA2GFVaKFASA5ls01CfHLAcrKxSVixditXvsjeIqhddB7Pnbsx20RdzPQoeo9/hF + WeIrh4zePDPZChuLR8ZyxeVJhLB71nTrTDDjwXarVez9Xw== + -----END CERTIFICATE----- + """; + + private static final String CERT_ALIAS = "jlink-upgrade-test"; + + public static void main(String[] args) throws Exception { + UpgradeableFileCacertsTest test = new UpgradeableFileCacertsTest(); + test.run(); + } + + @Override + String initialImageName() { + return "java-base-jlink-upgrade-cacerts"; + } + + @Override + void testAndAssert(Path modifiedFile, Helper helper, Path initialImage) throws Exception { + CapturingHandler handler = new CapturingHandler(); + jlinkUsingImage(new JlinkSpecBuilder() + .helper(helper) + .imagePath(initialImage) + .name("java-base-jlink-upgrade-cacerts-target") + .addModule("java.base") + .validatingModule("java.base") + .build(), handler); + OutputAnalyzer analyzer = handler.analyzer(); + // verify we don't get any modified warning + analyzer.stdoutShouldNotContain(modifiedFile.toString() + " has been modified"); + analyzer.stdoutShouldNotContain("java.lang.IllegalArgumentException"); + analyzer.stdoutShouldNotContain("IOException"); + } + + // Add an extra certificate in the cacerts file so that it no longer matches + // the recorded hash sum at build time. + protected Path modifyFileInImage(Path jmodLessImg) + throws IOException, AssertionError { + Path cacerts = jmodLessImg.resolve(Path.of("lib", "security", "cacerts")); + try (FileInputStream fin = new FileInputStream(cacerts.toFile())) { + KeyStore certStore = KeyStore.getInstance(cacerts.toFile(), + (char[])null); + certStore.load(fin, (char[])null); + X509Certificate cert; + try (ByteArrayInputStream bin = new ByteArrayInputStream(CERT.getBytes())) { + cert = (X509Certificate)generateCertificate(bin); + } catch (ClassCastException | CertificateException ce) { + throw new AssertionError("Test failed unexpectedly", ce); + } + certStore.setCertificateEntry(CERT_ALIAS, cert); + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + certStore.store(bout, (char[])null); + try (FileOutputStream fout = new FileOutputStream(cacerts.toFile())) { + fout.write(bout.toByteArray()); + } + } catch (Exception e) { + throw new AssertionError("Test failed unexpectedly: ", e); + } + return cacerts; + } + + private Certificate generateCertificate(InputStream in) + throws CertificateException, IOException { + byte[] data = in.readAllBytes(); + return CertificateFactory.getInstance("X.509") + .generateCertificate(new ByteArrayInputStream(data)); + } +} From 03fd43fc91ea383418c1c7e0fd96a61a1f42c75e Mon Sep 17 00:00:00 2001 From: Patrick Strawderman Date: Tue, 15 Apr 2025 11:26:36 +0000 Subject: [PATCH 0587/1101] 8353453: URLDecoder should use HexFormat Reviewed-by: rriggs, jpai --- src/java.base/share/classes/java/net/URLDecoder.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/java/net/URLDecoder.java b/src/java.base/share/classes/java/net/URLDecoder.java index 45d18c9a47053..c7cdd7c4931a4 100644 --- a/src/java.base/share/classes/java/net/URLDecoder.java +++ b/src/java.base/share/classes/java/net/URLDecoder.java @@ -29,6 +29,7 @@ import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; +import java.util.HexFormat; import java.util.Objects; /** @@ -204,11 +205,7 @@ public static String decode(String s, Charset charset) { while ( ((i+2) < numChars) && (c=='%')) { - int v = Integer.parseInt(s, i + 1, i + 3, 16); - if (v < 0) - throw new IllegalArgumentException( - "URLDecoder: Illegal hex characters in escape " - + "(%) pattern - negative value"); + int v = HexFormat.fromHexDigits(s, i + 1, i + 3); bytes[pos++] = (byte) v; i+= 3; if (i < numChars) From 5fc18f5b8aa1b5f4fb4313b8d11fd15330795959 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Tue, 15 Apr 2025 11:41:47 +0000 Subject: [PATCH 0588/1101] 8350279: HttpClient: Add a new HttpResponse method to identify connections Reviewed-by: dfuchs, jpai --- .../classes/java/net/http/HttpResponse.java | 22 + .../net/http/AbstractAsyncSSLConnection.java | 5 +- .../internal/net/http/AsyncSSLConnection.java | 7 +- .../net/http/AsyncSSLTunnelConnection.java | 7 +- .../jdk/internal/net/http/HttpConnection.java | 49 +- .../internal/net/http/HttpResponseImpl.java | 16 +- .../net/http/PlainHttpConnection.java | 6 +- .../net/http/PlainProxyConnection.java | 6 +- .../net/http/PlainTunnelingConnection.java | 9 +- .../jdk/internal/net/http/SocketTube.java | 13 +- .../HttpResponseConnectionLabelTest.java | 491 ++++++++++++++++++ .../internal/net/http/ConnectionPoolTest.java | 4 +- 12 files changed, 600 insertions(+), 35 deletions(-) create mode 100644 test/jdk/java/net/httpclient/HttpResponseConnectionLabelTest.java diff --git a/src/java.net.http/share/classes/java/net/http/HttpResponse.java b/src/java.net.http/share/classes/java/net/http/HttpResponse.java index 5a274980fa311..52f5298452a7a 100644 --- a/src/java.net.http/share/classes/java/net/http/HttpResponse.java +++ b/src/java.net.http/share/classes/java/net/http/HttpResponse.java @@ -99,6 +99,28 @@ public interface HttpResponse { */ public int statusCode(); + /** + * {@return if present, a label identifying the connection on which the + * response was received} + *

+ * The format of the string is opaque, but the value is fixed and unique + * for any connection in the scope of the associated {@link HttpClient} + * instance. + * + * @implSpec + * The default implementation of this method returns + * {@link Optional#empty() Optional.empty()}. + * + * @implNote + * Instances of {@code HttpResponse} returned by the JDK built-in + * implementation of {@code HttpClient} always return a non-empty value. + * + * @since 25 + */ + default Optional connectionLabel() { + return Optional.empty(); + } + /** * Returns the {@link HttpRequest} corresponding to this response. * diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/AbstractAsyncSSLConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/AbstractAsyncSSLConnection.java index 20f727a99328e..52037ba497f16 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/AbstractAsyncSSLConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/AbstractAsyncSSLConnection.java @@ -74,8 +74,9 @@ abstract class AbstractAsyncSSLConnection extends HttpConnection AbstractAsyncSSLConnection(InetSocketAddress addr, HttpClientImpl client, ServerName serverName, int port, - String[] alpn) { - super(addr, client); + String[] alpn, + String label) { + super(addr, client, label); this.sniServerNames = formSNIServerNames(serverName, client); SSLContext context = client.theSSLContext(); sslParameters = createSSLParameters(client, this.sniServerNames, alpn); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLConnection.java index 598af68e37a72..56477e9604e68 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLConnection.java @@ -44,9 +44,10 @@ class AsyncSSLConnection extends AbstractAsyncSSLConnection { AsyncSSLConnection(InetSocketAddress addr, HttpClientImpl client, - String[] alpn) { - super(addr, client, Utils.getServerName(addr), addr.getPort(), alpn); - plainConnection = new PlainHttpConnection(addr, client); + String[] alpn, + String label) { + super(addr, client, Utils.getServerName(addr), addr.getPort(), alpn, label); + plainConnection = new PlainHttpConnection(addr, client, label); writePublisher = new PlainHttpPublisher(); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLTunnelConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLTunnelConnection.java index 862013cbf938b..1210f4dd62be1 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLTunnelConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLTunnelConnection.java @@ -47,10 +47,11 @@ class AsyncSSLTunnelConnection extends AbstractAsyncSSLConnection { HttpClientImpl client, String[] alpn, InetSocketAddress proxy, - ProxyHeaders proxyHeaders) + ProxyHeaders proxyHeaders, + String label) { - super(addr, client, Utils.getServerName(addr), addr.getPort(), alpn); - this.plainConnection = new PlainTunnelingConnection(addr, proxy, client, proxyHeaders); + super(addr, client, Utils.getServerName(addr), addr.getPort(), alpn, label); + this.plainConnection = new PlainTunnelingConnection(addr, proxy, client, proxyHeaders, label); this.writePublisher = new PlainHttpPublisher(); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java index d9dd533c0f03c..dd8f6652290f5 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ import java.io.Closeable; import java.io.IOException; import java.net.InetSocketAddress; +import java.net.http.HttpResponse; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.Arrays; @@ -39,6 +40,7 @@ import java.util.concurrent.CompletionStage; import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.Flow; +import java.util.concurrent.atomic.AtomicLong; import java.util.function.BiPredicate; import java.util.function.Predicate; import java.net.http.HttpClient; @@ -76,17 +78,46 @@ abstract class HttpConnection implements Closeable { public static final Comparator COMPARE_BY_ID = Comparator.comparing(HttpConnection::id); + private static final AtomicLong LABEL_COUNTER = new AtomicLong(); + /** The address this connection is connected to. Could be a server or a proxy. */ final InetSocketAddress address; private final HttpClientImpl client; private final TrailingOperations trailingOperations; + + /** + * A unique identifier that provides a total order among instances. + */ private final long id; - HttpConnection(InetSocketAddress address, HttpClientImpl client) { + /** + * A label to identify the connection. + *

+ * This label helps with associating multiple components participating in a + * connection. For instance, an {@link AsyncSSLConnection} and the + * {@link PlainHttpConnection} it wraps will share the same label. + *

+ */ + private final String label; + + HttpConnection(InetSocketAddress address, HttpClientImpl client, String label) { this.address = address; this.client = client; trailingOperations = new TrailingOperations(); this.id = newConnectionId(client); + this.label = label; + } + + private static String nextLabel() { + return "" + LABEL_COUNTER.incrementAndGet(); + } + + /** + * {@return a label identifying the connection to facilitate + * {@link HttpResponse#connectionLabel() HttpResponse::connectionLabel}} + */ + public final String label() { + return label; } // This is overridden in tests @@ -303,11 +334,13 @@ private static HttpConnection getSSLConnection(InetSocketAddress addr, String[] alpn, HttpRequestImpl request, HttpClientImpl client) { + String label = nextLabel(); if (proxy != null) return new AsyncSSLTunnelConnection(addr, client, alpn, proxy, - proxyTunnelHeaders(request)); + proxyTunnelHeaders(request), + label); else - return new AsyncSSLConnection(addr, client, alpn); + return new AsyncSSLConnection(addr, client, alpn, label); } /** @@ -381,14 +414,16 @@ private static HttpConnection getPlainConnection(InetSocketAddress addr, InetSocketAddress proxy, HttpRequestImpl request, HttpClientImpl client) { + String label = nextLabel(); if (request.isWebSocket() && proxy != null) return new PlainTunnelingConnection(addr, proxy, client, - proxyTunnelHeaders(request)); + proxyTunnelHeaders(request), + label); if (proxy == null) - return new PlainHttpConnection(addr, client); + return new PlainHttpConnection(addr, client, label); else - return new PlainProxyConnection(proxy, client); + return new PlainProxyConnection(proxy, client, label); } void closeOrReturnToCache(HttpHeaders hdrs) { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpResponseImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpResponseImpl.java index 52d281cc04e04..1552cd40edec0 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpResponseImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpResponseImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ class HttpResponseImpl implements HttpResponse, RawChannel.Provider { final int responseCode; + private final String connectionLabel; final HttpRequest initialRequest; final Optional> previousResponse; final HttpHeaders headers; @@ -59,6 +60,7 @@ public HttpResponseImpl(HttpRequest initialRequest, T body, Exchange exch) { this.responseCode = response.statusCode(); + this.connectionLabel = connectionLabel(exch).orElse(null); this.initialRequest = initialRequest; this.previousResponse = Optional.ofNullable(previousResponse); this.headers = response.headers(); @@ -70,11 +72,23 @@ public HttpResponseImpl(HttpRequest initialRequest, this.body = body; } + private static Optional connectionLabel(Exchange exchange) { + return Optional.ofNullable(exchange) + .map(e -> e.exchImpl) + .map(ExchangeImpl::connection) + .map(HttpConnection::label); + } + @Override public int statusCode() { return responseCode; } + @Override + public Optional connectionLabel() { + return Optional.ofNullable(connectionLabel); + } + @Override public HttpRequest request() { return initialRequest; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java index 76fbebe6cd01d..190df8a00bae8 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java @@ -310,8 +310,8 @@ final FlowTube getConnectionFlow() { return tube; } - PlainHttpConnection(InetSocketAddress addr, HttpClientImpl client) { - super(addr, client); + PlainHttpConnection(InetSocketAddress addr, HttpClientImpl client, String label) { + super(addr, client, label); try { this.chan = SocketChannel.open(); chan.configureBlocking(false); @@ -335,7 +335,7 @@ final FlowTube getConnectionFlow() { } chan.setOption(StandardSocketOptions.TCP_NODELAY, true); // wrap the channel in a Tube for async reading and writing - tube = new SocketTube(client(), chan, Utils::getBuffer); + tube = new SocketTube(client(), chan, Utils::getBuffer, label); } catch (IOException e) { throw new InternalError(e); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/PlainProxyConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/PlainProxyConnection.java index 5cd9a1d9c8f6e..c11fd4891774b 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/PlainProxyConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/PlainProxyConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,8 +29,8 @@ class PlainProxyConnection extends PlainHttpConnection { - PlainProxyConnection(InetSocketAddress proxy, HttpClientImpl client) { - super(proxy, client); + PlainProxyConnection(InetSocketAddress proxy, HttpClientImpl client, String label) { + super(proxy, client, label); } @Override diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/PlainTunnelingConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/PlainTunnelingConnection.java index 80ca6ba8a3aad..7a8eb9c79c57b 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/PlainTunnelingConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/PlainTunnelingConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,11 +54,12 @@ final class PlainTunnelingConnection extends HttpConnection { protected PlainTunnelingConnection(InetSocketAddress addr, InetSocketAddress proxy, HttpClientImpl client, - ProxyHeaders proxyHeaders) { - super(addr, client); + ProxyHeaders proxyHeaders, + String label) { + super(addr, client, label); this.proxyAddr = proxy; this.proxyHeaders = proxyHeaders; - delegate = new PlainHttpConnection(proxy, client); + delegate = new PlainHttpConnection(proxy, client, label); } @Override diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java b/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java index d0e30806d5363..cc083d7e066c6 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ import java.util.Objects; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Flow; -import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; @@ -59,7 +58,6 @@ final class SocketTube implements FlowTube { final Logger debug = Utils.getDebugLogger(this::dbgString, Utils.DEBUG); - static final AtomicLong IDS = new AtomicLong(); private final HttpClientImpl client; private final SocketChannel channel; @@ -68,14 +66,15 @@ final class SocketTube implements FlowTube { private final AtomicReference errorRef = new AtomicReference<>(); private final InternalReadPublisher readPublisher; private final InternalWriteSubscriber writeSubscriber; - private final long id = IDS.incrementAndGet(); + private final String connectionLabel; public SocketTube(HttpClientImpl client, SocketChannel channel, - Supplier buffersFactory) { + Supplier buffersFactory, + String connectionLabel) { this.client = client; this.channel = channel; this.sliceBuffersSource = new SliceBufferSource(buffersFactory); - + this.connectionLabel = connectionLabel; this.readPublisher = new InternalReadPublisher(); this.writeSubscriber = new InternalWriteSubscriber(); } @@ -1343,7 +1342,7 @@ public String toString() { } final String dbgString() { - return "SocketTube("+id+")"; + return "SocketTube("+ connectionLabel +")"; } final String channelDescr() { diff --git a/test/jdk/java/net/httpclient/HttpResponseConnectionLabelTest.java b/test/jdk/java/net/httpclient/HttpResponseConnectionLabelTest.java new file mode 100644 index 0000000000000..b6c13c51ee19a --- /dev/null +++ b/test/jdk/java/net/httpclient/HttpResponseConnectionLabelTest.java @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Verifies `HttpResponse::connectionLabel` + * @library /test/lib + * /test/jdk/java/net/httpclient/lib + * @build jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * + * @comment Use a higher idle timeout to increase the chances of the same connection being used for sequential HTTP requests + * @run junit/othervm -Djdk.httpclient.keepalive.timeout=120 HttpResponseConnectionLabelTest + */ + +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestHandler; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer; +import jdk.internal.net.http.common.Logger; +import jdk.internal.net.http.common.Utils; +import jdk.test.lib.net.SimpleSSLContext; +import org.junit.jupiter.api.AfterAll; +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 javax.net.ssl.SSLContext; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.System.Logger.Level; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpClient.Version; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.nio.charset.Charset; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Stream; + +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.nio.charset.StandardCharsets.US_ASCII; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class HttpResponseConnectionLabelTest { + + private static final String CLASS_NAME = HttpResponseConnectionLabelTest.class.getSimpleName(); + + private static final Logger LOGGER = Utils.getDebugLogger(CLASS_NAME::toString, Utils.DEBUG); + + private static final Charset CHARSET = US_ASCII; + + private static final String CONNECTION_KEY_HEADER_NAME = "X-Connection-Key"; + + private static final String SERVER_ID_HEADER_NAME = "X-Server-Id"; + + private static final SSLContext SSL_CONTEXT = createSslContext(); + + // Start with a fresh client having no connections in the pool + private final HttpClient client = HttpClient.newBuilder().sslContext(SSL_CONTEXT).proxy(NO_PROXY).build(); + + // Primary server-client pairs + + private static final ServerRequestPair PRI_HTTP1 = ServerRequestPair.of(Version.HTTP_1_1, false); + + private static final ServerRequestPair PRI_HTTPS1 = ServerRequestPair.of(Version.HTTP_1_1, true); + + private static final ServerRequestPair PRI_HTTP2 = ServerRequestPair.of(Version.HTTP_2, false); + + private static final ServerRequestPair PRI_HTTPS2 = ServerRequestPair.of(Version.HTTP_2, true); + + // Secondary server-client pairs + + private static final ServerRequestPair SEC_HTTP1 = ServerRequestPair.of(Version.HTTP_1_1, false); + + private static final ServerRequestPair SEC_HTTPS1 = ServerRequestPair.of(Version.HTTP_1_1, true); + + private static final ServerRequestPair SEC_HTTP2 = ServerRequestPair.of(Version.HTTP_2, false); + + private static final ServerRequestPair SEC_HTTPS2 = ServerRequestPair.of(Version.HTTP_2, true); + + private static SSLContext createSslContext() { + try { + return new SimpleSSLContext().get(); + } catch (IOException exception) { + throw new UncheckedIOException(exception); + } + } + + private record ServerRequestPair( + HttpTestServer server, + ExecutorService executor, + HttpRequest request, + boolean secure, + AtomicReference serverResponseLatchRef) { + + private static final AtomicInteger SERVER_COUNTER = new AtomicInteger(); + + private static final AtomicInteger SERVER_RESPONSE_COUNTER = new AtomicInteger(); + + private static ServerRequestPair of(Version version, boolean secure) { + + // Create the server and the request URI + SSLContext sslContext = secure ? SSL_CONTEXT : null; + String serverId = "" + SERVER_COUNTER.getAndIncrement(); + ExecutorService[] executorRef = {null}; + HttpTestServer server = createServer(version, secure, sslContext, serverId, executorRef); + String handlerPath = "/%s/".formatted(CLASS_NAME); + String requestUriScheme = secure ? "https" : "http"; + URI requestUri = URI.create("%s://%s%sx".formatted(requestUriScheme, server.serverAuthority(), handlerPath)); + + // Register the request handler + AtomicReference serverResponseLatchRef = new AtomicReference<>(); + server.addHandler(createServerHandler(serverId, serverResponseLatchRef), handlerPath); + + // Create the client and the request + HttpRequest request = HttpRequest.newBuilder(requestUri).version(version).build(); + + // Create the pair + ServerRequestPair pair = new ServerRequestPair( + server, + executorRef[0], + request, + secure, + serverResponseLatchRef); + pair.server.start(); + LOGGER.log("Server[%s] is started at `%s`", serverId, server.serverAuthority()); + return pair; + + } + + private static HttpTestServer createServer( + Version version, + boolean secure, + SSLContext sslContext, + String serverId, + ExecutorService[] executorRef) { + try { + // Only create a dedicated executor for HTTP/1.1, because + // + // - Only the HTTP/1.1 test server gets wedged when running + // tests involving parallel request handling. + // + // - The HTTP/2 test server creates its own sufficiently sized + // executor, and the thread names used there makes it easy to + // find which server they belong to. + executorRef[0] = Version.HTTP_1_1.equals(version) + ? createExecutor(version, secure, serverId) + : null; + return HttpTestServer.create(version, sslContext, executorRef[0]); + } catch (IOException exception) { + throw new UncheckedIOException(exception); + } + } + + private static ExecutorService createExecutor(Version version, boolean secure, String serverId) { + return Executors.newThreadPerTaskExecutor(runnable -> { + String name = "%s-%s-%c-%s".formatted( + CLASS_NAME, version, secure ? 's' : 'c', serverId); + Thread thread = new Thread(runnable, name); + thread.setDaemon(true); // Avoid blocking the JVM exit + return thread; + }); + } + + private static HttpTestHandler createServerHandler( + String serverId, + AtomicReference serverResponseLatchRef) { + return (exchange) -> { + String responseBody = "" + SERVER_RESPONSE_COUNTER.getAndIncrement(); + String connectionKey = exchange.getConnectionKey(); + LOGGER.log("Server[%d] has received request (connectionKey=%s)", serverId, connectionKey); + try (exchange) { + + // Participate in the latch count down + CountDownLatch serverResponseLatch = serverResponseLatchRef.get(); + if (serverResponseLatch != null) { + serverResponseLatch.countDown(); + LOGGER.log( + "Server[%s] is waiting for the latch... (connectionKey=%s, responseBody=%s)", + serverId, connectionKey, responseBody); + serverResponseLatch.await(); + } + + // Write the response + LOGGER.log( + "Server[%s] is responding... (connectionKey=%s, responseBody=%s)", + serverId, connectionKey, responseBody); + exchange.getResponseHeaders().addHeader(CONNECTION_KEY_HEADER_NAME, connectionKey); + exchange.getResponseHeaders().addHeader(SERVER_ID_HEADER_NAME, serverId); + byte[] responseBodyBytes = responseBody.getBytes(CHARSET); + exchange.sendResponseHeaders(200, responseBodyBytes.length); + exchange.getResponseBody().write(responseBodyBytes); + + } catch (Exception exception) { + String message = "Server[%s] has failed! (connectionKey=%s, responseBody=%s)" + .formatted(serverId, connectionKey, responseBody); + LOGGER.log(Level.ERROR, message, exception); + if (exception instanceof InterruptedException) { + // Restore the interrupt + Thread.currentThread().interrupt(); + } + throw new RuntimeException(message, exception); + } + }; + } + + @Override + public String toString() { + String version = server.getVersion().toString(); + return secure ? version.replaceFirst("_", "S_") : version; + } + + } + + @AfterAll + static void closeServers() { + Exception[] exceptionRef = {null}; + Stream + .of(PRI_HTTP1, PRI_HTTPS1, PRI_HTTP2, PRI_HTTPS2, SEC_HTTP1, SEC_HTTPS1, SEC_HTTP2, SEC_HTTPS2) + .flatMap(pair -> Stream.of( + pair.server::stop, + () -> { if (pair.executor != null) { pair.executor.shutdownNow(); } })) + .forEach(terminator -> { + try { + terminator.run(); + } catch (Exception exception) { + if (exceptionRef[0] == null) { + exceptionRef[0] = exception; + } else { + exceptionRef[0].addSuppressed(exception); + } + } + }); + if (exceptionRef[0] != null) { + throw new RuntimeException("failed closing one or more server resources", exceptionRef[0]); + } + } + + @AfterEach + void closeClient() { + client.close(); + } + + static ServerRequestPair[] testParallelRequestsToSameServer() { + return new ServerRequestPair[]{ + PRI_HTTP1, + PRI_HTTPS1, + PRI_HTTP2, + PRI_HTTPS2 + }; + } + + @ParameterizedTest + @MethodSource("testParallelRequestsToSameServer") + void testParallelRequestsToSameServer(ServerRequestPair pair) throws Exception { + + // There is no implementation-agnostic reliable way to force admission + // of multiple connections targeting the same server to an HTTP/2 pool. + if (Version.HTTP_2.equals(pair.server.getVersion())) { + return; + } + + // Configure a synchronization point for 4 events: + // + // 1. client --(req1)--> server + // 2. server --(res1)--> client + // 3. client --(req2)--> server + // 4. server --(res2)--> client + // + // This effectively will ensure: + // + // - Server waits for the rendezvous before responding. + // Hence, client won't be able to reuse the connection, but create a new one. + // + // - Client waits for the rendezvous before consuming responses. + CountDownLatch latch = new CountDownLatch(4); + pair.serverResponseLatchRef.set(latch); + + // Fire requests + LOGGER.log("Firing request 1..."); + CompletableFuture> response1Future = + client.sendAsync(pair.request, BodyHandlers.ofString(CHARSET)); + LOGGER.log("Firing request 2..."); + CompletableFuture> response2Future = + client.sendAsync(pair.request, BodyHandlers.ofString(CHARSET)); + + // Release latches to allow the server handlers to proceed + latch.countDown(); + latch.countDown(); + + // Wait for all parties to be ready + LOGGER.log("Client is waiting for the latch..."); + latch.await(); + LOGGER.log("Client is continuing..."); + + // Collect responses + HttpResponse response1 = response1Future.get(); + HttpResponse response2 = response2Future.get(); + + // Verify successful responses + assertEquals(200, response1.statusCode()); + assertEquals(200, response2.statusCode()); + + // Verify that connection keys differ; that is, requests are served through different connections + String connectionKey1 = response1.headers().firstValue(CONNECTION_KEY_HEADER_NAME).get(); + String connectionKey2 = response2.headers().firstValue(CONNECTION_KEY_HEADER_NAME).get(); + assertNotEquals(connectionKey1, connectionKey2); + + // Verify that server IDs match; that is, both requests targeted the same server. + // (Using `parseInt` to validate the content.) + int serverId1 = Integer.parseInt(response1.headers().firstValue(SERVER_ID_HEADER_NAME).get()); + int serverId2 = Integer.parseInt(response2.headers().firstValue(SERVER_ID_HEADER_NAME).get()); + assertEquals(serverId1, serverId2); + + // Verify that response bodies differ. + // (Using `parseInt` to validate the content.) + int body1 = Integer.parseInt(response1.body()); + int body2 = Integer.parseInt(response2.body()); + assertNotEquals(body1, body2); + + // Verify that connection labels differ; that is, requests are served through different connections + String label1 = response1.connectionLabel().orElse(null); + assertNotNull(label1); + LOGGER.log("Connection label 1: %s", label1); + String label2 = response2.connectionLabel().orElse(null); + assertNotNull(label2); + LOGGER.log("Connection label 2: %s", label2); + assertNotEquals(label1, label2); + + } + + static Stream testParallelRequestsToDifferentServers() { + return Stream + .of(PRI_HTTP1, PRI_HTTPS1, PRI_HTTP2, PRI_HTTPS2) + .flatMap(source -> Stream + .of(SEC_HTTP1, SEC_HTTPS1, SEC_HTTP2, SEC_HTTPS2) + .map(target -> Arguments.of(source, target))); + } + + @ParameterizedTest + @MethodSource("testParallelRequestsToDifferentServers") + void testParallelRequestsToDifferentServers(ServerRequestPair pair1, ServerRequestPair pair2) throws Exception { + + // Configure a synchronization point for 4 events: + // + // 1. client --> server1 + // 2. server1 --> client + // 3. client --> server2 + // 4. server2 --> client + // + // This effectively will ensure: + // + // - Server waits for the rendezvous before responding. + // Hence, client won't be able to reuse the connection, but create a new one. + // + // - Client waits for the rendezvous before consuming responses. + CountDownLatch latch = new CountDownLatch(4); + pair1.serverResponseLatchRef.set(latch); + pair2.serverResponseLatchRef.set(latch); + + // Fire requests + LOGGER.log("Firing request 1..."); + CompletableFuture> response1Future = + client.sendAsync(pair1.request, BodyHandlers.ofString(CHARSET)); + LOGGER.log("Firing request 2..."); + CompletableFuture> response2Future = + client.sendAsync(pair2.request, BodyHandlers.ofString(CHARSET)); + + // Release latches to allow the server handlers to proceed + latch.countDown(); + latch.countDown(); + + // Wait for all parties to be ready + LOGGER.log("Client is waiting for the latch..."); + latch.await(); + LOGGER.log("Client is continuing..."); + + // Collect responses + HttpResponse response1 = response1Future.get(); + HttpResponse response2 = response2Future.get(); + + // Verify successful responses + assertEquals(200, response1.statusCode()); + assertEquals(200, response2.statusCode()); + + // Verify that connection keys differ; that is, requests are served through different connections + String connectionKey1 = response1.headers().firstValue(CONNECTION_KEY_HEADER_NAME).get(); + String connectionKey2 = response2.headers().firstValue(CONNECTION_KEY_HEADER_NAME).get(); + assertNotEquals(connectionKey1, connectionKey2); + + // Verify that server IDs differ. + // (Using `parseInt` to validate the content.) + int serverId1 = response1.headers().firstValue(SERVER_ID_HEADER_NAME).map(Integer::parseInt).get(); + int serverId2 = response2.headers().firstValue(SERVER_ID_HEADER_NAME).map(Integer::parseInt).get(); + assertNotEquals(serverId1, serverId2); + + // Verify that response bodies differ. + // (Using `parseInt` to validate the content.) + int body1 = Integer.parseInt(response1.body()); + int body2 = Integer.parseInt(response2.body()); + assertNotEquals(body1, body2); + + // Verify that connection labels differ; that is, requests are served through different connections + String label1 = response1.connectionLabel().orElse(null); + assertNotNull(label1); + LOGGER.log("Connection label 1: %s", label1); + String label2 = response2.connectionLabel().orElse(null); + assertNotNull(label2); + LOGGER.log("Connection label 2: %s", label2); + assertNotEquals(label1, label2); + + } + + static Stream testSerialRequestsToSameServer() { + return Stream.of(PRI_HTTP1, PRI_HTTPS1, PRI_HTTP2, PRI_HTTPS2); + } + + @ParameterizedTest + @MethodSource("testSerialRequestsToSameServer") + void testSerialRequestsToSameServer(ServerRequestPair pair) throws Exception { + + // Disarm the synchronization point + pair.serverResponseLatchRef.set(null); + + // Fire requests + LOGGER.log("Firing request 1..."); + HttpResponse response1 = client.send(pair.request, BodyHandlers.ofString(CHARSET)); + LOGGER.log("Firing request 2..."); + HttpResponse response2 = client.send(pair.request, BodyHandlers.ofString(CHARSET)); + + // Verify successful responses + assertEquals(200, response1.statusCode()); + assertEquals(200, response2.statusCode()); + + // Verify that connection keys match; that is, requests are served through the same connection + String connectionKey1 = response1.headers().firstValue(CONNECTION_KEY_HEADER_NAME).get(); + String connectionKey2 = response2.headers().firstValue(CONNECTION_KEY_HEADER_NAME).get(); + assertEquals(connectionKey1, connectionKey2); + + // Verify that server IDs match. + // (Using `parseInt` to validate the content.) + int serverId1 = response1.headers().firstValue(SERVER_ID_HEADER_NAME).map(Integer::parseInt).get(); + int serverId2 = response2.headers().firstValue(SERVER_ID_HEADER_NAME).map(Integer::parseInt).get(); + assertEquals(serverId1, serverId2); + + // Verify that response bodies differ. + // (Using `parseInt` to validate the content.) + int body1 = Integer.parseInt(response1.body()); + int body2 = Integer.parseInt(response2.body()); + assertNotEquals(body1, body2); + + // Verify that connection labels match; that is, requests are served through the same connection + String label1 = response1.connectionLabel().orElse(null); + assertNotNull(label1); + LOGGER.log("Connection label 1: %s", label1); + String label2 = response2.connectionLabel().orElse(null); + assertNotNull(label2); + LOGGER.log("Connection label 2: %s", label2); + assertEquals(label1, label2); + + } + +} diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/ConnectionPoolTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/ConnectionPoolTest.java index 9667969ec082e..729fdb084e177 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/ConnectionPoolTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/ConnectionPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -459,7 +459,7 @@ public HttpConnectionStub( InetSocketAddress address, InetSocketAddress proxy, boolean secured) { - super(address, impl); + super(address, impl, "testConn-" + IDS.incrementAndGet()); this.key = ConnectionPool.cacheKey(secured, address, proxy); this.address = address; this.proxy = proxy; From 273a9a61558fdfc422772fa2c6045a4d3c709a41 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Tue, 15 Apr 2025 11:49:58 +0000 Subject: [PATCH 0589/1101] 8354448: [REDO] Remove friends for ObjectMonitor Reviewed-by: kbarrett, shade, dholmes --- src/hotspot/share/runtime/objectMonitor.hpp | 7 ++----- src/hotspot/share/runtime/objectMonitor.inline.hpp | 5 +++++ src/hotspot/share/runtime/synchronizer.cpp | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index 729316811c29c..c8daeb65b50d1 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -148,9 +148,6 @@ class ObjectWaiter : public CHeapObj { #define OM_CACHE_LINE_SIZE DEFAULT_CACHE_LINE_SIZE class ObjectMonitor : public CHeapObj { - friend class LightweightSynchronizer; - friend class ObjectSynchronizer; - friend class ObjectWaiter; friend class VMStructs; JVMCI_ONLY(friend class JVMCIVMStructs;) @@ -334,6 +331,7 @@ class ObjectMonitor : public CHeapObj { void add_to_contentions(int value); intx recursions() const { return _recursions; } void set_recursions(size_t recursions); + void increment_recursions(JavaThread* current); // JVM/TI GetObjectMonitorUsage() needs this: int waiters() const; @@ -424,13 +422,12 @@ class ObjectMonitor : public CHeapObj { bool short_fixed_spin(JavaThread* current, int spin_count, bool adapt); void exit_epilog(JavaThread* current, ObjectWaiter* Wakee); + public: // Deflation support bool deflate_monitor(Thread* current); - private: void install_displaced_markword_in_object(const oop obj); // JFR support -public: static bool is_jfr_excluded(const Klass* monitor_klass); }; diff --git a/src/hotspot/share/runtime/objectMonitor.inline.hpp b/src/hotspot/share/runtime/objectMonitor.inline.hpp index 89f6deaab2108..7dabc50fca767 100644 --- a/src/hotspot/share/runtime/objectMonitor.inline.hpp +++ b/src/hotspot/share/runtime/objectMonitor.inline.hpp @@ -150,6 +150,11 @@ inline void ObjectMonitor::set_recursions(size_t recursions) { _recursions = checked_cast(recursions); } +inline void ObjectMonitor::increment_recursions(JavaThread* current) { + assert(has_owner(current), "must be the owner"); + _recursions++; +} + // Clear _owner field; current value must match old_value. inline void ObjectMonitor::release_clear_owner(JavaThread* old_owner) { int64_t old_value = owner_id_from(old_owner); diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index d608ffbdc02f2..503b783335175 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -423,7 +423,7 @@ bool ObjectSynchronizer::quick_enter_legacy(oop obj, BasicLock* lock, JavaThread // Case: TLE inimical operations such as nested/recursive synchronization if (m->has_owner(current)) { - m->_recursions++; + m->increment_recursions(current); current->inc_held_monitor_count(); return true; } @@ -440,7 +440,7 @@ bool ObjectSynchronizer::quick_enter_legacy(oop obj, BasicLock* lock, JavaThread lock->set_displaced_header(markWord::unused_mark()); if (!m->has_owner() && m->try_set_owner(current)) { - assert(m->_recursions == 0, "invariant"); + assert(m->recursions() == 0, "invariant"); current->inc_held_monitor_count(); return true; } From 36864a2a08b5b64e63a9265d595ba7fb608994cb Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 15 Apr 2025 11:55:47 +0000 Subject: [PATCH 0590/1101] 8351491: Add info from release file to hserr file Reviewed-by: dholmes, lucy --- src/hotspot/share/runtime/os.cpp | 50 +++++++++++++++++++++++++ src/hotspot/share/runtime/os.hpp | 5 +++ src/hotspot/share/runtime/threads.cpp | 17 +++++++++ src/hotspot/share/utilities/vmError.cpp | 8 ++++ 4 files changed, 80 insertions(+) diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 99559cee2879e..e4bab3410c1a7 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1534,6 +1534,56 @@ bool os::set_boot_path(char fileSep, char pathSep) { return false; } +static char* _image_release_file_content = nullptr; + +void os::read_image_release_file() { + assert(_image_release_file_content == nullptr, "release file content must not be already set"); + const char* home = Arguments::get_java_home(); + stringStream ss; + ss.print("%s/release", home); + + FILE* file = fopen(ss.base(), "rb"); + if (file == nullptr) { + return; + } + fseek(file, 0, SEEK_END); + long sz = ftell(file); + if (sz == -1) { + return; + } + fseek(file, 0, SEEK_SET); + + char* tmp = (char*) os::malloc(sz + 1, mtInternal); + if (tmp == nullptr) { + fclose(file); + return; + } + + size_t elements_read = fread(tmp, 1, sz, file); + if (elements_read < (size_t)sz) { + tmp[elements_read] = '\0'; + } else { + tmp[sz] = '\0'; + } + // issues with \r in line endings on Windows, so better replace those + for (size_t i = 0; i < elements_read; i++) { + if (tmp[i] == '\r') { + tmp[i] = ' '; + } + } + Atomic::release_store(&_image_release_file_content, tmp); + fclose(file); +} + +void os::print_image_release_file(outputStream* st) { + char* ifrc = Atomic::load_acquire(&_image_release_file_content); + if (ifrc != nullptr) { + st->print_cr("%s", ifrc); + } else { + st->print_cr(""); + } +} + bool os::file_exists(const char* filename) { struct stat statbuf; if (filename == nullptr || strlen(filename) == 0) { diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 242959034afb1..16a74cd7ea957 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -670,6 +670,11 @@ class os: AllStatic { static FILE* fopen(const char* path, const char* mode); static jlong lseek(int fd, jlong offset, int whence); static bool file_exists(const char* file); + + // read/store and print the release file of the image + static void read_image_release_file(); + static void print_image_release_file(outputStream* st); + // This function, on Windows, canonicalizes a given path (see os_windows.cpp for details). // On Posix, this function is a noop: it does not change anything and just returns // the input pointer. diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 1d515c9fe7d45..203062582a0e2 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -425,6 +425,19 @@ void Threads::initialize_jsr292_core_classes(TRAPS) { } } +// One-shot PeriodicTask subclass for reading the release file +class ReadReleaseFileTask : public PeriodicTask { + public: + ReadReleaseFileTask() : PeriodicTask(100) {} + + virtual void task() { + os::read_image_release_file(); + + // Reclaim our storage and disenroll ourself. + delete this; + } +}; + jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { extern void JDK_Version_init(); @@ -580,6 +593,10 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { return status; } + // Have the WatcherThread read the release file in the background. + ReadReleaseFileTask* read_task = new ReadReleaseFileTask(); + read_task->enroll(); + // Create WatcherThread as soon as we can since we need it in case // of hangs during error reporting. WatcherThread::start(); diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index ccd31269d0de4..e1940123d678a 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1259,6 +1259,10 @@ void VMError::report(outputStream* st, bool _verbose) { LogConfiguration::describe_current_configuration(st); st->cr(); + STEP_IF("printing release file content", _verbose) + st->print_cr("Release file:"); + os::print_image_release_file(st); + STEP_IF("printing all environment variables", _verbose) os::print_environment_variables(st, env_list); st->cr(); @@ -1439,6 +1443,10 @@ void VMError::print_vm_info(outputStream* st) { LogConfiguration::describe(st); st->cr(); + // STEP("printing release file content") + st->print_cr("Release file:"); + os::print_image_release_file(st); + // STEP("printing all environment variables") os::print_environment_variables(st, env_list); From fc1464727f95508935cfc65d689b74e1709d3649 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 15 Apr 2025 16:06:12 +0000 Subject: [PATCH 0591/1101] 8354320: Changes to jpackage.md cause pandoc warning Reviewed-by: almatvee, ihse, alanb --- make/autoconf/basic_tools.m4 | 10 +++++++++- src/jdk.jpackage/share/man/jpackage.md | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/make/autoconf/basic_tools.m4 b/make/autoconf/basic_tools.m4 index eac14207b1da9..5815c55c962ab 100644 --- a/make/autoconf/basic_tools.m4 +++ b/make/autoconf/basic_tools.m4 @@ -468,7 +468,15 @@ AC_DEFUN_ONCE([BASIC_SETUP_PANDOC], AC_MSG_CHECKING([if the pandoc smart extension needs to be disabled for markdown]) if $PANDOC --list-extensions | $GREP -q '+smart'; then AC_MSG_RESULT([yes]) - PANDOC_MARKDOWN_FLAG="markdown-smart" + PANDOC_MARKDOWN_FLAG="$PANDOC_MARKDOWN_FLAG-smart" + else + AC_MSG_RESULT([no]) + fi + + AC_MSG_CHECKING([if the pandoc tex_math_dollars extension needs to be disabled for markdown]) + if $PANDOC --list-extensions | $GREP -q '+tex_math_dollars'; then + AC_MSG_RESULT([yes]) + PANDOC_MARKDOWN_FLAG="$PANDOC_MARKDOWN_FLAG-tex_math_dollars" else AC_MSG_RESULT([no]) fi diff --git a/src/jdk.jpackage/share/man/jpackage.md b/src/jdk.jpackage/share/man/jpackage.md index c50370c9641b5..34e524f9eeece 100644 --- a/src/jdk.jpackage/share/man/jpackage.md +++ b/src/jdk.jpackage/share/man/jpackage.md @@ -236,7 +236,7 @@ The `jpackage` tool will take as input a Java application and a Java run-time im will be ignored, and these expandable substrings will be replaced by values calculated by the app launcher. - Prefix the dollar sign character with the backslash character (\) + Prefix the dollar sign character with the backslash character (\\) to prevent substring expansion. `--java-options` *options* From cec48ed270d3bdf704c389a091b42a32c2ed6440 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 15 Apr 2025 16:19:03 +0000 Subject: [PATCH 0592/1101] 8354542: Clean up x86 stubs after 32-bit x86 removal Reviewed-by: adinn, kvn --- src/hotspot/cpu/x86/methodHandles_x86.cpp | 27 +-- src/hotspot/cpu/x86/methodHandles_x86.hpp | 2 +- src/hotspot/cpu/x86/sharedRuntime_x86.cpp | 9 +- src/hotspot/cpu/x86/stubDeclarations_x86.hpp | 210 +++++++++---------- src/hotspot/cpu/x86/stubRoutines_x86.cpp | 6 - src/hotspot/cpu/x86/stubRoutines_x86.hpp | 31 --- 6 files changed, 109 insertions(+), 176 deletions(-) diff --git a/src/hotspot/cpu/x86/methodHandles_x86.cpp b/src/hotspot/cpu/x86/methodHandles_x86.cpp index 92993dcbf640d..ee4dc26ae404e 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.cpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp @@ -82,8 +82,8 @@ void MethodHandles::verify_klass(MacroAssembler* _masm, __ verify_oop(obj); __ testptr(obj, obj); __ jcc(Assembler::zero, L_bad); -#define PUSH { __ push(temp); LP64_ONLY( __ push(rscratch1); ) } -#define POP { LP64_ONLY( __ pop(rscratch1); ) __ pop(temp); } +#define PUSH { __ push(temp); __ push(rscratch1); } +#define POP { __ pop(rscratch1); __ pop(temp); } PUSH; __ load_klass(temp, obj, rscratch1); __ cmpptr(temp, ExternalAddress((address) klass_addr), rscratch1); @@ -139,15 +139,9 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth // JVMTI events, such as single-stepping, are implemented partly by avoiding running // compiled code in threads for which the event is enabled. Check here for // interp_only_mode if these events CAN be enabled. -#ifdef _LP64 - Register rthread = r15_thread; -#else - Register rthread = temp; - __ get_thread(rthread); -#endif // interp_only is an int, on little endian it is sufficient to test the byte only // Is a cmpl faster? - __ cmpb(Address(rthread, JavaThread::interp_only_mode_offset()), 0); + __ cmpb(Address(r15_thread, JavaThread::interp_only_mode_offset()), 0); __ jccb(Assembler::zero, run_compiled_code); __ jmp(Address(method, Method::interpreter_entry_offset())); __ BIND(run_compiled_code); @@ -324,7 +318,6 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, assert(is_signature_polymorphic(iid), "expected invoke iid"); Register rbx_method = rbx; // eventual target of this invocation // temps used in this code are not used in *either* compiled or interpreted calling sequences -#ifdef _LP64 Register temp1 = rscratch1; Register temp2 = rscratch2; Register temp3 = rax; @@ -333,19 +326,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, assert_different_registers(temp1, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5); assert_different_registers(temp2, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5); assert_different_registers(temp3, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5); - } -#else - Register temp1 = (for_compiler_entry ? rsi : rdx); - Register temp2 = rdi; - Register temp3 = rax; - if (for_compiler_entry) { - assert(receiver_reg == (iid == vmIntrinsics::_linkToStatic || iid == vmIntrinsics::_linkToNative ? noreg : rcx), "only valid assignment"); - assert_different_registers(temp1, rcx, rdx); - assert_different_registers(temp2, rcx, rdx); - assert_different_registers(temp3, rcx, rdx); - } -#endif - else { + } else { assert_different_registers(temp1, temp2, temp3, saved_last_sp_register()); // don't trash lastSP } assert_different_registers(temp1, temp2, temp3, receiver_reg); diff --git a/src/hotspot/cpu/x86/methodHandles_x86.hpp b/src/hotspot/cpu/x86/methodHandles_x86.hpp index 6574fec66017a..9ffe5e198acd8 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.hpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.hpp @@ -60,5 +60,5 @@ enum /* platform_dependent_constants */ { static Register saved_last_sp_register() { // Should be in sharedRuntime, not here. - return LP64_ONLY(r13) NOT_LP64(rsi); + return r13; } diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp index 0a277a4eb69f6..b8a4b82915921 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp @@ -73,21 +73,14 @@ void SharedRuntime::inline_check_hashcode_from_object_header(MacroAssembler* mas } // get hash -#ifdef _LP64 // Read the header and build a mask to get its hash field. // Depend on hash_mask being at most 32 bits and avoid the use of hash_mask_in_place // because it could be larger than 32 bits in a 64-bit vm. See markWord.hpp. __ shrptr(result, markWord::hash_shift); __ andptr(result, markWord::hash_mask); -#else - __ andptr(result, markWord::hash_mask_in_place); -#endif //_LP64 // test if hashCode exists - __ jcc(Assembler::zero, slowCase); -#ifndef _LP64 - __ shrptr(result, markWord::hash_shift); -#endif + __ jccb(Assembler::zero, slowCase); __ ret(0); __ bind(slowCase); } diff --git a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp index 406dbb9aa6dc7..dcb919ddcd097 100644 --- a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp +++ b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp @@ -34,45 +34,43 @@ do_stub(initial, verify_mxcsr) \ do_arch_entry(x86, initial, verify_mxcsr, verify_mxcsr_entry, \ verify_mxcsr_entry) \ - LP64_ONLY( \ - do_stub(initial, get_previous_sp) \ - do_arch_entry(x86, initial, get_previous_sp, \ - get_previous_sp_entry, \ - get_previous_sp_entry) \ - do_stub(initial, f2i_fixup) \ - do_arch_entry(x86, initial, f2i_fixup, f2i_fixup, f2i_fixup) \ - do_stub(initial, f2l_fixup) \ - do_arch_entry(x86, initial, f2l_fixup, f2l_fixup, f2l_fixup) \ - do_stub(initial, d2i_fixup) \ - do_arch_entry(x86, initial, d2i_fixup, d2i_fixup, d2i_fixup) \ - do_stub(initial, d2l_fixup) \ - do_arch_entry(x86, initial, d2l_fixup, d2l_fixup, d2l_fixup) \ - do_stub(initial, float_sign_mask) \ - do_arch_entry(x86, initial, float_sign_mask, float_sign_mask, \ - float_sign_mask) \ - do_stub(initial, float_sign_flip) \ - do_arch_entry(x86, initial, float_sign_flip, float_sign_flip, \ - float_sign_flip) \ - do_stub(initial, double_sign_mask) \ - do_arch_entry(x86, initial, double_sign_mask, double_sign_mask, \ - double_sign_mask) \ - do_stub(initial, double_sign_flip) \ - do_arch_entry(x86, initial, double_sign_flip, double_sign_flip, \ - double_sign_flip) \ - ) \ + do_stub(initial, get_previous_sp) \ + do_arch_entry(x86, initial, get_previous_sp, \ + get_previous_sp_entry, \ + get_previous_sp_entry) \ + do_stub(initial, f2i_fixup) \ + do_arch_entry(x86, initial, f2i_fixup, f2i_fixup, f2i_fixup) \ + do_stub(initial, f2l_fixup) \ + do_arch_entry(x86, initial, f2l_fixup, f2l_fixup, f2l_fixup) \ + do_stub(initial, d2i_fixup) \ + do_arch_entry(x86, initial, d2i_fixup, d2i_fixup, d2i_fixup) \ + do_stub(initial, d2l_fixup) \ + do_arch_entry(x86, initial, d2l_fixup, d2l_fixup, d2l_fixup) \ + do_stub(initial, float_sign_mask) \ + do_arch_entry(x86, initial, float_sign_mask, float_sign_mask, \ + float_sign_mask) \ + do_stub(initial, float_sign_flip) \ + do_arch_entry(x86, initial, float_sign_flip, float_sign_flip, \ + float_sign_flip) \ + do_stub(initial, double_sign_mask) \ + do_arch_entry(x86, initial, double_sign_mask, double_sign_mask, \ + double_sign_mask) \ + do_stub(initial, double_sign_flip) \ + do_arch_entry(x86, initial, double_sign_flip, double_sign_flip, \ + double_sign_flip) \ #define STUBGEN_CONTINUATION_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(continuation, 1000 LP64_ONLY(+2000)) \ + do_arch_blob(continuation, 3000) \ #define STUBGEN_COMPILER_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(compiler, 20000 LP64_ONLY(+89000) WINDOWS_ONLY(+2000)) \ + do_arch_blob(compiler, 109000 WINDOWS_ONLY(+2000)) \ do_stub(compiler, vector_float_sign_mask) \ do_arch_entry(x86, compiler, vector_float_sign_mask, \ vector_float_sign_mask, vector_float_sign_mask) \ @@ -160,90 +158,88 @@ do_arch_entry(x86, compiler, pshuffle_byte_flip_mask, \ pshuffle_byte_flip_mask_addr, \ pshuffle_byte_flip_mask_addr) \ - LP64_ONLY( \ - /* x86_64 exposes these 3 stubs via a generic entry array */ \ - /* oher arches use arch-specific entries */ \ - /* this really needs rationalising */ \ - do_stub(compiler, string_indexof_linear_ll) \ - do_stub(compiler, string_indexof_linear_uu) \ - do_stub(compiler, string_indexof_linear_ul) \ - do_stub(compiler, pshuffle_byte_flip_mask_sha512) \ - do_arch_entry(x86, compiler, pshuffle_byte_flip_mask_sha512, \ - pshuffle_byte_flip_mask_addr_sha512, \ - pshuffle_byte_flip_mask_addr_sha512) \ - do_stub(compiler, compress_perm_table32) \ - do_arch_entry(x86, compiler, compress_perm_table32, \ - compress_perm_table32, compress_perm_table32) \ - do_stub(compiler, compress_perm_table64) \ - do_arch_entry(x86, compiler, compress_perm_table64, \ - compress_perm_table64, compress_perm_table64) \ - do_stub(compiler, expand_perm_table32) \ - do_arch_entry(x86, compiler, expand_perm_table32, \ - expand_perm_table32, expand_perm_table32) \ - do_stub(compiler, expand_perm_table64) \ - do_arch_entry(x86, compiler, expand_perm_table64, \ - expand_perm_table64, expand_perm_table64) \ - do_stub(compiler, avx2_shuffle_base64) \ - do_arch_entry(x86, compiler, avx2_shuffle_base64, \ - avx2_shuffle_base64, base64_avx2_shuffle_addr) \ - do_stub(compiler, avx2_input_mask_base64) \ - do_arch_entry(x86, compiler, avx2_input_mask_base64, \ - avx2_input_mask_base64, \ - base64_avx2_input_mask_addr) \ - do_stub(compiler, avx2_lut_base64) \ - do_arch_entry(x86, compiler, avx2_lut_base64, \ - avx2_lut_base64, base64_avx2_lut_addr) \ - do_stub(compiler, avx2_decode_tables_base64) \ - do_arch_entry(x86, compiler, avx2_decode_tables_base64, \ - avx2_decode_tables_base64, \ - base64_AVX2_decode_tables_addr) \ - do_stub(compiler, avx2_decode_lut_tables_base64) \ - do_arch_entry(x86, compiler, avx2_decode_lut_tables_base64, \ - avx2_decode_lut_tables_base64, \ - base64_AVX2_decode_LUT_tables_addr) \ - do_stub(compiler, shuffle_base64) \ - do_arch_entry(x86, compiler, shuffle_base64, shuffle_base64, \ - base64_shuffle_addr) \ - do_stub(compiler, lookup_lo_base64) \ - do_arch_entry(x86, compiler, lookup_lo_base64, lookup_lo_base64, \ - base64_vbmi_lookup_lo_addr) \ - do_stub(compiler, lookup_hi_base64) \ - do_arch_entry(x86, compiler, lookup_hi_base64, lookup_hi_base64, \ - base64_vbmi_lookup_hi_addr) \ - do_stub(compiler, lookup_lo_base64url) \ - do_arch_entry(x86, compiler, lookup_lo_base64url, \ - lookup_lo_base64url, \ - base64_vbmi_lookup_lo_url_addr) \ - do_stub(compiler, lookup_hi_base64url) \ - do_arch_entry(x86, compiler, lookup_hi_base64url, \ - lookup_hi_base64url, \ - base64_vbmi_lookup_hi_url_addr) \ - do_stub(compiler, pack_vec_base64) \ - do_arch_entry(x86, compiler, pack_vec_base64, pack_vec_base64, \ - base64_vbmi_pack_vec_addr) \ - do_stub(compiler, join_0_1_base64) \ - do_arch_entry(x86, compiler, join_0_1_base64, join_0_1_base64, \ - base64_vbmi_join_0_1_addr) \ - do_stub(compiler, join_1_2_base64) \ - do_arch_entry(x86, compiler, join_1_2_base64, join_1_2_base64, \ - base64_vbmi_join_1_2_addr) \ - do_stub(compiler, join_2_3_base64) \ - do_arch_entry(x86, compiler, join_2_3_base64, join_2_3_base64, \ - base64_vbmi_join_2_3_addr) \ - do_stub(compiler, encoding_table_base64) \ - do_arch_entry(x86, compiler, encoding_table_base64, \ - encoding_table_base64, base64_encoding_table_addr) \ - do_stub(compiler, decoding_table_base64) \ - do_arch_entry(x86, compiler, decoding_table_base64, \ - decoding_table_base64, base64_decoding_table_addr) \ - ) \ + /* x86_64 exposes these 3 stubs via a generic entry array */ \ + /* other arches use arch-specific entries */ \ + /* this really needs rationalising */ \ + do_stub(compiler, string_indexof_linear_ll) \ + do_stub(compiler, string_indexof_linear_uu) \ + do_stub(compiler, string_indexof_linear_ul) \ + do_stub(compiler, pshuffle_byte_flip_mask_sha512) \ + do_arch_entry(x86, compiler, pshuffle_byte_flip_mask_sha512, \ + pshuffle_byte_flip_mask_addr_sha512, \ + pshuffle_byte_flip_mask_addr_sha512) \ + do_stub(compiler, compress_perm_table32) \ + do_arch_entry(x86, compiler, compress_perm_table32, \ + compress_perm_table32, compress_perm_table32) \ + do_stub(compiler, compress_perm_table64) \ + do_arch_entry(x86, compiler, compress_perm_table64, \ + compress_perm_table64, compress_perm_table64) \ + do_stub(compiler, expand_perm_table32) \ + do_arch_entry(x86, compiler, expand_perm_table32, \ + expand_perm_table32, expand_perm_table32) \ + do_stub(compiler, expand_perm_table64) \ + do_arch_entry(x86, compiler, expand_perm_table64, \ + expand_perm_table64, expand_perm_table64) \ + do_stub(compiler, avx2_shuffle_base64) \ + do_arch_entry(x86, compiler, avx2_shuffle_base64, \ + avx2_shuffle_base64, base64_avx2_shuffle_addr) \ + do_stub(compiler, avx2_input_mask_base64) \ + do_arch_entry(x86, compiler, avx2_input_mask_base64, \ + avx2_input_mask_base64, \ + base64_avx2_input_mask_addr) \ + do_stub(compiler, avx2_lut_base64) \ + do_arch_entry(x86, compiler, avx2_lut_base64, \ + avx2_lut_base64, base64_avx2_lut_addr) \ + do_stub(compiler, avx2_decode_tables_base64) \ + do_arch_entry(x86, compiler, avx2_decode_tables_base64, \ + avx2_decode_tables_base64, \ + base64_AVX2_decode_tables_addr) \ + do_stub(compiler, avx2_decode_lut_tables_base64) \ + do_arch_entry(x86, compiler, avx2_decode_lut_tables_base64, \ + avx2_decode_lut_tables_base64, \ + base64_AVX2_decode_LUT_tables_addr) \ + do_stub(compiler, shuffle_base64) \ + do_arch_entry(x86, compiler, shuffle_base64, shuffle_base64, \ + base64_shuffle_addr) \ + do_stub(compiler, lookup_lo_base64) \ + do_arch_entry(x86, compiler, lookup_lo_base64, lookup_lo_base64, \ + base64_vbmi_lookup_lo_addr) \ + do_stub(compiler, lookup_hi_base64) \ + do_arch_entry(x86, compiler, lookup_hi_base64, lookup_hi_base64, \ + base64_vbmi_lookup_hi_addr) \ + do_stub(compiler, lookup_lo_base64url) \ + do_arch_entry(x86, compiler, lookup_lo_base64url, \ + lookup_lo_base64url, \ + base64_vbmi_lookup_lo_url_addr) \ + do_stub(compiler, lookup_hi_base64url) \ + do_arch_entry(x86, compiler, lookup_hi_base64url, \ + lookup_hi_base64url, \ + base64_vbmi_lookup_hi_url_addr) \ + do_stub(compiler, pack_vec_base64) \ + do_arch_entry(x86, compiler, pack_vec_base64, pack_vec_base64, \ + base64_vbmi_pack_vec_addr) \ + do_stub(compiler, join_0_1_base64) \ + do_arch_entry(x86, compiler, join_0_1_base64, join_0_1_base64, \ + base64_vbmi_join_0_1_addr) \ + do_stub(compiler, join_1_2_base64) \ + do_arch_entry(x86, compiler, join_1_2_base64, join_1_2_base64, \ + base64_vbmi_join_1_2_addr) \ + do_stub(compiler, join_2_3_base64) \ + do_arch_entry(x86, compiler, join_2_3_base64, join_2_3_base64, \ + base64_vbmi_join_2_3_addr) \ + do_stub(compiler, encoding_table_base64) \ + do_arch_entry(x86, compiler, encoding_table_base64, \ + encoding_table_base64, base64_encoding_table_addr) \ + do_stub(compiler, decoding_table_base64) \ + do_arch_entry(x86, compiler, decoding_table_base64, \ + decoding_table_base64, base64_decoding_table_addr) \ #define STUBGEN_FINAL_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(final, 11000 LP64_ONLY(+20000) \ - WINDOWS_ONLY(+22000) ZGC_ONLY(+20000)) \ + do_arch_blob(final, 31000 \ + WINDOWS_ONLY(+22000) ZGC_ONLY(+20000)) \ #endif // CPU_X86_STUBDECLARATIONS_HPP diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.cpp b/src/hotspot/cpu/x86/stubRoutines_x86.cpp index 861c1e1216e3b..9b524ae94cf45 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.cpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.cpp @@ -46,10 +46,8 @@ STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT) #undef DEFINE_ARCH_ENTRY address StubRoutines::x86::_k256_adr = nullptr; -#ifdef _LP64 address StubRoutines::x86::_k256_W_adr = nullptr; address StubRoutines::x86::_k512_W_addr = nullptr; -#endif const uint64_t StubRoutines::x86::_crc_by128_masks[] = { @@ -146,7 +144,6 @@ const juint StubRoutines::x86::_crc_table[] = 0x2d02ef8dUL }; -#ifdef _LP64 const juint StubRoutines::x86::_crc_table_avx512[] = { 0xe95c1271UL, 0x00000000UL, 0xce3371cbUL, 0x00000000UL, @@ -193,7 +190,6 @@ const juint StubRoutines::x86::_shuf_table_crc32_avx512[] = 0x83828100UL, 0x87868584UL, 0x8b8a8988UL, 0x8f8e8d8cUL, 0x03020100UL, 0x07060504UL, 0x0b0a0908UL, 0x000e0d0cUL }; -#endif // _LP64 const jint StubRoutines::x86::_arrays_hashcode_powers_of_31[] = { @@ -356,7 +352,6 @@ ATTRIBUTE_ALIGNED(64) const juint StubRoutines::x86::_k256[] = 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL }; -#ifdef _LP64 // used in MacroAssembler::sha256_AVX2 // dynamically built from _k256 ATTRIBUTE_ALIGNED(64) juint StubRoutines::x86::_k256_W[2*sizeof(StubRoutines::x86::_k256)]; @@ -405,4 +400,3 @@ ATTRIBUTE_ALIGNED(64) const julong StubRoutines::x86::_k512_W[] = 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL, }; -#endif diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.hpp b/src/hotspot/cpu/x86/stubRoutines_x86.hpp index aaf84eb843777..c4930e1593c47 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.hpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.hpp @@ -75,39 +75,16 @@ class x86 { #undef DEFINE_ARCH_ENTRY_GETTER_INIT #undef DEFINE_ARCH_GETTER_ENTRY - -#ifndef _LP64 - - static jint _fpu_cntrl_wrd_std; - static jint _fpu_cntrl_wrd_24; - static jint _fpu_cntrl_wrd_trunc; - - static jint _fpu_subnormal_bias1[3]; - static jint _fpu_subnormal_bias2[3]; - - static address addr_fpu_cntrl_wrd_std() { return (address)&_fpu_cntrl_wrd_std; } - static address addr_fpu_cntrl_wrd_24() { return (address)&_fpu_cntrl_wrd_24; } - static address addr_fpu_cntrl_wrd_trunc() { return (address)&_fpu_cntrl_wrd_trunc; } - static address addr_fpu_subnormal_bias1() { return (address)&_fpu_subnormal_bias1; } - static address addr_fpu_subnormal_bias2() { return (address)&_fpu_subnormal_bias2; } - - static jint fpu_cntrl_wrd_std() { return _fpu_cntrl_wrd_std; } -#endif // !LP64 - private: static jint _mxcsr_std; -#ifdef _LP64 static jint _mxcsr_rz; -#endif // _LP64 // masks and table for CRC32 static const uint64_t _crc_by128_masks[]; static const juint _crc_table[]; -#ifdef _LP64 static const juint _crc_by128_masks_avx512[]; static const juint _crc_table_avx512[]; static const juint _crc32c_table_avx512[]; static const juint _shuf_table_crc32_avx512[]; -#endif // _LP64 // table for CRC32C static juint* _crc32c_table; // table for arrays_hashcode @@ -115,30 +92,22 @@ class x86 { //k256 table for sha256 static const juint _k256[]; static address _k256_adr; -#ifdef _LP64 static juint _k256_W[]; static address _k256_W_adr; static const julong _k512_W[]; static address _k512_W_addr; -#endif public: static address addr_mxcsr_std() { return (address)&_mxcsr_std; } -#ifdef _LP64 static address addr_mxcsr_rz() { return (address)&_mxcsr_rz; } -#endif // _LP64 static address crc_by128_masks_addr() { return (address)_crc_by128_masks; } -#ifdef _LP64 static address crc_by128_masks_avx512_addr() { return (address)_crc_by128_masks_avx512; } static address shuf_table_crc32_avx512_addr() { return (address)_shuf_table_crc32_avx512; } static address crc_table_avx512_addr() { return (address)_crc_table_avx512; } static address crc32c_table_avx512_addr() { return (address)_crc32c_table_avx512; } -#endif // _LP64 static address k256_addr() { return _k256_adr; } -#ifdef _LP64 static address k256_W_addr() { return _k256_W_adr; } static address k512_W_addr() { return _k512_W_addr; } -#endif static address arrays_hashcode_powers_of_31() { return (address)_arrays_hashcode_powers_of_31; } static void generate_CRC32C_table(bool is_pclmulqdq_supported); From 4e3f1848eeb28a78d71c6ffbda31279cee3fc5ea Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Tue, 15 Apr 2025 19:36:10 +0000 Subject: [PATCH 0593/1101] 8353000: Open source several swing tests batch2 Reviewed-by: azvegint --- .../JavaLAFMenuAcceleratorDelimiter.java | 83 +++++++ .../metal/MetalIconFactory/bug4952462.java | 98 ++++++++ .../MetalSliderUI/4186347/bug4186347.java | 74 ++++++ .../plaf/metal/MetalSliderUI/4186347/duke.gif | Bin 0 -> 1617 bytes .../metal/OceanTheme/4969419/bug4969419.java | 229 ++++++++++++++++++ .../plaf/metal/OceanTheme/4969419/duke.gif | Bin 0 -> 1929 bytes 6 files changed, 484 insertions(+) create mode 100644 test/jdk/javax/swing/plaf/metal/MenuItemUI/JavaLAFMenuAcceleratorDelimiter.java create mode 100644 test/jdk/javax/swing/plaf/metal/MetalIconFactory/bug4952462.java create mode 100644 test/jdk/javax/swing/plaf/metal/MetalSliderUI/4186347/bug4186347.java create mode 100644 test/jdk/javax/swing/plaf/metal/MetalSliderUI/4186347/duke.gif create mode 100644 test/jdk/javax/swing/plaf/metal/OceanTheme/4969419/bug4969419.java create mode 100644 test/jdk/javax/swing/plaf/metal/OceanTheme/4969419/duke.gif diff --git a/test/jdk/javax/swing/plaf/metal/MenuItemUI/JavaLAFMenuAcceleratorDelimiter.java b/test/jdk/javax/swing/plaf/metal/MenuItemUI/JavaLAFMenuAcceleratorDelimiter.java new file mode 100644 index 0000000000000..f9885c985705d --- /dev/null +++ b/test/jdk/javax/swing/plaf/metal/MenuItemUI/JavaLAFMenuAcceleratorDelimiter.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4210461 + * @summary Confirm Metal Look & Feel's MenuItem Accelerator Delimiter + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual JavaLAFMenuAcceleratorDelimiter + */ + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; + +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.KeyStroke; +import javax.swing.UIManager; + +public class JavaLAFMenuAcceleratorDelimiter { + static final String INSTRUCTIONS = """ + A simple check. The visual design specification for JLF/Metal asks for + a "-" to delimit the other two entities in a menu item's accelerator. + The test passes if the delimiter for the accelerator is correct when + opening the example menu. Otherwise, the test fails. + """; + + public static void main(String[] args) throws Exception { + // Set Metal L&F + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + PassFailJFrame.builder() + .title("JavaLAFMenuAcceleratorDelimiter Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(JavaLAFMenuAcceleratorDelimiter::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("Metal L&F Accelerator Delimiter Test"); + JPanel menuPanel = new JPanel(); + JMenuBar menuBar = new JMenuBar(); + menuBar.setOpaque(true); + JMenu exampleMenu = new JMenu("Example"); + JMenuItem hiMenuItem = new JMenuItem("Hi There!"); + hiMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, + ActionEvent.CTRL_MASK)); + exampleMenu.add(hiMenuItem); + menuBar.add(exampleMenu); + menuPanel.add(menuBar); + + frame.getContentPane().setLayout(new BorderLayout()); + frame.getContentPane().add(menuPanel, BorderLayout.CENTER); + frame.setSize(250, 150); + return frame; + } +} diff --git a/test/jdk/javax/swing/plaf/metal/MetalIconFactory/bug4952462.java b/test/jdk/javax/swing/plaf/metal/MetalIconFactory/bug4952462.java new file mode 100644 index 0000000000000..f3562108314d2 --- /dev/null +++ b/test/jdk/javax/swing/plaf/metal/MetalIconFactory/bug4952462.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4952462 + * @summary Ocean: Tests that disabled selected JRadioButton dot is NOT + * painted with the foreground color + * @modules java.desktop/sun.awt + * @library /test/lib + * @key headful + * @run main bug4952462 + */ + +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.Point; +import java.awt.Robot; + +import javax.swing.JFrame; +import javax.swing.JRadioButton; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.plaf.metal.MetalTheme; + +import jtreg.SkippedException; +import sun.awt.AppContext; + +public class bug4952462 { + private static JFrame frame; + private static JRadioButton rb; + + public static void main(String[] args) throws Exception { + try { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + + MetalTheme theme = (MetalTheme) AppContext.getAppContext().get("currentMetalTheme"); + if (theme == null || !"Ocean".equals(theme.getName())) { + throw new SkippedException("Current theme is not Ocean. Test is " + + "only for Metal's Ocean theme. Skipping test."); + } else { + Robot r = new Robot(); + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("Metal JRadioButton Foreground Color Test"); + frame.getContentPane().setLayout(new FlowLayout()); + rb = new JRadioButton("RadioButton", true); + rb.setEnabled(false); + rb.setForeground(Color.RED); + frame.getContentPane().add(rb); + frame.setSize(250, 100); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + + r.waitForIdle(); + r.delay(500); + + SwingUtilities.invokeAndWait(() -> { + Point p = rb.getLocationOnScreen(); + for (int i = 0; i < 50; i++) { + Color c = r.getPixelColor(p.x + 10 + i, p.y + (rb.getHeight() / 2)); + System.out.println(c); + if (c.getRed() > 200 && c.getBlue() < 200 && c.getGreen() < 200) { + throw new RuntimeException("Test failed. Radiobutton is red " + + "and not grey."); + } + } + }); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } +} diff --git a/test/jdk/javax/swing/plaf/metal/MetalSliderUI/4186347/bug4186347.java b/test/jdk/javax/swing/plaf/metal/MetalSliderUI/4186347/bug4186347.java new file mode 100644 index 0000000000000..9de9d851805ef --- /dev/null +++ b/test/jdk/javax/swing/plaf/metal/MetalSliderUI/4186347/bug4186347.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4186347 + * @summary Tests changing Slider.horizontalThumbIcon UIResource + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4186347 + */ + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JSlider; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.IconUIResource; + +public class bug4186347 { + static final String INSTRUCTIONS = """ + If the slider's thumb icon is painted correctly + (that is centered vertically relative to slider + channel) then test passed, otherwise it failed. + """; + + public static void main(String[] args) throws Exception { + // Set Metal L&F + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + PassFailJFrame.builder() + .title("bug4186347 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4186347::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("Metal JSlider Icon Test"); + String a = System.getProperty("test.src", ".") + + System.getProperty("file.separator") + + "duke.gif"; + Icon icon = new ImageIcon(a); + IconUIResource iconResource = new IconUIResource(icon); + UIDefaults defaults = UIManager.getDefaults(); + defaults.put("Slider.horizontalThumbIcon", iconResource); + JSlider s = new JSlider(); + frame.getContentPane().add(s); + frame.setSize(250, 150); + return frame; + } +} diff --git a/test/jdk/javax/swing/plaf/metal/MetalSliderUI/4186347/duke.gif b/test/jdk/javax/swing/plaf/metal/MetalSliderUI/4186347/duke.gif new file mode 100644 index 0000000000000000000000000000000000000000..a02a42fd606741170756cd1a33b48f609692b7f3 GIT binary patch literal 1617 zcmdUu>r)d~7>7?Fz!CwMYgeQ;%S983OoA0jYb}I;F*qYe>gWm@T%>g3RCKjoq7KRm zM%Eift#q|OSSYr!$gu6$c56UMLG9L#8nqu%I@$)QHZs#T)mG92^`GeZupi#DGw<(t zesdNrF3Qzb+|{iet#ekaB`fLq7VR30B``502l!<0YCsi0$>4v z0w56Zi=rFH;ZBrua!%eUxCJ|FXE~O#QWnZWT1XRNB1l4K)M<5EjaGvzaSX>$3`I}` zAOOWN+Ro@qM#4hASR4$xVVKD%ydZFs`Ceq@IGSN#dVeqoF|0HVd3d)QvT-~Q@gOIp zrR{cz2gxBnv|xgBf`CS}Mk7=M1wl;!LF^n%E3%vu!l#;`FHMPG z?#i1zZ+BI~>B`jRW@-KNkGfoGODjrd=HwGMrw&b5g{qHXomJO?tmeuF^H}k>3*)YB zFTWO-F`!s8pf4MG&uKrn=#F>C%FjDe^|e`^^5JejSeX8Ic$Hz>W63GWvxRFE9iOTt z^Uam%@+*I&0R4Ker|vmV3|zYkp1Z0*}z_~j|*(Jg4sVWnaCWb?($o}?o8 zA>|K)?>J&gdgZT(vVT(sXO1(Auo~WBZa7 zXU$FP4jPC5bmYI8pnfYtzRP@neXF|1cDOjX@8-0nNw3z&fsz_SGKqym&N{NI$(B-_ zb+59fLY96#Rw@2uNN?QIW}BIOWm;!=u4;vEV-j+1qz$O>QX=)WtLEmMCl%fO?g`?6Yl_mH8eUMfY% z{RPHHdHJl#+*dKx^x5-|H3iGI$W95w%?xmnj@s(^?w0mt51Fa literal 0 HcmV?d00001 diff --git a/test/jdk/javax/swing/plaf/metal/OceanTheme/4969419/bug4969419.java b/test/jdk/javax/swing/plaf/metal/OceanTheme/4969419/bug4969419.java new file mode 100644 index 0000000000000..023f17f4c43c2 --- /dev/null +++ b/test/jdk/javax/swing/plaf/metal/OceanTheme/4969419/bug4969419.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4969419 + * @summary Tests that generated disabled icons have same look with Ocean + * and are updated when theme is switched + * @modules java.desktop/sun.awt + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @key headful + * @run main/manual bug4969419 + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.FlowLayout; + +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.JToggleButton; +import javax.swing.LookAndFeel; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.plaf.metal.DefaultMetalTheme; +import javax.swing.plaf.metal.MetalLookAndFeel; +import javax.swing.plaf.metal.MetalTheme; + +import sun.awt.AppContext; + +public class bug4969419 { + static final String INSTRUCTIONS = """ + When the test starts you'll see several components with icons. + Use the bottom combo box and the "Set" button to switch between + the Ocean theme and DefaultMetalTheme. + + 1. Set the Ocean theme. Ensure all the icons are the same + Note that they all are of the same brightness: none of them + can be brighter or darker than the others. + + 2. Switch to DefaultMetalTheme. Ensure all the icons changed + (became slightly darker). + + 3. Switch back to Ocean. Ensure all the icons changed + (became brighter). + """; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + PassFailJFrame.builder() + .title("bug4969419 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4969419::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("Metal Themes Icon Test"); + Container pane = frame.getContentPane(); + + LFSwitch lfswitch = new LFSwitch(pane); + if (!lfswitch.obtainOceanTheme()) { + throw new RuntimeException("No Ocean theme available"); + } + + pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS)); + + String prefix = System.getProperty("test.src", + System.getProperty("user.dir")) + System.getProperty("file.separator"); + ImageIcon icon = new ImageIcon(prefix + "duke.gif"); + + JPanel panel = new JPanel(); + JButton b = new JButton(icon); + b.setEnabled(false); + + JLabel label = new JLabel(icon, SwingConstants.LEFT); + label.setEnabled(false); + + JTabbedPane tp = new JTabbedPane(); + tp.addTab("", icon, new JPanel()); + tp.addTab("", icon, new JPanel()); + tp.setEnabledAt(0, false); + tp.setEnabledAt(1, false); + + JButton sb = new JButton(icon); + sb.setSelectedIcon(icon); + sb.setSelected(true); + sb.setEnabled(false); + + JToggleButton tb = new JToggleButton(icon); + tb.setEnabled(false); + + JToggleButton stb = new JToggleButton(icon); + stb.setSelectedIcon(icon); + stb.setSelected(true); + stb.setEnabled(false); + + pane.setBackground(Color.white); + panel.setBackground(Color.white); + b.setBackground(Color.white); + label.setBackground(Color.white); + tp.setBackground(Color.white); + sb.setBackground(Color.white); + tb.setBackground(Color.white); + stb.setBackground(Color.white); + + panel.add(b); + panel.add(label); + panel.add(tp); + panel.add(sb); + panel.add(tb); + panel.add(stb); + + pane.add(panel); + pane.add(lfswitch); + frame.setSize(400, 400); + return frame; + } + + static class LFSwitch extends JPanel { + private Component target; + static MetalTheme oceanTheme; + JComboBox lfcombo; + + public LFSwitch(Component target) { + this.target = target; + setLayout(new FlowLayout()); + lfcombo = new JComboBox(lookAndFeels); + add(lfcombo); + JButton setLfBut = new JButton("Set"); + add(setLfBut); + setLfBut.addActionListener(e -> setLf(lfcombo.getSelectedIndex(), + LFSwitch.this.target)); + } + + boolean obtainOceanTheme() { + if (oceanTheme != null) { + return true; + } + try { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + SwingUtilities.updateComponentTreeUI(this); + } catch (Exception e) { + JOptionPane.showMessageDialog(this, + "Unexpected error: couldn't set Metal", "Error", + JOptionPane.ERROR_MESSAGE); + return false; + } + MetalTheme theme = (MetalTheme) AppContext.getAppContext(). + get("currentMetalTheme"); + if (theme == null || theme.getName() != "Ocean") { + JOptionPane.showMessageDialog(this, + "The Ocean theme is not the default Metal theme,\n" + + "but this test requires it to be default.\n" + + "Therefore simply click PASS"); + return false; + } + oceanTheme = theme; + return true; + } + + void setLf(int idx, final Component root) { + try { + UIManager.setLookAndFeel((LookAndFeel) lfs[idx]); + if (root != null) { + SwingUtilities.updateComponentTreeUI(root); + } + } catch (UnsupportedLookAndFeelException e) { + JOptionPane.showMessageDialog(root, + "The selected look and feel is unsupported on this platform", + "Error", JOptionPane.ERROR_MESSAGE); + } catch (Exception exc) { + JOptionPane.showMessageDialog(root, + "Error setting the selected look and feel", "Error", + JOptionPane.ERROR_MESSAGE); + } + } + + static Object[] lookAndFeels = { + "Metal (Ocean)", "Metal (DefaultMetalTheme)", + }; + static Object[] lfs = { + new MetalLookAndFeel() { + protected void createDefaultTheme() { + setCurrentTheme(oceanTheme); + } + }, + new MetalLookAndFeel() { + protected void createDefaultTheme() { + MetalTheme dt = new DefaultMetalTheme(); + setCurrentTheme(dt); + } + }, + }; + } +} diff --git a/test/jdk/javax/swing/plaf/metal/OceanTheme/4969419/duke.gif b/test/jdk/javax/swing/plaf/metal/OceanTheme/4969419/duke.gif new file mode 100644 index 0000000000000000000000000000000000000000..ed32e0ff79b05c07b82863ce6fb07fa9898adaa2 GIT binary patch literal 1929 zcmWlYe^AtB8pi`HvM4_?{J2I$8$dLc1#@!R2zwgXMWdj^k;9xr+bDW&4{JlE8WpDj z7F-cwwK{H<)?L&#SJz$!;hJ{%BY2FYf)Wp^xl?aq!5Xcdi$c#hV~>m9_n-Hl=Xsy+ z=li^?*Q~;pZ+R1N1J40KRkeWM7ew3~jLM24A{CM-A}~TzqzYpq&od0GC=z71!w_=b z-==B0rt2t*nA}((5YSLs6a*Z@X__WqiSjTW6oLo{5km&|K1mGAimYjhs#wwZtvV8SV~7LCFpgub+-TTAk%UQb0dE_cj+pc?!+0o?qG$?% zVFD)%!w7Z;g)ndE8Uk6Aky=+kLaUQ{UW`XS?Nn*s@SQ{VmFgGdkV{&&98EcEQ5hjc@H$`e)fX zj@&GdchxpMUo|-A^M4iBP3(#Ib53Ap?5{nGT7SBA_V!o!TTzL5R~FUWe)4X?@iTd8 z1;TcF^rQLj?4p0uy?@ikb2eUSXdHVa_jIn=@W%a<6~57D>am6&Z!{lzc=@ZbuGB8` zpU38H8d~@82Da!+qdYG5ls&Cx?~|oPMnbqTHMw%I*KlV~?fc{rSwe29?Om}fsknG# z@n5IwY=4Mx>>0WJLG>=yJX^WbHA30iQ$H!X)3<4K zBe1|sf3NKKTS;)mg{$k(2eDJG^u5=&x{@M!V>EWgzRA((>}?o{WQBehp1mIHU!BGG zYz5_6B(+KIVdCVoum2ItM&gXZd+SB^vQTN=a zeYbbah=i-xCho2{4Pazv_i%2mH`EkM{r8XYDLbdY@(a7Ud}$%!$QrTN_DqwNXA9~g zTGKxKyfto7NDp;5A3O5zgb(hyxjN@OAG!(zy^*Ug4!yjF=Y*8aHA@ovB1({&a4;sR zTf1CVC{>Pgy`m$lG;P1$pC_6F7u%iP+qz0q4{lXT`i9g-ThiYgO^GXC`f?JNo*|@p zr{b%U-tSKw99q0|YJa9{Va?`H{IaNICo>p5lGEY*+IDR4bfIUwq~CTRuC_mGWA%~W zea{@eKJ(Iq^7MvdsPsR%&vt$@4i&s?bPptz#y#!FcRZEaMS0WFTyXMCUEfsNxnJ_9 zPwpt`Er4O>``2G{7=4r1GCSTO8#0xw+{<^L4X(K8y1wKj72KLrYD}Y7SJuY7y==wf z;UkI5?(v?h+4r;vR{P*U`ul~=D@U7K5$eV8c!%rX-38vE>azU80UrhFXCv#d`(ylZS4+i2a^vI91MTIxCx%9gd2&N&D9RC&xcpx8#f=GZv%9;F z#?CEVT%UV$nk;L%RJA+d=f8ZB@U*Xz-TZbG?HKKT(VJZMBH!)$#qRuwbFc%Aljqha zoNBs8od~V$_^vux0ZSk!iP!hI($t35SxY8`FV{pxCjpU}Ova2VIg1&>V)CvvMb_ Date: Tue, 15 Apr 2025 21:25:06 +0000 Subject: [PATCH 0594/1101] 8354544: Fix bugs in increment and xor APX codegen Reviewed-by: thartmann, jbhateja --- src/hotspot/cpu/x86/x86_64.ad | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 5781ffce4bdc4..078150c61fbc5 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -7396,7 +7396,7 @@ instruct addL_mem_imm(memory dst, immL32 src, rFlagsReg cr) ins_pipe(ialu_mem_imm); %} -instruct incL_rReg(rRegI dst, immL1 src, rFlagsReg cr) +instruct incL_rReg(rRegL dst, immL1 src, rFlagsReg cr) %{ predicate(!UseAPX && UseIncDec); match(Set dst (AddL dst src)); @@ -7409,7 +7409,7 @@ instruct incL_rReg(rRegI dst, immL1 src, rFlagsReg cr) ins_pipe(ialu_reg); %} -instruct incL_rReg_ndd(rRegI dst, rRegI src, immL1 val, rFlagsReg cr) +instruct incL_rReg_ndd(rRegL dst, rRegI src, immL1 val, rFlagsReg cr) %{ predicate(UseAPX && UseIncDec); match(Set dst (AddL src val)); @@ -7422,7 +7422,7 @@ instruct incL_rReg_ndd(rRegI dst, rRegI src, immL1 val, rFlagsReg cr) ins_pipe(ialu_reg); %} -instruct incL_rReg_mem_ndd(rRegI dst, memory src, immL1 val, rFlagsReg cr) +instruct incL_rReg_mem_ndd(rRegL dst, memory src, immL1 val, rFlagsReg cr) %{ predicate(UseAPX && UseIncDec); match(Set dst (AddL (LoadL src) val)); @@ -11345,7 +11345,7 @@ instruct xorL_rReg_mem_rReg_ndd(rRegL dst, memory src1, rRegL src2, rFlagsReg cr ins_cost(150); format %{ "exorq $dst, $src1, $src2\t# long ndd" %} ins_encode %{ - __ exorq($dst$$Register, $src1$$Address, $src1$$Register, false); + __ exorq($dst$$Register, $src1$$Address, $src2$$Register, false); %} ins_pipe(ialu_reg_mem); %} From a2dc9c71e47a1cdf70ab351c557a5f1835eb5f4a Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Tue, 15 Apr 2025 23:48:27 +0000 Subject: [PATCH 0595/1101] 8352908: Open source several swing tests batch1 Reviewed-by: honkar --- .../javax/swing/JSplitPane/bug4749792.java | 77 ++++++++++++ test/jdk/javax/swing/JToolBar/bug4188825.java | 70 +++++++++++ test/jdk/javax/swing/JToolBar/bug4251592.java | 93 ++++++++++++++ test/jdk/javax/swing/JToolBar/bug5035668.java | 113 ++++++++++++++++++ 4 files changed, 353 insertions(+) create mode 100644 test/jdk/javax/swing/JSplitPane/bug4749792.java create mode 100644 test/jdk/javax/swing/JToolBar/bug4188825.java create mode 100644 test/jdk/javax/swing/JToolBar/bug4251592.java create mode 100644 test/jdk/javax/swing/JToolBar/bug5035668.java diff --git a/test/jdk/javax/swing/JSplitPane/bug4749792.java b/test/jdk/javax/swing/JSplitPane/bug4749792.java new file mode 100644 index 0000000000000..1d9823073b72d --- /dev/null +++ b/test/jdk/javax/swing/JSplitPane/bug4749792.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4749792 + * @requires (os.family == "windows") + * @summary Split pane border is not painted properly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4749792 + */ + +import java.awt.BorderLayout; +import java.awt.Dimension; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSplitPane; + +public class bug4749792 { + static final String INSTRUCTIONS = """ + If the right/bottom edges of JSplitPane's border is missing then the + test fails. If it is visible, then the test passes. + """; + + static JFrame createUI() { + JFrame frame = new JFrame("JSplitPane Border Test"); + frame.setSize(450, 220); + JPanel left = new JPanel(); + JPanel right = new JPanel(); + left.setPreferredSize(new Dimension(200, 200)); + right.setPreferredSize(new Dimension(200, 200)); + JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, right); + frame.add(sp); + + JPanel south = new JPanel(); + south.setPreferredSize(new Dimension(20, 20)); + frame.add(south, BorderLayout.SOUTH); + + JPanel east = new JPanel(); + east.setPreferredSize(new Dimension(20, 20)); + frame.add(east, BorderLayout.EAST); + + return frame; + } + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4749792 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4749792::createUI) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/javax/swing/JToolBar/bug4188825.java b/test/jdk/javax/swing/JToolBar/bug4188825.java new file mode 100644 index 0000000000000..e5dd6538de42c --- /dev/null +++ b/test/jdk/javax/swing/JToolBar/bug4188825.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4188825 + * @summary Tests if toolbars return to original location when closed + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4188825 + */ + +import java.awt.BorderLayout; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JToolBar; + +public class bug4188825 { + static final String INSTRUCTIONS = """ + Drag the toolbar out of frame and close it. If it returns to + the original location, then the test succeeded, otherwise it failed. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4188825 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4188825::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("Toolbar Drag Test"); + frame.setLayout(new BorderLayout()); + JToolBar tb = new JToolBar(); + tb.setOrientation(JToolBar.VERTICAL); + tb.add(new JButton("a")); + tb.add(new JButton("b")); + tb.add(new JButton("c")); + frame.add(tb, BorderLayout.WEST); + JButton l = new JButton("Get me!!!"); + l.setSize(200, 200); + frame.add(l); + frame.setSize(200, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JToolBar/bug4251592.java b/test/jdk/javax/swing/JToolBar/bug4251592.java new file mode 100644 index 0000000000000..add4eb8ec923e --- /dev/null +++ b/test/jdk/javax/swing/JToolBar/bug4251592.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4251592 + * @summary JToolBar should have ability to set custom layout. + * @key headful + * @run main bug4251592 + */ + +import java.awt.BorderLayout; +import java.awt.GridLayout; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JToolBar; +import javax.swing.SwingUtilities; + +public class bug4251592 { + private static final int OFFSET = 3; + private static volatile Point loc; + private static JFrame frame; + private static JToolBar toolBar; + private static GridLayout customLayout; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(100); + try { + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("Toolbar Layout Save Test"); + toolBar = new JToolBar(); + customLayout = new GridLayout(); + frame.setLayout(new BorderLayout()); + frame.add(toolBar, BorderLayout.NORTH); + + toolBar.setLayout(customLayout); + toolBar.add(new JButton("Button1")); + toolBar.add(new JButton("Button2")); + toolBar.add(new JButton("Button3")); + toolBar.setFloatable(true); + + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> loc = toolBar.getLocationOnScreen()); + + robot.mouseMove(loc.x + OFFSET, loc.y + OFFSET); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseMove(loc.x + OFFSET, loc.y + 50); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + if (toolBar.getLayout() != customLayout) { + throw new RuntimeException("Custom layout not saved..."); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } +} diff --git a/test/jdk/javax/swing/JToolBar/bug5035668.java b/test/jdk/javax/swing/JToolBar/bug5035668.java new file mode 100644 index 0000000000000..b0cdef7c7ef70 --- /dev/null +++ b/test/jdk/javax/swing/JToolBar/bug5035668.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5035668 + * @summary Test that metal ToolBar border correctly sizes the MetalBumps used + * for the grip + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug5035668 + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.ComponentOrientation; +import java.awt.GridLayout; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JToolBar; +import javax.swing.UIManager; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; + +public class bug5035668 { + static final String INSTRUCTIONS = """ + This test is for Metal LaF only. + + All of them have an empty border around their own border. + If you see that in any toolbar the grip (little dotted strip) overlaps + the empty border press Fail. If you see that grips are completely + inside empty borders press Pass. + """; + + public static void main(String[] args) throws Exception { + // Set metal l&f + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + PassFailJFrame.builder() + .title("bug4251592 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug5035668::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("Metal JToolBar Border Overlap Test"); + frame.setLayout(new BorderLayout()); + frame.setBackground(Color.white); + + // Horizontal toolbar left-to-right + final JToolBar toolBar = new JToolBar(); + toolBar.setBorder(new CompoundBorder(new EmptyBorder(10, 10, 10, 10), + toolBar.getBorder())); + toolBar.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + toolBar.add(new ToolBarButton(toolBar)); + + // Horizontal toolbar right-to-left + JToolBar toolBar2 = new JToolBar(); + toolBar2.setBorder(new CompoundBorder(new EmptyBorder(10, 10, 10, 10), + toolBar2.getBorder())); + toolBar2.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); + toolBar2.add(new ToolBarButton(toolBar2)); + + JPanel topPanel = new JPanel(new GridLayout(2, 0)); + topPanel.add(toolBar); + topPanel.add(toolBar2); + frame.add(topPanel, BorderLayout.NORTH); + + JToolBar toolBar3 = new JToolBar(); + toolBar3.setBorder(new CompoundBorder(new EmptyBorder(10, 10, 10, 10), + toolBar3.getBorder())); + toolBar3.setOrientation(JToolBar.VERTICAL); + toolBar3.add(new ToolBarButton(toolBar3)); + frame.add(toolBar3, BorderLayout.EAST); + + frame.setSize(200, 200); + return frame; + } + + static class ToolBarButton extends JButton { + final JToolBar toolBar; + + public ToolBarButton(JToolBar p_toolBar) { + super("Change toolbar's orientation"); + this.toolBar = p_toolBar; + addActionListener(e -> toolBar.setOrientation(1 - toolBar.getOrientation())); + } + } +} From 5526490743a75786a40754b6805f4381ae2892b5 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Wed, 16 Apr 2025 01:57:57 +0000 Subject: [PATCH 0596/1101] 8354565: jtreg failure handler GatherProcessInfoTimeoutHandler has a leftover call to System.loadLibrary Reviewed-by: alanb, kbarrett --- .../jtreg/GatherProcessInfoTimeoutHandler.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java index 82b0151d86c5f..63ed7e5f2c783 100644 --- a/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java @@ -36,19 +36,7 @@ * A timeout handler for jtreg, which gathers information about the timed out * process and its children. */ -@SuppressWarnings("restricted") public class GatherProcessInfoTimeoutHandler extends TimeoutHandler { - private static final boolean HAS_NATIVE_LIBRARY; - static { - boolean value = true; - try { - System.loadLibrary("timeoutHandler"); - } catch (UnsatisfiedLinkError ignore) { - // not all os need timeoutHandler native-library - value = false; - } - HAS_NATIVE_LIBRARY = value; - } private static final String LOG_FILENAME = "processes.log"; private static final String OUTPUT_FILENAME = "processes.html"; From 55afcb57a5d9dbc7bfad75e35df6b96932f6b074 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 16 Apr 2025 03:58:17 +0000 Subject: [PATCH 0597/1101] 8352682: Opensource JComponent tests Reviewed-by: jdv, honkar --- .../javax/swing/JComponent/bug4235215.java | 64 +++++++++ .../javax/swing/JComponent/bug4247610.java | 128 ++++++++++++++++++ .../javax/swing/JComponent/bug4254995.java | 60 ++++++++ 3 files changed, 252 insertions(+) create mode 100644 test/jdk/javax/swing/JComponent/bug4235215.java create mode 100644 test/jdk/javax/swing/JComponent/bug4247610.java create mode 100644 test/jdk/javax/swing/JComponent/bug4254995.java diff --git a/test/jdk/javax/swing/JComponent/bug4235215.java b/test/jdk/javax/swing/JComponent/bug4235215.java new file mode 100644 index 0000000000000..471f713ee4679 --- /dev/null +++ b/test/jdk/javax/swing/JComponent/bug4235215.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4235215 + * @summary Tests that Toolkit.getPrintJob() do not throw NPE + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4235215 + */ + +import java.awt.Toolkit; +import javax.swing.JButton; +import javax.swing.JFrame; + +public class bug4235215 { + + private static final String INSTRUCTIONS = """ + Press "Print Dialog" button. + If you see a print dialog, test passes. + Click "Cancel" button to close it."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4235215 Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(bug4235215::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("bug4235215"); + JButton button = new JButton("Print Dialog"); + button.addActionListener(ev -> { + Toolkit.getDefaultToolkit().getPrintJob(frame, "Test Printing", null); + }); + frame.add(button); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/javax/swing/JComponent/bug4247610.java b/test/jdk/javax/swing/JComponent/bug4247610.java new file mode 100644 index 0000000000000..e5470606f6e05 --- /dev/null +++ b/test/jdk/javax/swing/JComponent/bug4247610.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4247610 + * @summary Tests an unnecessary repaint issue + * @key headful + * @run main bug4247610 + */ + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import javax.swing.JButton; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.Random; + +public class bug4247610 { + + private static JFrame frame; + private static JButton damager; + private static volatile Point loc; + private static volatile Dimension size; + private static volatile boolean traced; + private static volatile boolean failed; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("bug4247610"); + JDesktopPane pane = new JDesktopPane(); + + JInternalFrame jif = new JInternalFrame( + "Damager", true, true, true, true); + InternalFramePanel ifp = new InternalFramePanel(); + damager = new JButton("Damage!"); + ifp.add(damager); + jif.setContentPane(ifp); + jif.setBounds(0, 0, 300, 300); + jif.setVisible(true); + pane.add(jif); + + jif = new JInternalFrame("Damagee", true, true, true, true); + JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + final JLabel damagee = new JLabel(""); + panel.add(damagee); + jif.setContentPane(panel); + jif.setBounds(60, 220, 300, 100); + jif.setVisible(true); + pane.add(jif); + + final Random random = new Random(); + + damager.addActionListener((e) -> { + System.out.println("trace paints enabled"); + traced = true; + damagee.setText(Integer.toString(random.nextInt())); + }); + frame.setContentPane(pane); + frame.setSize(500, 500); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(1000); + SwingUtilities.invokeAndWait(() -> { + loc = damager.getLocationOnScreen(); + size = damager.getSize(); + }); + robot.mouseMove(loc.x + size.width / 2, loc.y + size.height / 2); + robot.waitForIdle(); + robot.delay(200); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + if (failed) { + throw new RuntimeException("Failed: unnecessary repaint occured"); + } + } + + + static class InternalFramePanel extends JPanel { + final AtomicInteger repaintCounter = new AtomicInteger(0); + InternalFramePanel() { + super(new FlowLayout()); + setOpaque(true); + } + + public synchronized void paintComponent(Graphics g) { + super.paintComponent(g); + repaintCounter.incrementAndGet(); + System.out.println("repaintCounter " + repaintCounter.intValue()); + if (traced) { + failed = true; + } + } + } +} diff --git a/test/jdk/javax/swing/JComponent/bug4254995.java b/test/jdk/javax/swing/JComponent/bug4254995.java new file mode 100644 index 0000000000000..8947558f128bf --- /dev/null +++ b/test/jdk/javax/swing/JComponent/bug4254995.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4254995 + * @summary Tests that html in renderer works correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4254995 + */ + +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JScrollPane; + +public class bug4254995 { + + private static final String INSTRUCTIONS = """ + If you see a list containing digits from one to seven, test passes. + Otherwise it fails."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4254995 Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(bug4254995::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("bug4254995"); + String[] data = { "1", "2", "3", "4", "5", "6", "7" }; + frame.add(new JScrollPane(new JList(data))); + frame.pack(); + return frame; + } +} From 2be5bc847a444f08a4ebb41b58e8a2bf4553d621 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Wed, 16 Apr 2025 04:48:25 +0000 Subject: [PATCH 0598/1101] 8354214: Open source Swing tests Batch 2 Reviewed-by: abhiscxk, honkar --- test/jdk/javax/swing/JList/bug4193267.java | 117 +++++++++++++++++++ test/jdk/javax/swing/JList/bug4249161.java | 96 ++++++++++++++++ test/jdk/javax/swing/JList/bug4618767.java | 127 +++++++++++++++++++++ 3 files changed, 340 insertions(+) create mode 100644 test/jdk/javax/swing/JList/bug4193267.java create mode 100644 test/jdk/javax/swing/JList/bug4249161.java create mode 100644 test/jdk/javax/swing/JList/bug4618767.java diff --git a/test/jdk/javax/swing/JList/bug4193267.java b/test/jdk/javax/swing/JList/bug4193267.java new file mode 100644 index 0000000000000..cb447644d154d --- /dev/null +++ b/test/jdk/javax/swing/JList/bug4193267.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4193267 + * @summary Tests that JList first and last visible indices are + * updated properly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4193267 + */ + +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.GridLayout; +import java.util.List; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +public class bug4193267 { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Resize the frame "JList" with a different ways and scroll the list + (if it possible). The indices of first and last visible elements + should be indicated in the corresponding fields in "Index" frame. + If the indicated indices is not right then test fails. + + Note: + - the first and last visible indices should be -1 if nothing + is visible; + - the first or last visible cells may only be partially visible. + """; + PassFailJFrame.builder() + .title("bug4193267 Instructions") + .instructions(INSTRUCTIONS) + .positionTestUI(WindowLayouts::rightOneRow) + .columns(35) + .testUI(bug4193267::initialize) + .build() + .awaitAndCheck(); + } + + private static List initialize() { + String[] data = {"000000000000000", "111111111111111", + "222222222222222", "333333333333333", + "444444444444444", "555555555555555", + "666666666666666", "777777777777777", + "888888888888888", "999999999999999"}; + + JFrame[] fr = new JFrame[2]; + fr[0] = new JFrame("JList"); + JList lst = new JList(data); + lst.setLayoutOrientation(JList.VERTICAL_WRAP); + lst.setVisibleRowCount(4); + JScrollPane jsp = new JScrollPane(lst); + fr[0].add(jsp); + fr[0].setSize(400, 200); + + JPanel pL = new JPanel(); + pL.setLayout(new GridLayout(2, 1)); + pL.add(new JLabel("First Visible Index")); + pL.add(new JLabel("Last Visible Index")); + + JPanel p = new JPanel(); + p.setLayout(new GridLayout(2, 1)); + JTextField first = new JTextField("0", 2); + first.setEditable(false); + first.setBackground(Color.white); + p.add(first); + JTextField last = new JTextField("9", 2); + last.setEditable(false); + last.setBackground(Color.white); + p.add(last); + + fr[1] = new JFrame("Index"); + fr[1].setSize(200, 200); + fr[1].setLayout(new FlowLayout()); + fr[1].add(pL); + fr[1].add(p); + + jsp.getViewport().addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + first.setText(String.valueOf(lst.getFirstVisibleIndex())); + last.setText(String.valueOf(lst.getLastVisibleIndex())); + } + }); + List frameList = List.of(fr[0], fr[1]); + return frameList; + } +} diff --git a/test/jdk/javax/swing/JList/bug4249161.java b/test/jdk/javax/swing/JList/bug4249161.java new file mode 100644 index 0000000000000..09bdd93600f07 --- /dev/null +++ b/test/jdk/javax/swing/JList/bug4249161.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4249161 + * @summary Tests that JList.setComponentOrientation() works correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4249161 + */ + +import java.awt.BorderLayout; +import java.awt.ComponentOrientation; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JScrollPane; + +public class bug4249161 { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. With a scroll bar, confirm that all words ("one" - "twenty") are + aligned at the left side of a list. + 2. Press "Change!" button. All words on the list should be moved + to the right side. + 3. Press the same button again. All words should be moved to the + left side. + + If all items in a list are moved as soon as "Change!" button is + pressed, test passes. + """; + PassFailJFrame.builder() + .title("bug4249161 Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(bug4249161::initialize) + .build() + .awaitAndCheck(); + } + + private static JFrame initialize() { + JFrame fr = new JFrame("bug4249161"); + + String[] data = {"one", "two", "three", "four", "five", + "six", "seven", "eight", "nine", "ten", + "eleven", "twelve", "thirteen", "fourteen", "fifteen", + "sixteen", "seventeen", "eighteen", "nineteen", "twenty" + }; + final JList list = new JList(data); + list.setSize(200, 200); + list.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + JScrollPane pane = new JScrollPane(list); + fr.add(pane); + + JButton button = new JButton("Change!"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (list.getComponentOrientation() != + ComponentOrientation.RIGHT_TO_LEFT) { + list.setComponentOrientation + (ComponentOrientation.RIGHT_TO_LEFT); + } else { + list.setComponentOrientation + (ComponentOrientation.LEFT_TO_RIGHT); + } + } + }); + fr.add(button, BorderLayout.SOUTH); + fr.setSize(200, 300); + fr.setAlwaysOnTop(true); + return fr; + } +} diff --git a/test/jdk/javax/swing/JList/bug4618767.java b/test/jdk/javax/swing/JList/bug4618767.java new file mode 100644 index 0000000000000..f01e20f365c9e --- /dev/null +++ b/test/jdk/javax/swing/JList/bug4618767.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4618767 + * @summary First letter navigation in JList interferes with mnemonics + * @key headful + * @run main bug4618767 + */ + +import java.awt.Robot; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.SwingUtilities; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuListener; + +public class bug4618767 { + private static JFrame f; + private static final JList list = new + JList(new String[] {"one", "two", "three", "four"}); + private static boolean menuSelected; + private static volatile boolean failed; + private static CountDownLatch listGainedFocusLatch = new CountDownLatch(1); + + public static void main(String[] args) throws Exception { + try { + createUI(); + runTest(); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private static void createUI() throws Exception { + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("bug4618767"); + JMenu menu = new JMenu("File"); + menu.setMnemonic('F'); + JMenuItem menuItem = new JMenuItem("item"); + menu.add(menuItem); + JMenuBar menuBar = new JMenuBar(); + menuBar.add(menu); + f.setJMenuBar(menuBar); + + menu.addMenuListener(new MenuListener() { + public void menuCanceled(MenuEvent e) {} + public void menuDeselected(MenuEvent e) {} + public void menuSelected(MenuEvent e) { + menuSelected = true; + } + }); + + list.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + listGainedFocusLatch.countDown(); + } + }); + f.add(list); + f.pack(); + f.setLocationRelativeTo(null); + f.setAlwaysOnTop(true); + f.setVisible(true); + }); + } + + private static void runTest() throws Exception { + if (!listGainedFocusLatch.await(3, TimeUnit.SECONDS)) { + throw new RuntimeException("Waited too long, but can't gain" + + " focus for list"); + } + Robot robot = new Robot(); + robot.setAutoDelay(200); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_O); + robot.keyRelease(KeyEvent.VK_O); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_ALT); + + SwingUtilities.invokeAndWait(() -> { + if (menuSelected && list.getSelectedIndex()!= 0) { + failed = true; + } + }); + if (failed) { + throw new RuntimeException("Mnemonics interferes with Jlist" + + " item selection using KeyEvent"); + } + } +} From 9a5c7b3fa90c7f550773e98ee9466ca1665aff4f Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 16 Apr 2025 05:54:21 +0000 Subject: [PATCH 0599/1101] 8351162: Clean up x86 (Macro)Assembler after 32-bit x86 removal Reviewed-by: kvn, coleenp --- src/hotspot/cpu/x86/assembler_x86.cpp | 249 +---- src/hotspot/cpu/x86/assembler_x86.hpp | 107 +- src/hotspot/cpu/x86/assembler_x86.inline.hpp | 54 - src/hotspot/cpu/x86/macroAssembler_x86.cpp | 921 ++---------------- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 180 +--- .../cpu/x86/macroAssembler_x86_sha.cpp | 28 - ...ssemblerx86.cpp => test_assembler_x86.cpp} | 1 + 7 files changed, 143 insertions(+), 1397 deletions(-) rename test/hotspot/gtest/x86/{test_assemblerx86.cpp => test_assembler_x86.cpp} (99%) diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 82a16dc4dd13b..6853af9e74642 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -24,6 +24,8 @@ #include "asm/assembler.hpp" #include "asm/assembler.inline.hpp" +#include "asm/codeBuffer.hpp" +#include "code/codeCache.hpp" #include "gc/shared/cardTableBarrierSet.hpp" #include "interpreter/interpreter.hpp" #include "memory/resourceArea.hpp" @@ -119,8 +121,6 @@ AddressLiteral::AddressLiteral(address target, relocInfo::relocType rtype) { // Implementation of Address -#ifdef _LP64 - Address Address::make_array(ArrayAddress adr) { // Not implementable on 64bit machines // Should have been handled higher up the call chain. @@ -157,30 +157,6 @@ Address::Address(int disp, address loc, relocInfo::relocType rtype) { ShouldNotReachHere(); } } -#else // LP64 - -Address Address::make_array(ArrayAddress adr) { - AddressLiteral base = adr.base(); - Address index = adr.index(); - assert(index._disp == 0, "must not have disp"); // maybe it can? - Address array(index._base, index._index, index._scale, (intptr_t) base.target()); - array._rspec = base._rspec; - return array; -} - -// exceedingly dangerous constructor -Address::Address(address loc, RelocationHolder spec) { - _base = noreg; - _index = noreg; - _scale = no_scale; - _disp = (intptr_t) loc; - _rspec = spec; - _xmmindex = xnoreg; - _isxmmindex = false; -} - -#endif // _LP64 - // Convert the raw encoding form into the form expected by the constructor for @@ -214,7 +190,6 @@ void Assembler::init_attributes(void) { _legacy_mode_dq = (VM_Version::supports_avx512dq() == false); _legacy_mode_vl = (VM_Version::supports_avx512vl() == false); _legacy_mode_vlbw = (VM_Version::supports_avx512vlbw() == false); - NOT_LP64(_is_managed = false;) _attributes = nullptr; } @@ -744,8 +719,8 @@ void Assembler::emit_operand_helper(int reg_enc, int base_enc, int index_enc, assert(inst_mark() != nullptr, "must be inside InstructionMark"); address next_ip = pc() + sizeof(int32_t) + post_addr_length; int64_t adjusted = disp; - // Do rip-rel adjustment for 64bit - LP64_ONLY(adjusted -= (next_ip - inst_mark())); + // Do rip-rel adjustment + adjusted -= (next_ip - inst_mark()); assert(is_simm32(adjusted), "must be 32bit offset (RIP relative address)"); emit_data((int32_t) adjusted, rspec, disp32_operand); @@ -846,7 +821,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case FS_segment: case GS_segment: // Seems dubious - LP64_ONLY(assert(false, "shouldn't have that prefix")); + assert(false, "shouldn't have that prefix"); assert(ip == inst+1, "only one prefix allowed"); goto again_after_prefix; @@ -859,11 +834,9 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case REX_RB: case REX_RX: case REX_RXB: - NOT_LP64(assert(false, "64bit prefixes")); goto again_after_prefix; case REX2: - NOT_LP64(assert(false, "64bit prefixes")); if ((0xFF & *ip++) & REX2BIT_W) { is_64bit = true; } @@ -877,7 +850,6 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case REX_WRB: case REX_WRX: case REX_WRXB: - NOT_LP64(assert(false, "64bit prefixes")); is_64bit = true; goto again_after_prefix; @@ -916,11 +888,9 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case REX_WRB: case REX_WRX: case REX_WRXB: - NOT_LP64(assert(false, "64bit prefix found")); goto again_after_size_prefix2; case REX2: - NOT_LP64(assert(false, "64bit prefix found")); if ((0xFF & *ip++) & REX2BIT_W) { is_64bit = true; } @@ -945,14 +915,9 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case REP8(0xB8): // movl/q r, #32/#64(oop?) if (which == end_pc_operand) return ip + (is_64bit ? 8 : 4); // these asserts are somewhat nonsensical -#ifndef _LP64 - assert(which == imm_operand || which == disp32_operand, - "which %d is_64_bit %d ip " INTPTR_FORMAT, which, is_64bit, p2i(ip)); -#else assert(((which == call32_operand || which == imm_operand) && is_64bit) || (which == narrow_oop_operand && !is_64bit), "which %d is_64_bit %d ip " INTPTR_FORMAT, which, is_64bit, p2i(ip)); -#endif // _LP64 return ip; case 0x69: // imul r, a, #32 @@ -1113,8 +1078,6 @@ address Assembler::locate_operand(address inst, WhichOperand which) { // to check for them in product version. // Check second byte - NOT_LP64(assert((0xC0 & *ip) == 0xC0, "shouldn't have LDS and LES instructions")); - int vex_opcode; // First byte if ((0xFF & *inst) == VEX_3bytes) { @@ -1216,8 +1179,8 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case REX_WRX: case REX_WRXB: case REX2: - NOT_LP64(assert(false, "found 64bit prefix")); ip++; + // fall-through default: ip++; } @@ -1232,12 +1195,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { } assert(which != call32_operand, "instruction is not a call, jmp, or jcc"); -#ifdef _LP64 assert(which != imm_operand, "instruction is not a movq reg, imm64"); -#else - // assert(which != imm_operand || has_imm32, "instruction has no imm32 field"); - assert(which != imm_operand || has_disp32, "instruction has no imm32 field"); -#endif // LP64 assert(which != disp32_operand || has_disp32, "instruction has no disp32 field"); // parse the output of emit_operand @@ -1292,11 +1250,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { return ip + tail_size; } -#ifdef _LP64 assert(which == narrow_oop_operand && !is_64bit, "instruction is not a movl adr, imm32"); -#else - assert(which == imm_operand, "instruction has only an imm field"); -#endif // LP64 return ip; } @@ -1319,8 +1273,7 @@ void Assembler::check_relocation(RelocationHolder const& rspec, int format) { // assert(format == imm32_operand, "cannot specify a nonzero format"); opnd = locate_operand(inst, call32_operand); } else if (r->is_data()) { - assert(format == imm_operand || format == disp32_operand - LP64_ONLY(|| format == narrow_oop_operand), "format ok"); + assert(format == imm_operand || format == disp32_operand || format == narrow_oop_operand, "format ok"); opnd = locate_operand(inst, (WhichOperand)format); } else { assert(format == imm_operand, "cannot specify a format"); @@ -1830,9 +1783,6 @@ void Assembler::blsrl(Register dst, Address src) { } void Assembler::call(Label& L, relocInfo::relocType rtype) { - // suspect disp32 is always good - int operand = LP64_ONLY(disp32_operand) NOT_LP64(imm_operand); - if (L.is_bound()) { const int long_size = 5; int offs = (int)( target(L) - pc() ); @@ -1840,14 +1790,14 @@ void Assembler::call(Label& L, relocInfo::relocType rtype) { InstructionMark im(this); // 1110 1000 #32-bit disp emit_int8((unsigned char)0xE8); - emit_data(offs - long_size, rtype, operand); + emit_data(offs - long_size, rtype, disp32_operand); } else { InstructionMark im(this); // 1110 1000 #32-bit disp L.add_patch_at(code(), locator()); emit_int8((unsigned char)0xE8); - emit_data(int(0), rtype, operand); + emit_data(int(0), rtype, disp32_operand); } } @@ -1874,8 +1824,7 @@ void Assembler::call_literal(address entry, RelocationHolder const& rspec) { // Technically, should use call32_operand, but this format is // implied by the fact that we're emitting a call instruction. - int operand = LP64_ONLY(disp32_operand) NOT_LP64(call32_operand); - emit_data((int) disp, rspec, operand); + emit_data((int) disp, rspec, disp32_operand); } void Assembler::cdql() { @@ -1887,7 +1836,6 @@ void Assembler::cld() { } void Assembler::cmovl(Condition cc, Register dst, Register src) { - NOT_LP64(guarantee(VM_Version::supports_cmov(), "illegal instruction")); int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); emit_opcode_prefix_and_encoding(0x40 | cc, 0xC0, encode); } @@ -1900,7 +1848,6 @@ void Assembler::ecmovl(Condition cc, Register dst, Register src1, Register src2) void Assembler::cmovl(Condition cc, Register dst, Address src) { InstructionMark im(this); - NOT_LP64(guarantee(VM_Version::supports_cmov(), "illegal instruction")); prefix(src, dst, false, true /* is_map1 */); emit_int8((0x40 | cc)); emit_operand(dst, src, 0); @@ -2091,8 +2038,7 @@ void Assembler::crc32(Register crc, Register v, int8_t sizeInBytes) { case 2: case 4: break; - LP64_ONLY(case 8:) - // This instruction is not valid in 32 bits + case 8: // Note: // http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf // @@ -2111,7 +2057,7 @@ void Assembler::crc32(Register crc, Register v, int8_t sizeInBytes) { assert(0, "Unsupported value for a sizeInBytes argument"); break; } - LP64_ONLY(prefix(crc, v, p);) + prefix(crc, v, p); emit_int32(0x0F, 0x38, 0xF0 | w, @@ -2140,15 +2086,14 @@ void Assembler::crc32(Register crc, Address adr, int8_t sizeInBytes) { case 2: case 4: break; - LP64_ONLY(case 8:) - // This instruction is not valid in 32 bits + case 8: p = REX_W; break; default: assert(0, "Unsupported value for a sizeInBytes argument"); break; } - LP64_ONLY(prefix(crc, adr, p);) + prefix(crc, adr, p); emit_int24(0x0F, 0x38, (0xF0 | w)); emit_operand(crc, adr, 0); } @@ -2840,7 +2785,6 @@ void Assembler::leal(Register dst, Address src) { emit_operand(dst, src, 0); } -#ifdef _LP64 void Assembler::lea(Register dst, Label& L) { emit_prefix_and_int8(get_prefixq(Address(), dst), (unsigned char)0x8D); if (!L.is_bound()) { @@ -2858,7 +2802,6 @@ void Assembler::lea(Register dst, Label& L) { emit_int32(disp); } } -#endif void Assembler::lfence() { emit_int24(0x0F, (unsigned char)0xAE, (unsigned char)0xE8); @@ -2916,7 +2859,7 @@ void Assembler::sfence() { } void Assembler::mov(Register dst, Register src) { - LP64_ONLY(movq(dst, src)) NOT_LP64(movl(dst, src)); + movq(dst, src); } void Assembler::movapd(XMMRegister dst, XMMRegister src) { @@ -2941,7 +2884,6 @@ void Assembler::movlhps(XMMRegister dst, XMMRegister src) { } void Assembler::movb(Register dst, Address src) { - NOT_LP64(assert(dst->has_byte_register(), "must have byte register")); InstructionMark im(this); prefix(src, dst, true); emit_int8((unsigned char)0x8A); @@ -3932,7 +3874,6 @@ void Assembler::movsbl(Register dst, Address src) { // movsxb } void Assembler::movsbl(Register dst, Register src) { // movsxb - NOT_LP64(assert(src->has_byte_register(), "must have byte register")); int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true, true /* is_map1 */); emit_opcode_prefix_and_encoding((unsigned char)0xBE, 0xC0, encode); } @@ -4082,7 +4023,6 @@ void Assembler::movzbl(Register dst, Address src) { // movzxb } void Assembler::movzbl(Register dst, Register src) { // movzxb - NOT_LP64(assert(src->has_byte_register(), "must have byte register")); int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true, true /* is_map1 */); emit_opcode_prefix_and_encoding((unsigned char)0xB6, 0xC0, encode); } @@ -5810,16 +5750,6 @@ void Assembler::popf() { emit_int8((unsigned char)0x9D); } -#ifndef _LP64 // no 32bit push/pop on amd64 -void Assembler::popl(Address dst) { - // NOTE: this will adjust stack by 8byte on 64bits - InstructionMark im(this); - prefix(dst); - emit_int8((unsigned char)0x8F); - emit_operand(rax, dst, 0); -} -#endif - void Assembler::prefetchnta(Address src) { InstructionMark im(this); prefix(src, true /* is_map1 */); @@ -6220,7 +6150,6 @@ void Assembler::evpunpckhqdq(XMMRegister dst, KRegister mask, XMMRegister src1, emit_int16(0x6D, (0xC0 | encode)); } -#ifdef _LP64 void Assembler::push2(Register src1, Register src2, bool with_ppx) { assert(VM_Version::supports_apx_f(), "requires APX"); InstructionAttr attributes(0, /* rex_w */ with_ppx, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); @@ -6282,8 +6211,6 @@ void Assembler::popp(Register dst) { int encode = prefixq_and_encode_rex2(dst->encoding()); emit_int8((unsigned char)0x58 | encode); } -#endif //_LP64 - void Assembler::push(int32_t imm32) { // in 64bits we push 64bits onto the stack but only @@ -6301,16 +6228,6 @@ void Assembler::pushf() { emit_int8((unsigned char)0x9C); } -#ifndef _LP64 // no 32bit push/pop on amd64 -void Assembler::pushl(Address src) { - // Note this will push 64bit on 64bit - InstructionMark im(this); - prefix(src); - emit_int8((unsigned char)0xFF); - emit_operand(rsi, src, 0); -} -#endif - void Assembler::rcll(Register dst, int imm8) { assert(isShiftCount(imm8), "illegal shift count"); int encode = prefix_and_encode(dst->encoding()); @@ -6353,43 +6270,37 @@ void Assembler::rdtsc() { void Assembler::rep_mov() { // REP // MOVSQ - LP64_ONLY(emit_int24((unsigned char)0xF3, REX_W, (unsigned char)0xA5);) - NOT_LP64( emit_int16((unsigned char)0xF3, (unsigned char)0xA5);) + emit_int24((unsigned char)0xF3, REX_W, (unsigned char)0xA5); } // sets rcx bytes with rax, value at [edi] void Assembler::rep_stosb() { // REP // STOSB - LP64_ONLY(emit_int24((unsigned char)0xF3, REX_W, (unsigned char)0xAA);) - NOT_LP64( emit_int16((unsigned char)0xF3, (unsigned char)0xAA);) + emit_int24((unsigned char)0xF3, REX_W, (unsigned char)0xAA); } // sets rcx pointer sized words with rax, value at [edi] // generic void Assembler::rep_stos() { // REP - // LP64:STOSQ, LP32:STOSD - LP64_ONLY(emit_int24((unsigned char)0xF3, REX_W, (unsigned char)0xAB);) - NOT_LP64( emit_int16((unsigned char)0xF3, (unsigned char)0xAB);) + // STOSQ + emit_int24((unsigned char)0xF3, REX_W, (unsigned char)0xAB); } // scans rcx pointer sized words at [edi] for occurrence of rax, // generic void Assembler::repne_scan() { // repne_scan // SCASQ - LP64_ONLY(emit_int24((unsigned char)0xF2, REX_W, (unsigned char)0xAF);) - NOT_LP64( emit_int16((unsigned char)0xF2, (unsigned char)0xAF);) + emit_int24((unsigned char)0xF2, REX_W, (unsigned char)0xAF); } -#ifdef _LP64 // scans rcx 4 byte words at [edi] for occurrence of rax, // generic void Assembler::repne_scanl() { // repne_scan // SCASL emit_int16((unsigned char)0xF2, (unsigned char)0xAF); } -#endif void Assembler::ret(int imm16) { if (imm16 == 0) { @@ -6464,7 +6375,6 @@ void Assembler::erorl(Register dst, Register src, bool no_flags) { emit_int16((unsigned char)0xD3, (0xC8 | encode)); } -#ifdef _LP64 void Assembler::rorq(Register dst) { int encode = prefixq_and_encode(dst->encoding()); emit_int16((unsigned char)0xD3, (0xC8 | encode)); @@ -6527,15 +6437,6 @@ void Assembler::erolq(Register dst, Register src, int imm8, bool no_flags) { } else { emit_int24((unsigned char)0xC1, (0xc0 | encode), imm8); } - } -#endif - -void Assembler::sahf() { -#ifdef _LP64 - // Not supported in 64bit mode - ShouldNotReachHere(); -#endif - emit_int8((unsigned char)0x9E); } void Assembler::sall(Address dst, int imm8) { @@ -6988,7 +6889,6 @@ void Assembler::eshrdl(Register dst, Register src1, Register src2, int8_t imm8, emit_int24(0x2C, (0xC0 | encode), imm8); } -#ifdef _LP64 void Assembler::shldq(Register dst, Register src, int8_t imm8) { int encode = prefixq_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */); emit_opcode_prefix_and_encoding((unsigned char)0xA4, 0xC0, encode, imm8); @@ -7014,7 +6914,6 @@ void Assembler::eshrdq(Register dst, Register src1, Register src2, int8_t imm8, int encode = evex_prefix_and_encode_ndd(src2->encoding(), dst->encoding(), src1->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); emit_int24(0x2C, (0xC0 | encode), imm8); } -#endif // copies a single word from [esi] to [edi] void Assembler::smovl() { @@ -7208,7 +7107,6 @@ void Assembler::subss(XMMRegister dst, Address src) { } void Assembler::testb(Register dst, int imm8, bool use_ral) { - NOT_LP64(assert(dst->has_byte_register(), "must have byte register")); if (dst == rax) { if (use_ral) { emit_int8((unsigned char)0xA8); @@ -12872,54 +12770,6 @@ void Assembler::emit_farith(int b1, int b2, int i) { emit_int16(b1, b2 + i); } -#ifndef _LP64 -// 32bit only pieces of the assembler - -void Assembler::emms() { - NOT_LP64(assert(VM_Version::supports_mmx(), "")); - emit_int16(0x0F, 0x77); -} - -void Assembler::vzeroupper() { - vzeroupper_uncached(); -} - -void Assembler::cmp_literal32(Register src1, int32_t imm32, RelocationHolder const& rspec) { - // NO PREFIX AS NEVER 64BIT - InstructionMark im(this); - emit_int16((unsigned char)0x81, (0xF8 | src1->encoding())); - emit_data(imm32, rspec, 0); -} - -void Assembler::cmp_literal32(Address src1, int32_t imm32, RelocationHolder const& rspec) { - // NO PREFIX AS NEVER 64BIT (not even 32bit versions of 64bit regs - InstructionMark im(this); - emit_int8((unsigned char)0x81); - emit_operand(rdi, src1, 4); - emit_data(imm32, rspec, 0); -} - -// The 64-bit (32bit platform) cmpxchg compares the value at adr with the contents of rdx:rax, -// and stores rcx:rbx into adr if so; otherwise, the value at adr is loaded -// into rdx:rax. The ZF is set if the compared values were equal, and cleared otherwise. -void Assembler::cmpxchg8(Address adr) { - InstructionMark im(this); - emit_int16(0x0F, (unsigned char)0xC7); - emit_operand(rcx, adr, 0); -} - -void Assembler::decl(Register dst) { - // Don't use it directly. Use MacroAssembler::decrementl() instead. - emit_int8(0x48 | dst->encoding()); -} - -void Assembler::edecl(Register dst, Register src, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8(0x48 | src->encoding()); -} -#endif // !_LP64 - // SSE SIMD prefix byte values corresponding to VexSimdPrefix encoding. static int simd_pre[4] = { 0, 0x66, 0xF3, 0xF2 }; // SSE opcode second byte values (first is 0x0F) corresponding to VexOpcode encoding. @@ -13053,7 +12903,7 @@ void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix // is allowed in legacy mode and has resources which will fit in it. // Pure EVEX instructions will have is_evex_instruction set in their definition. if (!attributes->is_legacy_mode()) { - if (UseAVX > 2 && !attributes->is_evex_instruction() && !is_managed()) { + if (UseAVX > 2 && !attributes->is_evex_instruction()) { if ((attributes->get_vector_len() != AVX_512bit) && !is_extended) { attributes->set_is_legacy_mode(); } @@ -13068,7 +12918,6 @@ void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix assert((!is_extended || (!attributes->is_legacy_mode())),"XMM register should be 0-15"); } - clear_managed(); if (UseAVX > 2 && !attributes->is_legacy_mode()) { bool evex_r = (xreg_enc >= 16); @@ -13116,7 +12965,7 @@ int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexS // is allowed in legacy mode and has resources which will fit in it. // Pure EVEX instructions will have is_evex_instruction set in their definition. if (!attributes->is_legacy_mode()) { - if (UseAVX > 2 && !attributes->is_evex_instruction() && !is_managed()) { + if (UseAVX > 2 && !attributes->is_evex_instruction()) { if ((!attributes->uses_vl() || (attributes->get_vector_len() != AVX_512bit)) && !is_extended) { attributes->set_is_legacy_mode(); @@ -13138,7 +12987,6 @@ int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexS assert(((!is_extended) || (!attributes->is_legacy_mode())),"XMM register should be 0-15"); } - clear_managed(); if (UseAVX > 2 && !attributes->is_legacy_mode()) { bool evex_r = (dst_enc >= 16); @@ -14038,55 +13886,6 @@ void Assembler::evcompresspd(XMMRegister dst, KRegister mask, XMMRegister src, b emit_int16((unsigned char)0x8A, (0xC0 | encode)); } -#ifndef _LP64 - -void Assembler::incl(Register dst) { - // Don't use it directly. Use MacroAssembler::incrementl() instead. - emit_int8(0x40 | dst->encoding()); -} - -void Assembler::eincl(Register dst, Register src, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8(0x40 | src->encoding()); -} - -void Assembler::lea(Register dst, Address src) { - leal(dst, src); -} - -void Assembler::mov_literal32(Address dst, int32_t imm32, RelocationHolder const& rspec) { - InstructionMark im(this); - emit_int8((unsigned char)0xC7); - emit_operand(rax, dst, 4); - emit_data((int)imm32, rspec, 0); -} - -void Assembler::mov_literal32(Register dst, int32_t imm32, RelocationHolder const& rspec) { - InstructionMark im(this); - int encode = prefix_and_encode(dst->encoding()); - emit_int8((0xB8 | encode)); - emit_data((int)imm32, rspec, 0); -} - -void Assembler::popa() { // 32bit - emit_int8(0x61); -} - -void Assembler::push_literal32(int32_t imm32, RelocationHolder const& rspec) { - InstructionMark im(this); - emit_int8(0x68); - emit_data(imm32, rspec, 0); -} - -void Assembler::pusha() { // 32bit - emit_int8(0x60); -} - -#else // LP64 - -// 64bit only pieces of the assembler - // This should only be used by 64bit instructions that can use rip-relative // it cannot be used by instructions that want an immediate value. @@ -16039,7 +15838,6 @@ void Assembler::rorxq(Register dst, Address src, int imm8) { emit_int8(imm8); } -#ifdef _LP64 void Assembler::salq(Address dst, int imm8) { InstructionMark im(this); assert(isShiftCount(imm8 >> 1), "illegal shift count"); @@ -16194,7 +15992,6 @@ void Assembler::esarq(Register dst, Register src, bool no_flags) { int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); emit_int16((unsigned char)0xD3, (0xF8 | encode)); } -#endif void Assembler::sbbq(Address dst, int32_t imm32) { InstructionMark im(this); @@ -16539,8 +16336,6 @@ void Assembler::exorq(Register dst, Address src1, Register src2, bool no_flags) emit_operand(src2, src1, 0); } -#endif // !LP64 - void InstructionAttr::set_address_attributes(int tuple_type, int input_size_in_bits) { if (VM_Version::supports_evex()) { _tuple_type = tuple_type; diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 33fd0745fb66e..6395be02f273c 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -35,7 +35,6 @@ class Argument { public: enum { -#ifdef _LP64 #ifdef _WIN64 n_int_register_parameters_c = 4, // rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...) n_float_register_parameters_c = 4, // xmm0 - xmm3 (c_farg0, c_farg1, ... ) @@ -49,16 +48,10 @@ class Argument { #endif // _WIN64 n_int_register_parameters_j = 6, // j_rarg0, j_rarg1, ... n_float_register_parameters_j = 8 // j_farg0, j_farg1, ... -#else - n_register_parameters = 0, // 0 registers used to pass arguments - n_int_register_parameters_j = 0, - n_float_register_parameters_j = 0 -#endif // _LP64 }; }; -#ifdef _LP64 // Symbolically name the register arguments used by the c calling convention. // Windows is different from linux/solaris. So much for standards... @@ -138,15 +131,6 @@ constexpr Register rscratch2 = r11; // volatile constexpr Register r12_heapbase = r12; // callee-saved constexpr Register r15_thread = r15; // callee-saved -#else -// rscratch1 will appear in 32bit code that is dead but of course must compile -// Using noreg ensures if the dead code is incorrectly live and executed it -// will cause an assertion failure -#define rscratch1 noreg -#define rscratch2 noreg - -#endif // _LP64 - // JSR 292 // On x86, the SP does not have to be saved when invoking method handle intrinsics // or compiled lambda forms. We indicate that by setting rbp_mh_SP_save to noreg. @@ -168,7 +152,7 @@ class Address { times_2 = 1, times_4 = 2, times_8 = 3, - times_ptr = LP64_ONLY(times_8) NOT_LP64(times_4) + times_ptr = times_8 }; static ScaleFactor times(int size) { assert(size >= 1 && size <= 8 && is_power_of_2(size), "bad scale size"); @@ -197,7 +181,6 @@ class Address { // Easily misused constructors make them private // %%% can we make these go away? - NOT_LP64(Address(address loc, RelocationHolder spec);) Address(int disp, address loc, relocInfo::relocType rtype); Address(int disp, address loc, RelocationHolder spec); @@ -456,7 +439,7 @@ class InstructionAttr; // 64-bit reflect the fxsave size which is 512 bytes and the new xsave area on EVEX which is another 2176 bytes // See fxsave and xsave(EVEX enabled) documentation for layout -const int FPUStateSizeInWords = NOT_LP64(27) LP64_ONLY(2688 / wordSize); +const int FPUStateSizeInWords = 2688 / wordSize; // The Intel x86/Amd64 Assembler: Pure assembler doing NO optimizations on the instruction // level (e.g. mov rax, 0 is not translated into xor rax, rax!); i.e., what you write @@ -628,12 +611,8 @@ class Assembler : public AbstractAssembler { imm_operand = 0, // embedded 32-bit|64-bit immediate operand disp32_operand = 1, // embedded 32-bit displacement or address call32_operand = 2, // embedded 32-bit self-relative displacement -#ifndef _LP64 - _WhichOperand_limit = 3 -#else - narrow_oop_operand = 3, // embedded 32-bit immediate narrow oop + narrow_oop_operand = 3, // embedded 32-bit immediate narrow oop _WhichOperand_limit = 4 -#endif }; // Comparison predicates for integral types & FP types when using SSE @@ -721,7 +700,6 @@ class Assembler : public AbstractAssembler { bool _legacy_mode_dq; bool _legacy_mode_vl; bool _legacy_mode_vlbw; - NOT_LP64(bool _is_managed;) InstructionAttr *_attributes; void set_attributes(InstructionAttr* attributes); @@ -907,25 +885,13 @@ class Assembler : public AbstractAssembler { void emit_opcode_prefix_and_encoding(int byte1, int ocp_and_encoding); void emit_opcode_prefix_and_encoding(int byte1, int byte2, int ocp_and_encoding); void emit_opcode_prefix_and_encoding(int byte1, int byte2, int ocp_and_encoding, int byte3); - bool always_reachable(AddressLiteral adr) NOT_LP64( { return true; } ); - bool reachable(AddressLiteral adr) NOT_LP64( { return true; } ); + bool always_reachable(AddressLiteral adr); + bool reachable(AddressLiteral adr); // These are all easily abused and hence protected public: - // 32BIT ONLY SECTION -#ifndef _LP64 - // Make these disappear in 64bit mode since they would never be correct - void cmp_literal32(Register src1, int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY - void cmp_literal32(Address src1, int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY - - void mov_literal32(Register dst, int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY - void mov_literal32(Address dst, int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY - - void push_literal32(int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY -#else - // 64BIT ONLY SECTION void mov_literal64(Register dst, intptr_t imm64, RelocationHolder const& rspec); // 64BIT ONLY void cmp_narrow_oop(Register src1, int32_t imm32, RelocationHolder const& rspec); @@ -933,7 +899,6 @@ class Assembler : public AbstractAssembler { void mov_narrow_oop(Register dst, int32_t imm32, RelocationHolder const& rspec); void mov_narrow_oop(Address dst, int32_t imm32, RelocationHolder const& rspec); -#endif // _LP64 protected: // These are unique in that we are ensured by the caller that the 32bit @@ -1017,17 +982,10 @@ class Assembler : public AbstractAssembler { void init_attributes(void); void clear_attributes(void) { _attributes = nullptr; } - void set_managed(void) { NOT_LP64(_is_managed = true;) } - void clear_managed(void) { NOT_LP64(_is_managed = false;) } - bool is_managed(void) { - NOT_LP64(return _is_managed;) - LP64_ONLY(return false;) } - void lea(Register dst, Address src); void mov(Register dst, Register src); -#ifdef _LP64 // support caching the result of some routines // must be called before pusha(), popa(), vzeroupper() - checked with asserts @@ -1047,7 +1005,6 @@ class Assembler : public AbstractAssembler { // New Zero Upper setcc instruction. void esetzucc(Condition cc, Register dst); -#endif void vzeroupper_uncached(); void decq(Register dst); void edecq(Register dst, Register src, bool no_flags); @@ -1069,9 +1026,7 @@ class Assembler : public AbstractAssembler { void rep_stos(); void rep_stosb(); void repne_scan(); -#ifdef _LP64 void repne_scanl(); -#endif // Vanilla instructions in lexical order @@ -1121,7 +1076,6 @@ class Assembler : public AbstractAssembler { void eincq(Register dst, Register src, bool no_flags); void eincq(Register dst, Address src, bool no_flags); -#ifdef _LP64 //Add Unsigned Integers with Carry Flag void adcxq(Register dst, Register src); void eadcxq(Register dst, Register src1, Register src2); @@ -1129,7 +1083,6 @@ class Assembler : public AbstractAssembler { //Add Unsigned Integers with Overflow Flag void adoxq(Register dst, Register src); void eadoxq(Register dst, Register src1, Register src2); -#endif void addr_nop_4(); void addr_nop_5(); @@ -1206,10 +1159,8 @@ class Assembler : public AbstractAssembler { void bsfl(Register dst, Register src); void bsrl(Register dst, Register src); -#ifdef _LP64 void bsfq(Register dst, Register src); void bsrq(Register dst, Register src); -#endif void bswapl(Register reg); @@ -1395,10 +1346,6 @@ class Assembler : public AbstractAssembler { void emit_farith(int b1, int b2, int i); public: -#ifndef _LP64 - void emms(); -#endif // !_LP64 - // operands that only take the original 32bit registers void emit_operand32(Register reg, Address adr, int post_addr_length); @@ -1417,12 +1364,10 @@ class Assembler : public AbstractAssembler { void divl(Register src); // Unsigned division void edivl(Register src, bool no_flags); // Unsigned division -#ifdef _LP64 void idivq(Register src); void eidivq(Register src, bool no_flags); void divq(Register src); // Unsigned division void edivq(Register src, bool no_flags); // Unsigned division -#endif void imull(Register src); void eimull(Register src, bool no_flags); @@ -1435,7 +1380,6 @@ class Assembler : public AbstractAssembler { void imull(Register dst, Address src); void eimull(Register dst, Register src1, Address src2, bool no_flags); -#ifdef _LP64 void imulq(Register dst, Register src); void eimulq(Register dst, Register src, bool no_flags); void eimulq(Register dst, Register src1, Register src2, bool no_flags); @@ -1448,7 +1392,6 @@ class Assembler : public AbstractAssembler { void eimulq(Register dst, Register src1, Address src2, bool no_flags); void imulq(Register dst); void eimulq(Register dst, bool no_flags); -#endif // jcc is the generic conditional branch generator to run- // time routines, jcc is used for branches to labels. jcc @@ -1500,9 +1443,7 @@ class Assembler : public AbstractAssembler { void leaq(Register dst, Address src); -#ifdef _LP64 void lea(Register dst, Label& L); -#endif void lfence(); @@ -1514,12 +1455,10 @@ class Assembler : public AbstractAssembler { void lzcntl(Register dst, Address src); void elzcntl(Register dst, Address src, bool no_flags); -#ifdef _LP64 void lzcntq(Register dst, Register src); void elzcntq(Register dst, Register src, bool no_flags); void lzcntq(Register dst, Address src); void elzcntq(Register dst, Address src, bool no_flags); -#endif enum Membar_mask_bits { StoreStore = 1 << 3, @@ -1679,13 +1618,11 @@ class Assembler : public AbstractAssembler { void movl(Register dst, Address src); void movl(Address dst, Register src); -#ifdef _LP64 void movq(Register dst, Register src); void movq(Register dst, Address src); void movq(Address dst, Register src); void movq(Address dst, int32_t imm32); void movq(Register dst, int32_t imm32); -#endif // Move Quadword void movq(Address dst, XMMRegister src); @@ -1700,7 +1637,6 @@ class Assembler : public AbstractAssembler { void vmovw(XMMRegister dst, Register src); void vmovw(Register dst, XMMRegister src); -#ifdef _LP64 void movsbq(Register dst, Address src); void movsbq(Register dst, Register src); @@ -1709,15 +1645,12 @@ class Assembler : public AbstractAssembler { void movslq(Register dst, Address src); void movslq(Register dst, Register src); -#endif void movswl(Register dst, Address src); void movswl(Register dst, Register src); -#ifdef _LP64 void movswq(Register dst, Address src); void movswq(Register dst, Register src); -#endif void movups(XMMRegister dst, Address src); void vmovups(XMMRegister dst, Address src, int vector_len); @@ -1731,18 +1664,14 @@ class Assembler : public AbstractAssembler { void movzbl(Register dst, Address src); void movzbl(Register dst, Register src); -#ifdef _LP64 void movzbq(Register dst, Address src); void movzbq(Register dst, Register src); -#endif void movzwl(Register dst, Address src); void movzwl(Register dst, Register src); -#ifdef _LP64 void movzwq(Register dst, Address src); void movzwq(Register dst, Register src); -#endif // Unsigned multiply with RAX destination register void mull(Address src); @@ -1750,13 +1679,11 @@ class Assembler : public AbstractAssembler { void mull(Register src); void emull(Register src, bool no_flags); -#ifdef _LP64 void mulq(Address src); void emulq(Address src, bool no_flags); void mulq(Register src); void emulq(Register src, bool no_flags); void mulxq(Register dst1, Register dst2, Register src); -#endif // Multiply Scalar Double-Precision Floating-Point Values void mulsd(XMMRegister dst, Address src); @@ -1771,26 +1698,22 @@ class Assembler : public AbstractAssembler { void negl(Address dst); void enegl(Register dst, Address src, bool no_flags); -#ifdef _LP64 void negq(Register dst); void enegq(Register dst, Register src, bool no_flags); void negq(Address dst); void enegq(Register dst, Address src, bool no_flags); -#endif void nop(uint i = 1); void notl(Register dst); void enotl(Register dst, Register src); -#ifdef _LP64 void notq(Register dst); void enotq(Register dst, Register src); void btsq(Address dst, int imm8); void btrq(Address dst, int imm8); void btq(Register src, int imm8); -#endif void btq(Register dst, Register src); void eorw(Register dst, Register src1, Register src2, bool no_flags); @@ -2009,14 +1932,8 @@ class Assembler : public AbstractAssembler { // Multiply add accumulate void evpdpwssd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); -#ifndef _LP64 // no 32bit push/pop on amd64 - void popl(Address dst); -#endif - -#ifdef _LP64 void popq(Address dst); void popq(Register dst); -#endif void popcntl(Register dst, Address src); void epopcntl(Register dst, Address src, bool no_flags); @@ -2028,12 +1945,10 @@ class Assembler : public AbstractAssembler { void evpopcntd(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len); void evpopcntq(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len); -#ifdef _LP64 void popcntq(Register dst, Address src); void epopcntq(Register dst, Address src, bool no_flags); void popcntq(Register dst, Register src); void epopcntq(Register dst, Register src, bool no_flags); -#endif // Prefetches (SSE, SSE2, 3DNOW only) @@ -2125,10 +2040,6 @@ class Assembler : public AbstractAssembler { // Vector sum of absolute difference. void vpsadbw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); -#ifndef _LP64 // no 32bit push/pop on amd64 - void pushl(Address src); -#endif - void pushq(Address src); void rcll(Register dst, int imm8); @@ -2160,7 +2071,6 @@ class Assembler : public AbstractAssembler { void rorl(Register dst, int imm8); void erorl(Register dst, Register src, int imm8, bool no_flags); -#ifdef _LP64 void rolq(Register dst); void erolq(Register dst, Register src, bool no_flags); void rolq(Register dst, int imm8); @@ -2173,9 +2083,6 @@ class Assembler : public AbstractAssembler { void rorxl(Register dst, Address src, int imm8); void rorxq(Register dst, Register src, int imm8); void rorxq(Register dst, Address src, int imm8); -#endif - - void sahf(); void sall(Register dst, int imm8); void esall(Register dst, Register src, int imm8, bool no_flags); @@ -2195,7 +2102,6 @@ class Assembler : public AbstractAssembler { void sarl(Register dst); void esarl(Register dst, Register src, bool no_flags); -#ifdef _LP64 void salq(Register dst, int imm8); void esalq(Register dst, Register src, int imm8, bool no_flags); void salq(Register dst); @@ -2213,7 +2119,6 @@ class Assembler : public AbstractAssembler { void esarq(Register dst, Register src, int imm8, bool no_flags); void sarq(Register dst); void esarq(Register dst, Register src, bool no_flags); -#endif void sbbl(Address dst, int32_t imm32); void sbbl(Register dst, int32_t imm32); @@ -2254,12 +2159,10 @@ class Assembler : public AbstractAssembler { void eshrdl(Register dst, Register src1, Register src2, bool no_flags); void shrdl(Register dst, Register src, int8_t imm8); void eshrdl(Register dst, Register src1, Register src2, int8_t imm8, bool no_flags); -#ifdef _LP64 void shldq(Register dst, Register src, int8_t imm8); void eshldq(Register dst, Register src1, Register src2, int8_t imm8, bool no_flags); void shrdq(Register dst, Register src, int8_t imm8); void eshrdq(Register dst, Register src1, Register src2, int8_t imm8, bool no_flags); -#endif void shll(Register dst, int imm8); void eshll(Register dst, Register src, int imm8, bool no_flags); diff --git a/src/hotspot/cpu/x86/assembler_x86.inline.hpp b/src/hotspot/cpu/x86/assembler_x86.inline.hpp index f5cc75a55c5d8..6fae97643060a 100644 --- a/src/hotspot/cpu/x86/assembler_x86.inline.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.inline.hpp @@ -25,58 +25,4 @@ #ifndef CPU_X86_ASSEMBLER_X86_INLINE_HPP #define CPU_X86_ASSEMBLER_X86_INLINE_HPP -#include "asm/assembler.inline.hpp" -#include "asm/codeBuffer.hpp" -#include "code/codeCache.hpp" - -#ifndef _LP64 -inline int Assembler::prefix_and_encode(int reg_enc, bool byteinst, bool is_map1) -{ - int opc_prefix = is_map1 ? 0x0F00 : 0; - return opc_prefix | reg_enc; -} - -inline int Assembler::prefixq_and_encode(int reg_enc, bool is_map1) { - int opc_prefix = is_map1 ? 0xF00 : 0; - return opc_prefix | reg_enc; -} - -inline int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte, bool is_map1) { - int opc_prefix = is_map1 ? 0xF00 : 0; - return opc_prefix | (dst_enc << 3 | src_enc); -} - -inline int Assembler::prefixq_and_encode(int dst_enc, int src_enc, bool is_map1) { - int opc_prefix = is_map1 ? 0xF00 : 0; - return opc_prefix | dst_enc << 3 | src_enc; -} - -inline void Assembler::prefix(Register reg) {} -inline void Assembler::prefix(Register dst, Register src, Prefix p) {} -inline void Assembler::prefix(Register dst, Address adr, Prefix p) {} - -inline void Assembler::prefix(Address adr, bool is_map1) { - if (is_map1) { - emit_int8(0x0F); - } -} - -inline void Assembler::prefixq(Address adr) {} - -inline void Assembler::prefix(Address adr, Register reg, bool byteinst, bool is_map1) { - if (is_map1) { - emit_int8(0x0F); - } -} -inline void Assembler::prefixq(Address adr, Register reg, bool is_map1) { - if (is_map1) { - emit_int8(0x0F); - } -} - -inline void Assembler::prefix(Address adr, XMMRegister reg) {} -inline void Assembler::prefixq(Address adr, XMMRegister reg) {} - -#endif // _LP64 - #endif // CPU_X86_ASSEMBLER_X86_INLINE_HPP diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index e5aa7d213e137..6093ad6951921 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -93,375 +93,6 @@ static const Assembler::Condition reverse[] = { // Implementation of MacroAssembler -// First all the versions that have distinct versions depending on 32/64 bit -// Unless the difference is trivial (1 line or so). - -#ifndef _LP64 - -// 32bit versions - -Address MacroAssembler::as_Address(AddressLiteral adr) { - return Address(adr.target(), adr.rspec()); -} - -Address MacroAssembler::as_Address(ArrayAddress adr, Register rscratch) { - assert(rscratch == noreg, ""); - return Address::make_array(adr); -} - -void MacroAssembler::call_VM_leaf_base(address entry_point, - int number_of_arguments) { - call(RuntimeAddress(entry_point)); - increment(rsp, number_of_arguments * wordSize); -} - -void MacroAssembler::cmpklass(Address src1, Metadata* obj) { - cmp_literal32(src1, (int32_t)obj, metadata_Relocation::spec_for_immediate()); -} - - -void MacroAssembler::cmpklass(Register src1, Metadata* obj) { - cmp_literal32(src1, (int32_t)obj, metadata_Relocation::spec_for_immediate()); -} - -void MacroAssembler::cmpoop(Address src1, jobject obj) { - cmp_literal32(src1, (int32_t)obj, oop_Relocation::spec_for_immediate()); -} - -void MacroAssembler::cmpoop(Register src1, jobject obj, Register rscratch) { - assert(rscratch == noreg, "redundant"); - cmp_literal32(src1, (int32_t)obj, oop_Relocation::spec_for_immediate()); -} - -void MacroAssembler::extend_sign(Register hi, Register lo) { - // According to Intel Doc. AP-526, "Integer Divide", p.18. - if (VM_Version::is_P6() && hi == rdx && lo == rax) { - cdql(); - } else { - movl(hi, lo); - sarl(hi, 31); - } -} - -// 32bit can do a case table jump in one instruction but we no longer allow the base -// to be installed in the Address class -void MacroAssembler::jump(ArrayAddress entry, Register rscratch) { - assert(rscratch == noreg, "not needed"); - jmp(as_Address(entry, noreg)); -} - -// Note: y_lo will be destroyed -void MacroAssembler::lcmp2int(Register x_hi, Register x_lo, Register y_hi, Register y_lo) { - // Long compare for Java (semantics as described in JVM spec.) - Label high, low, done; - - cmpl(x_hi, y_hi); - jcc(Assembler::less, low); - jcc(Assembler::greater, high); - // x_hi is the return register - xorl(x_hi, x_hi); - cmpl(x_lo, y_lo); - jcc(Assembler::below, low); - jcc(Assembler::equal, done); - - bind(high); - xorl(x_hi, x_hi); - increment(x_hi); - jmp(done); - - bind(low); - xorl(x_hi, x_hi); - decrementl(x_hi); - - bind(done); -} - -void MacroAssembler::lea(Register dst, AddressLiteral src) { - mov_literal32(dst, (int32_t)src.target(), src.rspec()); -} - -void MacroAssembler::lea(Address dst, AddressLiteral adr, Register rscratch) { - assert(rscratch == noreg, "not needed"); - - // leal(dst, as_Address(adr)); - // see note in movl as to why we must use a move - mov_literal32(dst, (int32_t)adr.target(), adr.rspec()); -} - -void MacroAssembler::leave() { - mov(rsp, rbp); - pop(rbp); -} - -void MacroAssembler::lmul(int x_rsp_offset, int y_rsp_offset) { - // Multiplication of two Java long values stored on the stack - // as illustrated below. Result is in rdx:rax. - // - // rsp ---> [ ?? ] \ \ - // .... | y_rsp_offset | - // [ y_lo ] / (in bytes) | x_rsp_offset - // [ y_hi ] | (in bytes) - // .... | - // [ x_lo ] / - // [ x_hi ] - // .... - // - // Basic idea: lo(result) = lo(x_lo * y_lo) - // hi(result) = hi(x_lo * y_lo) + lo(x_hi * y_lo) + lo(x_lo * y_hi) - Address x_hi(rsp, x_rsp_offset + wordSize); Address x_lo(rsp, x_rsp_offset); - Address y_hi(rsp, y_rsp_offset + wordSize); Address y_lo(rsp, y_rsp_offset); - Label quick; - // load x_hi, y_hi and check if quick - // multiplication is possible - movl(rbx, x_hi); - movl(rcx, y_hi); - movl(rax, rbx); - orl(rbx, rcx); // rbx, = 0 <=> x_hi = 0 and y_hi = 0 - jcc(Assembler::zero, quick); // if rbx, = 0 do quick multiply - // do full multiplication - // 1st step - mull(y_lo); // x_hi * y_lo - movl(rbx, rax); // save lo(x_hi * y_lo) in rbx, - // 2nd step - movl(rax, x_lo); - mull(rcx); // x_lo * y_hi - addl(rbx, rax); // add lo(x_lo * y_hi) to rbx, - // 3rd step - bind(quick); // note: rbx, = 0 if quick multiply! - movl(rax, x_lo); - mull(y_lo); // x_lo * y_lo - addl(rdx, rbx); // correct hi(x_lo * y_lo) -} - -void MacroAssembler::lneg(Register hi, Register lo) { - negl(lo); - adcl(hi, 0); - negl(hi); -} - -void MacroAssembler::lshl(Register hi, Register lo) { - // Java shift left long support (semantics as described in JVM spec., p.305) - // (basic idea for shift counts s >= n: x << s == (x << n) << (s - n)) - // shift value is in rcx ! - assert(hi != rcx, "must not use rcx"); - assert(lo != rcx, "must not use rcx"); - const Register s = rcx; // shift count - const int n = BitsPerWord; - Label L; - andl(s, 0x3f); // s := s & 0x3f (s < 0x40) - cmpl(s, n); // if (s < n) - jcc(Assembler::less, L); // else (s >= n) - movl(hi, lo); // x := x << n - xorl(lo, lo); - // Note: subl(s, n) is not needed since the Intel shift instructions work rcx mod n! - bind(L); // s (mod n) < n - shldl(hi, lo); // x := x << s - shll(lo); -} - - -void MacroAssembler::lshr(Register hi, Register lo, bool sign_extension) { - // Java shift right long support (semantics as described in JVM spec., p.306 & p.310) - // (basic idea for shift counts s >= n: x >> s == (x >> n) >> (s - n)) - assert(hi != rcx, "must not use rcx"); - assert(lo != rcx, "must not use rcx"); - const Register s = rcx; // shift count - const int n = BitsPerWord; - Label L; - andl(s, 0x3f); // s := s & 0x3f (s < 0x40) - cmpl(s, n); // if (s < n) - jcc(Assembler::less, L); // else (s >= n) - movl(lo, hi); // x := x >> n - if (sign_extension) sarl(hi, 31); - else xorl(hi, hi); - // Note: subl(s, n) is not needed since the Intel shift instructions work rcx mod n! - bind(L); // s (mod n) < n - shrdl(lo, hi); // x := x >> s - if (sign_extension) sarl(hi); - else shrl(hi); -} - -void MacroAssembler::movoop(Register dst, jobject obj) { - mov_literal32(dst, (int32_t)obj, oop_Relocation::spec_for_immediate()); -} - -void MacroAssembler::movoop(Address dst, jobject obj, Register rscratch) { - assert(rscratch == noreg, "redundant"); - mov_literal32(dst, (int32_t)obj, oop_Relocation::spec_for_immediate()); -} - -void MacroAssembler::mov_metadata(Register dst, Metadata* obj) { - mov_literal32(dst, (int32_t)obj, metadata_Relocation::spec_for_immediate()); -} - -void MacroAssembler::mov_metadata(Address dst, Metadata* obj, Register rscratch) { - assert(rscratch == noreg, "redundant"); - mov_literal32(dst, (int32_t)obj, metadata_Relocation::spec_for_immediate()); -} - -void MacroAssembler::movptr(Register dst, AddressLiteral src) { - if (src.is_lval()) { - mov_literal32(dst, (intptr_t)src.target(), src.rspec()); - } else { - movl(dst, as_Address(src)); - } -} - -void MacroAssembler::movptr(ArrayAddress dst, Register src, Register rscratch) { - assert(rscratch == noreg, "redundant"); - movl(as_Address(dst, noreg), src); -} - -void MacroAssembler::movptr(Register dst, ArrayAddress src) { - movl(dst, as_Address(src, noreg)); -} - -void MacroAssembler::movptr(Address dst, intptr_t src, Register rscratch) { - assert(rscratch == noreg, "redundant"); - movl(dst, src); -} - -void MacroAssembler::pushoop(jobject obj, Register rscratch) { - assert(rscratch == noreg, "redundant"); - push_literal32((int32_t)obj, oop_Relocation::spec_for_immediate()); -} - -void MacroAssembler::pushklass(Metadata* obj, Register rscratch) { - assert(rscratch == noreg, "redundant"); - push_literal32((int32_t)obj, metadata_Relocation::spec_for_immediate()); -} - -void MacroAssembler::pushptr(AddressLiteral src, Register rscratch) { - assert(rscratch == noreg, "redundant"); - if (src.is_lval()) { - push_literal32((int32_t)src.target(), src.rspec()); - } else { - pushl(as_Address(src)); - } -} - -static void pass_arg0(MacroAssembler* masm, Register arg) { - masm->push(arg); -} - -static void pass_arg1(MacroAssembler* masm, Register arg) { - masm->push(arg); -} - -static void pass_arg2(MacroAssembler* masm, Register arg) { - masm->push(arg); -} - -static void pass_arg3(MacroAssembler* masm, Register arg) { - masm->push(arg); -} - -#ifndef PRODUCT -extern "C" void findpc(intptr_t x); -#endif - -void MacroAssembler::debug32(int rdi, int rsi, int rbp, int rsp, int rbx, int rdx, int rcx, int rax, int eip, char* msg) { - // In order to get locks to work, we need to fake a in_VM state - JavaThread* thread = JavaThread::current(); - JavaThreadState saved_state = thread->thread_state(); - thread->set_thread_state(_thread_in_vm); - if (ShowMessageBoxOnError) { - JavaThread* thread = JavaThread::current(); - JavaThreadState saved_state = thread->thread_state(); - thread->set_thread_state(_thread_in_vm); - if (CountBytecodes || TraceBytecodes || StopInterpreterAt) { - ttyLocker ttyl; - BytecodeCounter::print(); - } - // To see where a verify_oop failed, get $ebx+40/X for this frame. - // This is the value of eip which points to where verify_oop will return. - if (os::message_box(msg, "Execution stopped, print registers?")) { - print_state32(rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax, eip); - BREAKPOINT; - } - } - fatal("DEBUG MESSAGE: %s", msg); -} - -void MacroAssembler::print_state32(int rdi, int rsi, int rbp, int rsp, int rbx, int rdx, int rcx, int rax, int eip) { - ttyLocker ttyl; - DebuggingContext debugging{}; - tty->print_cr("eip = 0x%08x", eip); -#ifndef PRODUCT - if ((WizardMode || Verbose) && PrintMiscellaneous) { - tty->cr(); - findpc(eip); - tty->cr(); - } -#endif -#define PRINT_REG(rax) \ - { tty->print("%s = ", #rax); os::print_location(tty, rax); } - PRINT_REG(rax); - PRINT_REG(rbx); - PRINT_REG(rcx); - PRINT_REG(rdx); - PRINT_REG(rdi); - PRINT_REG(rsi); - PRINT_REG(rbp); - PRINT_REG(rsp); -#undef PRINT_REG - // Print some words near top of staack. - int* dump_sp = (int*) rsp; - for (int col1 = 0; col1 < 8; col1++) { - tty->print("(rsp+0x%03x) 0x%08x: ", (int)((intptr_t)dump_sp - (intptr_t)rsp), (intptr_t)dump_sp); - os::print_location(tty, *dump_sp++); - } - for (int row = 0; row < 16; row++) { - tty->print("(rsp+0x%03x) 0x%08x: ", (int)((intptr_t)dump_sp - (intptr_t)rsp), (intptr_t)dump_sp); - for (int col = 0; col < 8; col++) { - tty->print(" 0x%08x", *dump_sp++); - } - tty->cr(); - } - // Print some instructions around pc: - Disassembler::decode((address)eip-64, (address)eip); - tty->print_cr("--------"); - Disassembler::decode((address)eip, (address)eip+32); -} - -void MacroAssembler::stop(const char* msg) { - // push address of message - ExternalAddress message((address)msg); - pushptr(message.addr(), noreg); - { Label L; call(L, relocInfo::none); bind(L); } // push eip - pusha(); // push registers - call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug32))); - hlt(); -} - -void MacroAssembler::warn(const char* msg) { - push_CPU_state(); - - // push address of message - ExternalAddress message((address)msg); - pushptr(message.addr(), noreg); - - call(RuntimeAddress(CAST_FROM_FN_PTR(address, warning))); - addl(rsp, wordSize); // discard argument - pop_CPU_state(); -} - -void MacroAssembler::print_state() { - { Label L; call(L, relocInfo::none); bind(L); } // push eip - pusha(); // push registers - - push_CPU_state(); - call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::print_state32))); - pop_CPU_state(); - - popa(); - addl(rsp, wordSize); -} - -#else // _LP64 - -// 64 bit versions - Address MacroAssembler::as_Address(AddressLiteral adr) { // amd64 always does this as a pc-rel // we can be absolute or disp based on the instruction type @@ -1073,20 +704,16 @@ void MacroAssembler::object_move(OopMap* map, } } -#endif // _LP64 - -// Now versions that are common to 32/64 bit - void MacroAssembler::addptr(Register dst, int32_t imm32) { - LP64_ONLY(addq(dst, imm32)) NOT_LP64(addl(dst, imm32)); + addq(dst, imm32); } void MacroAssembler::addptr(Register dst, Register src) { - LP64_ONLY(addq(dst, src)) NOT_LP64(addl(dst, src)); + addq(dst, src); } void MacroAssembler::addptr(Address dst, Register src) { - LP64_ONLY(addq(dst, src)) NOT_LP64(addl(dst, src)); + addq(dst, src); } void MacroAssembler::addsd(XMMRegister dst, AddressLiteral src, Register rscratch) { @@ -1196,10 +823,9 @@ void MacroAssembler::andps(XMMRegister dst, AddressLiteral src, Register rscratc } void MacroAssembler::andptr(Register dst, int32_t imm32) { - LP64_ONLY(andq(dst, imm32)) NOT_LP64(andl(dst, imm32)); + andq(dst, imm32); } -#ifdef _LP64 void MacroAssembler::andq(Register dst, AddressLiteral src, Register rscratch) { assert(rscratch != noreg || always_reachable(src), "missing"); @@ -1210,7 +836,6 @@ void MacroAssembler::andq(Register dst, AddressLiteral src, Register rscratch) { andq(dst, Address(rscratch, 0)); } } -#endif void MacroAssembler::atomic_incl(Address counter_addr) { lock(); @@ -1228,7 +853,6 @@ void MacroAssembler::atomic_incl(AddressLiteral counter_addr, Register rscratch) } } -#ifdef _LP64 void MacroAssembler::atomic_incq(Address counter_addr) { lock(); incrementq(counter_addr); @@ -1244,7 +868,6 @@ void MacroAssembler::atomic_incq(AddressLiteral counter_addr, Register rscratch) atomic_incq(Address(rscratch, 0)); } } -#endif // Writes to stack successive pages until offset reached to check for // stack overflow + shadow pages. This clobbers tmp. @@ -1276,13 +899,11 @@ void MacroAssembler::bang_stack_size(Register size, Register tmp) { void MacroAssembler::reserved_stack_check() { // testing if reserved zone needs to be enabled Label no_reserved_zone_enabling; - Register thread = NOT_LP64(rsi) LP64_ONLY(r15_thread); - NOT_LP64(get_thread(rsi);) - cmpptr(rsp, Address(thread, JavaThread::reserved_stack_activation_offset())); + cmpptr(rsp, Address(r15_thread, JavaThread::reserved_stack_activation_offset())); jcc(Assembler::below, no_reserved_zone_enabling); - call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), thread); + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), r15_thread); jump(RuntimeAddress(SharedRuntime::throw_delayed_StackOverflowError_entry())); should_not_reach_here(); @@ -1320,24 +941,19 @@ void MacroAssembler::call(AddressLiteral entry, Register rscratch) { void MacroAssembler::ic_call(address entry, jint method_index) { RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index); -#ifdef _LP64 // Needs full 64-bit immediate for later patching. mov64(rax, (int64_t)Universe::non_oop_word()); -#else - movptr(rax, (intptr_t)Universe::non_oop_word()); -#endif call(AddressLiteral(entry, rh)); } int MacroAssembler::ic_check_size() { - return - LP64_ONLY(UseCompactObjectHeaders ? 17 : 14) NOT_LP64(12); + return UseCompactObjectHeaders ? 17 : 14; } int MacroAssembler::ic_check(int end_alignment) { - Register receiver = LP64_ONLY(j_rarg0) NOT_LP64(rcx); + Register receiver = j_rarg0; Register data = rax; - Register temp = LP64_ONLY(rscratch1) NOT_LP64(rbx); + Register temp = rscratch1; // The UEP of a code blob ensures that the VEP is padded. However, the padding of the UEP is placed // before the inline cache check, so we don't have to execute any nop instructions when dispatching @@ -1347,13 +963,10 @@ int MacroAssembler::ic_check(int end_alignment) { int uep_offset = offset(); -#ifdef _LP64 if (UseCompactObjectHeaders) { load_narrow_klass_compact(temp, receiver); cmpl(temp, Address(data, CompiledICData::speculated_klass_offset())); - } else -#endif - if (UseCompressedClassPointers) { + } else if (UseCompressedClassPointers) { movl(temp, Address(receiver, oopDesc::klass_offset_in_bytes())); cmpl(temp, Address(data, CompiledICData::speculated_klass_offset())); } else { @@ -1418,7 +1031,7 @@ void MacroAssembler::call_VM(Register oop_result, bind(C); - LP64_ONLY(assert_different_registers(arg_1, c_rarg2)); + assert_different_registers(arg_1, c_rarg2); pass_arg2(this, arg_2); pass_arg1(this, arg_1); @@ -1440,8 +1053,8 @@ void MacroAssembler::call_VM(Register oop_result, bind(C); - LP64_ONLY(assert_different_registers(arg_1, c_rarg2, c_rarg3)); - LP64_ONLY(assert_different_registers(arg_2, c_rarg3)); + assert_different_registers(arg_1, c_rarg2, c_rarg3); + assert_different_registers(arg_2, c_rarg3); pass_arg3(this, arg_3); pass_arg2(this, arg_2); pass_arg1(this, arg_1); @@ -1475,7 +1088,7 @@ void MacroAssembler::call_VM(Register oop_result, Register arg_2, bool check_exceptions) { - LP64_ONLY(assert_different_registers(arg_1, c_rarg2)); + assert_different_registers(arg_1, c_rarg2); pass_arg2(this, arg_2); pass_arg1(this, arg_1); call_VM(oop_result, last_java_sp, entry_point, 2, check_exceptions); @@ -1488,8 +1101,8 @@ void MacroAssembler::call_VM(Register oop_result, Register arg_2, Register arg_3, bool check_exceptions) { - LP64_ONLY(assert_different_registers(arg_1, c_rarg2, c_rarg3)); - LP64_ONLY(assert_different_registers(arg_2, c_rarg3)); + assert_different_registers(arg_1, c_rarg2, c_rarg3); + assert_different_registers(arg_2, c_rarg3); pass_arg3(this, arg_3); pass_arg2(this, arg_2); pass_arg1(this, arg_1); @@ -1520,7 +1133,7 @@ void MacroAssembler::super_call_VM(Register oop_result, Register arg_2, bool check_exceptions) { - LP64_ONLY(assert_different_registers(arg_1, c_rarg2)); + assert_different_registers(arg_1, c_rarg2); pass_arg2(this, arg_2); pass_arg1(this, arg_1); super_call_VM(oop_result, last_java_sp, entry_point, 2, check_exceptions); @@ -1533,8 +1146,8 @@ void MacroAssembler::super_call_VM(Register oop_result, Register arg_2, Register arg_3, bool check_exceptions) { - LP64_ONLY(assert_different_registers(arg_1, c_rarg2, c_rarg3)); - LP64_ONLY(assert_different_registers(arg_2, c_rarg3)); + assert_different_registers(arg_1, c_rarg2, c_rarg3); + assert_different_registers(arg_2, c_rarg3); pass_arg3(this, arg_3); pass_arg2(this, arg_2); pass_arg1(this, arg_1); @@ -1645,15 +1258,15 @@ void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0) { void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0, Register arg_1) { - LP64_ONLY(assert_different_registers(arg_0, c_rarg1)); + assert_different_registers(arg_0, c_rarg1); pass_arg1(this, arg_1); pass_arg0(this, arg_0); call_VM_leaf(entry_point, 2); } void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2) { - LP64_ONLY(assert_different_registers(arg_0, c_rarg1, c_rarg2)); - LP64_ONLY(assert_different_registers(arg_1, c_rarg2)); + assert_different_registers(arg_0, c_rarg1, c_rarg2); + assert_different_registers(arg_1, c_rarg2); pass_arg2(this, arg_2); pass_arg1(this, arg_1); pass_arg0(this, arg_0); @@ -1661,9 +1274,9 @@ void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0, Register } void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2, Register arg_3) { - LP64_ONLY(assert_different_registers(arg_0, c_rarg1, c_rarg2, c_rarg3)); - LP64_ONLY(assert_different_registers(arg_1, c_rarg2, c_rarg3)); - LP64_ONLY(assert_different_registers(arg_2, c_rarg3)); + assert_different_registers(arg_0, c_rarg1, c_rarg2, c_rarg3); + assert_different_registers(arg_1, c_rarg2, c_rarg3); + assert_different_registers(arg_2, c_rarg3); pass_arg3(this, arg_3); pass_arg2(this, arg_2); pass_arg1(this, arg_1); @@ -1677,15 +1290,15 @@ void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0) { } void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1) { - LP64_ONLY(assert_different_registers(arg_0, c_rarg1)); + assert_different_registers(arg_0, c_rarg1); pass_arg1(this, arg_1); pass_arg0(this, arg_0); MacroAssembler::call_VM_leaf_base(entry_point, 2); } void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2) { - LP64_ONLY(assert_different_registers(arg_0, c_rarg1, c_rarg2)); - LP64_ONLY(assert_different_registers(arg_1, c_rarg2)); + assert_different_registers(arg_0, c_rarg1, c_rarg2); + assert_different_registers(arg_1, c_rarg2); pass_arg2(this, arg_2); pass_arg1(this, arg_1); pass_arg0(this, arg_0); @@ -1693,9 +1306,9 @@ void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Reg } void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2, Register arg_3) { - LP64_ONLY(assert_different_registers(arg_0, c_rarg1, c_rarg2, c_rarg3)); - LP64_ONLY(assert_different_registers(arg_1, c_rarg2, c_rarg3)); - LP64_ONLY(assert_different_registers(arg_2, c_rarg3)); + assert_different_registers(arg_0, c_rarg1, c_rarg2, c_rarg3); + assert_different_registers(arg_1, c_rarg2, c_rarg3); + assert_different_registers(arg_2, c_rarg3); pass_arg3(this, arg_3); pass_arg2(this, arg_2); pass_arg1(this, arg_1); @@ -1808,7 +1421,6 @@ void MacroAssembler::cmp8(AddressLiteral src1, int imm, Register rscratch) { } void MacroAssembler::cmpptr(Register src1, AddressLiteral src2, Register rscratch) { -#ifdef _LP64 assert(rscratch != noreg || always_reachable(src2), "missing"); if (src2.is_lval()) { @@ -1820,26 +1432,13 @@ void MacroAssembler::cmpptr(Register src1, AddressLiteral src2, Register rscratc lea(rscratch, src2); Assembler::cmpq(src1, Address(rscratch, 0)); } -#else - assert(rscratch == noreg, "not needed"); - if (src2.is_lval()) { - cmp_literal32(src1, (int32_t)src2.target(), src2.rspec()); - } else { - cmpl(src1, as_Address(src2)); - } -#endif // _LP64 } void MacroAssembler::cmpptr(Address src1, AddressLiteral src2, Register rscratch) { assert(src2.is_lval(), "not a mem-mem compare"); -#ifdef _LP64 // moves src2's literal address movptr(rscratch, src2); Assembler::cmpq(src1, rscratch); -#else - assert(rscratch == noreg, "not needed"); - cmp_literal32(src1, (int32_t)src2.target(), src2.rspec()); -#endif // _LP64 } void MacroAssembler::cmpoop(Register src1, Register src2) { @@ -1850,12 +1449,10 @@ void MacroAssembler::cmpoop(Register src1, Address src2) { cmpptr(src1, src2); } -#ifdef _LP64 void MacroAssembler::cmpoop(Register src1, jobject src2, Register rscratch) { movoop(rscratch, src2); cmpptr(src1, rscratch); } -#endif void MacroAssembler::locked_cmpxchgptr(Register reg, AddressLiteral adr, Register rscratch) { assert(rscratch != noreg || always_reachable(adr), "missing"); @@ -1871,7 +1468,7 @@ void MacroAssembler::locked_cmpxchgptr(Register reg, AddressLiteral adr, Registe } void MacroAssembler::cmpxchgptr(Register reg, Address adr) { - LP64_ONLY(cmpxchgq(reg, adr)) NOT_LP64(cmpxchgl(reg, adr)); + cmpxchgq(reg, adr); } void MacroAssembler::comisd(XMMRegister dst, AddressLiteral src, Register rscratch) { @@ -2193,15 +1790,8 @@ void MacroAssembler::ldmxcsr(AddressLiteral src, Register rscratch) { } int MacroAssembler::load_signed_byte(Register dst, Address src) { - int off; - if (LP64_ONLY(true ||) VM_Version::is_P6()) { - off = offset(); - movsbl(dst, src); // movsxb - } else { - off = load_unsigned_byte(dst, src); - shll(dst, 24); - sarl(dst, 24); - } + int off = offset(); + movsbl(dst, src); // movsxb return off; } @@ -2210,33 +1800,19 @@ int MacroAssembler::load_signed_byte(Register dst, Address src) { // manual, which means 16 bits, that usage is found nowhere in HotSpot code. // The term "word" in HotSpot means a 32- or 64-bit machine word. int MacroAssembler::load_signed_short(Register dst, Address src) { - int off; - if (LP64_ONLY(true ||) VM_Version::is_P6()) { - // This is dubious to me since it seems safe to do a signed 16 => 64 bit - // version but this is what 64bit has always done. This seems to imply - // that users are only using 32bits worth. - off = offset(); - movswl(dst, src); // movsxw - } else { - off = load_unsigned_short(dst, src); - shll(dst, 16); - sarl(dst, 16); - } + // This is dubious to me since it seems safe to do a signed 16 => 64 bit + // version but this is what 64bit has always done. This seems to imply + // that users are only using 32bits worth. + int off = offset(); + movswl(dst, src); // movsxw return off; } int MacroAssembler::load_unsigned_byte(Register dst, Address src) { // According to Intel Doc. AP-526, "Zero-Extension of Short", p.16, // and "3.9 Partial Register Penalties", p. 22). - int off; - if (LP64_ONLY(true || ) VM_Version::is_P6() || src.uses(dst)) { - off = offset(); - movzbl(dst, src); // movzxb - } else { - xorl(dst, dst); - off = offset(); - movb(dst, src); - } + int off = offset(); + movzbl(dst, src); // movzxb return off; } @@ -2244,29 +1820,14 @@ int MacroAssembler::load_unsigned_byte(Register dst, Address src) { int MacroAssembler::load_unsigned_short(Register dst, Address src) { // According to Intel Doc. AP-526, "Zero-Extension of Short", p.16, // and "3.9 Partial Register Penalties", p. 22). - int off; - if (LP64_ONLY(true ||) VM_Version::is_P6() || src.uses(dst)) { - off = offset(); - movzwl(dst, src); // movzxw - } else { - xorl(dst, dst); - off = offset(); - movw(dst, src); - } + int off = offset(); + movzwl(dst, src); // movzxw return off; } void MacroAssembler::load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed, Register dst2) { switch (size_in_bytes) { -#ifndef _LP64 - case 8: - assert(dst2 != noreg, "second dest register required"); - movl(dst, src); - movl(dst2, src.plus_disp(BytesPerInt)); - break; -#else case 8: movq(dst, src); break; -#endif case 4: movl(dst, src); break; case 2: is_signed ? load_signed_short(dst, src) : load_unsigned_short(dst, src); break; case 1: is_signed ? load_signed_byte( dst, src) : load_unsigned_byte( dst, src); break; @@ -2276,15 +1837,7 @@ void MacroAssembler::load_sized_value(Register dst, Address src, size_t size_in_ void MacroAssembler::store_sized_value(Address dst, Register src, size_t size_in_bytes, Register src2) { switch (size_in_bytes) { -#ifndef _LP64 - case 8: - assert(src2 != noreg, "second source register required"); - movl(dst, src); - movl(dst.plus_disp(BytesPerInt), src2); - break; -#else case 8: movq(dst, src); break; -#endif case 4: movl(dst, src); break; case 2: movw(dst, src); break; case 1: movb(dst, src); break; @@ -2403,16 +1956,15 @@ void MacroAssembler::movflt(XMMRegister dst, AddressLiteral src, Register rscrat } void MacroAssembler::movptr(Register dst, Register src) { - LP64_ONLY(movq(dst, src)) NOT_LP64(movl(dst, src)); + movq(dst, src); } void MacroAssembler::movptr(Register dst, Address src) { - LP64_ONLY(movq(dst, src)) NOT_LP64(movl(dst, src)); + movq(dst, src); } // src should NEVER be a real pointer. Use AddressLiteral for true pointers void MacroAssembler::movptr(Register dst, intptr_t src) { -#ifdef _LP64 if (is_uimm32(src)) { movl(dst, checked_cast(src)); } else if (is_simm32(src)) { @@ -2420,17 +1972,14 @@ void MacroAssembler::movptr(Register dst, intptr_t src) { } else { mov64(dst, src); } -#else - movl(dst, src); -#endif } void MacroAssembler::movptr(Address dst, Register src) { - LP64_ONLY(movq(dst, src)) NOT_LP64(movl(dst, src)); + movq(dst, src); } void MacroAssembler::movptr(Address dst, int32_t src) { - LP64_ONLY(movslq(dst, src)) NOT_LP64(movl(dst, src)); + movslq(dst, src); } void MacroAssembler::movdqu(Address dst, XMMRegister src) { @@ -2808,9 +2357,7 @@ void MacroAssembler::unimplemented(const char* what) { stop(buf); } -#ifdef _LP64 #define XSTATE_BV 0x200 -#endif void MacroAssembler::pop_CPU_state() { pop_FPU_state(); @@ -2818,17 +2365,13 @@ void MacroAssembler::pop_CPU_state() { } void MacroAssembler::pop_FPU_state() { -#ifndef _LP64 - frstor(Address(rsp, 0)); -#else fxrstor(Address(rsp, 0)); -#endif addptr(rsp, FPUStateSizeInWords * wordSize); } void MacroAssembler::pop_IU_state() { popa(); - LP64_ONLY(addq(rsp, 8)); + addq(rsp, 8); popf(); } @@ -2841,19 +2384,14 @@ void MacroAssembler::push_CPU_state() { void MacroAssembler::push_FPU_state() { subptr(rsp, FPUStateSizeInWords * wordSize); -#ifndef _LP64 - fnsave(Address(rsp, 0)); - fwait(); -#else fxsave(Address(rsp, 0)); -#endif // LP64 } void MacroAssembler::push_IU_state() { // Push flags first because pusha kills them pushf(); // Make sure rsp stays 16-byte aligned - LP64_ONLY(subq(rsp, 8)); + subq(rsp, 8); pusha(); } @@ -2963,29 +2501,19 @@ void MacroAssembler::set_last_Java_frame(Register last_java_sp, } void MacroAssembler::shlptr(Register dst, int imm8) { - LP64_ONLY(shlq(dst, imm8)) NOT_LP64(shll(dst, imm8)); + shlq(dst, imm8); } void MacroAssembler::shrptr(Register dst, int imm8) { - LP64_ONLY(shrq(dst, imm8)) NOT_LP64(shrl(dst, imm8)); + shrq(dst, imm8); } void MacroAssembler::sign_extend_byte(Register reg) { - if (LP64_ONLY(true ||) (VM_Version::is_P6() && reg->has_byte_register())) { - movsbl(reg, reg); // movsxb - } else { - shll(reg, 24); - sarl(reg, 24); - } + movsbl(reg, reg); // movsxb } void MacroAssembler::sign_extend_short(Register reg) { - if (LP64_ONLY(true ||) VM_Version::is_P6()) { - movswl(reg, reg); // movsxw - } else { - shll(reg, 16); - sarl(reg, 16); - } + movswl(reg, reg); // movsxw } void MacroAssembler::testl(Address dst, int32_t imm32) { @@ -3009,8 +2537,6 @@ void MacroAssembler::testl(Register dst, AddressLiteral src) { testl(dst, as_Address(src)); } -#ifdef _LP64 - void MacroAssembler::testq(Address dst, int32_t imm32) { if (imm32 >= 0) { testl(dst, imm32); @@ -3027,8 +2553,6 @@ void MacroAssembler::testq(Register dst, int32_t imm32) { } } -#endif - void MacroAssembler::pcmpeqb(XMMRegister dst, XMMRegister src) { assert(((dst->encoding() < 16 && src->encoding() < 16) || VM_Version::supports_avx512vlbw()),"XMM register should be 0-15"); Assembler::pcmpeqb(dst, src); @@ -3874,16 +3398,16 @@ void MacroAssembler::resolve_global_jobject(Register value, } void MacroAssembler::subptr(Register dst, int32_t imm32) { - LP64_ONLY(subq(dst, imm32)) NOT_LP64(subl(dst, imm32)); + subq(dst, imm32); } // Force generation of a 4 byte immediate value even if it fits into 8bit void MacroAssembler::subptr_imm32(Register dst, int32_t imm32) { - LP64_ONLY(subq_imm32(dst, imm32)) NOT_LP64(subl_imm32(dst, imm32)); + subq_imm32(dst, imm32); } void MacroAssembler::subptr(Register dst, Register src) { - LP64_ONLY(subq(dst, src)) NOT_LP64(subl(dst, src)); + subq(dst, src); } // C++ bool manipulation @@ -3901,7 +3425,7 @@ void MacroAssembler::testbool(Register dst) { } void MacroAssembler::testptr(Register dst, Register src) { - LP64_ONLY(testq(dst, src)) NOT_LP64(testl(dst, src)); + testq(dst, src); } // Defines obj, preserves var_size_in_bytes, okay for t2 == var_size_in_bytes. @@ -3917,20 +3441,14 @@ void MacroAssembler::tlab_allocate(Register obj, RegSet MacroAssembler::call_clobbered_gp_registers() { RegSet regs; -#ifdef _LP64 regs += RegSet::of(rax, rcx, rdx); #ifndef _WINDOWS regs += RegSet::of(rsi, rdi); #endif regs += RegSet::range(r8, r11); -#else - regs += RegSet::of(rax, rcx, rdx); -#endif -#ifdef _LP64 if (UseAPX) { regs += RegSet::range(r16, as_Register(Register::number_of_registers - 1)); } -#endif return regs; } @@ -4100,27 +3618,12 @@ void MacroAssembler::zero_memory(Register address, Register length_in_bytes, int shrptr(index, 2); // use 2 instructions to avoid partial flag stall shrptr(index, 1); } -#ifndef _LP64 - // index could have not been a multiple of 8 (i.e., bit 2 was set) - { - Label even; - // note: if index was a multiple of 8, then it cannot - // be 0 now otherwise it must have been 0 before - // => if it is even, we don't need to check for 0 again - jcc(Assembler::carryClear, even); - // clear topmost word (no jump would be needed if conditional assignment worked here) - movptr(Address(address, index, Address::times_8, offset_in_bytes - 0*BytesPerWord), temp); - // index could be 0 now, must check again - jcc(Assembler::zero, done); - bind(even); - } -#endif // !_LP64 + // initialize remaining object fields: index is a multiple of 2 now { Label loop; bind(loop); movptr(Address(address, index, Address::times_8, offset_in_bytes - 1*BytesPerWord), temp); - NOT_LP64(movptr(Address(address, index, Address::times_8, offset_in_bytes - 2*BytesPerWord), temp);) decrement(index); jcc(Assembler::notZero, loop); } @@ -4497,9 +4000,8 @@ void MacroAssembler::check_klass_subtype_slow_path_linear(Register sub_klass, #ifndef PRODUCT uint* pst_counter = &SharedRuntime::_partial_subtype_ctr; ExternalAddress pst_counter_addr((address) pst_counter); - NOT_LP64( incrementl(pst_counter_addr) ); - LP64_ONLY( lea(rcx, pst_counter_addr) ); - LP64_ONLY( incrementl(Address(rcx, 0)) ); + lea(rcx, pst_counter_addr); + incrementl(Address(rcx, 0)); #endif //PRODUCT // We will consult the secondary-super array. @@ -4545,22 +4047,6 @@ void MacroAssembler::check_klass_subtype_slow_path_linear(Register sub_klass, bind(L_fallthrough); } -#ifndef _LP64 - -// 32-bit x86 only: always use the linear search. -void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, - Register super_klass, - Register temp_reg, - Register temp2_reg, - Label* L_success, - Label* L_failure, - bool set_cond_codes) { - check_klass_subtype_slow_path_linear - (sub_klass, super_klass, temp_reg, temp2_reg, L_success, L_failure, set_cond_codes); -} - -#else // _LP64 - void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, Register super_klass, Register temp_reg, @@ -5144,8 +4630,6 @@ void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass, #undef LOOKUP_SECONDARY_SUPERS_TABLE_REGISTERS -#endif // LP64 - void MacroAssembler::clinit_barrier(Register klass, Label* L_fast_path, Label* L_slow_path) { assert(L_fast_path != nullptr || L_slow_path != nullptr, "at least one is required"); @@ -5200,9 +4684,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file, if (!VerifyOops) return; BLOCK_COMMENT("verify_oop {"); -#ifdef _LP64 push(rscratch1); -#endif push(rax); // save rax push(reg); // pass register argument @@ -5260,9 +4742,7 @@ Address MacroAssembler::argument_address(RegisterOrConstant arg_slot, void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* file, int line) { if (!VerifyOops) return; -#ifdef _LP64 push(rscratch1); -#endif push(rax); // save rax, // addr may contain rsp so we will have to adjust it based on the push // we just did (and on 64 bit we do two pushes) @@ -5270,7 +4750,7 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f // stores rax into addr which is backwards of what was intended. if (addr.uses(rsp)) { lea(rax, addr); - pushptr(Address(rax, LP64_ONLY(2 *) BytesPerWord)); + pushptr(Address(rax, 2 * BytesPerWord)); } else { pushptr(addr); } @@ -5297,27 +4777,23 @@ void MacroAssembler::verify_tlab() { if (UseTLAB && VerifyOops) { Label next, ok; Register t1 = rsi; - Register thread_reg = NOT_LP64(rbx) LP64_ONLY(r15_thread); push(t1); - NOT_LP64(push(thread_reg)); - NOT_LP64(get_thread(thread_reg)); - movptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_top_offset()))); - cmpptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_start_offset()))); + movptr(t1, Address(r15_thread, in_bytes(JavaThread::tlab_top_offset()))); + cmpptr(t1, Address(r15_thread, in_bytes(JavaThread::tlab_start_offset()))); jcc(Assembler::aboveEqual, next); STOP("assert(top >= start)"); should_not_reach_here(); bind(next); - movptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_end_offset()))); - cmpptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_top_offset()))); + movptr(t1, Address(r15_thread, in_bytes(JavaThread::tlab_end_offset()))); + cmpptr(t1, Address(r15_thread, in_bytes(JavaThread::tlab_top_offset()))); jcc(Assembler::aboveEqual, ok); STOP("assert(top <= end)"); should_not_reach_here(); bind(ok); - NOT_LP64(pop(thread_reg)); pop(t1); } #endif @@ -5658,27 +5134,23 @@ void MacroAssembler::load_method_holder(Register holder, Register method) { movptr(holder, Address(holder, ConstantPool::pool_holder_offset())); // InstanceKlass* } -#ifdef _LP64 void MacroAssembler::load_narrow_klass_compact(Register dst, Register src) { assert(UseCompactObjectHeaders, "expect compact object headers"); movq(dst, Address(src, oopDesc::mark_offset_in_bytes())); shrq(dst, markWord::klass_shift); } -#endif void MacroAssembler::load_klass(Register dst, Register src, Register tmp) { assert_different_registers(src, tmp); assert_different_registers(dst, tmp); -#ifdef _LP64 + if (UseCompactObjectHeaders) { load_narrow_klass_compact(dst, src); decode_klass_not_null(dst, tmp); } else if (UseCompressedClassPointers) { movl(dst, Address(src, oopDesc::klass_offset_in_bytes())); decode_klass_not_null(dst, tmp); - } else -#endif - { + } else { movptr(dst, Address(src, oopDesc::klass_offset_in_bytes())); } } @@ -5687,17 +5159,15 @@ void MacroAssembler::store_klass(Register dst, Register src, Register tmp) { assert(!UseCompactObjectHeaders, "not with compact headers"); assert_different_registers(src, tmp); assert_different_registers(dst, tmp); -#ifdef _LP64 if (UseCompressedClassPointers) { encode_klass_not_null(src, tmp); movl(Address(dst, oopDesc::klass_offset_in_bytes()), src); - } else -#endif + } else { movptr(Address(dst, oopDesc::klass_offset_in_bytes()), src); + } } void MacroAssembler::cmp_klass(Register klass, Register obj, Register tmp) { -#ifdef _LP64 if (UseCompactObjectHeaders) { assert(tmp != noreg, "need tmp"); assert_different_registers(klass, obj, tmp); @@ -5705,15 +5175,12 @@ void MacroAssembler::cmp_klass(Register klass, Register obj, Register tmp) { cmpl(klass, tmp); } else if (UseCompressedClassPointers) { cmpl(klass, Address(obj, oopDesc::klass_offset_in_bytes())); - } else -#endif - { + } else { cmpptr(klass, Address(obj, oopDesc::klass_offset_in_bytes())); } } void MacroAssembler::cmp_klasses_from_objects(Register obj1, Register obj2, Register tmp1, Register tmp2) { -#ifdef _LP64 if (UseCompactObjectHeaders) { assert(tmp2 != noreg, "need tmp2"); assert_different_registers(obj1, obj2, tmp1, tmp2); @@ -5723,9 +5190,7 @@ void MacroAssembler::cmp_klasses_from_objects(Register obj1, Register obj2, Regi } else if (UseCompressedClassPointers) { movl(tmp1, Address(obj1, oopDesc::klass_offset_in_bytes())); cmpl(tmp1, Address(obj2, oopDesc::klass_offset_in_bytes())); - } else -#endif - { + } else { movptr(tmp1, Address(obj1, oopDesc::klass_offset_in_bytes())); cmpptr(tmp1, Address(obj2, oopDesc::klass_offset_in_bytes())); } @@ -5774,7 +5239,6 @@ void MacroAssembler::store_heap_oop_null(Address dst) { access_store_at(T_OBJECT, IN_HEAP, dst, noreg, noreg, noreg, noreg); } -#ifdef _LP64 void MacroAssembler::store_klass_gap(Register dst, Register src) { assert(!UseCompactObjectHeaders, "Don't use with compact headers"); if (UseCompressedClassPointers) { @@ -6096,8 +5560,6 @@ void MacroAssembler::reinit_heapbase() { } } -#endif // _LP64 - #if COMPILER2_OR_JVMCI // clear memory of size 'cnt' qwords, starting at 'base' using XMM/YMM/ZMM registers @@ -6276,8 +5738,6 @@ void MacroAssembler::clear_mem(Register base, Register cnt, Register tmp, XMMReg cmpptr(cnt, InitArrayShortSize/BytesPerLong); jccb(Assembler::greater, LONG); - NOT_LP64(shlptr(cnt, 1);) // convert to number of 32-bit words for 32-bit VM - decrement(cnt); jccb(Assembler::negative, DONE); // Zero length @@ -6298,7 +5758,6 @@ void MacroAssembler::clear_mem(Register base, Register cnt, Register tmp, XMMReg } else if (UseXMMForObjInit) { xmm_clear_mem(base, cnt, tmp, xtmp, mask); } else { - NOT_LP64(shlptr(cnt, 1);) // convert to number of 32-bit words for 32-bit VM rep_stos(); } @@ -6316,7 +5775,7 @@ void MacroAssembler::generate_fill(BasicType t, bool aligned, Label L_exit; Label L_fill_2_bytes, L_fill_4_bytes; -#if defined(COMPILER2) && defined(_LP64) +#if defined(COMPILER2) if(MaxVectorSize >=32 && VM_Version::supports_avx512vlbw() && VM_Version::supports_bmi2()) { @@ -6696,7 +6155,6 @@ void MacroAssembler::encode_iso_array(Register src, Register dst, Register len, bind(L_done); } -#ifdef _LP64 /** * Helper for multiply_to_len(). */ @@ -7871,7 +7329,6 @@ void MacroAssembler::mul_add(Register out, Register in, Register offs, pop(tmp2); pop(tmp1); } -#endif /** * Emits code to update CRC-32 with a byte value according to constants in table @@ -8094,7 +7551,6 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, Regi notl(crc); // ~c } -#ifdef _LP64 // Helper function for AVX 512 CRC32 // Fold 512-bit data chunks void MacroAssembler::fold512bit_crc32_avx512(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, Register buf, @@ -8612,155 +8068,7 @@ void MacroAssembler::crc32c_proc_chunk(uint32_t size, uint32_t const_or_pre_comp bind(L_exit); } -#else -void MacroAssembler::crc32c_ipl_alg4(Register in_out, uint32_t n, - Register tmp1, Register tmp2, Register tmp3, - XMMRegister xtmp1, XMMRegister xtmp2) { - lea(tmp3, ExternalAddress(StubRoutines::crc32c_table_addr())); - if (n > 0) { - addl(tmp3, n * 256 * 8); - } - // Q1 = TABLEExt[n][B & 0xFF]; - movl(tmp1, in_out); - andl(tmp1, 0x000000FF); - shll(tmp1, 3); - addl(tmp1, tmp3); - movq(xtmp1, Address(tmp1, 0)); - - // Q2 = TABLEExt[n][B >> 8 & 0xFF]; - movl(tmp2, in_out); - shrl(tmp2, 8); - andl(tmp2, 0x000000FF); - shll(tmp2, 3); - addl(tmp2, tmp3); - movq(xtmp2, Address(tmp2, 0)); - - psllq(xtmp2, 8); - pxor(xtmp1, xtmp2); - - // Q3 = TABLEExt[n][B >> 16 & 0xFF]; - movl(tmp2, in_out); - shrl(tmp2, 16); - andl(tmp2, 0x000000FF); - shll(tmp2, 3); - addl(tmp2, tmp3); - movq(xtmp2, Address(tmp2, 0)); - - psllq(xtmp2, 16); - pxor(xtmp1, xtmp2); - - // Q4 = TABLEExt[n][B >> 24 & 0xFF]; - shrl(in_out, 24); - andl(in_out, 0x000000FF); - shll(in_out, 3); - addl(in_out, tmp3); - movq(xtmp2, Address(in_out, 0)); - - psllq(xtmp2, 24); - pxor(xtmp1, xtmp2); // Result in CXMM - // return Q1 ^ Q2 << 8 ^ Q3 << 16 ^ Q4 << 24; -} - -void MacroAssembler::crc32c_pclmulqdq(XMMRegister w_xtmp1, - Register in_out, - uint32_t const_or_pre_comp_const_index, bool is_pclmulqdq_supported, - XMMRegister w_xtmp2, - Register tmp1, - Register n_tmp2, Register n_tmp3) { - if (is_pclmulqdq_supported) { - movdl(w_xtmp1, in_out); - - movl(tmp1, const_or_pre_comp_const_index); - movdl(w_xtmp2, tmp1); - pclmulqdq(w_xtmp1, w_xtmp2, 0); - // Keep result in XMM since GPR is 32 bit in length - } else { - crc32c_ipl_alg4(in_out, const_or_pre_comp_const_index, tmp1, n_tmp2, n_tmp3, w_xtmp1, w_xtmp2); - } -} - -void MacroAssembler::crc32c_rec_alt2(uint32_t const_or_pre_comp_const_index_u1, uint32_t const_or_pre_comp_const_index_u2, bool is_pclmulqdq_supported, Register in_out, Register in1, Register in2, - XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, - Register tmp1, Register tmp2, - Register n_tmp3) { - crc32c_pclmulqdq(w_xtmp1, in_out, const_or_pre_comp_const_index_u1, is_pclmulqdq_supported, w_xtmp3, tmp1, tmp2, n_tmp3); - crc32c_pclmulqdq(w_xtmp2, in1, const_or_pre_comp_const_index_u2, is_pclmulqdq_supported, w_xtmp3, tmp1, tmp2, n_tmp3); - - psllq(w_xtmp1, 1); - movdl(tmp1, w_xtmp1); - psrlq(w_xtmp1, 32); - movdl(in_out, w_xtmp1); - xorl(tmp2, tmp2); - crc32(tmp2, tmp1, 4); - xorl(in_out, tmp2); - - psllq(w_xtmp2, 1); - movdl(tmp1, w_xtmp2); - psrlq(w_xtmp2, 32); - movdl(in1, w_xtmp2); - - xorl(tmp2, tmp2); - crc32(tmp2, tmp1, 4); - xorl(in1, tmp2); - xorl(in_out, in1); - xorl(in_out, in2); -} - -void MacroAssembler::crc32c_proc_chunk(uint32_t size, uint32_t const_or_pre_comp_const_index_u1, uint32_t const_or_pre_comp_const_index_u2, bool is_pclmulqdq_supported, - Register in_out1, Register in_out2, Register in_out3, - Register tmp1, Register tmp2, Register tmp3, - XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, - Register tmp4, Register tmp5, - Register n_tmp6) { - Label L_processPartitions; - Label L_processPartition; - Label L_exit; - - bind(L_processPartitions); - cmpl(in_out1, 3 * size); - jcc(Assembler::less, L_exit); - xorl(tmp1, tmp1); - xorl(tmp2, tmp2); - movl(tmp3, in_out2); - addl(tmp3, size); - - bind(L_processPartition); - crc32(in_out3, Address(in_out2, 0), 4); - crc32(tmp1, Address(in_out2, size), 4); - crc32(tmp2, Address(in_out2, size*2), 4); - crc32(in_out3, Address(in_out2, 0+4), 4); - crc32(tmp1, Address(in_out2, size+4), 4); - crc32(tmp2, Address(in_out2, size*2+4), 4); - addl(in_out2, 8); - cmpl(in_out2, tmp3); - jcc(Assembler::less, L_processPartition); - - push(tmp3); - push(in_out1); - push(in_out2); - tmp4 = tmp3; - tmp5 = in_out1; - n_tmp6 = in_out2; - - crc32c_rec_alt2(const_or_pre_comp_const_index_u1, const_or_pre_comp_const_index_u2, is_pclmulqdq_supported, in_out3, tmp1, tmp2, - w_xtmp1, w_xtmp2, w_xtmp3, - tmp4, tmp5, - n_tmp6); - - pop(in_out2); - pop(in_out1); - pop(tmp3); - - addl(in_out2, 2 * size); - subl(in_out1, 3 * size); - jmp(L_processPartitions); - - bind(L_exit); -} -#endif //LP64 - -#ifdef _LP64 // Algorithm 2: Pipelined usage of the CRC32 instruction. // Input: A buffer I of L bytes. // Output: the CRC32C value of the buffer. @@ -8852,84 +8160,6 @@ void MacroAssembler::crc32c_ipl_alg2_alt2(Register in_out, Register in1, Registe BIND(L_exit); } -#else -void MacroAssembler::crc32c_ipl_alg2_alt2(Register in_out, Register in1, Register in2, - Register tmp1, Register tmp2, Register tmp3, - Register tmp4, Register tmp5, Register tmp6, - XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, - bool is_pclmulqdq_supported) { - uint32_t const_or_pre_comp_const_index[CRC32C_NUM_PRECOMPUTED_CONSTANTS]; - Label L_wordByWord; - Label L_byteByByteProlog; - Label L_byteByByte; - Label L_exit; - - if (is_pclmulqdq_supported) { - const_or_pre_comp_const_index[1] = *(uint32_t *)StubRoutines::crc32c_table_addr(); - const_or_pre_comp_const_index[0] = *((uint32_t *)StubRoutines::crc32c_table_addr() + 1); - - const_or_pre_comp_const_index[3] = *((uint32_t *)StubRoutines::crc32c_table_addr() + 2); - const_or_pre_comp_const_index[2] = *((uint32_t *)StubRoutines::crc32c_table_addr() + 3); - - const_or_pre_comp_const_index[5] = *((uint32_t *)StubRoutines::crc32c_table_addr() + 4); - const_or_pre_comp_const_index[4] = *((uint32_t *)StubRoutines::crc32c_table_addr() + 5); - } else { - const_or_pre_comp_const_index[0] = 1; - const_or_pre_comp_const_index[1] = 0; - - const_or_pre_comp_const_index[2] = 3; - const_or_pre_comp_const_index[3] = 2; - - const_or_pre_comp_const_index[4] = 5; - const_or_pre_comp_const_index[5] = 4; - } - crc32c_proc_chunk(CRC32C_HIGH, const_or_pre_comp_const_index[0], const_or_pre_comp_const_index[1], is_pclmulqdq_supported, - in2, in1, in_out, - tmp1, tmp2, tmp3, - w_xtmp1, w_xtmp2, w_xtmp3, - tmp4, tmp5, - tmp6); - crc32c_proc_chunk(CRC32C_MIDDLE, const_or_pre_comp_const_index[2], const_or_pre_comp_const_index[3], is_pclmulqdq_supported, - in2, in1, in_out, - tmp1, tmp2, tmp3, - w_xtmp1, w_xtmp2, w_xtmp3, - tmp4, tmp5, - tmp6); - crc32c_proc_chunk(CRC32C_LOW, const_or_pre_comp_const_index[4], const_or_pre_comp_const_index[5], is_pclmulqdq_supported, - in2, in1, in_out, - tmp1, tmp2, tmp3, - w_xtmp1, w_xtmp2, w_xtmp3, - tmp4, tmp5, - tmp6); - movl(tmp1, in2); - andl(tmp1, 0x00000007); - negl(tmp1); - addl(tmp1, in2); - addl(tmp1, in1); - - BIND(L_wordByWord); - cmpl(in1, tmp1); - jcc(Assembler::greaterEqual, L_byteByByteProlog); - crc32(in_out, Address(in1,0), 4); - addl(in1, 4); - jmp(L_wordByWord); - - BIND(L_byteByByteProlog); - andl(in2, 0x00000007); - movl(tmp2, 1); - - BIND(L_byteByByte); - cmpl(tmp2, in2); - jccb(Assembler::greater, L_exit); - movb(tmp1, Address(in1, 0)); - crc32(in_out, tmp1, 1); - incl(in1); - incl(tmp2); - jmp(L_byteByByte); - - BIND(L_exit); -} -#endif // LP64 #undef BIND #undef BLOCK_COMMENT @@ -9923,7 +9153,6 @@ void MacroAssembler::fill64(Register dst, int disp, XMMRegister xmm, bool use64b fill64(Address(dst, disp), xmm, use64byteVector); } -#ifdef _LP64 void MacroAssembler::generate_fill_avx3(BasicType type, Register to, Register value, Register count, Register rtmp, XMMRegister xtmp) { Label L_exit; @@ -10100,11 +9329,9 @@ void MacroAssembler::generate_fill_avx3(BasicType type, Register to, Register va } bind(L_exit); } -#endif #endif //COMPILER2_OR_JVMCI -#ifdef _LP64 void MacroAssembler::convert_f2i(Register dst, XMMRegister src) { Label done; cvttss2sil(dst, src); @@ -10268,8 +9495,6 @@ void MacroAssembler::cache_wbsync(bool is_pre) } } -#endif // _LP64 - Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) { switch (cond) { // Note some conditions are synonyms for others @@ -10455,7 +9680,6 @@ void MacroAssembler::lightweight_unlock(Register obj, Register reg_rax, Register bind(unlocked); } -#ifdef _LP64 // Saves legacy GPRs state on stack. void MacroAssembler::save_legacy_gprs() { subq(rsp, 16 * wordSize); @@ -10504,4 +9728,3 @@ void MacroAssembler::setcc(Assembler::Condition comparison, Register dst) { movzbl(dst, dst); } } -#endif diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 5e26b79e8ae3f..bc25138f82151 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -140,10 +140,10 @@ class MacroAssembler: public Assembler { // Support for inc/dec with optimal instruction selection depending on value - void increment(Register reg, int value = 1) { LP64_ONLY(incrementq(reg, value)) NOT_LP64(incrementl(reg, value)) ; } - void decrement(Register reg, int value = 1) { LP64_ONLY(decrementq(reg, value)) NOT_LP64(decrementl(reg, value)) ; } - void increment(Address dst, int value = 1) { LP64_ONLY(incrementq(dst, value)) NOT_LP64(incrementl(dst, value)) ; } - void decrement(Address dst, int value = 1) { LP64_ONLY(decrementq(dst, value)) NOT_LP64(decrementl(dst, value)) ; } + void increment(Register reg, int value = 1) { incrementq(reg, value); } + void decrement(Register reg, int value = 1) { decrementq(reg, value); } + void increment(Address dst, int value = 1) { incrementq(dst, value); } + void decrement(Address dst, int value = 1) { decrementq(dst, value); } void decrementl(Address dst, int value = 1); void decrementl(Register reg, int value = 1); @@ -221,7 +221,6 @@ class MacroAssembler: public Assembler { // Normally, JavaThread pointer is available in r15_thread, use that where possible. void get_thread_slow(Register thread); -#ifdef _LP64 // Support for argument shuffling // bias in bytes @@ -237,7 +236,6 @@ class MacroAssembler: public Assembler { VMRegPair dst, bool is_receiver, int* receiver_offset); -#endif // _LP64 // Support for VM calls // @@ -351,9 +349,7 @@ class MacroAssembler: public Assembler { void load_method_holder(Register holder, Register method); // oop manipulations -#ifdef _LP64 void load_narrow_klass_compact(Register dst, Register src); -#endif void load_klass(Register dst, Register src, Register tmp); void store_klass(Register dst, Register src, Register tmp); @@ -379,7 +375,6 @@ class MacroAssembler: public Assembler { // stored using routines that take a jobject. void store_heap_oop_null(Address dst); -#ifdef _LP64 void store_klass_gap(Register dst, Register src); // This dummy is to prevent a call to store_heap_oop from @@ -414,8 +409,6 @@ class MacroAssembler: public Assembler { DEBUG_ONLY(void verify_heapbase(const char* msg);) -#endif // _LP64 - // Int division/remainder for Java // (as idivl, but checks for special case as described in JVM spec.) // returns idivl instruction offset for implicit exception handling @@ -582,7 +575,6 @@ class MacroAssembler: public Assembler { Label* L_failure, bool set_cond_codes = false); -#ifdef _LP64 // The 64-bit version, which may do a hashed subclass lookup. void check_klass_subtype_slow_path(Register sub_klass, Register super_klass, @@ -592,7 +584,6 @@ class MacroAssembler: public Assembler { Register temp4_reg, Label* L_success, Label* L_failure); -#endif // Three parts of a hashed subclass lookup: a simple linear search, // a table lookup, and a fallback that does linear probing in the @@ -629,7 +620,6 @@ class MacroAssembler: public Assembler { Register result, u1 super_klass_slot); -#ifdef _LP64 using Assembler::salq; void salq(Register dest, Register count); using Assembler::rorq; @@ -657,7 +647,6 @@ class MacroAssembler: public Assembler { Register temp1, Register temp2, Register temp3); -#endif void repne_scanq(Register addr, Register value, Register count, Register limit, Label* L_success, @@ -766,10 +755,10 @@ class MacroAssembler: public Assembler { // Arithmetics - void addptr(Address dst, int32_t src) { LP64_ONLY(addq(dst, src)) NOT_LP64(addl(dst, src)) ; } + void addptr(Address dst, int32_t src) { addq(dst, src); } void addptr(Address dst, Register src); - void addptr(Register dst, Address src) { LP64_ONLY(addq(dst, src)) NOT_LP64(addl(dst, src)); } + void addptr(Register dst, Address src) { addq(dst, src); } void addptr(Register dst, int32_t src); void addptr(Register dst, Register src); void addptr(Register dst, RegisterOrConstant src) { @@ -778,12 +767,10 @@ class MacroAssembler: public Assembler { } void andptr(Register dst, int32_t src); - void andptr(Register src1, Register src2) { LP64_ONLY(andq(src1, src2)) NOT_LP64(andl(src1, src2)) ; } + void andptr(Register src1, Register src2) { andq(src1, src2); } -#ifdef _LP64 using Assembler::andq; void andq(Register dst, AddressLiteral src, Register rscratch = noreg); -#endif void cmp8(AddressLiteral src1, int imm, Register rscratch = noreg); @@ -796,12 +783,6 @@ class MacroAssembler: public Assembler { void cmp32(Register src1, Address src2); -#ifndef _LP64 - void cmpklass(Address dst, Metadata* obj); - void cmpklass(Register dst, Metadata* obj); - void cmpoop(Address dst, jobject obj); -#endif // _LP64 - void cmpoop(Register src1, Register src2); void cmpoop(Register src1, Address src2); void cmpoop(Register dst, jobject obj, Register rscratch); @@ -811,12 +792,11 @@ class MacroAssembler: public Assembler { void cmpptr(Register src1, AddressLiteral src2, Register rscratch = noreg); - void cmpptr(Register src1, Register src2) { LP64_ONLY(cmpq(src1, src2)) NOT_LP64(cmpl(src1, src2)) ; } - void cmpptr(Register src1, Address src2) { LP64_ONLY(cmpq(src1, src2)) NOT_LP64(cmpl(src1, src2)) ; } - // void cmpptr(Address src1, Register src2) { LP64_ONLY(cmpq(src1, src2)) NOT_LP64(cmpl(src1, src2)) ; } + void cmpptr(Register src1, Register src2) { cmpq(src1, src2); } + void cmpptr(Register src1, Address src2) { cmpq(src1, src2); } - void cmpptr(Register src1, int32_t src2) { LP64_ONLY(cmpq(src1, src2)) NOT_LP64(cmpl(src1, src2)) ; } - void cmpptr(Address src1, int32_t src2) { LP64_ONLY(cmpq(src1, src2)) NOT_LP64(cmpl(src1, src2)) ; } + void cmpptr(Register src1, int32_t src2) { cmpq(src1, src2); } + void cmpptr(Address src1, int32_t src2) { cmpq(src1, src2); } // cmp64 to avoild hiding cmpq void cmp64(Register src1, AddressLiteral src, Register rscratch = noreg); @@ -825,26 +805,26 @@ class MacroAssembler: public Assembler { void locked_cmpxchgptr(Register reg, AddressLiteral adr, Register rscratch = noreg); - void imulptr(Register dst, Register src) { LP64_ONLY(imulq(dst, src)) NOT_LP64(imull(dst, src)); } - void imulptr(Register dst, Register src, int imm32) { LP64_ONLY(imulq(dst, src, imm32)) NOT_LP64(imull(dst, src, imm32)); } + void imulptr(Register dst, Register src) { imulq(dst, src); } + void imulptr(Register dst, Register src, int imm32) { imulq(dst, src, imm32); } - void negptr(Register dst) { LP64_ONLY(negq(dst)) NOT_LP64(negl(dst)); } + void negptr(Register dst) { negq(dst); } - void notptr(Register dst) { LP64_ONLY(notq(dst)) NOT_LP64(notl(dst)); } + void notptr(Register dst) { notq(dst); } void shlptr(Register dst, int32_t shift); - void shlptr(Register dst) { LP64_ONLY(shlq(dst)) NOT_LP64(shll(dst)); } + void shlptr(Register dst) { shlq(dst); } void shrptr(Register dst, int32_t shift); - void shrptr(Register dst) { LP64_ONLY(shrq(dst)) NOT_LP64(shrl(dst)); } + void shrptr(Register dst) { shrq(dst); } - void sarptr(Register dst) { LP64_ONLY(sarq(dst)) NOT_LP64(sarl(dst)); } - void sarptr(Register dst, int32_t src) { LP64_ONLY(sarq(dst, src)) NOT_LP64(sarl(dst, src)); } + void sarptr(Register dst) { sarq(dst); } + void sarptr(Register dst, int32_t src) { sarq(dst, src); } - void subptr(Address dst, int32_t src) { LP64_ONLY(subq(dst, src)) NOT_LP64(subl(dst, src)); } + void subptr(Address dst, int32_t src) { subq(dst, src); } - void subptr(Register dst, Address src) { LP64_ONLY(subq(dst, src)) NOT_LP64(subl(dst, src)); } + void subptr(Register dst, Address src) { subq(dst, src); } void subptr(Register dst, int32_t src); // Force generation of a 4 byte immediate value even if it fits into 8bit void subptr_imm32(Register dst, int32_t src); @@ -854,13 +834,13 @@ class MacroAssembler: public Assembler { else subptr(dst, src.as_register()); } - void sbbptr(Address dst, int32_t src) { LP64_ONLY(sbbq(dst, src)) NOT_LP64(sbbl(dst, src)); } - void sbbptr(Register dst, int32_t src) { LP64_ONLY(sbbq(dst, src)) NOT_LP64(sbbl(dst, src)); } + void sbbptr(Address dst, int32_t src) { sbbq(dst, src); } + void sbbptr(Register dst, int32_t src) { sbbq(dst, src); } - void xchgptr(Register src1, Register src2) { LP64_ONLY(xchgq(src1, src2)) NOT_LP64(xchgl(src1, src2)) ; } - void xchgptr(Register src1, Address src2) { LP64_ONLY(xchgq(src1, src2)) NOT_LP64(xchgl(src1, src2)) ; } + void xchgptr(Register src1, Register src2) { xchgq(src1, src2); } + void xchgptr(Register src1, Address src2) { xchgq(src1, src2); } - void xaddptr(Address src1, Register src2) { LP64_ONLY(xaddq(src1, src2)) NOT_LP64(xaddl(src1, src2)) ; } + void xaddptr(Address src1, Register src2) { xaddq(src1, src2); } @@ -870,12 +850,10 @@ class MacroAssembler: public Assembler { // Unconditional atomic increment. void atomic_incl(Address counter_addr); void atomic_incl(AddressLiteral counter_addr, Register rscratch = noreg); -#ifdef _LP64 void atomic_incq(Address counter_addr); void atomic_incq(AddressLiteral counter_addr, Register rscratch = noreg); -#endif - void atomic_incptr(AddressLiteral counter_addr, Register rscratch = noreg) { LP64_ONLY(atomic_incq(counter_addr, rscratch)) NOT_LP64(atomic_incl(counter_addr, rscratch)) ; } - void atomic_incptr(Address counter_addr) { LP64_ONLY(atomic_incq(counter_addr)) NOT_LP64(atomic_incl(counter_addr)) ; } + void atomic_incptr(AddressLiteral counter_addr, Register rscratch = noreg) { atomic_incq(counter_addr, rscratch); } + void atomic_incptr(Address counter_addr) { atomic_incq(counter_addr); } using Assembler::lea; void lea(Register dst, AddressLiteral adr); @@ -893,18 +871,18 @@ class MacroAssembler: public Assembler { void testq(Address dst, int32_t imm32); void testq(Register dst, int32_t imm32); - void orptr(Register dst, Address src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); } - void orptr(Register dst, Register src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); } - void orptr(Register dst, int32_t src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); } - void orptr(Address dst, int32_t imm32) { LP64_ONLY(orq(dst, imm32)) NOT_LP64(orl(dst, imm32)); } + void orptr(Register dst, Address src) { orq(dst, src); } + void orptr(Register dst, Register src) { orq(dst, src); } + void orptr(Register dst, int32_t src) { orq(dst, src); } + void orptr(Address dst, int32_t imm32) { orq(dst, imm32); } - void testptr(Register src, int32_t imm32) { LP64_ONLY(testq(src, imm32)) NOT_LP64(testl(src, imm32)); } - void testptr(Register src1, Address src2) { LP64_ONLY(testq(src1, src2)) NOT_LP64(testl(src1, src2)); } - void testptr(Address src, int32_t imm32) { LP64_ONLY(testq(src, imm32)) NOT_LP64(testl(src, imm32)); } + void testptr(Register src, int32_t imm32) { testq(src, imm32); } + void testptr(Register src1, Address src2) { testq(src1, src2); } + void testptr(Address src, int32_t imm32) { testq(src, imm32); } void testptr(Register src1, Register src2); - void xorptr(Register dst, Register src) { LP64_ONLY(xorq(dst, src)) NOT_LP64(xorl(dst, src)); } - void xorptr(Register dst, Address src) { LP64_ONLY(xorq(dst, src)) NOT_LP64(xorl(dst, src)); } + void xorptr(Register dst, Register src) { xorq(dst, src); } + void xorptr(Register dst, Address src) { xorq(dst, src); } // Calls @@ -1033,7 +1011,6 @@ class MacroAssembler: public Assembler { void ldmxcsr(Address src) { Assembler::ldmxcsr(src); } void ldmxcsr(AddressLiteral src, Register rscratch = noreg); -#ifdef _LP64 private: void sha256_AVX2_one_round_compute( Register reg_old_h, @@ -1083,7 +1060,6 @@ class MacroAssembler: public Assembler { Register buf, Register state, Register ofs, Register limit, Register rsp, bool multi_block, XMMRegister shuf_mask); void sha512_update_ni_x1(Register arg_hash, Register arg_msg, Register ofs, Register limit, bool multi_block); -#endif // _LP64 void fast_md5(Register buf, Address state, Address ofs, Address limit, bool multi_block); @@ -1093,68 +1069,15 @@ class MacroAssembler: public Assembler { Register buf, Register state, Register ofs, Register limit, Register rsp, bool multi_block); -#ifdef _LP64 void fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegister state1, XMMRegister msgtmp0, XMMRegister msgtmp1, XMMRegister msgtmp2, XMMRegister msgtmp3, XMMRegister msgtmp4, Register buf, Register state, Register ofs, Register limit, Register rsp, bool multi_block, XMMRegister shuf_mask); -#else - void fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegister state1, XMMRegister msgtmp0, - XMMRegister msgtmp1, XMMRegister msgtmp2, XMMRegister msgtmp3, XMMRegister msgtmp4, - Register buf, Register state, Register ofs, Register limit, Register rsp, - bool multi_block); -#endif void fast_exp(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, Register rax, Register rcx, Register rdx, Register tmp); -#ifndef _LP64 - private: - // Initialized in macroAssembler_x86_constants.cpp - static address ONES; - static address L_2IL0FLOATPACKET_0; - static address PI4_INV; - static address PI4X3; - static address PI4X4; - - public: - void fast_log(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, - XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, - Register rax, Register rcx, Register rdx, Register tmp1); - - void fast_log10(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, - XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, - Register rax, Register rcx, Register rdx, Register tmp); - - void fast_pow(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, XMMRegister xmm4, - XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, Register rax, Register rcx, - Register rdx, Register tmp); - - void fast_sin(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, - XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, - Register rax, Register rbx, Register rdx); - - void fast_cos(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, - XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, - Register rax, Register rcx, Register rdx, Register tmp); - - void libm_sincos_huge(XMMRegister xmm0, XMMRegister xmm1, Register eax, Register ecx, - Register edx, Register ebx, Register esi, Register edi, - Register ebp, Register esp); - - void libm_reduce_pi04l(Register eax, Register ecx, Register edx, Register ebx, - Register esi, Register edi, Register ebp, Register esp); - - void libm_tancot_huge(XMMRegister xmm0, XMMRegister xmm1, Register eax, Register ecx, - Register edx, Register ebx, Register esi, Register edi, - Register ebp, Register esp); - - void fast_tan(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, - XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, - Register rax, Register rcx, Register rdx, Register tmp); -#endif // !_LP64 - private: // these are private because users should be doing movflt/movdbl @@ -1921,8 +1844,8 @@ class MacroAssembler: public Assembler { void cmov( Condition cc, Register dst, Register src) { cmovptr(cc, dst, src); } - void cmovptr(Condition cc, Register dst, Address src) { LP64_ONLY(cmovq(cc, dst, src)) NOT_LP64(cmov32(cc, dst, src)); } - void cmovptr(Condition cc, Register dst, Register src) { LP64_ONLY(cmovq(cc, dst, src)) NOT_LP64(cmov32(cc, dst, src)); } + void cmovptr(Condition cc, Register dst, Address src) { cmovq(cc, dst, src); } + void cmovptr(Condition cc, Register dst, Register src) { cmovq(cc, dst, src); } void movoop(Register dst, jobject obj); void movoop(Address dst, jobject obj, Register rscratch); @@ -1961,15 +1884,15 @@ class MacroAssembler: public Assembler { // Can push value or effective address void pushptr(AddressLiteral src, Register rscratch); - void pushptr(Address src) { LP64_ONLY(pushq(src)) NOT_LP64(pushl(src)); } - void popptr(Address src) { LP64_ONLY(popq(src)) NOT_LP64(popl(src)); } + void pushptr(Address src) { pushq(src); } + void popptr(Address src) { popq(src); } void pushoop(jobject obj, Register rscratch); void pushklass(Metadata* obj, Register rscratch); // sign extend as need a l to ptr sized element - void movl2ptr(Register dst, Address src) { LP64_ONLY(movslq(dst, src)) NOT_LP64(movl(dst, src)); } - void movl2ptr(Register dst, Register src) { LP64_ONLY(movslq(dst, src)) NOT_LP64(if (dst != src) movl(dst, src)); } + void movl2ptr(Register dst, Address src) { movslq(dst, src); } + void movl2ptr(Register dst, Register src) { movslq(dst, src); } public: @@ -1992,7 +1915,6 @@ class MacroAssembler: public Assembler { XMMRegister tmp1, XMMRegister tmp2, XMMRegister tmp3, XMMRegister tmp4, Register tmp5, Register result, bool ascii); -#ifdef _LP64 void add2_with_carry(Register dest_hi, Register dest_lo, Register src1, Register src2); void multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart, Register y, Register y_idx, Register z, @@ -2033,32 +1955,22 @@ class MacroAssembler: public Assembler { void vectorized_mismatch(Register obja, Register objb, Register length, Register log2_array_indxscale, Register result, Register tmp1, Register tmp2, XMMRegister vec1, XMMRegister vec2, XMMRegister vec3); -#endif // CRC32 code for java.util.zip.CRC32::updateBytes() intrinsic. void update_byte_crc32(Register crc, Register val, Register table); void kernel_crc32(Register crc, Register buf, Register len, Register table, Register tmp); - -#ifdef _LP64 void kernel_crc32_avx512(Register crc, Register buf, Register len, Register table, Register tmp1, Register tmp2); void kernel_crc32_avx512_256B(Register crc, Register buf, Register len, Register key, Register pos, Register tmp1, Register tmp2, Label& L_barrett, Label& L_16B_reduction_loop, Label& L_get_last_two_xmms, Label& L_128_done, Label& L_cleanup); -#endif // _LP64 // CRC32C code for java.util.zip.CRC32C::updateBytes() intrinsic // Note on a naming convention: // Prefix w = register only used on a Westmere+ architecture // Prefix n = register only used on a Nehalem architecture -#ifdef _LP64 void crc32c_ipl_alg4(Register in_out, uint32_t n, Register tmp1, Register tmp2, Register tmp3); -#else - void crc32c_ipl_alg4(Register in_out, uint32_t n, - Register tmp1, Register tmp2, Register tmp3, - XMMRegister xtmp1, XMMRegister xtmp2); -#endif void crc32c_pclmulqdq(XMMRegister w_xtmp1, Register in_out, uint32_t const_or_pre_comp_const_index, bool is_pclmulqdq_supported, @@ -2083,10 +1995,8 @@ class MacroAssembler: public Assembler { // Fold 128-bit data chunk void fold_128bit_crc32(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, Register buf, int offset); void fold_128bit_crc32(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, XMMRegister xbuf); -#ifdef _LP64 // Fold 512-bit data chunk void fold512bit_crc32_avx512(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, Register buf, Register pos, int offset); -#endif // _LP64 // Fold 8-bit data void fold_8bit_crc32(Register crc, Register table, Register tmp); void fold_8bit_crc32(XMMRegister crc, Register table, XMMRegister xtmp, Register tmp); @@ -2120,7 +2030,6 @@ class MacroAssembler: public Assembler { void fill64(Register dst, int dis, XMMRegister xmm, bool use64byteVector = false); -#ifdef _LP64 void convert_f2i(Register dst, XMMRegister src); void convert_d2i(Register dst, XMMRegister src); void convert_f2l(Register dst, XMMRegister src); @@ -2135,7 +2044,6 @@ class MacroAssembler: public Assembler { void generate_fill_avx3(BasicType type, Register to, Register value, Register count, Register rtmp, XMMRegister xtmp); #endif // COMPILER2_OR_JVMCI -#endif // _LP64 void vallones(XMMRegister dst, int vector_len); @@ -2144,11 +2052,9 @@ class MacroAssembler: public Assembler { void lightweight_lock(Register basic_lock, Register obj, Register reg_rax, Register tmp, Label& slow); void lightweight_unlock(Register obj, Register reg_rax, Register tmp, Label& slow); -#ifdef _LP64 void save_legacy_gprs(); void restore_legacy_gprs(); void setcc(Assembler::Condition comparison, Register dst); -#endif }; #endif // CPU_X86_MACROASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp b/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp index e2753b701da97..432f927754904 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp @@ -235,17 +235,10 @@ void MacroAssembler::fast_sha1(XMMRegister abcd, XMMRegister e0, XMMRegister e1, // and state0 and state1 can never use xmm0 register. // ofs and limit are used for multi-block byte array. // int com.sun.security.provider.DigestBase.implCompressMultiBlock(byte[] b, int ofs, int limit) -#ifdef _LP64 void MacroAssembler::fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegister state1, XMMRegister msgtmp0, XMMRegister msgtmp1, XMMRegister msgtmp2, XMMRegister msgtmp3, XMMRegister msgtmp4, Register buf, Register state, Register ofs, Register limit, Register rsp, bool multi_block, XMMRegister shuf_mask) { -#else -void MacroAssembler::fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegister state1, XMMRegister msgtmp0, - XMMRegister msgtmp1, XMMRegister msgtmp2, XMMRegister msgtmp3, XMMRegister msgtmp4, - Register buf, Register state, Register ofs, Register limit, Register rsp, - bool multi_block) { -#endif Label done_hash, loop0; address K256 = StubRoutines::x86::k256_addr(); @@ -260,9 +253,7 @@ void MacroAssembler::fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegiste palignr(state0, state1, 8); pblendw(state1, msgtmp4, 0xF0); -#ifdef _LP64 movdqu(shuf_mask, ExternalAddress(pshuffle_byte_flip_mask)); -#endif lea(rax, ExternalAddress(K256)); bind(loop0); @@ -271,11 +262,7 @@ void MacroAssembler::fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegiste // Rounds 0-3 movdqu(msg, Address(buf, 0)); -#ifdef _LP64 pshufb(msg, shuf_mask); -#else - pshufb(msg, ExternalAddress(pshuffle_byte_flip_mask)); -#endif movdqa(msgtmp0, msg); paddd(msg, Address(rax, 0)); sha256rnds2(state1, state0); @@ -284,11 +271,7 @@ void MacroAssembler::fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegiste // Rounds 4-7 movdqu(msg, Address(buf, 16)); -#ifdef _LP64 pshufb(msg, shuf_mask); -#else - pshufb(msg, ExternalAddress(pshuffle_byte_flip_mask)); -#endif movdqa(msgtmp1, msg); paddd(msg, Address(rax, 16)); sha256rnds2(state1, state0); @@ -298,11 +281,7 @@ void MacroAssembler::fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegiste // Rounds 8-11 movdqu(msg, Address(buf, 32)); -#ifdef _LP64 pshufb(msg, shuf_mask); -#else - pshufb(msg, ExternalAddress(pshuffle_byte_flip_mask)); -#endif movdqa(msgtmp2, msg); paddd(msg, Address(rax, 32)); sha256rnds2(state1, state0); @@ -312,11 +291,7 @@ void MacroAssembler::fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegiste // Rounds 12-15 movdqu(msg, Address(buf, 48)); -#ifdef _LP64 pshufb(msg, shuf_mask); -#else - pshufb(msg, ExternalAddress(pshuffle_byte_flip_mask)); -#endif movdqa(msgtmp3, msg); paddd(msg, Address(rax, 48)); sha256rnds2(state1, state0); @@ -491,7 +466,6 @@ void MacroAssembler::fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegiste } -#ifdef _LP64 /* The algorithm below is based on Intel publication: "Fast SHA-256 Implementations on Intel(R) Architecture Processors" by Jim Guilford, Kirk Yap and Vinodh Gopal. @@ -1696,5 +1670,3 @@ void MacroAssembler::sha512_update_ni_x1(Register arg_hash, Register arg_msg, Re bind(done_hash); } - -#endif //#ifdef _LP64 diff --git a/test/hotspot/gtest/x86/test_assemblerx86.cpp b/test/hotspot/gtest/x86/test_assembler_x86.cpp similarity index 99% rename from test/hotspot/gtest/x86/test_assemblerx86.cpp rename to test/hotspot/gtest/x86/test_assembler_x86.cpp index eee9fc714886a..32315e06fdec7 100644 --- a/test/hotspot/gtest/x86/test_assemblerx86.cpp +++ b/test/hotspot/gtest/x86/test_assembler_x86.cpp @@ -30,6 +30,7 @@ #include "asm/assembler.hpp" #include "asm/assembler.inline.hpp" #include "asm/macroAssembler.hpp" +#include "code/codeCache.hpp" #include "memory/resourceArea.hpp" #include "unittest.hpp" From 43b2b0bd1e5e6fad4581957a3072836921ef6683 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Mon, 2 Dec 2024 05:21:55 +0000 Subject: [PATCH 0600/1101] 8343007: Enhance Buffered Image handling Reviewed-by: rhalade, mschoene, jdv, prr --- .../share/native/libawt/java2d/loops/Blit.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/java.desktop/share/native/libawt/java2d/loops/Blit.c b/src/java.desktop/share/native/libawt/java2d/loops/Blit.c index fee108b833a4d..8a41584deefe8 100644 --- a/src/java.desktop/share/native/libawt/java2d/loops/Blit.c +++ b/src/java.desktop/share/native/libawt/java2d/loops/Blit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -68,14 +68,30 @@ Java_sun_java2d_loops_Blit_Blit return; } + if (width <= 0 || height <= 0) { + return; + } + srcInfo.bounds.x1 = srcx; srcInfo.bounds.y1 = srcy; + if (UNSAFE_TO_ADD(srcx, width) || + UNSAFE_TO_ADD(srcy, height) || + UNSAFE_TO_ADD(dstx, width) || + UNSAFE_TO_ADD(dsty, height)) { + return; + } + srcInfo.bounds.x2 = srcx + width; srcInfo.bounds.y2 = srcy + height; dstInfo.bounds.x1 = dstx; dstInfo.bounds.y1 = dsty; dstInfo.bounds.x2 = dstx + width; dstInfo.bounds.y2 = dsty + height; + if (UNSAFE_TO_SUB(srcx, dstx) || + UNSAFE_TO_SUB(srcy, dsty)) { + return; + } + srcx -= dstx; srcy -= dsty; SurfaceData_IntersectBounds(&dstInfo.bounds, &clipInfo.bounds); From cf871db447660e657a3db82bffae8fce1b7e57a5 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Fri, 13 Dec 2024 04:29:18 +0000 Subject: [PATCH 0601/1101] 8342562: Enhance Deflater operations Reviewed-by: rhalade, alanb, lancea --- .../java/util/zip/DeflaterOutputStream.java | 40 +++++++++++++++---- .../java/util/zip/GZIPOutputStream.java | 4 +- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java b/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java index 3fca6a1b75981..85ba968dc9b69 100644 --- a/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java @@ -57,6 +57,26 @@ * @since 1.1 */ public class DeflaterOutputStream extends FilterOutputStream { + + /* + * The default size of the output buffer + */ + static final int DEFAULT_BUF_SIZE = 512; + + /* + * When calling Deflater.deflate() with Deflater.SYNC_FLUSH or Deflater.FULL_FLUSH, + * the callers are expected to ensure that the size of the buffer is greater than 6. + * This expectation comes from the underlying zlib library which in its zlib.h + * states: + * "If deflate returns with avail_out == 0, this function must be called again + * with the same value of the flush parameter and more output space (updated + * avail_out), until the flush is complete (deflate returns with non-zero + * avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + * avail_out is greater than six when the flush marker begins, in order to avoid + * repeated flush markers upon calling deflate() again when avail_out == 0." + */ + private static final int SYNC_FLUSH_MIN_BUF_SIZE = 7; + /** * Compressor for this stream. */ @@ -152,7 +172,7 @@ public DeflaterOutputStream(OutputStream out, Deflater def, int size) { public DeflaterOutputStream(OutputStream out, Deflater def, boolean syncFlush) { - this(out, def, 512, syncFlush); + this(out, def, DEFAULT_BUF_SIZE, syncFlush); } @@ -171,7 +191,7 @@ public DeflaterOutputStream(OutputStream out, * @param def the compressor ("deflater") */ public DeflaterOutputStream(OutputStream out, Deflater def) { - this(out, def, 512, false); + this(out, def, DEFAULT_BUF_SIZE, false); } boolean usesDefaultDeflater = false; @@ -195,7 +215,7 @@ public DeflaterOutputStream(OutputStream out, Deflater def) { * @since 1.7 */ public DeflaterOutputStream(OutputStream out, boolean syncFlush) { - this(out, out != null ? new Deflater() : null, 512, syncFlush); + this(out, out != null ? new Deflater() : null, DEFAULT_BUF_SIZE, syncFlush); usesDefaultDeflater = true; } @@ -342,10 +362,16 @@ protected void deflate() throws IOException { public void flush() throws IOException { if (syncFlush && !def.finished()) { int len = 0; - while ((len = def.deflate(buf, 0, buf.length, Deflater.SYNC_FLUSH)) > 0) - { - out.write(buf, 0, len); - if (len < buf.length) + // For SYNC_FLUSH, the Deflater.deflate() expects the callers + // to use a buffer whose length is greater than 6 to avoid + // flush marker (5 bytes) being repeatedly output to the output buffer + // every time it is invoked. + final byte[] flushBuf = buf.length < SYNC_FLUSH_MIN_BUF_SIZE + ? new byte[DEFAULT_BUF_SIZE] + : buf; + while ((len = def.deflate(flushBuf, 0, flushBuf.length, Deflater.SYNC_FLUSH)) > 0) { + out.write(flushBuf, 0, len); + if (len < flushBuf.length) break; } } diff --git a/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java b/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java index cea0880fca62f..12abd53350f2f 100644 --- a/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java @@ -113,7 +113,7 @@ public GZIPOutputStream(OutputStream out, int size, boolean syncFlush) * @throws IOException If an I/O error has occurred. */ public GZIPOutputStream(OutputStream out) throws IOException { - this(out, 512, false); + this(out, DeflaterOutputStream.DEFAULT_BUF_SIZE, false); } /** @@ -135,7 +135,7 @@ public GZIPOutputStream(OutputStream out) throws IOException { public GZIPOutputStream(OutputStream out, boolean syncFlush) throws IOException { - this(out, 512, syncFlush); + this(out, DeflaterOutputStream.DEFAULT_BUF_SIZE, syncFlush); } /** From ef38a04b448f97036c516ba87cb86afcc7559d1f Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Thu, 2 Jan 2025 19:03:53 +0000 Subject: [PATCH 0602/1101] 8337494: Clarify JarInputStream behavior Reviewed-by: jpai, rhalade, lancea --- .../share/classes/java/util/jar/JarFile.java | 3 ++- .../share/classes/java/util/jar/JarInputStream.java | 12 +++++++++++- .../share/classes/java/util/jar/JarVerifier.java | 5 ++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/util/jar/JarFile.java b/src/java.base/share/classes/java/util/jar/JarFile.java index e7725c8636f38..dc2d65bcc99c0 100644 --- a/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/src/java.base/share/classes/java/util/jar/JarFile.java @@ -409,7 +409,8 @@ private Manifest getManifestFromReference() throws IOException { jv = new JarVerifier(manEntry.getName(), b); } else { if (JarVerifier.debug != null) { - JarVerifier.debug.println("Multiple MANIFEST.MF found. Treat JAR file as unsigned"); + JarVerifier.debug.println( + JarVerifier.MULTIPLE_MANIFEST_WARNING); } } } diff --git a/src/java.base/share/classes/java/util/jar/JarInputStream.java b/src/java.base/share/classes/java/util/jar/JarInputStream.java index e4ffd09fb1e59..5c29d74f92a1e 100644 --- a/src/java.base/share/classes/java/util/jar/JarInputStream.java +++ b/src/java.base/share/classes/java/util/jar/JarInputStream.java @@ -151,7 +151,17 @@ private JarEntry checkManifest(JarEntry e) jv = new JarVerifier(e.getName(), bytes); mev = new ManifestEntryVerifier(man, jv.manifestName); } - return (JarEntry)super.getNextEntry(); + JarEntry nextEntry = (JarEntry)super.getNextEntry(); + if (nextEntry != null && + JarFile.MANIFEST_NAME.equalsIgnoreCase(nextEntry.getName())) { + if (JarVerifier.debug != null) { + JarVerifier.debug.println(JarVerifier.MULTIPLE_MANIFEST_WARNING); + } + + jv = null; + mev = null; + } + return nextEntry; } return e; } diff --git a/src/java.base/share/classes/java/util/jar/JarVerifier.java b/src/java.base/share/classes/java/util/jar/JarVerifier.java index 92cb09448b876..fe58c4dffecce 100644 --- a/src/java.base/share/classes/java/util/jar/JarVerifier.java +++ b/src/java.base/share/classes/java/util/jar/JarVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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,6 +46,9 @@ */ class JarVerifier { + public static final String MULTIPLE_MANIFEST_WARNING = + "WARNING: Multiple MANIFEST.MF found. Treat JAR file as unsigned."; + /* Are we debugging ? */ static final Debug debug = Debug.getInstance("jar"); From e91b3f0c3dddba1ed1e5f2fa87f9cd9d135b4439 Mon Sep 17 00:00:00 2001 From: Jamil Nimeh Date: Wed, 8 Jan 2025 20:39:38 +0000 Subject: [PATCH 0603/1101] 8337692: Better TLS connection support Co-authored-by: Ferenc Rakoczi Reviewed-by: rhalade, valeriep, pkumaraswamy, mpowers, ahgross, mbalao --- .../com/sun/crypto/provider/RSACipher.java | 67 +++++++---- .../classes/sun/security/rsa/RSAPadding.java | 109 +++++++++++++----- .../classes/sun/security/util/KeyUtil.java | 32 +++-- 3 files changed, 150 insertions(+), 58 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java index b48917e755713..9f19e1415bda4 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java @@ -236,7 +236,8 @@ protected void engineInit(int opmode, Key key, params.getParameterSpec(OAEPParameterSpec.class); init(opmode, key, random, spec); } catch (InvalidParameterSpecException ipse) { - throw new InvalidAlgorithmParameterException("Wrong parameter", ipse); + throw new InvalidAlgorithmParameterException("Wrong parameter", + ipse); } } } @@ -380,7 +381,7 @@ private byte[] doFinal() throws BadPaddingException, byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs); paddingCopy = RSACore.rsa(decryptBuffer, privateKey, false); result = padding.unpad(paddingCopy); - if (result == null && !forTlsPremasterSecret) { + if (!forTlsPremasterSecret && result == null) { throw new BadPaddingException ("Padding error in decryption"); } @@ -400,6 +401,34 @@ private byte[] doFinal() throws BadPaddingException, } } + // TLS master secret decode version of the doFinal() method. + private byte[] doFinalForTls(int clientVersion, int serverVersion) + throws BadPaddingException, IllegalBlockSizeException { + if (bufOfs > buffer.length) { + throw new IllegalBlockSizeException("Data must not be longer " + + "than " + buffer.length + " bytes"); + } + byte[] paddingCopy = null; + byte[] result = null; + try { + byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs); + + paddingCopy = RSACore.rsa(decryptBuffer, privateKey, false); + result = padding.unpadForTls(paddingCopy, clientVersion, + serverVersion); + + return result; + } finally { + Arrays.fill(buffer, 0, bufOfs, (byte)0); + bufOfs = 0; + if (paddingCopy != null + && paddingCopy != buffer // already cleaned + && paddingCopy != result) { // DO NOT CLEAN, THIS IS RESULT + Arrays.fill(paddingCopy, (byte)0); + } + } + } + // see JCE spec protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { update(in, inOfs, inLen); @@ -469,41 +498,37 @@ protected Key engineUnwrap(byte[] wrappedKey, String algorithm, boolean isTlsRsaPremasterSecret = algorithm.equals("TlsRsaPremasterSecret"); - byte[] encoded; + byte[] encoded = null; update(wrappedKey, 0, wrappedKey.length); - try { - encoded = doFinal(); - } catch (BadPaddingException | IllegalBlockSizeException e) { - // BadPaddingException cannot happen for TLS RSA unwrap. - // In that case, padding error is indicated by returning null. - // IllegalBlockSizeException cannot happen in any case, - // because of the length check above. - throw new InvalidKeyException("Unwrapping failed", e); - } - try { if (isTlsRsaPremasterSecret) { if (!forTlsPremasterSecret) { throw new IllegalStateException( "No TlsRsaPremasterSecretParameterSpec specified"); } - - // polish the TLS premaster secret - encoded = KeyUtil.checkTlsPreMasterSecretKey( - ((TlsRsaPremasterSecretParameterSpec) spec).getClientVersion(), - ((TlsRsaPremasterSecretParameterSpec) spec).getServerVersion(), - random, encoded, encoded == null); + TlsRsaPremasterSecretParameterSpec parameterSpec = + (TlsRsaPremasterSecretParameterSpec) spec; + encoded = doFinalForTls(parameterSpec.getClientVersion(), + parameterSpec.getServerVersion()); + } else { + encoded = doFinal(); } - return ConstructKeys.constructKey(encoded, algorithm, type); + + } catch (BadPaddingException | IllegalBlockSizeException e) { + // BadPaddingException cannot happen for TLS RSA unwrap. + // Neither padding error nor server version error is indicated + // for TLS, but a fake unwrapped value is returned. + // IllegalBlockSizeException cannot happen in any case, + // because of the length check above. + throw new InvalidKeyException("Unwrapping failed", e); } finally { if (encoded != null) { Arrays.fill(encoded, (byte) 0); } } } - // see JCE spec protected int engineGetKeySize(Key key) throws InvalidKeyException { RSAKey rsaKey = RSAKeyFactory.toRSAKey(key); diff --git a/src/java.base/share/classes/sun/security/rsa/RSAPadding.java b/src/java.base/share/classes/sun/security/rsa/RSAPadding.java index 3fd6aa537ec7f..919c734eaca20 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAPadding.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAPadding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, 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 @@ -321,48 +321,103 @@ private byte[] padV15(byte[] data, int ofs, int len) { * Note that we want to make it a constant-time operation */ private byte[] unpadV15(byte[] padded) { - int k = 0; - boolean bp = false; + int paddedLength = padded.length; - if (padded[k++] != 0) { - bp = true; - } - if (padded[k++] != type) { - bp = true; + if (paddedLength < 2) { + return null; } - int p = 0; - while (k < padded.length) { + + // The following check ensures that the lead byte is zero and + // the second byte is equivalent to the padding type. The + // bp (bad padding) variable throughout this unpadding process will + // be updated and remain 0 if good padding, 1 if bad. + int p0 = padded[0]; + int p1 = padded[1]; + int bp = (-(p0 & 0xff) | ((p1 - type) | (type - p1))) >>> 31; + + int padLen = 0; + int k = 2; + // Walk through the random, nonzero padding bytes. For each padding + // byte bp and padLen will remain zero. When the end-of-padding + // byte (0x00) is reached then padLen will be set to the index of the + // first byte of the message content. + while (k < paddedLength) { int b = padded[k++] & 0xff; - if ((b == 0) && (p == 0)) { - p = k; - } - if ((k == padded.length) && (p == 0)) { - bp = true; - } - if ((type == PAD_BLOCKTYPE_1) && (b != 0xff) && - (p == 0)) { - bp = true; + padLen += (k * (1 - ((-(b | padLen)) >>> 31))); + if (k == paddedLength) { + bp = bp | (1 - ((-padLen) >>> 31)); } + bp = bp | (1 - (-(((type - PAD_BLOCKTYPE_1) & 0xff) | + padLen | (1 - ((b - 0xff) >>> 31))) >>> 31)); } - int n = padded.length - p; - if (n > maxDataSize) { - bp = true; - } + int n = paddedLength - padLen; + // So long as n <= maxDataSize, bp will remain zero + bp = bp | ((maxDataSize - n) >>> 31); // copy useless padding array for a constant-time method - byte[] padding = new byte[p]; - System.arraycopy(padded, 0, padding, 0, p); + byte[] padding = new byte[padLen + 2]; + for (int i = 0; i < padLen; i++) { + padding[i] = padded[i]; + } byte[] data = new byte[n]; - System.arraycopy(padded, p, data, 0, n); + for (int i = 0; i < n; i++) { + data[i] = padded[padLen + i]; + } - if (bp) { + if ((bp | padding[bp]) != 0) { + // using the array padding here hoping that this way + // the compiler does not eliminate the above useless copy return null; } else { return data; } } + public byte[] unpadForTls(byte[] padded, int clientVersion, + int serverVersion) { + int paddedLength = padded.length; + + // bp is positive if the padding is bad and 0 if it is good so far + int bp = (((int) padded[0] | ((int)padded[1] - PAD_BLOCKTYPE_2)) & + 0xFFF); + + int k = 2; + while (k < paddedLength - 49) { + int b = padded[k++] & 0xFF; + bp = bp | (1 - (-b >>> 31)); // if (padded[k] == 0) bp |= 1; + } + bp |= ((int)padded[k++] & 0xFF); + int encodedVersion = ((padded[k] & 0xFF) << 8) | (padded[k + 1] & 0xFF); + + int bv1 = clientVersion - encodedVersion; + bv1 |= -bv1; + int bv3 = serverVersion - encodedVersion; + bv3 |= -bv3; + int bv2 = (0x301 - clientVersion); + + bp |= ((bv1 & (bv2 | bv3)) >>> 28); + + byte[] data = Arrays.copyOfRange(padded, paddedLength - 48, + paddedLength); + if (random == null) { + random = JCAUtil.getSecureRandom(); + } + + byte[] fake = new byte[48]; + random.nextBytes(fake); + + bp = (-bp >> 24); + + // Now bp is 0 if the padding and version number were good and + // -1 otherwise. + for (int i = 0; i < 48; i++) { + data[i] = (byte)((~bp & data[i]) | (bp & fake[i])); + } + + return data; + } + /** * PKCS#1 v2.0 OAEP padding (MGF1). * Paragraph references refer to PKCS#1 v2.1 (June 14, 2002) diff --git a/src/java.base/share/classes/sun/security/util/KeyUtil.java b/src/java.base/share/classes/sun/security/util/KeyUtil.java index 2c9416c09831f..95223ec0b127c 100644 --- a/src/java.base/share/classes/sun/security/util/KeyUtil.java +++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java @@ -320,19 +320,31 @@ public static byte[] checkTlsPreMasterSecretKey( tmp = encoded; } + // At this point tmp.length is 48 int encodedVersion = ((tmp[0] & 0xFF) << 8) | (tmp[1] & 0xFF); - int check1 = 0; - int check2 = 0; - int check3 = 0; - if (clientVersion != encodedVersion) check1 = 1; - if (clientVersion > 0x0301) check2 = 1; - if (serverVersion != encodedVersion) check3 = 1; - if ((check1 & (check2 | check3)) == 1) { - return replacer; - } else { - return tmp; + + // The following code is a time-constant version of + // if ((clientVersion != encodedVersion) || + // ((clientVersion > 0x301) && (serverVersion != encodedVersion))) { + // return replacer; + // } else { return tmp; } + int check1 = (clientVersion - encodedVersion) | + (encodedVersion - clientVersion); + int check2 = 0x0301 - clientVersion; + int check3 = (serverVersion - encodedVersion) | + (encodedVersion - serverVersion); + + check1 = (check1 & (check2 | check3)) >> 24; + + // Now check1 is either 0 or -1 + check2 = ~check1; + + for (int i = 0; i < 48; i++) { + tmp[i] = (byte) ((tmp[i] & check2) | (replacer[i] & check1)); } + + return tmp; } /** From 38afa4d42ff27f9c9ef18ee1691885ed4cf8dde5 Mon Sep 17 00:00:00 2001 From: Damon Fenacci Date: Mon, 20 Jan 2025 12:00:07 +0000 Subject: [PATCH 0604/1101] 8338430: Improve compiler transformations Co-authored-by: Emanuel Peter Reviewed-by: ahgross, rhalade, thartmann, epeter --- src/hotspot/share/opto/addnode.cpp | 37 ++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index a097a08607ae9..143398c57d068 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -1179,6 +1179,14 @@ static bool can_overflow(const TypeInt* t, jint c) { (c > 0 && (java_add(t_hi, c) < t_hi))); } +// Check if addition of a long with type 't' and a constant 'c' can overflow. +static bool can_overflow(const TypeLong* t, jlong c) { + jlong t_lo = t->_lo; + jlong t_hi = t->_hi; + return ((c < 0 && (java_add(t_lo, c) > t_lo)) || + (c > 0 && (java_add(t_hi, c) < t_hi))); +} + // Let = x_operands and = y_operands. // If x == y and neither add(x, x_off) nor add(y, y_off) overflow, return // add(x, op(x_off, y_off)). Otherwise, return nullptr. @@ -1363,6 +1371,31 @@ const Type *MinINode::add_ring( const Type *t0, const Type *t1 ) const { // // Note: we assume that SubL was already replaced by an AddL, and that the stride // has its sign flipped: SubL(limit, stride) -> AddL(limit, -stride). +// +// Proof MaxL collapsed version equivalent to original (MinL version similar): +// is_sub_con ensures that con1, con2 ∈ [min_int, 0[ +// +// Original: +// - AddL2 underflow => x + con2 ∈ ]max_long - min_int, max_long], ALWAYS BAILOUT as x + con1 + con2 surely fails can_overflow (*) +// - AddL2 no underflow => x + con2 ∈ [min_long, max_long] +// - MaxL2 clamp => min_int +// - AddL1 underflow: NOT POSSIBLE: cannot underflow since min_int + con1 ∈ [2 * min_int, min_int] always > min_long +// - AddL1 no underflow => min_int + con1 ∈ [2 * min_int, min_int] +// - MaxL1 clamp => min_int (RESULT 1) +// - MaxL1 no clamp: NOT POSSIBLE: min_int + con1 ∈ [2 * min_int, min_int] always <= min_int, so clamp always taken +// - MaxL2 no clamp => x + con2 ∈ [min_int, max_long] +// - AddL1 underflow: NOT POSSIBLE: cannot underflow since x + con2 + con1 ∈ [2 * min_int, max_long] always > min_long +// - AddL1 no underflow => x + con2 + con1 ∈ [2 * min_int, max_long] +// - MaxL1 clamp => min_int (RESULT 2) +// - MaxL1 no clamp => x + con2 + con1 ∈ ]min_int, max_long] (RESULT 3) +// +// Collapsed: +// - AddL2 (cannot underflow) => con2 + con1 ∈ [2 * min_int, 0] +// - AddL1 underflow: NOT POSSIBLE: would have bailed out at can_overflow (*) +// - AddL1 no underflow => x + con2 + con1 ∈ [min_long, max_long] +// - MaxL clamp => min_int (RESULT 1 and RESULT 2) +// - MaxL no clamp => x + con2 + con1 ∈ ]min_int, max_long] (RESULT 3) +// static Node* fold_subI_no_underflow_pattern(Node* n, PhaseGVN* phase) { assert(n->Opcode() == Op_MaxL || n->Opcode() == Op_MinL, "sanity"); // Check that the two clamps have the correct values. @@ -1392,6 +1425,10 @@ static Node* fold_subI_no_underflow_pattern(Node* n, PhaseGVN* phase) { Node* x = add2->in(1); Node* con2 = add2->in(2); if (is_sub_con(con2)) { + // Collapsed graph not equivalent if potential over/underflow -> bailing out (*) + if (can_overflow(phase->type(x)->is_long(), con1->get_long() + con2->get_long())) { + return nullptr; + } Node* new_con = phase->transform(new AddLNode(con1, con2)); Node* new_sub = phase->transform(new AddLNode(x, new_con)); n->set_req_X(1, new_sub, phase); From ed30fce6df57b1cbf7a6efebabc3558550f8ec16 Mon Sep 17 00:00:00 2001 From: Artur Barashev Date: Mon, 27 Jan 2025 21:11:23 +0000 Subject: [PATCH 0605/1101] 8347847: Enhance jar file support Reviewed-by: rhalade, jnibedita, pkumaraswamy, ahgross, hchao, weijun, mullan --- .../security/util/SignatureFileVerifier.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java b/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java index 7accd3cbf10bb..d7e65b6aef0fd 100644 --- a/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java +++ b/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -518,6 +518,8 @@ private boolean verifyManifestMainAttrs(Manifest sf, ManifestDigester md) boolean attrsVerified = true; // If only weak algorithms are used. boolean weakAlgs = true; + // If only unsupported algorithms are used. + boolean unsupportedAlgs = true; // If a ATTR_DIGEST entry is found. boolean validEntry = false; @@ -542,6 +544,7 @@ private boolean verifyManifestMainAttrs(Manifest sf, ManifestDigester md) MessageDigest digest = getDigest(algorithm); if (digest != null) { + unsupportedAlgs = false; ManifestDigester.Entry mde = md.getMainAttsEntry(false); if (mde == null) { throw new SignatureException("Manifest Main Attribute check " + @@ -584,12 +587,22 @@ private boolean verifyManifestMainAttrs(Manifest sf, ManifestDigester md) } } - // If there were only weak algorithms entries used, throw an exception. - if (validEntry && weakAlgs) { - throw new SignatureException("Manifest Main Attribute check " + - "failed (" + ATTR_DIGEST + "). " + - "Disabled algorithm(s) used: " + - getWeakAlgorithms(ATTR_DIGEST)); + if (validEntry) { + // If there were only weak algorithms entries used, throw an exception. + if (weakAlgs) { + throw new SignatureException( + "Manifest Main Attribute check " + + "failed (" + ATTR_DIGEST + "). " + + "Disabled algorithm(s) used: " + + getWeakAlgorithms(ATTR_DIGEST)); + } + + // If there were only unsupported algorithms entries used, throw an exception. + if (unsupportedAlgs) { + throw new SignatureException( + "Manifest Main Attribute check failed (" + + ATTR_DIGEST + "). Unsupported algorithm(s) used"); + } } // this method returns 'true' if either: From 18d605fadbd57090f5eb02c18e6e8860d9086515 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Wed, 16 Apr 2025 08:23:03 +0000 Subject: [PATCH 0606/1101] 8354629: Test tools/jlink/ClassFileInMetaInfo.java fails on builds with configure option --enable-linkable-runtime Reviewed-by: alanb --- test/jdk/tools/jlink/ClassFileInMetaInfo.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/tools/jlink/ClassFileInMetaInfo.java b/test/jdk/tools/jlink/ClassFileInMetaInfo.java index 028da2cbe5042..42b0bd511a252 100644 --- a/test/jdk/tools/jlink/ClassFileInMetaInfo.java +++ b/test/jdk/tools/jlink/ClassFileInMetaInfo.java @@ -29,7 +29,7 @@ * @modules java.base/jdk.internal.module * jdk.jlink * jdk.jartool - * @run junit ClassFileInMetaInfo + * @run junit/othervm ClassFileInMetaInfo */ import java.lang.module.ModuleDescriptor; @@ -117,4 +117,4 @@ private void test(String modulePath) throws Exception { .shouldContain("contains p") .shouldNotContain("META-INF"); } -} \ No newline at end of file +} From 4c3c2b32a1b9dea6f3e258cf44666932afc179e4 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Wed, 16 Apr 2025 08:35:05 +0000 Subject: [PATCH 0607/1101] 8354576: InetAddress.getLocalHost() on macos may return address of an interface which is not UP - leading to "Network is down" error Reviewed-by: alanb, dfuchs, vyazici --- src/java.base/unix/native/libnet/Inet6AddressImpl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c index bad7872c179fd..83354356936db 100644 --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -126,7 +126,7 @@ lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6, int cha while (iter) { if (iter->ifa_addr != NULL) { int family = iter->ifa_addr->sa_family; - if (iter->ifa_name[0] != '\0') { + if (iter->ifa_name[0] != '\0' && (iter->ifa_flags & IFF_UP) == IFF_UP) { jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK; if (family == AF_INET) { addrs4++; @@ -163,7 +163,7 @@ lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6, int cha // Now loop around the ifaddrs iter = ifa; while (iter != NULL) { - if (iter->ifa_addr != NULL) { + if (iter->ifa_addr != NULL && (iter->ifa_flags & IFF_UP) == IFF_UP) { jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK; int family = iter->ifa_addr->sa_family; From cfbbcd78bc7be2c7740de7c0b49180f56f6ccf49 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 16 Apr 2025 09:23:15 +0000 Subject: [PATCH 0608/1101] 8350595: jshell completion on arrays does not work for clone() Reviewed-by: asotona --- .../jdk/jshell/SourceCodeAnalysisImpl.java | 24 ++++++++++++++----- .../jdk/jshell/CompletionSuggestionTest.java | 5 +++- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java index d17b13fbd13a3..7fb354d4d1d2c 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java @@ -54,10 +54,12 @@ import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.CompletionFailure; +import com.sun.tools.javac.code.Symbol.MethodSymbol; import com.sun.tools.javac.code.Symbol.VarSymbol; import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type.ClassType; +import com.sun.tools.javac.code.Type.MethodType; import com.sun.tools.javac.parser.Scanner; import com.sun.tools.javac.parser.ScannerFactory; import com.sun.tools.javac.parser.Tokens.Token; @@ -1073,7 +1075,7 @@ private List membersOf(AnalyzeTask at, TypeMirror site, boole if (jlObject != null) { result.addAll(membersOf(at, jlObject)); } - result.add(createArrayLengthSymbol(at, site)); + result.addAll(createArraySymbols(at, site)); if (shouldGenerateDotClassItem) result.add(createDotClassSymbol(at, site)); return result; @@ -1161,11 +1163,21 @@ private PackageElement createPackageElement(AnalyzeTask at, String packageName) return existing; } - private Element createArrayLengthSymbol(AnalyzeTask at, TypeMirror site) { - Name length = Names.instance(at.getContext()).length; - Type intType = Symtab.instance(at.getContext()).intType; - - return new VarSymbol(Flags.PUBLIC | Flags.FINAL, length, intType, ((Type) site).tsym); + private List createArraySymbols(AnalyzeTask at, TypeMirror site) { + Symtab syms = Symtab.instance(at.getContext()); + Names names = Names.instance(at.getContext()); + Name length = names.length; + Name clone = names.clone; + Type lengthType = syms.intType; + Type cloneType = new MethodType(com.sun.tools.javac.util.List.nil(), + (Type) site, + com.sun.tools.javac.util.List.nil(), + syms.methodClass); + + return List.of( + new VarSymbol(Flags.PUBLIC | Flags.FINAL, length, lengthType, ((Type) site).tsym), + new MethodSymbol(Flags.PUBLIC | Flags.FINAL, clone, cloneType, ((Type) site).tsym) + ); } private Element createDotClassSymbol(AnalyzeTask at, TypeMirror site) { diff --git a/test/langtools/jdk/jshell/CompletionSuggestionTest.java b/test/langtools/jdk/jshell/CompletionSuggestionTest.java index 8e4be046471bb..8564c5d1da2bb 100644 --- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java +++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110 8177466 8197439 8221759 8234896 8240658 8278039 8286206 8296789 8314662 8326333 + * @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110 8177466 8197439 8221759 8234896 8240658 8278039 8286206 8296789 8314662 8326333 8326333 * @summary Test Completion and Documentation * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -812,13 +812,16 @@ public void testDuplicateImport() { } //JDK-8326333: verify completion returns sensible output for arrays: + //JDK-8326333: jshell completion on arrays is incomplete public void testArray() { assertEval("String[] strs = null;"); assertCompletion("strs.to|", "toString()"); assertCompletion("strs.le|", "length"); + assertCompletion("strs.cl|", "clone()"); assertEval("int[] ints = null;"); assertCompletion("ints.no|", "notify()", "notifyAll()"); assertCompletion("ints.le|", "length"); + assertCompletion("ints.cl|", "clone()"); assertCompletion("String[].|", "class"); } } From 8c6b611f35af22af5b6c3eb663b30985857c1da3 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 16 Apr 2025 09:52:53 +0000 Subject: [PATCH 0609/1101] 8353832: Opensource FontClass, Selection and Icon tests Reviewed-by: jdv --- .../FontClass/FontTransformAttributeTest.java | 84 +++++++++++++ .../awt/FontClass/FontUnderscoreTest.java | 77 ++++++++++++ .../jdk/java/awt/Icon/ChildFrameIconTest.java | 76 ++++++++++++ .../jdk/java/awt/Selection/TestClipboard.java | 113 ++++++++++++++++++ 4 files changed, 350 insertions(+) create mode 100644 test/jdk/java/awt/FontClass/FontTransformAttributeTest.java create mode 100644 test/jdk/java/awt/FontClass/FontUnderscoreTest.java create mode 100644 test/jdk/java/awt/Icon/ChildFrameIconTest.java create mode 100644 test/jdk/java/awt/Selection/TestClipboard.java diff --git a/test/jdk/java/awt/FontClass/FontTransformAttributeTest.java b/test/jdk/java/awt/FontClass/FontTransformAttributeTest.java new file mode 100644 index 0000000000000..7bbf5d11d28b4 --- /dev/null +++ b/test/jdk/java/awt/FontClass/FontTransformAttributeTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.font.TextAttribute; +import java.awt.font.TransformAttribute; +import java.awt.geom.AffineTransform; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; + +import javax.swing.JPanel; + +/* + * @test + * @bug 4650042 + * @summary Draw text using a transform to simulate superscript, it should look like a superscript + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FontTransformAttributeTest + */ + +public class FontTransformAttributeTest extends JPanel { + AttributedCharacterIterator iter; + + public static void main(String[] args) throws Exception { + final String INSTRUCTIONS = """ + This test should display a string ending with the superscripted number '11'. + Pass the test if you see the superscript."""; + + PassFailJFrame.builder() + .title("FontTransformAttributeTest Instruction") + .instructions(INSTRUCTIONS) + .columns(35) + .splitUI(FontTransformAttributeTest::new) + .build() + .awaitAndCheck(); + } + + FontTransformAttributeTest() { + AffineTransform superTransform = AffineTransform.getScaleInstance(0.65, 0.65); + superTransform.translate(0, -7); + TransformAttribute superAttribute = new TransformAttribute(superTransform); + String s = "a big number 7 11"; + AttributedString as = new AttributedString(s); + as.addAttribute(TextAttribute.TRANSFORM, superAttribute, 15, 17); + iter = as.getIterator(); + setBackground(Color.WHITE); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(200, 100); + } + + @Override + public void paint(Graphics g) { + Graphics2D g2 = (Graphics2D) g; + Dimension d = getSize(); + g2.drawString(iter, 20, d.height / 2 + 8); + } +} diff --git a/test/jdk/java/awt/FontClass/FontUnderscoreTest.java b/test/jdk/java/awt/FontClass/FontUnderscoreTest.java new file mode 100644 index 0000000000000..101a0b4908867 --- /dev/null +++ b/test/jdk/java/awt/FontClass/FontUnderscoreTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; + +import javax.swing.JPanel; + +/* + * @test + * @bug 4248579 + * @summary Make sure the underscore glyph appears in the different strings + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FontUnderscoreTest + */ + +public class FontUnderscoreTest extends JPanel { + public static void main(String[] args) throws Exception { + final String INSTRUCTIONS = """ + Make sure all 8 underscore characters appear in each + of the 3 strings. + + Press PASS if all 8 are there, else FAIL."""; + + PassFailJFrame.builder() + .title("FontUnderscoreTest Instruction") + .instructions(INSTRUCTIONS) + .columns(35) + .splitUI(FontUnderscoreTest::new) + .build() + .awaitAndCheck(); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(550, 230); + } + + @Override + public void paint(Graphics g) { + Font f = new Font(Font.SANS_SERIF, Font.PLAIN, 24); + g.setFont(f); + g.drawString ("8 underscore characters appear in each string", 5, 200); + + g.drawString("J_A_V_A_2_j_a_v_a", 25, 50); + + f = new Font(Font.SERIF, Font.PLAIN, 24); + g.setFont(f); + g.drawString("J_A_V_A_2_j_a_v_a", 25, 100); + + f = new Font(Font.MONOSPACED, Font.PLAIN, 24); + g.setFont(f); + g.drawString("J_A_V_A_2_j_a_v_a", 25, 150); + } +} diff --git a/test/jdk/java/awt/Icon/ChildFrameIconTest.java b/test/jdk/java/awt/Icon/ChildFrameIconTest.java new file mode 100644 index 0000000000000..6d83fa95acba7 --- /dev/null +++ b/test/jdk/java/awt/Icon/ChildFrameIconTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JOptionPane; + +/* + * @test + * @bug 4284610 + * @summary Tests that a child of the non-resizable dialog acquires valid icon. + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ChildFrameIconTest + */ + +public class ChildFrameIconTest { + public static void main(String[] args) throws Exception { + final String INSTRUCTIONS = """ + Press "Show Dialog" button to open a dialog with this message: + Do you see a coffee cup icon in the upper left corner ? + + Look at the icon in the upper left corner of the message dialog. + + Press Pass if you see default coffee cup icon else press Fail."""; + + PassFailJFrame.builder() + .title("ChildFrameIconTest Instruction") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(ChildFrameIconTest::createUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createUI() { + JFrame f = new JFrame("ChildFrameIconTest UI"); + JButton b = new JButton("Show Dialog"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + String msg = "Do you see a coffee cup icon in the upper left corner ?"; + JDialog dlg = new JDialog(f, "Non-resizable JDialog", false); + dlg.setResizable(false); + JOptionPane.showMessageDialog(dlg, msg); + } + }); + f.add(b); + f.setSize(250, 100); + return f; + } +} diff --git a/test/jdk/java/awt/Selection/TestClipboard.java b/test/jdk/java/awt/Selection/TestClipboard.java new file mode 100644 index 0000000000000..ed65d55489c3c --- /dev/null +++ b/test/jdk/java/awt/Selection/TestClipboard.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import java.io.Serializable; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JOptionPane; + +/* + * @test + * @bug 4139552 + * @summary Checks to see if 'isDataFlavorSupported' throws exception. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestClipboard + */ + +public class TestClipboard { + + public static void main(String[] args) throws Exception { + final String INSTRUCTIONS = """ + This test has two steps: + + 1. you need to place some text onto the system clipboard, + for example, + on Windows, you could highlight some text in notepad, and do a Ctrl-C + or select menu Edit->Copy; + + on Linux or Mac, you can do the same with any Terminal or Console or + Text application. + + 2. After you copy to system clipboard, press "Click Me" button. + + Test will fail if any exception is thrown. + + Press Pass if you see "Test Passed" in log area."""; + + PassFailJFrame.builder() + .title("TestClipboard Instruction") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(TestClipboard::createUI) + .logArea(4) + .build() + .awaitAndCheck(); + } + + private static JFrame createUI() { + JFrame f = new JFrame("ChildFrameIconTest UI"); + JButton b = new JButton("Click Me"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + try { + new MyTest(); + } catch (Exception ex) { + throw new RuntimeException("Exception Thrown : " + ex); + } + } + }); + f.add(b); + f.setSize(200, 100); + return f; + } + + static class MyFlavor extends Object implements Serializable { + // Stub class needed in order to define the data flavor type + } + + static class MyTest { + public MyTest() throws Exception { + // Create an arbitrary dataflavor + DataFlavor myFlavor = new DataFlavor(MyFlavor.class, "TestClipboard"); + // Get the system clipboard + Clipboard theClipboard = + Toolkit.getDefaultToolkit().getSystemClipboard(); + // Get the current contents of the clipboard + Transferable theTransfer = theClipboard.getContents(this); + + // See if the flavor is supported. This may result in a null + // pointer exception. + theTransfer.isDataFlavorSupported(myFlavor); + PassFailJFrame.log("Test Passed"); + } + } +} From fe3bd5d62fdedb7890bd3d589b04285be79c24ed Mon Sep 17 00:00:00 2001 From: Robbin Ehn Date: Wed, 16 Apr 2025 09:56:39 +0000 Subject: [PATCH 0610/1101] 8354667: [TESTBUG] AccessZeroNKlassHitsProtectionZone cds tests require cds Reviewed-by: lmesnik, syan --- .../ErrorHandling/AccessZeroNKlassHitsProtectionZone.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java b/test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java index 189f1c0891679..fde81148a0204 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java @@ -38,7 +38,7 @@ /* * @test id=no_coh_cds * @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone - * @requires vm.bits == 64 & vm.debug == true & vm.flagless + * @requires vm.cds & vm.bits == 64 & vm.debug == true & vm.flagless * @requires os.family != "aix" * @library /test/lib * @modules java.base/jdk.internal.misc @@ -64,7 +64,7 @@ /* * @test id=coh_cds * @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone - * @requires vm.bits == 64 & vm.debug == true & vm.flagless + * @requires vm.cds & vm.bits == 64 & vm.debug == true & vm.flagless * @requires os.family != "aix" * @library /test/lib * @modules java.base/jdk.internal.misc From 7ffad35dac1439bc5aa12a6c16b5e8254251170b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Wed, 16 Apr 2025 11:32:47 +0000 Subject: [PATCH 0611/1101] 8352568: Test gtest/AsyncLogGtest.java failed at droppingMessage_vm Reviewed-by: mbaesken, dholmes --- src/hotspot/share/logging/logAsyncWriter.cpp | 24 ----------- src/hotspot/share/logging/logAsyncWriter.hpp | 10 ----- test/hotspot/gtest/logging/test_asynclog.cpp | 42 +++++++++++++++----- test/hotspot/jtreg/gtest/AsyncLogGtest.java | 4 +- 4 files changed, 34 insertions(+), 46 deletions(-) diff --git a/src/hotspot/share/logging/logAsyncWriter.cpp b/src/hotspot/share/logging/logAsyncWriter.cpp index ea5cc5c96ab53..cfb6a991c4cb3 100644 --- a/src/hotspot/share/logging/logAsyncWriter.cpp +++ b/src/hotspot/share/logging/logAsyncWriter.cpp @@ -354,27 +354,3 @@ void AsyncLogWriter::flush() { _instance->_flush_sem.wait(); } } - -AsyncLogWriter::BufferUpdater::BufferUpdater(size_t newsize) { - ConsumerLocker clocker; - auto p = AsyncLogWriter::_instance; - - _buf1 = p->_buffer; - _buf2 = p->_buffer_staging; - p->_buffer = new Buffer(newsize); - p->_buffer_staging = new Buffer(newsize); -} - -AsyncLogWriter::BufferUpdater::~BufferUpdater() { - AsyncLogWriter::flush(); - auto p = AsyncLogWriter::_instance; - - { - ConsumerLocker clocker; - - delete p->_buffer; - delete p->_buffer_staging; - p->_buffer = _buf1; - p->_buffer_staging = _buf2; - } -} diff --git a/src/hotspot/share/logging/logAsyncWriter.hpp b/src/hotspot/share/logging/logAsyncWriter.hpp index 355d15b904c0b..5ffd9dc7b33cb 100644 --- a/src/hotspot/share/logging/logAsyncWriter.hpp +++ b/src/hotspot/share/logging/logAsyncWriter.hpp @@ -199,16 +199,6 @@ class AsyncLogWriter : public NonJavaThread { st->cr(); } - // for testing-only - class BufferUpdater { - Buffer* _buf1; - Buffer* _buf2; - - public: - BufferUpdater(size_t newsize); - ~BufferUpdater(); - }; - static bool is_enqueue_allowed(); public: diff --git a/test/hotspot/gtest/logging/test_asynclog.cpp b/test/hotspot/gtest/logging/test_asynclog.cpp index ebc3e35a4b928..efd4027fa3f30 100644 --- a/test/hotspot/gtest/logging/test_asynclog.cpp +++ b/test/hotspot/gtest/logging/test_asynclog.cpp @@ -69,21 +69,22 @@ LOG_LEVEL_LIST log_debug(logging)("log_debug-test"); } - // Caveat: BufferUpdater is not MT-safe. We use it only for testing. - // We would observe missing loglines if we interleaved buffers. - // Emit all logs between constructor and destructor of BufferUpdater. void test_asynclog_drop_messages() { - const size_t sz = 2000; + const size_t sz = AsyncLogBufferSize / 2; + const char* str = "a lot of log..."; + const size_t str_size = strlen(str); - // shrink async buffer. - AsyncLogWriter::BufferUpdater saver(1024); test_asynclog_ls(); // roughly 200 bytes. LogMessage(logging) lm; // write more messages than its capacity in burst - for (size_t i = 0; i < sz; ++i) { - lm.debug("a lot of log..."); + for (size_t i = 0; i < (sz / str_size); ++i) { + lm.debug("%s", str); } + lm.debug("%s", str); + lm.debug("%s", str); + lm.debug("%s", str); + lm.debug("%s", str); lm.flush(); } @@ -244,13 +245,34 @@ TEST_VM_F(AsyncLogTest, logBuffer) { } TEST_VM_F(AsyncLogTest, droppingMessage) { - if (AsyncLogWriter::instance() == nullptr) { + if (AsyncLogWriter::instance() == nullptr) return; + if (LogConfiguration::async_mode() != LogConfiguration::AsyncMode::Drop) { + FAIL() << "This test must be run in drop mode if async UL is activated"; return; } set_log_config(TestLogFileName, "logging=debug"); test_asynclog_drop_messages(); - EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); + bool messages_dropped = file_contains_substring(TestLogFileName, "messages dropped due to async logging"); + if (!messages_dropped) { + stringStream content; + FILE* fp = os::fopen(TestLogFileName, "r"); + assert(fp != nullptr, "error opening file %s: %s", TestLogFileName, os::strerror(errno)); + { + ResourceMark rm; + char* line = read_line(fp); + while (line != nullptr) { + ResourceMark rm; + content.print_raw(line); + line = read_line(fp); + } + } + + // The thread is null and deattached. + // That means that UL degrades to synchronous logging for this thread, which means that no messages can be dropped. + EXPECT_NE(nullptr, Thread::current_or_null()) << "Thread was null"; + EXPECT_TRUE(messages_dropped) << "Log file content:\n" << content.freeze(); + } } TEST_VM_F(AsyncLogTest, stdoutOutput) { diff --git a/test/hotspot/jtreg/gtest/AsyncLogGtest.java b/test/hotspot/jtreg/gtest/AsyncLogGtest.java index 302730b1515a3..d2d393c12b7d6 100644 --- a/test/hotspot/jtreg/gtest/AsyncLogGtest.java +++ b/test/hotspot/jtreg/gtest/AsyncLogGtest.java @@ -35,6 +35,6 @@ * @modules java.base/jdk.internal.misc * java.xml * @requires vm.flagless - * @run main/native GTestWrapper --gtest_filter=AsyncLogTest* -Xlog:async - * @run main/native GTestWrapper --gtest_filter=Log*Test* -Xlog:async + * @run main/native GTestWrapper --gtest_filter=AsyncLogTest* -Xlog:async -XX:AsyncLogBufferSize=100K + * @run main/native GTestWrapper --gtest_filter=Log*Test* -Xlog:async -XX:AsyncLogBufferSize=100K */ From 1ad869f8440cb274e474abd9f89f88db11101071 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 16 Apr 2025 11:43:42 +0000 Subject: [PATCH 0612/1101] 8322706: AnnotationTypeMismatchException in javac with annotation processing Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Annotate.java | 27 ++-- .../TestAnnotationValuesResolved.java | 152 ++++++++++++++++++ 2 files changed, 168 insertions(+), 11 deletions(-) create mode 100644 test/langtools/tools/javac/annotations/TestAnnotationValuesResolved.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java index 49f5a7472aa74..35672b2b1bc93 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java @@ -187,17 +187,22 @@ public void flush() { startFlushing(); try { - while (q.nonEmpty()) { - q.next().run(); - } - while (typesQ.nonEmpty()) { - typesQ.next().run(); - } - while (afterTypesQ.nonEmpty()) { - afterTypesQ.next().run(); - } - while (validateQ.nonEmpty()) { - validateQ.next().run(); + while (q.nonEmpty() || + typesQ.nonEmpty() || + afterTypesQ.nonEmpty() || + validateQ.nonEmpty()) { + while (q.nonEmpty()) { + q.next().run(); + } + while (typesQ.nonEmpty()) { + typesQ.next().run(); + } + while (afterTypesQ.nonEmpty()) { + afterTypesQ.next().run(); + } + while (validateQ.nonEmpty()) { + validateQ.next().run(); + } } } finally { doneFlushing(); diff --git a/test/langtools/tools/javac/annotations/TestAnnotationValuesResolved.java b/test/langtools/tools/javac/annotations/TestAnnotationValuesResolved.java new file mode 100644 index 0000000000000..b18290b529ddf --- /dev/null +++ b/test/langtools/tools/javac/annotations/TestAnnotationValuesResolved.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8322706 + * @summary Verify that annotation values are de-proxies after loading from a classfile. + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.JavacTask toolbox.ToolBox toolbox.Task + * @run main TestAnnotationValuesResolved + */ + +import com.sun.source.tree.ClassTree; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskEvent.Kind; +import com.sun.source.util.TaskListener; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; +import java.nio.file.Files; +import toolbox.*; + +import java.nio.file.Path; +import java.nio.file.Paths; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.util.Elements; +import javax.lang.model.util.SimpleAnnotationValueVisitorPreview; + + +public class TestAnnotationValuesResolved extends TestRunner { + final toolbox.ToolBox tb = new ToolBox(); + + public TestAnnotationValuesResolved() { + super(System.err); + } + + public static void main(String[] args) throws Exception { + new TestAnnotationValuesResolved().runTests(); + } + + protected void runTests() throws Exception { + runTests(m -> new Object[] { Path.of(m.getName()) }); + } + + @Test + public void test(Path base) throws Exception { + Path lib = Paths.get("lib"); + Path libSrc = lib.resolve("src"); + Path libClasses = lib.resolve("classes"); + + tb.writeJavaFiles(libSrc, + """ + package org.example; + + public @interface MyFirstAnnotation { + MySecondAnnotation secondAnnotation() default @MySecondAnnotation; + } + """, + """ + package org.example; + + public @interface MySecondAnnotation { + String[] stringArray() default ""; + } + """ + ); + Files.createDirectories(libClasses); + new toolbox.JavacTask(tb) + .outdir(libClasses) + .files(tb.findJavaFiles(libSrc)) + .run(); + + Path test = Paths.get("test"); + Path testSrc = test.resolve("src"); + Path testClasses = test.resolve("classes"); + tb.writeJavaFiles(testSrc, + """ + package org.example; + + @MyFirstAnnotation + public class AnnotatedClass { + } + """); + Files.createDirectories(testClasses); + new toolbox.JavacTask(tb) + .classpath(libClasses) + .outdir(testClasses) + .files(tb.findJavaFiles(testSrc)) + .callback(task -> { + task.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() == Kind.ENTER) { + new TreePathScanner<>() { + @Override + public Object visitClass(ClassTree node, Object p) { + Trees trees = Trees.instance(task); + Element el = trees.getElement(getCurrentPath()); + verifyAnnotationValuesResolved(task, el); + return super.visitClass(node, p); + } + }.scan(e.getCompilationUnit(), null); + } + } + }); + }) + .run() + .writeAll(); + } + + private void verifyAnnotationValuesResolved(com.sun.source.util.JavacTask task, + Element forElement) { + Elements elements = task.getElements(); + + class SearchAnnotationValues extends SimpleAnnotationValueVisitorPreview { + @Override + public Object visitAnnotation(AnnotationMirror a, Object p) { + for (AnnotationValue av : elements.getElementValuesWithDefaults(a).values()) { + av.accept(this, null); + } + return super.visitAnnotation(a, p); + } + } + + for (AnnotationMirror mirror : forElement.getAnnotationMirrors()) { + new SearchAnnotationValues().visitAnnotation(mirror, null); + } + } +} From 465c8e658356f658ee04397936f555f6bdffc3c2 Mon Sep 17 00:00:00 2001 From: Ferenc Rakoczi Date: Wed, 16 Apr 2025 12:35:24 +0000 Subject: [PATCH 0613/1101] 8349721: Add aarch64 intrinsics for ML-KEM Reviewed-by: adinn --- src/hotspot/cpu/aarch64/register_aarch64.cpp | 20 - src/hotspot/cpu/aarch64/register_aarch64.hpp | 93 +- .../cpu/aarch64/stubDeclarations_aarch64.hpp | 2 +- .../cpu/aarch64/stubGenerator_aarch64.cpp | 1561 ++++++++++++++++- .../cpu/aarch64/stubRoutines_aarch64.cpp | 11 + .../cpu/aarch64/stubRoutines_aarch64.hpp | 1 + .../cpu/aarch64/vm_version_aarch64.cpp | 14 +- src/hotspot/share/classfile/vmIntrinsics.cpp | 8 + src/hotspot/share/classfile/vmIntrinsics.hpp | 21 + src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 7 + src/hotspot/share/opto/c2compiler.cpp | 7 + src/hotspot/share/opto/escape.cpp | 7 + src/hotspot/share/opto/library_call.cpp | 256 ++- src/hotspot/share/opto/library_call.hpp | 7 + src/hotspot/share/opto/runtime.cpp | 158 +- src/hotspot/share/opto/runtime.hpp | 46 + src/hotspot/share/runtime/globals.hpp | 2 + .../share/runtime/stubDeclarations.hpp | 15 + .../com/sun/crypto/provider/ML_KEM.java | 434 ++++- .../classes/sun/security/provider/ML_DSA.java | 2 +- 20 files changed, 2523 insertions(+), 149 deletions(-) diff --git a/src/hotspot/cpu/aarch64/register_aarch64.cpp b/src/hotspot/cpu/aarch64/register_aarch64.cpp index 349845154e2fe..82683daae4f08 100644 --- a/src/hotspot/cpu/aarch64/register_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/register_aarch64.cpp @@ -58,23 +58,3 @@ const char* PRegister::PRegisterImpl::name() const { }; return is_valid() ? names[encoding()] : "pnoreg"; } - -// convenience methods for splitting 8-way vector register sequences -// in half -- needed because vector operations can normally only be -// benefit from 4-way instruction parallelism - -VSeq<4> vs_front(const VSeq<8>& v) { - return VSeq<4>(v.base(), v.delta()); -} - -VSeq<4> vs_back(const VSeq<8>& v) { - return VSeq<4>(v.base() + 4 * v.delta(), v.delta()); -} - -VSeq<4> vs_even(const VSeq<8>& v) { - return VSeq<4>(v.base(), v.delta() * 2); -} - -VSeq<4> vs_odd(const VSeq<8>& v) { - return VSeq<4>(v.base() + 1, v.delta() * 2); -} diff --git a/src/hotspot/cpu/aarch64/register_aarch64.hpp b/src/hotspot/cpu/aarch64/register_aarch64.hpp index 45578336cfeaa..108f0f34140b4 100644 --- a/src/hotspot/cpu/aarch64/register_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/register_aarch64.hpp @@ -436,19 +436,20 @@ enum RC { rc_bad, rc_int, rc_float, rc_predicate, rc_stack }; // inputs into front and back halves or odd and even halves (see // convenience methods below). +// helper macro for computing register masks +#define VS_MASK_BIT(base, delta, i) (1 << (base + delta * i)) + template class VSeq { static_assert(N >= 2, "vector sequence length must be greater than 1"); - static_assert(N <= 8, "vector sequence length must not exceed 8"); - static_assert((N & (N - 1)) == 0, "vector sequence length must be power of two"); private: int _base; // index of first register in sequence int _delta; // increment to derive successive indices public: VSeq(FloatRegister base_reg, int delta = 1) : VSeq(base_reg->encoding(), delta) { } VSeq(int base, int delta = 1) : _base(base), _delta(delta) { - assert (_base >= 0, "invalid base register"); - assert (_delta >= 0, "invalid register delta"); - assert ((_base + (N - 1) * _delta) < 32, "range exceeded"); + assert (_base >= 0 && _base <= 31, "invalid base register"); + assert ((_base + (N - 1) * _delta) >= 0, "register range underflow"); + assert ((_base + (N - 1) * _delta) < 32, "register range overflow"); } // indexed access to sequence FloatRegister operator [](int i) const { @@ -457,27 +458,89 @@ template class VSeq { } int mask() const { int m = 0; - int bit = 1 << _base; for (int i = 0; i < N; i++) { - m |= bit << (i * _delta); + m |= VS_MASK_BIT(_base, _delta, i); } return m; } int base() const { return _base; } int delta() const { return _delta; } + bool is_constant() const { return _delta == 0; } }; -// declare convenience methods for splitting vector register sequences - -VSeq<4> vs_front(const VSeq<8>& v); -VSeq<4> vs_back(const VSeq<8>& v); -VSeq<4> vs_even(const VSeq<8>& v); -VSeq<4> vs_odd(const VSeq<8>& v); - -// methods for use in asserts to check VSeq inputs and oupts are +// methods for use in asserts to check VSeq inputs and outputs are // either disjoint or equal template bool vs_disjoint(const VSeq& n, const VSeq& m) { return (n.mask() & m.mask()) == 0; } template bool vs_same(const VSeq& n, const VSeq& m) { return n.mask() == m.mask(); } +// method for use in asserts to check whether registers appearing in +// an output sequence will be written before they are read from an +// input sequence. + +template bool vs_write_before_read(const VSeq& vout, const VSeq& vin) { + int b_in = vin.base(); + int d_in = vin.delta(); + int b_out = vout.base(); + int d_out = vout.delta(); + int bit_in = 1 << b_in; + int bit_out = 1 << b_out; + int mask_read = vin.mask(); // all pending reads + int mask_write = 0; // no writes as yet + + + for (int i = 0; i < N - 1; i++) { + // check whether a pending read clashes with a write + if ((mask_write & mask_read) != 0) { + return true; + } + // remove the pending input (so long as this is a constant + // sequence) + if (d_in != 0) { + mask_read ^= VS_MASK_BIT(b_in, d_in, i); + } + // record the next write + mask_write |= VS_MASK_BIT(b_out, d_out, i); + } + // no write before read + return false; +} + +// convenience methods for splitting 8-way or 4-way vector register +// sequences in half -- needed because vector operations can normally +// benefit from 4-way instruction parallelism or, occasionally, 2-way +// parallelism + +template +VSeq vs_front(const VSeq& v) { + static_assert(N > 0 && ((N & 1) == 0), "sequence length must be even"); + return VSeq(v.base(), v.delta()); +} + +template +VSeq vs_back(const VSeq& v) { + static_assert(N > 0 && ((N & 1) == 0), "sequence length must be even"); + return VSeq(v.base() + N / 2 * v.delta(), v.delta()); +} + +template +VSeq vs_even(const VSeq& v) { + static_assert(N > 0 && ((N & 1) == 0), "sequence length must be even"); + return VSeq(v.base(), v.delta() * 2); +} + +template +VSeq vs_odd(const VSeq& v) { + static_assert(N > 0 && ((N & 1) == 0), "sequence length must be even"); + return VSeq(v.base() + v.delta(), v.delta() * 2); +} + +// convenience method to construct a vector register sequence that +// indexes its elements in reverse order to the original + +template +VSeq vs_reverse(const VSeq& v) { + return VSeq(v.base() + (N - 1) * v.delta(), -v.delta()); +} + #endif // CPU_AARCH64_REGISTER_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp b/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp index a893aacaaf2dd..1107ec0a8f82a 100644 --- a/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp @@ -44,7 +44,7 @@ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(compiler, 55000 ZGC_ONLY(+5000)) \ + do_arch_blob(compiler, 75000 ZGC_ONLY(+5000)) \ do_stub(compiler, vector_iota_indices) \ do_arch_entry(aarch64, compiler, vector_iota_indices, \ vector_iota_indices, vector_iota_indices) \ diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index f0f145e3d7612..467505ed33784 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -4651,6 +4651,11 @@ class StubGenerator: public StubCodeGenerator { template void vs_addv(const VSeq& v, Assembler::SIMD_Arrangement T, const VSeq& v1, const VSeq& v2) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + assert(!vs_write_before_read(v, v2), "output overwrites input"); for (int i = 0; i < N; i++) { __ addv(v[i], T, v1[i], v2[i]); } @@ -4659,6 +4664,11 @@ class StubGenerator: public StubCodeGenerator { template void vs_subv(const VSeq& v, Assembler::SIMD_Arrangement T, const VSeq& v1, const VSeq& v2) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + assert(!vs_write_before_read(v, v2), "output overwrites input"); for (int i = 0; i < N; i++) { __ subv(v[i], T, v1[i], v2[i]); } @@ -4667,6 +4677,11 @@ class StubGenerator: public StubCodeGenerator { template void vs_mulv(const VSeq& v, Assembler::SIMD_Arrangement T, const VSeq& v1, const VSeq& v2) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + assert(!vs_write_before_read(v, v2), "output overwrites input"); for (int i = 0; i < N; i++) { __ mulv(v[i], T, v1[i], v2[i]); } @@ -4674,6 +4689,10 @@ class StubGenerator: public StubCodeGenerator { template void vs_negr(const VSeq& v, Assembler::SIMD_Arrangement T, const VSeq& v1) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); for (int i = 0; i < N; i++) { __ negr(v[i], T, v1[i]); } @@ -4682,6 +4701,10 @@ class StubGenerator: public StubCodeGenerator { template void vs_sshr(const VSeq& v, Assembler::SIMD_Arrangement T, const VSeq& v1, int shift) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); for (int i = 0; i < N; i++) { __ sshr(v[i], T, v1[i], shift); } @@ -4689,6 +4712,11 @@ class StubGenerator: public StubCodeGenerator { template void vs_andr(const VSeq& v, const VSeq& v1, const VSeq& v2) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + assert(!vs_write_before_read(v, v2), "output overwrites input"); for (int i = 0; i < N; i++) { __ andr(v[i], __ T16B, v1[i], v2[i]); } @@ -4696,18 +4724,51 @@ class StubGenerator: public StubCodeGenerator { template void vs_orr(const VSeq& v, const VSeq& v1, const VSeq& v2) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + assert(!vs_write_before_read(v, v2), "output overwrites input"); for (int i = 0; i < N; i++) { __ orr(v[i], __ T16B, v1[i], v2[i]); } } template - void vs_notr(const VSeq& v, const VSeq& v1) { + void vs_notr(const VSeq& v, const VSeq& v1) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); for (int i = 0; i < N; i++) { __ notr(v[i], __ T16B, v1[i]); } } + template + void vs_sqdmulh(const VSeq& v, Assembler::SIMD_Arrangement T, const VSeq& v1, const VSeq& v2) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + assert(!vs_write_before_read(v, v2), "output overwrites input"); + for (int i = 0; i < N; i++) { + __ sqdmulh(v[i], T, v1[i], v2[i]); + } + } + + template + void vs_mlsv(const VSeq& v, Assembler::SIMD_Arrangement T, const VSeq& v1, VSeq& v2) { + // output must not be constant + assert(N == 1 || !v.is_constant(), "cannot output multiple values to a constant vector"); + // output cannot overwrite pending inputs + assert(!vs_write_before_read(v, v1), "output overwrites input"); + assert(!vs_write_before_read(v, v2), "output overwrites input"); + for (int i = 0; i < N; i++) { + __ mlsv(v[i], T, v1[i], v2[i]); + } + } + // load N/2 successive pairs of quadword values from memory in order // into N successive vector registers of the sequence via the // address supplied in base. @@ -4723,6 +4784,7 @@ class StubGenerator: public StubCodeGenerator { // in base using post-increment addressing template void vs_ldpq_post(const VSeq& v, Register base) { + static_assert((N & (N - 1)) == 0, "sequence length must be even"); for (int i = 0; i < N; i += 2) { __ ldpq(v[i], v[i+1], __ post(base, 32)); } @@ -4733,11 +4795,55 @@ class StubGenerator: public StubCodeGenerator { // supplied in base using post-increment addressing template void vs_stpq_post(const VSeq& v, Register base) { + static_assert((N & (N - 1)) == 0, "sequence length must be even"); for (int i = 0; i < N; i += 2) { __ stpq(v[i], v[i+1], __ post(base, 32)); } } + // load N/2 pairs of quadword values from memory de-interleaved into + // N vector registers 2 at a time via the address supplied in base + // using post-increment addressing. + template + void vs_ld2_post(const VSeq& v, Assembler::SIMD_Arrangement T, Register base) { + static_assert((N & (N - 1)) == 0, "sequence length must be even"); + for (int i = 0; i < N; i += 2) { + __ ld2(v[i], v[i+1], T, __ post(base, 32)); + } + } + + // store N vector registers interleaved into N/2 pairs of quadword + // memory locations via the address supplied in base using + // post-increment addressing. + template + void vs_st2_post(const VSeq& v, Assembler::SIMD_Arrangement T, Register base) { + static_assert((N & (N - 1)) == 0, "sequence length must be even"); + for (int i = 0; i < N; i += 2) { + __ st2(v[i], v[i+1], T, __ post(base, 32)); + } + } + + // load N quadword values from memory de-interleaved into N vector + // registers 3 elements at a time via the address supplied in base. + template + void vs_ld3(const VSeq& v, Assembler::SIMD_Arrangement T, Register base) { + static_assert(N == ((N / 3) * 3), "sequence length must be multiple of 3"); + for (int i = 0; i < N; i += 3) { + __ ld3(v[i], v[i+1], v[i+2], T, base); + } + } + + // load N quadword values from memory de-interleaved into N vector + // registers 3 elements at a time via the address supplied in base + // using post-increment addressing. + template + void vs_ld3_post(const VSeq& v, Assembler::SIMD_Arrangement T, Register base) { + static_assert(N == ((N / 3) * 3), "sequence length must be multiple of 3"); + for (int i = 0; i < N; i += 3) { + __ ld3(v[i], v[i+1], v[i+2], T, __ post(base, 48)); + } + } + // load N/2 pairs of quadword values from memory into N vector // registers via the address supplied in base with each pair indexed // using the the start offset plus the corresponding entry in the @@ -4810,23 +4916,29 @@ class StubGenerator: public StubCodeGenerator { } } - // Helper routines for various flavours of dilithium montgomery - // multiply + // Helper routines for various flavours of Montgomery multiply - // Perform 16 32-bit Montgomery multiplications in parallel - // See the montMul() method of the sun.security.provider.ML_DSA class. + // Perform 16 32-bit (4x4S) or 32 16-bit (4 x 8H) Montgomery + // multiplications in parallel // - // Computes 4x4S results - // a = b * c * 2^-32 mod MONT_Q - // Inputs: vb, vc - 4x4S vector register sequences - // vq - 2x4S constants - // Temps: vtmp - 4x4S vector sequence trashed after call - // Outputs: va - 4x4S vector register sequences + + // See the montMul() method of the sun.security.provider.ML_DSA + // class. + // + // Computes 4x4S results or 8x8H results + // a = b * c * 2^MONT_R_BITS mod MONT_Q + // Inputs: vb, vc - 4x4S or 4x8H vector register sequences + // vq - 2x4S or 2x8H constants + // Temps: vtmp - 4x4S or 4x8H vector sequence trashed after call + // Outputs: va - 4x4S or 4x8H vector register sequences // vb, vc, vtmp and vq must all be disjoint // va must be disjoint from all other inputs/temps or must equal vc - // n.b. MONT_R_BITS is 32, so the right shift by it is implicit. - void dilithium_montmul16(const VSeq<4>& va, const VSeq<4>& vb, const VSeq<4>& vc, - const VSeq<4>& vtmp, const VSeq<2>& vq) { + // va must have a non-zero delta i.e. it must not be a constant vseq. + // n.b. MONT_R_BITS is 16 or 32, so the right shift by it is implicit. + void vs_montmul4(const VSeq<4>& va, const VSeq<4>& vb, const VSeq<4>& vc, + Assembler::SIMD_Arrangement T, + const VSeq<4>& vtmp, const VSeq<2>& vq) { + assert (T == __ T4S || T == __ T8H, "invalid arrangement for montmul"); assert(vs_disjoint(vb, vc), "vb and vc overlap"); assert(vs_disjoint(vb, vq), "vb and vq overlap"); assert(vs_disjoint(vb, vtmp), "vb and vtmp overlap"); @@ -4840,40 +4952,107 @@ class StubGenerator: public StubCodeGenerator { assert(vs_disjoint(va, vb), "va and vb overlap"); assert(vs_disjoint(va, vq), "va and vq overlap"); assert(vs_disjoint(va, vtmp), "va and vtmp overlap"); + assert(!va.is_constant(), "output vector must identify 4 different registers"); // schedule 4 streams of instructions across the vector sequences for (int i = 0; i < 4; i++) { - __ sqdmulh(vtmp[i], __ T4S, vb[i], vc[i]); // aHigh = hi32(2 * b * c) - __ mulv(va[i], __ T4S, vb[i], vc[i]); // aLow = lo32(b * c) + __ sqdmulh(vtmp[i], T, vb[i], vc[i]); // aHigh = hi32(2 * b * c) + __ mulv(va[i], T, vb[i], vc[i]); // aLow = lo32(b * c) } for (int i = 0; i < 4; i++) { - __ mulv(va[i], __ T4S, va[i], vq[0]); // m = aLow * qinv + __ mulv(va[i], T, va[i], vq[0]); // m = aLow * qinv } for (int i = 0; i < 4; i++) { - __ sqdmulh(va[i], __ T4S, va[i], vq[1]); // n = hi32(2 * m * q) + __ sqdmulh(va[i], T, va[i], vq[1]); // n = hi32(2 * m * q) } for (int i = 0; i < 4; i++) { - __ shsubv(va[i], __ T4S, vtmp[i], va[i]); // a = (aHigh - n) / 2 + __ shsubv(va[i], T, vtmp[i], va[i]); // a = (aHigh - n) / 2 } } - // Perform 2x16 32-bit Montgomery multiplications in parallel - // See the montMul() method of the sun.security.provider.ML_DSA class. + // Perform 8 32-bit (4x4S) or 16 16-bit (2 x 8H) Montgomery + // multiplications in parallel + // + + // See the montMul() method of the sun.security.provider.ML_DSA + // class. // - // Computes 8x4S results - // a = b * c * 2^-32 mod MONT_Q - // Inputs: vb, vc - 8x4S vector register sequences - // vq - 2x4S constants - // Temps: vtmp - 4x4S vector sequence trashed after call - // Outputs: va - 8x4S vector register sequences + // Computes 4x4S results or 8x8H results + // a = b * c * 2^MONT_R_BITS mod MONT_Q + // Inputs: vb, vc - 4x4S or 4x8H vector register sequences + // vq - 2x4S or 2x8H constants + // Temps: vtmp - 4x4S or 4x8H vector sequence trashed after call + // Outputs: va - 4x4S or 4x8H vector register sequences // vb, vc, vtmp and vq must all be disjoint // va must be disjoint from all other inputs/temps or must equal vc - // n.b. MONT_R_BITS is 32, so the right shift by it is implicit. - void vs_montmul32(const VSeq<8>& va, const VSeq<8>& vb, const VSeq<8>& vc, - const VSeq<4>& vtmp, const VSeq<2>& vq) { + // va must have a non-zero delta i.e. it must not be a constant vseq. + // n.b. MONT_R_BITS is 16 or 32, so the right shift by it is implicit. + void vs_montmul2(const VSeq<2>& va, const VSeq<2>& vb, const VSeq<2>& vc, + Assembler::SIMD_Arrangement T, + const VSeq<2>& vtmp, const VSeq<2>& vq) { + assert (T == __ T4S || T == __ T8H, "invalid arrangement for montmul"); + assert(vs_disjoint(vb, vc), "vb and vc overlap"); + assert(vs_disjoint(vb, vq), "vb and vq overlap"); + assert(vs_disjoint(vb, vtmp), "vb and vtmp overlap"); + + assert(vs_disjoint(vc, vq), "vc and vq overlap"); + assert(vs_disjoint(vc, vtmp), "vc and vtmp overlap"); + + assert(vs_disjoint(vq, vtmp), "vq and vtmp overlap"); + + assert(vs_disjoint(va, vc) || vs_same(va, vc), "va and vc neither disjoint nor equal"); + assert(vs_disjoint(va, vb), "va and vb overlap"); + assert(vs_disjoint(va, vq), "va and vq overlap"); + assert(vs_disjoint(va, vtmp), "va and vtmp overlap"); + assert(!va.is_constant(), "output vector must identify 2 different registers"); + + // schedule 2 streams of instructions across the vector sequences + for (int i = 0; i < 2; i++) { + __ sqdmulh(vtmp[i], T, vb[i], vc[i]); // aHigh = hi32(2 * b * c) + __ mulv(va[i], T, vb[i], vc[i]); // aLow = lo32(b * c) + } + + for (int i = 0; i < 2; i++) { + __ mulv(va[i], T, va[i], vq[0]); // m = aLow * qinv + } + + for (int i = 0; i < 2; i++) { + __ sqdmulh(va[i], T, va[i], vq[1]); // n = hi32(2 * m * q) + } + + for (int i = 0; i < 2; i++) { + __ shsubv(va[i], T, vtmp[i], va[i]); // a = (aHigh - n) / 2 + } + } + + // Perform 16 16-bit Montgomery multiplications in parallel. + void kyber_montmul16(const VSeq<2>& va, const VSeq<2>& vb, const VSeq<2>& vc, + const VSeq<2>& vtmp, const VSeq<2>& vq) { + // Use the helper routine to schedule a 2x8H Montgomery multiply. + // It will assert that the register use is valid + vs_montmul2(va, vb, vc, __ T8H, vtmp, vq); + } + + // Perform 32 16-bit Montgomery multiplications in parallel. + void kyber_montmul32(const VSeq<4>& va, const VSeq<4>& vb, const VSeq<4>& vc, + const VSeq<4>& vtmp, const VSeq<2>& vq) { + // Use the helper routine to schedule a 4x8H Montgomery multiply. + // It will assert that the register use is valid + vs_montmul4(va, vb, vc, __ T8H, vtmp, vq); + } + + // Perform 64 16-bit Montgomery multiplications in parallel. + void kyber_montmul64(const VSeq<8>& va, const VSeq<8>& vb, const VSeq<8>& vc, + const VSeq<4>& vtmp, const VSeq<2>& vq) { + // Schedule two successive 4x8H multiplies via the montmul helper + // on the front and back halves of va, vb and vc. The helper will + // assert that the register use has no overlap conflicts on each + // individual call but we also need to ensure that the necessary + // disjoint/equality constraints are met across both calls. + // vb, vc, vtmp and vq must be disjoint. va must either be // disjoint from all other registers or equal vc @@ -4891,8 +5070,8 @@ class StubGenerator: public StubCodeGenerator { assert(vs_disjoint(va, vq), "va and vq overlap"); assert(vs_disjoint(va, vtmp), "va and vtmp overlap"); - // we need to multiply the front and back halves of each sequence - // 4x4S at a time because + // we multiply the front and back halves of each sequence 4 at a + // time because // // 1) we are currently only able to get 4-way instruction // parallelism at best @@ -4901,14 +5080,1236 @@ class StubGenerator: public StubCodeGenerator { // scratch registers to hold intermediate results so vtmp can only // be a VSeq<4> which means we only have 4 scratch slots - dilithium_montmul16(vs_front(va), vs_front(vb), vs_front(vc), vtmp, vq); - dilithium_montmul16(vs_back(va), vs_back(vb), vs_back(vc), vtmp, vq); + vs_montmul4(vs_front(va), vs_front(vb), vs_front(vc), __ T8H, vtmp, vq); + vs_montmul4(vs_back(va), vs_back(vb), vs_back(vc), __ T8H, vtmp, vq); + } + + void kyber_montmul32_sub_add(const VSeq<4>& va0, const VSeq<4>& va1, + const VSeq<4>& vc, + const VSeq<4>& vtmp, + const VSeq<2>& vq) { + // compute a = montmul(a1, c) + kyber_montmul32(vc, va1, vc, vtmp, vq); + // ouptut a1 = a0 - a + vs_subv(va1, __ T8H, va0, vc); + // and a0 = a0 + a + vs_addv(va0, __ T8H, va0, vc); + } + + void kyber_sub_add_montmul32(const VSeq<4>& va0, const VSeq<4>& va1, + const VSeq<4>& vb, + const VSeq<4>& vtmp1, + const VSeq<4>& vtmp2, + const VSeq<2>& vq) { + // compute c = a0 - a1 + vs_subv(vtmp1, __ T8H, va0, va1); + // output a0 = a0 + a1 + vs_addv(va0, __ T8H, va0, va1); + // output a1 = b montmul c + kyber_montmul32(va1, vtmp1, vb, vtmp2, vq); + } + + void load64shorts(const VSeq<8>& v, Register shorts) { + vs_ldpq_post(v, shorts); + } + + void load32shorts(const VSeq<4>& v, Register shorts) { + vs_ldpq_post(v, shorts); + } + + void store64shorts(VSeq<8> v, Register tmpAddr) { + vs_stpq_post(v, tmpAddr); + } + + // Kyber NTT function. + // Implements + // static int implKyberNtt(short[] poly, short[] ntt_zetas) {} + // + // coeffs (short[256]) = c_rarg0 + // ntt_zetas (short[256]) = c_rarg1 + address generate_kyberNtt() { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = StubGenStubId::kyberNtt_id; + StubCodeMark mark(this, stub_id); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + + const Register kyberConsts = r10; + const Register tmpAddr = r11; + + VSeq<8> vs1(0), vs2(16), vs3(24); // 3 sets of 8x8H inputs/outputs + VSeq<4> vtmp = vs_front(vs3); // n.b. tmp registers overlap vs3 + VSeq<2> vq(30); // n.b. constants overlap vs3 + + __ lea(kyberConsts, ExternalAddress((address) StubRoutines::aarch64::_kyberConsts)); + // load the montmul constants + vs_ldpq(vq, kyberConsts); + + // Each level corresponds to an iteration of the outermost loop of the + // Java method seilerNTT(int[] coeffs). There are some differences + // from what is done in the seilerNTT() method, though: + // 1. The computation is using 16-bit signed values, we do not convert them + // to ints here. + // 2. The zetas are delivered in a bigger array, 128 zetas are stored in + // this array for each level, it is easier that way to fill up the vector + // registers. + // 3. In the seilerNTT() method we use R = 2^20 for the Montgomery + // multiplications (this is because that way there should not be any + // overflow during the inverse NTT computation), here we usr R = 2^16 so + // that we can use the 16-bit arithmetic in the vector unit. + // + // On each level, we fill up the vector registers in such a way that the + // array elements that need to be multiplied by the zetas go into one + // set of vector registers while the corresponding ones that don't need to + // be multiplied, go into another set. + // We can do 32 Montgomery multiplications in parallel, using 12 vector + // registers interleaving the steps of 4 identical computations, + // each done on 8 16-bit values per register. + + // At levels 0-3 the coefficients multiplied by or added/subtracted + // to the zetas occur in discrete blocks whose size is some multiple + // of 32. + + // level 0 + __ add(tmpAddr, coeffs, 256); + load64shorts(vs1, tmpAddr); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 0); + load64shorts(vs1, tmpAddr); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 0); + vs_stpq_post(vs1, tmpAddr); + __ add(tmpAddr, coeffs, 256); + vs_stpq_post(vs3, tmpAddr); + // restore montmul constants + vs_ldpq(vq, kyberConsts); + load64shorts(vs1, tmpAddr); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 128); + load64shorts(vs1, tmpAddr); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 128); + store64shorts(vs1, tmpAddr); + __ add(tmpAddr, coeffs, 384); + store64shorts(vs3, tmpAddr); + + // level 1 + // restore montmul constants + vs_ldpq(vq, kyberConsts); + __ add(tmpAddr, coeffs, 128); + load64shorts(vs1, tmpAddr); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 0); + load64shorts(vs1, tmpAddr); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 0); + store64shorts(vs1, tmpAddr); + store64shorts(vs3, tmpAddr); + vs_ldpq(vq, kyberConsts); + __ add(tmpAddr, coeffs, 384); + load64shorts(vs1, tmpAddr); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 256); + load64shorts(vs1, tmpAddr); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 256); + store64shorts(vs1, tmpAddr); + store64shorts(vs3, tmpAddr); + + // level 2 + vs_ldpq(vq, kyberConsts); + int offsets1[4] = { 0, 32, 128, 160 }; + vs_ldpq_indexed(vs1, coeffs, 64, offsets1); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_ldpq_indexed(vs1, coeffs, 0, offsets1); + // kyber_subv_addv64(); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 0); + vs_stpq_post(vs_front(vs1), tmpAddr); + vs_stpq_post(vs_front(vs3), tmpAddr); + vs_stpq_post(vs_back(vs1), tmpAddr); + vs_stpq_post(vs_back(vs3), tmpAddr); + vs_ldpq(vq, kyberConsts); + vs_ldpq_indexed(vs1, tmpAddr, 64, offsets1); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_ldpq_indexed(vs1, coeffs, 256, offsets1); + // kyber_subv_addv64(); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 256); + vs_stpq_post(vs_front(vs1), tmpAddr); + vs_stpq_post(vs_front(vs3), tmpAddr); + vs_stpq_post(vs_back(vs1), tmpAddr); + vs_stpq_post(vs_back(vs3), tmpAddr); + + // level 3 + vs_ldpq(vq, kyberConsts); + int offsets2[4] = { 0, 64, 128, 192 }; + vs_ldpq_indexed(vs1, coeffs, 32, offsets2); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_ldpq_indexed(vs1, coeffs, 0, offsets2); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + vs_stpq_indexed(vs1, coeffs, 0, offsets2); + vs_stpq_indexed(vs3, coeffs, 32, offsets2); + + vs_ldpq(vq, kyberConsts); + vs_ldpq_indexed(vs1, coeffs, 256 + 32, offsets2); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_ldpq_indexed(vs1, coeffs, 256, offsets2); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + vs_stpq_indexed(vs1, coeffs, 256, offsets2); + vs_stpq_indexed(vs3, coeffs, 256 + 32, offsets2); + + // level 4 + // At level 4 coefficients occur in 8 discrete blocks of size 16 + // so they are loaded using employing an ldr at 8 distinct offsets. + + vs_ldpq(vq, kyberConsts); + int offsets3[8] = { 0, 32, 64, 96, 128, 160, 192, 224 }; + vs_ldr_indexed(vs1, __ Q, coeffs, 16, offsets3); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_ldr_indexed(vs1, __ Q, coeffs, 0, offsets3); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + vs_str_indexed(vs1, __ Q, coeffs, 0, offsets3); + vs_str_indexed(vs3, __ Q, coeffs, 16, offsets3); + + vs_ldpq(vq, kyberConsts); + vs_ldr_indexed(vs1, __ Q, coeffs, 256 + 16, offsets3); + load64shorts(vs2, zetas); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_ldr_indexed(vs1, __ Q, coeffs, 256, offsets3); + vs_subv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_addv(vs1, __ T8H, vs1, vs2); + vs_str_indexed(vs1, __ Q, coeffs, 256, offsets3); + vs_str_indexed(vs3, __ Q, coeffs, 256 + 16, offsets3); + + // level 5 + // At level 5 related coefficients occur in discrete blocks of size 8 so + // need to be loaded interleaved using an ld2 operation with arrangement 2D. + + vs_ldpq(vq, kyberConsts); + int offsets4[4] = { 0, 32, 64, 96 }; + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 0, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 0, offsets4); + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 128, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 128, offsets4); + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 256, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 256, offsets4); + + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 384, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 384, offsets4); + + // level 6 + // At level 6 related coefficients occur in discrete blocks of size 4 so + // need to be loaded interleaved using an ld2 operation with arrangement 4S. + + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 0, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 0, offsets4); + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 128, offsets4); + // __ ldpq(v18, v19, __ post(zetas, 32)); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 128, offsets4); + + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 256, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 256, offsets4); + + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 384, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_montmul32_sub_add(vs_even(vs1), vs_odd(vs1), vs_front(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 384, offsets4); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // Kyber Inverse NTT function + // Implements + // static int implKyberInverseNtt(short[] poly, short[] zetas) {} + // + // coeffs (short[256]) = c_rarg0 + // ntt_zetas (short[256]) = c_rarg1 + address generate_kyberInverseNtt() { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = StubGenStubId::kyberInverseNtt_id; + StubCodeMark mark(this, stub_id); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + + const Register kyberConsts = r10; + const Register tmpAddr = r11; + const Register tmpAddr2 = c_rarg2; + + VSeq<8> vs1(0), vs2(16), vs3(24); // 3 sets of 8x8H inputs/outputs + VSeq<4> vtmp = vs_front(vs3); // n.b. tmp registers overlap vs3 + VSeq<2> vq(30); // n.b. constants overlap vs3 + + __ lea(kyberConsts, + ExternalAddress((address) StubRoutines::aarch64::_kyberConsts)); + + // level 0 + // At level 0 related coefficients occur in discrete blocks of size 4 so + // need to be loaded interleaved using an ld2 operation with arrangement 4S. + + vs_ldpq(vq, kyberConsts); + int offsets4[4] = { 0, 32, 64, 96 }; + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 0, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 0, offsets4); + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 128, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 128, offsets4); + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 256, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 256, offsets4); + vs_ld2_indexed(vs1, __ T4S, coeffs, tmpAddr, 384, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T4S, coeffs, tmpAddr, 384, offsets4); + + // level 1 + // At level 1 related coefficients occur in discrete blocks of size 8 so + // need to be loaded interleaved using an ld2 operation with arrangement 2D. + + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 0, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 0, offsets4); + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 128, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 128, offsets4); + + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 256, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 256, offsets4); + vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, 384, offsets4); + load32shorts(vs_front(vs2), zetas); + kyber_sub_add_montmul32(vs_even(vs1), vs_odd(vs1), + vs_front(vs2), vs_back(vs2), vtmp, vq); + vs_st2_indexed(vs1, __ T2D, coeffs, tmpAddr, 384, offsets4); + + // level 2 + // At level 2 coefficients occur in 8 discrete blocks of size 16 + // so they are loaded using employing an ldr at 8 distinct offsets. + + int offsets3[8] = { 0, 32, 64, 96, 128, 160, 192, 224 }; + vs_ldr_indexed(vs1, __ Q, coeffs, 0, offsets3); + vs_ldr_indexed(vs2, __ Q, coeffs, 16, offsets3); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + vs_str_indexed(vs3, __ Q, coeffs, 0, offsets3); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_str_indexed(vs2, __ Q, coeffs, 16, offsets3); + + vs_ldr_indexed(vs1, __ Q, coeffs, 256, offsets3); + vs_ldr_indexed(vs2, __ Q, coeffs, 256 + 16, offsets3); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + vs_str_indexed(vs3, __ Q, coeffs, 256, offsets3); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_str_indexed(vs2, __ Q, coeffs, 256 + 16, offsets3); + + // Barrett reduction at indexes where overflow may happen + + // load q and the multiplier for the Barrett reduction + __ add(tmpAddr, kyberConsts, 16); + vs_ldpq(vq, tmpAddr); + + VSeq<8> vq1 = VSeq<8>(vq[0], 0); // 2 constant 8 sequences + VSeq<8> vq2 = VSeq<8>(vq[1], 0); // for above two kyber constants + VSeq<8> vq3 = VSeq<8>(v29, 0); // 3rd sequence for const montmul + vs_ldr_indexed(vs1, __ Q, coeffs, 0, offsets3); + vs_sqdmulh(vs2, __ T8H, vs1, vq2); + vs_sshr(vs2, __ T8H, vs2, 11); + vs_mlsv(vs1, __ T8H, vs2, vq1); + vs_str_indexed(vs1, __ Q, coeffs, 0, offsets3); + vs_ldr_indexed(vs1, __ Q, coeffs, 256, offsets3); + vs_sqdmulh(vs2, __ T8H, vs1, vq2); + vs_sshr(vs2, __ T8H, vs2, 11); + vs_mlsv(vs1, __ T8H, vs2, vq1); + vs_str_indexed(vs1, __ Q, coeffs, 256, offsets3); + + // level 3 + // From level 3 upwards coefficients occur in discrete blocks whose size is + // some multiple of 32 so can be loaded using ldpq and suitable indexes. + + int offsets2[4] = { 0, 64, 128, 192 }; + vs_ldpq_indexed(vs1, coeffs, 0, offsets2); + vs_ldpq_indexed(vs2, coeffs, 32, offsets2); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + vs_stpq_indexed(vs3, coeffs, 0, offsets2); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_stpq_indexed(vs2, coeffs, 32, offsets2); + + vs_ldpq_indexed(vs1, coeffs, 256, offsets2); + vs_ldpq_indexed(vs2, coeffs, 256 + 32, offsets2); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + vs_stpq_indexed(vs3, coeffs, 256, offsets2); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_stpq_indexed(vs2, coeffs, 256 + 32, offsets2); + + // level 4 + + int offsets1[4] = { 0, 32, 128, 160 }; + vs_ldpq_indexed(vs1, coeffs, 0, offsets1); + vs_ldpq_indexed(vs2, coeffs, 64, offsets1); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + vs_stpq_indexed(vs3, coeffs, 0, offsets1); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_stpq_indexed(vs2, coeffs, 64, offsets1); + + vs_ldpq_indexed(vs1, coeffs, 256, offsets1); + vs_ldpq_indexed(vs2, coeffs, 256 + 64, offsets1); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + vs_stpq_indexed(vs3, coeffs, 256, offsets1); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + vs_stpq_indexed(vs2, coeffs, 256 + 64, offsets1); + + // level 5 + + __ add(tmpAddr, coeffs, 0); + load64shorts(vs1, tmpAddr); + __ add(tmpAddr, coeffs, 128); + load64shorts(vs2, tmpAddr); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 0); + store64shorts(vs3, tmpAddr); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 128); + store64shorts(vs2, tmpAddr); + + load64shorts(vs1, tmpAddr); + __ add(tmpAddr, coeffs, 384); + load64shorts(vs2, tmpAddr); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 256); + store64shorts(vs3, tmpAddr); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 384); + store64shorts(vs2, tmpAddr); + + // Barrett reduction at indexes where overflow may happen + + // load q and the multiplier for the Barrett reduction + __ add(tmpAddr, kyberConsts, 16); + vs_ldpq(vq, tmpAddr); + + int offsets0[2] = { 0, 256 }; + vs_ldpq_indexed(vs_front(vs1), coeffs, 0, offsets0); + vs_sqdmulh(vs2, __ T8H, vs1, vq2); + vs_sshr(vs2, __ T8H, vs2, 11); + vs_mlsv(vs1, __ T8H, vs2, vq1); + vs_stpq_indexed(vs_front(vs1), coeffs, 0, offsets0); + + // level 6 + + __ add(tmpAddr, coeffs, 0); + load64shorts(vs1, tmpAddr); + __ add(tmpAddr, coeffs, 256); + load64shorts(vs2, tmpAddr); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 0); + store64shorts(vs3, tmpAddr); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 256); + store64shorts(vs2, tmpAddr); + + __ add(tmpAddr, coeffs, 128); + load64shorts(vs1, tmpAddr); + __ add(tmpAddr, coeffs, 384); + load64shorts(vs2, tmpAddr); + vs_addv(vs3, __ T8H, vs1, vs2); // n.b. trashes vq + vs_subv(vs1, __ T8H, vs1, vs2); + __ add(tmpAddr, coeffs, 128); + store64shorts(vs3, tmpAddr); + load64shorts(vs2, zetas); + vs_ldpq(vq, kyberConsts); + kyber_montmul64(vs2, vs1, vs2, vtmp, vq); + __ add(tmpAddr, coeffs, 384); + store64shorts(vs2, tmpAddr); + + // multiply by 2^-n + + // load toMont(2^-n mod q) + __ add(tmpAddr, kyberConsts, 48); + __ ldr(v29, __ Q, tmpAddr); + + vs_ldpq(vq, kyberConsts); + __ add(tmpAddr, coeffs, 0); + load64shorts(vs1, tmpAddr); + kyber_montmul64(vs2, vs1, vq3, vtmp, vq); + __ add(tmpAddr, coeffs, 0); + store64shorts(vs2, tmpAddr); + + // now tmpAddr contains coeffs + 128 because store64shorts adjusted it so + load64shorts(vs1, tmpAddr); + kyber_montmul64(vs2, vs1, vq3, vtmp, vq); + __ add(tmpAddr, coeffs, 128); + store64shorts(vs2, tmpAddr); + + // now tmpAddr contains coeffs + 256 + load64shorts(vs1, tmpAddr); + kyber_montmul64(vs2, vs1, vq3, vtmp, vq); + __ add(tmpAddr, coeffs, 256); + store64shorts(vs2, tmpAddr); + + // now tmpAddr contains coeffs + 384 + load64shorts(vs1, tmpAddr); + kyber_montmul64(vs2, vs1, vq3, vtmp, vq); + __ add(tmpAddr, coeffs, 384); + store64shorts(vs2, tmpAddr); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // Kyber multiply polynomials in the NTT domain. + // Implements + // static int implKyberNttMult( + // short[] result, short[] ntta, short[] nttb, short[] zetas) {} + // + // result (short[256]) = c_rarg0 + // ntta (short[256]) = c_rarg1 + // nttb (short[256]) = c_rarg2 + // zetas (short[128]) = c_rarg3 + address generate_kyberNttMult() { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = StubGenStubId::kyberNttMult_id; + StubCodeMark mark(this, stub_id); + address start = __ pc(); + __ enter(); + + const Register result = c_rarg0; + const Register ntta = c_rarg1; + const Register nttb = c_rarg2; + const Register zetas = c_rarg3; + + const Register kyberConsts = r10; + const Register limit = r11; + + VSeq<4> vs1(0), vs2(4); // 4 sets of 8x8H inputs/outputs/tmps + VSeq<4> vs3(16), vs4(20); + VSeq<2> vq(30); // pair of constants for montmul: q, qinv + VSeq<2> vz(28); // pair of zetas + VSeq<4> vc(27, 0); // constant sequence for montmul: montRSquareModQ + + __ lea(kyberConsts, + ExternalAddress((address) StubRoutines::aarch64::_kyberConsts)); + + Label kyberNttMult_loop; + + __ add(limit, result, 512); + + // load q and qinv + vs_ldpq(vq, kyberConsts); + + // load R^2 mod q (to convert back from Montgomery representation) + __ add(kyberConsts, kyberConsts, 64); + __ ldr(v27, __ Q, kyberConsts); + + __ BIND(kyberNttMult_loop); + + // load 16 zetas + vs_ldpq_post(vz, zetas); + + // load 2 sets of 32 coefficients from the two input arrays + // interleaved as shorts. i.e. pairs of shorts adjacent in memory + // are striped across pairs of vector registers + vs_ld2_post(vs_front(vs1), __ T8H, ntta); // x 8H + vs_ld2_post(vs_back(vs1), __ T8H, nttb); // x 8H + vs_ld2_post(vs_front(vs4), __ T8H, ntta); // x 8H + vs_ld2_post(vs_back(vs4), __ T8H, nttb); // x 8H + + // compute 4 montmul cross-products for pairs (a0,a1) and (b0,b1) + // i.e. montmul the first and second halves of vs1 in order and + // then with one sequence reversed storing the two results in vs3 + // + // vs3[0] <- montmul(a0, b0) + // vs3[1] <- montmul(a1, b1) + // vs3[2] <- montmul(a0, b1) + // vs3[3] <- montmul(a1, b0) + kyber_montmul16(vs_front(vs3), vs_front(vs1), vs_back(vs1), vs_front(vs2), vq); + kyber_montmul16(vs_back(vs3), + vs_front(vs1), vs_reverse(vs_back(vs1)), vs_back(vs2), vq); + + // compute 4 montmul cross-products for pairs (a2,a3) and (b2,b3) + // i.e. montmul the first and second halves of vs4 in order and + // then with one sequence reversed storing the two results in vs1 + // + // vs1[0] <- montmul(a2, b2) + // vs1[1] <- montmul(a3, b3) + // vs1[2] <- montmul(a2, b3) + // vs1[3] <- montmul(a3, b2) + kyber_montmul16(vs_front(vs1), vs_front(vs4), vs_back(vs4), vs_front(vs2), vq); + kyber_montmul16(vs_back(vs1), + vs_front(vs4), vs_reverse(vs_back(vs4)), vs_back(vs2), vq); + + // montmul result 2 of each cross-product i.e. (a1*b1, a3*b3) by a zeta. + // We can schedule two montmuls at a time if we use a suitable vector + // sequence . + int delta = vs1[1]->encoding() - vs3[1]->encoding(); + VSeq<2> vs5(vs3[1], delta); + + // vs3[1] <- montmul(montmul(a1, b1), z0) + // vs1[1] <- montmul(montmul(a3, b3), z1) + kyber_montmul16(vs5, vz, vs5, vs_front(vs2), vq); + + // add results in pairs storing in vs3 + // vs3[0] <- montmul(a0, b0) + montmul(montmul(a1, b1), z0); + // vs3[1] <- montmul(a0, b1) + montmul(a1, b0); + vs_addv(vs_front(vs3), __ T8H, vs_even(vs3), vs_odd(vs3)); + + // vs3[2] <- montmul(a2, b2) + montmul(montmul(a3, b3), z1); + // vs3[3] <- montmul(a2, b3) + montmul(a3, b2); + vs_addv(vs_back(vs3), __ T8H, vs_even(vs1), vs_odd(vs1)); + + // vs1 <- montmul(vs3, montRSquareModQ) + kyber_montmul32(vs1, vs3, vc, vs2, vq); + + // store back the two pairs of result vectors de-interleaved as 8H elements + // i.e. storing each pairs of shorts striped across a register pair adjacent + // in memory + vs_st2_post(vs1, __ T8H, result); + + __ cmp(result, limit); + __ br(Assembler::NE, kyberNttMult_loop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // Kyber add 2 polynomials. + // Implements + // static int implKyberAddPoly(short[] result, short[] a, short[] b) {} + // + // result (short[256]) = c_rarg0 + // a (short[256]) = c_rarg1 + // b (short[256]) = c_rarg2 + address generate_kyberAddPoly_2() { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = StubGenStubId::kyberAddPoly_2_id; + StubCodeMark mark(this, stub_id); + address start = __ pc(); + __ enter(); + + const Register result = c_rarg0; + const Register a = c_rarg1; + const Register b = c_rarg2; + + const Register kyberConsts = r11; + + // We sum 256 sets of values in total i.e. 32 x 8H quadwords. + // So, we can load, add and store the data in 3 groups of 11, + // 11 and 10 at a time i.e. we need to map sets of 10 or 11 + // registers. A further constraint is that the mapping needs + // to skip callee saves. So, we allocate the register + // sequences using two 8 sequences, two 2 sequences and two + // single registers. + VSeq<8> vs1_1(0); + VSeq<2> vs1_2(16); + FloatRegister vs1_3 = v28; + VSeq<8> vs2_1(18); + VSeq<2> vs2_2(26); + FloatRegister vs2_3 = v29; + + // two constant vector sequences + VSeq<8> vc_1(31, 0); + VSeq<2> vc_2(31, 0); + + FloatRegister vc_3 = v31; + __ lea(kyberConsts, + ExternalAddress((address) StubRoutines::aarch64::_kyberConsts)); + + __ ldr(vc_3, __ Q, Address(kyberConsts, 16)); // q + for (int i = 0; i < 3; i++) { + // load 80 or 88 values from a into vs1_1/2/3 + vs_ldpq_post(vs1_1, a); + vs_ldpq_post(vs1_2, a); + if (i < 2) { + __ ldr(vs1_3, __ Q, __ post(a, 16)); + } + // load 80 or 88 values from b into vs2_1/2/3 + vs_ldpq_post(vs2_1, b); + vs_ldpq_post(vs2_2, b); + if (i < 2) { + __ ldr(vs2_3, __ Q, __ post(b, 16)); + } + // sum 80 or 88 values across vs1 and vs2 into vs1 + vs_addv(vs1_1, __ T8H, vs1_1, vs2_1); + vs_addv(vs1_2, __ T8H, vs1_2, vs2_2); + if (i < 2) { + __ addv(vs1_3, __ T8H, vs1_3, vs2_3); + } + // add constant to all 80 or 88 results + vs_addv(vs1_1, __ T8H, vs1_1, vc_1); + vs_addv(vs1_2, __ T8H, vs1_2, vc_2); + if (i < 2) { + __ addv(vs1_3, __ T8H, vs1_3, vc_3); + } + // store 80 or 88 values + vs_stpq_post(vs1_1, result); + vs_stpq_post(vs1_2, result); + if (i < 2) { + __ str(vs1_3, __ Q, __ post(result, 16)); + } + } + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // Kyber add 3 polynomials. + // Implements + // static int implKyberAddPoly(short[] result, short[] a, short[] b, short[] c) {} + // + // result (short[256]) = c_rarg0 + // a (short[256]) = c_rarg1 + // b (short[256]) = c_rarg2 + // c (short[256]) = c_rarg3 + address generate_kyberAddPoly_3() { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = StubGenStubId::kyberAddPoly_3_id; + StubCodeMark mark(this, stub_id); + address start = __ pc(); + __ enter(); + + const Register result = c_rarg0; + const Register a = c_rarg1; + const Register b = c_rarg2; + const Register c = c_rarg3; + + const Register kyberConsts = r11; + + // As above we sum 256 sets of values in total i.e. 32 x 8H + // quadwords. So, we can load, add and store the data in 3 + // groups of 11, 11 and 10 at a time i.e. we need to map sets + // of 10 or 11 registers. A further constraint is that the + // mapping needs to skip callee saves. So, we allocate the + // register sequences using two 8 sequences, two 2 sequences + // and two single registers. + VSeq<8> vs1_1(0); + VSeq<2> vs1_2(16); + FloatRegister vs1_3 = v28; + VSeq<8> vs2_1(18); + VSeq<2> vs2_2(26); + FloatRegister vs2_3 = v29; + + // two constant vector sequences + VSeq<8> vc_1(31, 0); + VSeq<2> vc_2(31, 0); + + FloatRegister vc_3 = v31; + + __ lea(kyberConsts, + ExternalAddress((address) StubRoutines::aarch64::_kyberConsts)); + + __ ldr(vc_3, __ Q, Address(kyberConsts, 16)); // q + for (int i = 0; i < 3; i++) { + // load 80 or 88 values from a into vs1_1/2/3 + vs_ldpq_post(vs1_1, a); + vs_ldpq_post(vs1_2, a); + if (i < 2) { + __ ldr(vs1_3, __ Q, __ post(a, 16)); + } + // load 80 or 88 values from b into vs2_1/2/3 + vs_ldpq_post(vs2_1, b); + vs_ldpq_post(vs2_2, b); + if (i < 2) { + __ ldr(vs2_3, __ Q, __ post(b, 16)); + } + // sum 80 or 88 values across vs1 and vs2 into vs1 + vs_addv(vs1_1, __ T8H, vs1_1, vs2_1); + vs_addv(vs1_2, __ T8H, vs1_2, vs2_2); + if (i < 2) { + __ addv(vs1_3, __ T8H, vs1_3, vs2_3); + } + // load 80 or 88 values from c into vs2_1/2/3 + vs_ldpq_post(vs2_1, c); + vs_ldpq_post(vs2_2, c); + if (i < 2) { + __ ldr(vs2_3, __ Q, __ post(c, 16)); + } + // sum 80 or 88 values across vs1 and vs2 into vs1 + vs_addv(vs1_1, __ T8H, vs1_1, vs2_1); + vs_addv(vs1_2, __ T8H, vs1_2, vs2_2); + if (i < 2) { + __ addv(vs1_3, __ T8H, vs1_3, vs2_3); + } + // add constant to all 80 or 88 results + vs_addv(vs1_1, __ T8H, vs1_1, vc_1); + vs_addv(vs1_2, __ T8H, vs1_2, vc_2); + if (i < 2) { + __ addv(vs1_3, __ T8H, vs1_3, vc_3); + } + // store 80 or 88 values + vs_stpq_post(vs1_1, result); + vs_stpq_post(vs1_2, result); + if (i < 2) { + __ str(vs1_3, __ Q, __ post(result, 16)); + } + } + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; } - // perform combined montmul then add/sub on 4x4S vectors + // Kyber parse XOF output to polynomial coefficient candidates + // or decodePoly(12, ...). + // Implements + // static int implKyber12To16( + // byte[] condensed, int index, short[] parsed, int parsedLength) {} + // + // (parsedLength or (parsedLength - 48) must be divisible by 64.) + // + // condensed (byte[]) = c_rarg0 + // condensedIndex = c_rarg1 + // parsed (short[112 or 256]) = c_rarg2 + // parsedLength (112 or 256) = c_rarg3 + address generate_kyber12To16() { + Label L_F00, L_loop, L_end; + + __ BIND(L_F00); + __ emit_int64(0x0f000f000f000f00); + __ emit_int64(0x0f000f000f000f00); + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = StubGenStubId::kyber12To16_id; + StubCodeMark mark(this, stub_id); + address start = __ pc(); + __ enter(); + + const Register condensed = c_rarg0; + const Register condensedOffs = c_rarg1; + const Register parsed = c_rarg2; + const Register parsedLength = c_rarg3; + + const Register tmpAddr = r11; + + // Data is input 96 bytes at a time i.e. in groups of 6 x 16B + // quadwords so we need a 6 vector sequence for the inputs. + // Parsing produces 64 shorts, employing two 8 vector + // sequences to store and combine the intermediate data. + VSeq<6> vin(24); + VSeq<8> va(0), vb(16); + + __ adr(tmpAddr, L_F00); + __ ldr(v31, __ Q, tmpAddr); // 8H times 0x0f00 + __ add(condensed, condensed, condensedOffs); + + __ BIND(L_loop); + // load 96 (6 x 16B) byte values + vs_ld3_post(vin, __ T16B, condensed); + + // The front half of sequence vin (vin[0], vin[1] and vin[2]) + // holds 48 (16x3) contiguous bytes from memory striped + // horizontally across each of the 16 byte lanes. Equivalently, + // that is 16 pairs of 12-bit integers. Likewise the back half + // holds the next 48 bytes in the same arrangement. + + // Each vector in the front half can also be viewed as a vertical + // strip across the 16 pairs of 12 bit integers. Each byte in + // vin[0] stores the low 8 bits of the first int in a pair. Each + // byte in vin[1] stores the high 4 bits of the first int and the + // low 4 bits of the second int. Each byte in vin[2] stores the + // high 8 bits of the second int. Likewise the vectors in second + // half. + + // Converting the data to 16-bit shorts requires first of all + // expanding each of the 6 x 16B vectors into 6 corresponding + // pairs of 8H vectors. Mask, shift and add operations on the + // resulting vector pairs can be used to combine 4 and 8 bit + // parts of related 8H vector elements. + // + // The middle vectors (vin[2] and vin[5]) are actually expanded + // twice, one copy manipulated to provide the lower 4 bits + // belonging to the first short in a pair and another copy + // manipulated to provide the higher 4 bits belonging to the + // second short in a pair. This is why the the vector sequences va + // and vb used to hold the expanded 8H elements are of length 8. + + // Expand vin[0] into va[0:1], and vin[1] into va[2:3] and va[4:5] + // n.b. target elements 2 and 3 duplicate elements 4 and 5 + __ ushll(va[0], __ T8H, vin[0], __ T8B, 0); + __ ushll2(va[1], __ T8H, vin[0], __ T16B, 0); + __ ushll(va[2], __ T8H, vin[1], __ T8B, 0); + __ ushll2(va[3], __ T8H, vin[1], __ T16B, 0); + __ ushll(va[4], __ T8H, vin[1], __ T8B, 0); + __ ushll2(va[5], __ T8H, vin[1], __ T16B, 0); + + // likewise expand vin[3] into vb[0:1], and vin[4] into vb[2:3] + // and vb[4:5] + __ ushll(vb[0], __ T8H, vin[3], __ T8B, 0); + __ ushll2(vb[1], __ T8H, vin[3], __ T16B, 0); + __ ushll(vb[2], __ T8H, vin[4], __ T8B, 0); + __ ushll2(vb[3], __ T8H, vin[4], __ T16B, 0); + __ ushll(vb[4], __ T8H, vin[4], __ T8B, 0); + __ ushll2(vb[5], __ T8H, vin[4], __ T16B, 0); + + // shift lo byte of copy 1 of the middle stripe into the high byte + __ shl(va[2], __ T8H, va[2], 8); + __ shl(va[3], __ T8H, va[3], 8); + __ shl(vb[2], __ T8H, vb[2], 8); + __ shl(vb[3], __ T8H, vb[3], 8); + + // expand vin[2] into va[6:7] and vin[5] into vb[6:7] but this + // time pre-shifted by 4 to ensure top bits of input 12-bit int + // are in bit positions [4..11]. + __ ushll(va[6], __ T8H, vin[2], __ T8B, 4); + __ ushll2(va[7], __ T8H, vin[2], __ T16B, 4); + __ ushll(vb[6], __ T8H, vin[5], __ T8B, 4); + __ ushll2(vb[7], __ T8H, vin[5], __ T16B, 4); + + // mask hi 4 bits of the 1st 12-bit int in a pair from copy1 and + // shift lo 4 bits of the 2nd 12-bit int in a pair to the bottom of + // copy2 + __ andr(va[2], __ T16B, va[2], v31); + __ andr(va[3], __ T16B, va[3], v31); + __ ushr(va[4], __ T8H, va[4], 4); + __ ushr(va[5], __ T8H, va[5], 4); + __ andr(vb[2], __ T16B, vb[2], v31); + __ andr(vb[3], __ T16B, vb[3], v31); + __ ushr(vb[4], __ T8H, vb[4], 4); + __ ushr(vb[5], __ T8H, vb[5], 4); + + // sum hi 4 bits and lo 8 bits of the 1st 12-bit int in each pair and + // hi 8 bits plus lo 4 bits of the 2nd 12-bit int in each pair + // n.b. the ordering ensures: i) inputs are consumed before they + // are overwritten ii) the order of 16-bit results across successive + // pairs of vectors in va and then vb reflects the order of the + // corresponding 12-bit inputs + __ addv(va[0], __ T8H, va[0], va[2]); + __ addv(va[2], __ T8H, va[1], va[3]); + __ addv(va[1], __ T8H, va[4], va[6]); + __ addv(va[3], __ T8H, va[5], va[7]); + __ addv(vb[0], __ T8H, vb[0], vb[2]); + __ addv(vb[2], __ T8H, vb[1], vb[3]); + __ addv(vb[1], __ T8H, vb[4], vb[6]); + __ addv(vb[3], __ T8H, vb[5], vb[7]); + + // store 64 results interleaved as shorts + vs_st2_post(vs_front(va), __ T8H, parsed); + vs_st2_post(vs_front(vb), __ T8H, parsed); + + __ sub(parsedLength, parsedLength, 64); + __ cmp(parsedLength, (u1)64); + __ br(Assembler::GE, L_loop); + __ cbz(parsedLength, L_end); + + // if anything is left it should be a final 72 bytes of input + // i.e. a final 48 12-bit values. so we handle this by loading + // 48 bytes into all 16B lanes of front(vin) and only 24 + // bytes into the lower 8B lane of back(vin) + vs_ld3_post(vs_front(vin), __ T16B, condensed); + vs_ld3(vs_back(vin), __ T8B, condensed); + + // Expand vin[0] into va[0:1], and vin[1] into va[2:3] and va[4:5] + // n.b. target elements 2 and 3 of va duplicate elements 4 and + // 5 and target element 2 of vb duplicates element 4. + __ ushll(va[0], __ T8H, vin[0], __ T8B, 0); + __ ushll2(va[1], __ T8H, vin[0], __ T16B, 0); + __ ushll(va[2], __ T8H, vin[1], __ T8B, 0); + __ ushll2(va[3], __ T8H, vin[1], __ T16B, 0); + __ ushll(va[4], __ T8H, vin[1], __ T8B, 0); + __ ushll2(va[5], __ T8H, vin[1], __ T16B, 0); + + // This time expand just the lower 8 lanes + __ ushll(vb[0], __ T8H, vin[3], __ T8B, 0); + __ ushll(vb[2], __ T8H, vin[4], __ T8B, 0); + __ ushll(vb[4], __ T8H, vin[4], __ T8B, 0); + + // shift lo byte of copy 1 of the middle stripe into the high byte + __ shl(va[2], __ T8H, va[2], 8); + __ shl(va[3], __ T8H, va[3], 8); + __ shl(vb[2], __ T8H, vb[2], 8); + + // expand vin[2] into va[6:7] and lower 8 lanes of vin[5] into + // vb[6] pre-shifted by 4 to ensure top bits of the input 12-bit + // int are in bit positions [4..11]. + __ ushll(va[6], __ T8H, vin[2], __ T8B, 4); + __ ushll2(va[7], __ T8H, vin[2], __ T16B, 4); + __ ushll(vb[6], __ T8H, vin[5], __ T8B, 4); + + // mask hi 4 bits of each 1st 12-bit int in pair from copy1 and + // shift lo 4 bits of each 2nd 12-bit int in pair to bottom of + // copy2 + __ andr(va[2], __ T16B, va[2], v31); + __ andr(va[3], __ T16B, va[3], v31); + __ ushr(va[4], __ T8H, va[4], 4); + __ ushr(va[5], __ T8H, va[5], 4); + __ andr(vb[2], __ T16B, vb[2], v31); + __ ushr(vb[4], __ T8H, vb[4], 4); + + + + // sum hi 4 bits and lo 8 bits of each 1st 12-bit int in pair and + // hi 8 bits plus lo 4 bits of each 2nd 12-bit int in pair + + // n.b. ordering ensures: i) inputs are consumed before they are + // overwritten ii) order of 16-bit results across succsessive + // pairs of vectors in va and then lower half of vb reflects order + // of corresponding 12-bit inputs + __ addv(va[0], __ T8H, va[0], va[2]); + __ addv(va[2], __ T8H, va[1], va[3]); + __ addv(va[1], __ T8H, va[4], va[6]); + __ addv(va[3], __ T8H, va[5], va[7]); + __ addv(vb[0], __ T8H, vb[0], vb[2]); + __ addv(vb[1], __ T8H, vb[4], vb[6]); + + // store 48 results interleaved as shorts + vs_st2_post(vs_front(va), __ T8H, parsed); + vs_st2_post(vs_front(vs_front(vb)), __ T8H, parsed); + + __ BIND(L_end); - void dilithium_montmul16_sub_add(const VSeq<4>& va0, const VSeq<4>& va1, const VSeq<4>& vc, - const VSeq<4>& vtmp, const VSeq<2>& vq) { + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // Kyber Barrett reduce function. + // Implements + // static int implKyberBarrettReduce(short[] coeffs) {} + // + // coeffs (short[256]) = c_rarg0 + address generate_kyberBarrettReduce() { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = StubGenStubId::kyberBarrettReduce_id; + StubCodeMark mark(this, stub_id); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + + const Register kyberConsts = r10; + const Register result = r11; + + // As above we process 256 sets of values in total i.e. 32 x + // 8H quadwords. So, we can load, add and store the data in 3 + // groups of 11, 11 and 10 at a time i.e. we need to map sets + // of 10 or 11 registers. A further constraint is that the + // mapping needs to skip callee saves. So, we allocate the + // register sequences using two 8 sequences, two 2 sequences + // and two single registers. + VSeq<8> vs1_1(0); + VSeq<2> vs1_2(16); + FloatRegister vs1_3 = v28; + VSeq<8> vs2_1(18); + VSeq<2> vs2_2(26); + FloatRegister vs2_3 = v29; + + // we also need a pair of corresponding constant sequences + + VSeq<8> vc1_1(30, 0); + VSeq<2> vc1_2(30, 0); + FloatRegister vc1_3 = v30; // for kyber_q + + VSeq<8> vc2_1(31, 0); + VSeq<2> vc2_2(31, 0); + FloatRegister vc2_3 = v31; // for kyberBarrettMultiplier + + __ add(result, coeffs, 0); + __ lea(kyberConsts, + ExternalAddress((address) StubRoutines::aarch64::_kyberConsts)); + + // load q and the multiplier for the Barrett reduction + __ add(kyberConsts, kyberConsts, 16); + __ ldpq(vc1_3, vc2_3, kyberConsts); + + for (int i = 0; i < 3; i++) { + // load 80 or 88 coefficients + vs_ldpq_post(vs1_1, coeffs); + vs_ldpq_post(vs1_2, coeffs); + if (i < 2) { + __ ldr(vs1_3, __ Q, __ post(coeffs, 16)); + } + + // vs2 <- (2 * vs1 * kyberBarrettMultiplier) >> 16 + vs_sqdmulh(vs2_1, __ T8H, vs1_1, vc2_1); + vs_sqdmulh(vs2_2, __ T8H, vs1_2, vc2_2); + if (i < 2) { + __ sqdmulh(vs2_3, __ T8H, vs1_3, vc2_3); + } + + // vs2 <- (vs1 * kyberBarrettMultiplier) >> 26 + vs_sshr(vs2_1, __ T8H, vs2_1, 11); + vs_sshr(vs2_2, __ T8H, vs2_2, 11); + if (i < 2) { + __ sshr(vs2_3, __ T8H, vs2_3, 11); + } + + // vs1 <- vs1 - vs2 * kyber_q + vs_mlsv(vs1_1, __ T8H, vs2_1, vc1_1); + vs_mlsv(vs1_2, __ T8H, vs2_2, vc1_2); + if (i < 2) { + __ mlsv(vs1_3, __ T8H, vs2_3, vc1_3); + } + + vs_stpq_post(vs1_1, result); + vs_stpq_post(vs1_2, result); + if (i < 2) { + __ str(vs1_3, __ Q, __ post(result, 16)); + } + } + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + + // Dilithium-specific montmul helper routines that generate parallel + // code for, respectively, a single 4x4s vector sequence montmul or + // two such multiplies in a row. + + // Perform 16 32-bit Montgomery multiplications in parallel + void dilithium_montmul16(const VSeq<4>& va, const VSeq<4>& vb, const VSeq<4>& vc, + const VSeq<4>& vtmp, const VSeq<2>& vq) { + // Use the helper routine to schedule a 4x4S Montgomery multiply. + // It will assert that the register use is valid + vs_montmul4(va, vb, vc, __ T4S, vtmp, vq); + } + + // Perform 2x16 32-bit Montgomery multiplications in parallel + void dilithium_montmul32(const VSeq<8>& va, const VSeq<8>& vb, const VSeq<8>& vc, + const VSeq<4>& vtmp, const VSeq<2>& vq) { + // Schedule two successive 4x4S multiplies via the montmul helper + // on the front and back halves of va, vb and vc. The helper will + // assert that the register use has no overlap conflicts on each + // individual call but we also need to ensure that the necessary + // disjoint/equality constraints are met across both calls. + + // vb, vc, vtmp and vq must be disjoint. va must either be + // disjoint from all other registers or equal vc + + assert(vs_disjoint(vb, vc), "vb and vc overlap"); + assert(vs_disjoint(vb, vq), "vb and vq overlap"); + assert(vs_disjoint(vb, vtmp), "vb and vtmp overlap"); + + assert(vs_disjoint(vc, vq), "vc and vq overlap"); + assert(vs_disjoint(vc, vtmp), "vc and vtmp overlap"); + + assert(vs_disjoint(vq, vtmp), "vq and vtmp overlap"); + + assert(vs_disjoint(va, vc) || vs_same(va, vc), "va and vc neither disjoint nor equal"); + assert(vs_disjoint(va, vb), "va and vb overlap"); + assert(vs_disjoint(va, vq), "va and vq overlap"); + assert(vs_disjoint(va, vtmp), "va and vtmp overlap"); + + // We multiply the front and back halves of each sequence 4 at a + // time because + // + // 1) we are currently only able to get 4-way instruction + // parallelism at best + // + // 2) we need registers for the constants in vq and temporary + // scratch registers to hold intermediate results so vtmp can only + // be a VSeq<4> which means we only have 4 scratch slots. + + vs_montmul4(vs_front(va), vs_front(vb), vs_front(vc), __ T4S, vtmp, vq); + vs_montmul4(vs_back(va), vs_back(vb), vs_back(vc), __ T4S, vtmp, vq); + } + + // Perform combined montmul then add/sub on 4x4S vectors. + void dilithium_montmul16_sub_add( + const VSeq<4>& va0, const VSeq<4>& va1, const VSeq<4>& vc, + const VSeq<4>& vtmp, const VSeq<2>& vq) { // compute a = montmul(a1, c) dilithium_montmul16(vc, va1, vc, vtmp, vq); // ouptut a1 = a0 - a @@ -4917,10 +6318,10 @@ class StubGenerator: public StubCodeGenerator { vs_addv(va0, __ T4S, va0, vc); } - // perform combined add/sub then montul on 4x4S vectors - - void dilithium_sub_add_montmul16(const VSeq<4>& va0, const VSeq<4>& va1, const VSeq<4>& vb, - const VSeq<4>& vtmp1, const VSeq<4>& vtmp2, const VSeq<2>& vq) { + // Perform combined add/sub then montul on 4x4S vectors. + void dilithium_sub_add_montmul16( + const VSeq<4>& va0, const VSeq<4>& va1, const VSeq<4>& vb, + const VSeq<4>& vtmp1, const VSeq<4>& vtmp2, const VSeq<2>& vq) { // compute c = a0 - a1 vs_subv(vtmp1, __ T4S, va0, va1); // output a0 = a0 + a1 @@ -4963,10 +6364,10 @@ class StubGenerator: public StubCodeGenerator { offsets[3] = 192; } - // for levels 1 - 4 we simply load 2 x 4 adjacent values at a + // For levels 1 - 4 we simply load 2 x 4 adjacent values at a // time at 4 different offsets and multiply them in order by the // next set of input values. So we employ indexed load and store - // pair instructions with arrangement 4S + // pair instructions with arrangement 4S. for (int i = 0; i < 4; i++) { // reload q and qinv vs_ldpq(vq, dilithiumConsts); // qInv, q @@ -4975,7 +6376,7 @@ class StubGenerator: public StubCodeGenerator { // load next 8x4S inputs == b vs_ldpq_post(vs2, zetas); // compute a == c2 * b mod MONT_Q - vs_montmul32(vs2, vs1, vs2, vtmp, vq); + dilithium_montmul32(vs2, vs1, vs2, vtmp, vq); // load 8x4s coefficients via first start pos == c1 vs_ldpq_indexed(vs1, coeffs, c1Start, offsets); // compute a1 = c1 + a @@ -5029,20 +6430,21 @@ class StubGenerator: public StubCodeGenerator { VSeq<8> vs1(0), vs2(16), vs3(24); // 3 sets of 8x4s inputs/outputs VSeq<4> vtmp = vs_front(vs3); // n.b. tmp registers overlap vs3 VSeq<2> vq(30); // n.b. constants overlap vs3 - int offsets[4] = {0, 32, 64, 96}; - int offsets1[8] = {16, 48, 80, 112, 144, 176, 208, 240 }; + int offsets[4] = { 0, 32, 64, 96}; + int offsets1[8] = { 16, 48, 80, 112, 144, 176, 208, 240 }; int offsets2[8] = { 0, 32, 64, 96, 128, 160, 192, 224 }; __ add(result, coeffs, 0); - __ lea(dilithiumConsts, ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); + __ lea(dilithiumConsts, + ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); - // Each level represents one iteration of the outer for loop of the Java version + // Each level represents one iteration of the outer for loop of the Java version. // level 0-4 dilithiumNttLevel0_4(dilithiumConsts, coeffs, zetas); // level 5 - // at level 5 the coefficients we need to combine with the zetas + // At level 5 the coefficients we need to combine with the zetas // are grouped in memory in blocks of size 4. So, for both sets of // coefficients we load 4 adjacent values at 8 different offsets // using an indexed ldr with register variant Q and multiply them @@ -5056,7 +6458,7 @@ class StubGenerator: public StubCodeGenerator { // load next 32 (8x4S) inputs = b vs_ldpq_post(vs2, zetas); // a = b montul c1 - vs_montmul32(vs2, vs1, vs2, vtmp, vq); + dilithium_montmul32(vs2, vs1, vs2, vtmp, vq); // load 32 (8x4S) coefficients via second offsets = c2 vs_ldr_indexed(vs1, __ Q, coeffs, i, offsets2); // add/sub with result of multiply @@ -5068,7 +6470,7 @@ class StubGenerator: public StubCodeGenerator { } // level 6 - // at level 6 the coefficients we need to combine with the zetas + // At level 6 the coefficients we need to combine with the zetas // are grouped in memory in pairs, the first two being montmul // inputs and the second add/sub inputs. We can still implement // the montmul+sub+add using 4-way parallelism but only if we @@ -5096,7 +6498,7 @@ class StubGenerator: public StubCodeGenerator { } // level 7 - // at level 7 the coefficients we need to combine with the zetas + // At level 7 the coefficients we need to combine with the zetas // occur singly with montmul inputs alterating with add/sub // inputs. Once again we can use 4-way parallelism to combine 16 // zetas at a time. However, we have to load 8 adjacent values at @@ -5168,10 +6570,10 @@ class StubGenerator: public StubCodeGenerator { offsets[3] = 96; } - // for levels 3 - 7 we simply load 2 x 4 adjacent values at a + // For levels 3 - 7 we simply load 2 x 4 adjacent values at a // time at 4 different offsets and multiply them in order by the // next set of input values. So we employ indexed load and store - // pair instructions with arrangement 4S + // pair instructions with arrangement 4S. for (int i = 0; i < 4; i++) { // load v1 32 (8x4S) coefficients relative to first start index vs_ldpq_indexed(vs1, coeffs, c1Start, offsets); @@ -5188,7 +6590,7 @@ class StubGenerator: public StubCodeGenerator { // load b next 32 (8x4S) inputs vs_ldpq_post(vs2, zetas); // a = a1 montmul b - vs_montmul32(vs2, vs1, vs2, vtmp, vq); + dilithium_montmul32(vs2, vs1, vs2, vtmp, vq); // save a relative to second start index vs_stpq_indexed(vs2, coeffs, c2Start, offsets); @@ -5239,16 +6641,16 @@ class StubGenerator: public StubCodeGenerator { int offsets2[8] = { 16, 48, 80, 112, 144, 176, 208, 240 }; __ add(result, coeffs, 0); - __ lea(dilithiumConsts, ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); + __ lea(dilithiumConsts, + ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); // Each level represents one iteration of the outer for loop of the Java version - // level0 // level 0 // At level 0 we need to interleave adjacent quartets of // coefficients before we multiply and add/sub by the next 16 // zetas just as we did for level 7 in the multiply code. So we - // load and store the values using an ld2/st2 with arrangement 4S + // load and store the values using an ld2/st2 with arrangement 4S. for (int i = 0; i < 1024; i += 128) { // load constants q, qinv // n.b. this can be moved out of the loop as they do not get @@ -5270,7 +6672,7 @@ class StubGenerator: public StubCodeGenerator { // At level 1 we need to interleave pairs of adjacent pairs of // coefficients before we multiply by the next 16 zetas just as we // did for level 6 in the multiply code. So we load and store the - // values an ld2/st2 with arrangement 2D + // values an ld2/st2 with arrangement 2D. for (int i = 0; i < 1024; i += 128) { // a0/a1 load interleaved 32 (8x2D) coefficients vs_ld2_indexed(vs1, __ T2D, coeffs, tmpAddr, i, offsets); @@ -5306,7 +6708,7 @@ class StubGenerator: public StubCodeGenerator { // reload constants q, qinv -- they were clobbered earlier vs_ldpq(vq, dilithiumConsts); // qInv, q // compute a1 = b montmul c - vs_montmul32(vs2, vs1, vs2, vtmp, vq); + dilithium_montmul32(vs2, vs1, vs2, vtmp, vq); // store a1 32 (8x4S) coefficients via second offsets vs_str_indexed(vs2, __ Q, coeffs, i, offsets2); } @@ -5319,7 +6721,6 @@ class StubGenerator: public StubCodeGenerator { __ ret(lr); return start; - } // Dilithium multiply polynomials in the NTT domain. @@ -5353,7 +6754,8 @@ class StubGenerator: public StubCodeGenerator { VSeq<2> vq(30); // n.b. constants overlap vs3 VSeq<8> vrsquare(29, 0); // for montmul by constant RSQUARE - __ lea(dilithiumConsts, ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); + __ lea(dilithiumConsts, + ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); // load constants q, qinv vs_ldpq(vq, dilithiumConsts); // qInv, q @@ -5370,9 +6772,9 @@ class StubGenerator: public StubCodeGenerator { // c load 32 (8x4S) next inputs from poly2 vs_ldpq_post(vs2, poly2); // compute a = b montmul c - vs_montmul32(vs2, vs1, vs2, vtmp, vq); + dilithium_montmul32(vs2, vs1, vs2, vtmp, vq); // compute a = rsquare montmul a - vs_montmul32(vs2, vrsquare, vs2, vtmp, vq); + dilithium_montmul32(vs2, vrsquare, vs2, vtmp, vq); // save a 32 (8x4S) results vs_stpq_post(vs2, result); @@ -5385,7 +6787,6 @@ class StubGenerator: public StubCodeGenerator { __ ret(lr); return start; - } // Dilithium Motgomery multiply an array by a constant. @@ -5413,13 +6814,14 @@ class StubGenerator: public StubCodeGenerator { const Register len = r12; VSeq<8> vs1(0), vs2(16), vs3(24); // 3 sets of 8x4s inputs/outputs - VSeq<4> vtmp = vs_front(vs3); // n.b. tmp registers overlap vs3 + VSeq<4> vtmp = vs_front(vs3); // n.b. tmp registers overlap vs3 VSeq<2> vq(30); // n.b. constants overlap vs3 VSeq<8> vconst(29, 0); // for montmul by constant // results track inputs __ add(result, coeffs, 0); - __ lea(dilithiumConsts, ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); + __ lea(dilithiumConsts, + ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); // load constants q, qinv -- they do not get clobbered by first two loops vs_ldpq(vq, dilithiumConsts); // qInv, q @@ -5433,7 +6835,7 @@ class StubGenerator: public StubCodeGenerator { // load next 32 inputs vs_ldpq_post(vs2, coeffs); // mont mul by constant - vs_montmul32(vs2, vconst, vs2, vtmp, vq); + dilithium_montmul32(vs2, vconst, vs2, vtmp, vq); // write next 32 results vs_stpq_post(vs2, result); @@ -5446,7 +6848,6 @@ class StubGenerator: public StubCodeGenerator { __ ret(lr); return start; - } // Dilithium decompose poly. @@ -5477,9 +6878,12 @@ class StubGenerator: public StubCodeGenerator { const Register dilithiumConsts = r10; const Register tmp = r11; - VSeq<4> vs1(0), vs2(4), vs3(8); // 6 independent sets of 4x4s values + // 6 independent sets of 4x4s values + VSeq<4> vs1(0), vs2(4), vs3(8); VSeq<4> vs4(12), vs5(16), vtmp(20); - VSeq<4> one(25, 0); // 7 constants for cross-multiplying + + // 7 constants for cross-multiplying + VSeq<4> one(25, 0); VSeq<4> qminus1(26, 0); VSeq<4> g2(27, 0); VSeq<4> twog2(28, 0); @@ -5489,7 +6893,8 @@ class StubGenerator: public StubCodeGenerator { __ enter(); - __ lea(dilithiumConsts, ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); + __ lea(dilithiumConsts, + ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); // save callee-saved registers __ stpd(v8, v9, __ pre(sp, -64)); @@ -5586,7 +6991,6 @@ class StubGenerator: public StubCodeGenerator { __ st4(vs3[0], vs3[1], vs3[2], vs3[3], __ T4S, __ post(lowPart, 64)); __ st4(vs1[0], vs1[1], vs1[2], vs1[3], __ T4S, __ post(highPart, 64)); - __ sub(len, len, 64); __ cmp(len, (u1)64); __ br(Assembler::GE, L_loop); @@ -5602,7 +7006,6 @@ class StubGenerator: public StubCodeGenerator { __ ret(lr); return start; - } /** @@ -10003,6 +11406,16 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_chacha20Block = generate_chacha20Block_qrpar(); } + if (UseKyberIntrinsics) { + StubRoutines::_kyberNtt = generate_kyberNtt(); + StubRoutines::_kyberInverseNtt = generate_kyberInverseNtt(); + StubRoutines::_kyberNttMult = generate_kyberNttMult(); + StubRoutines::_kyberAddPoly_2 = generate_kyberAddPoly_2(); + StubRoutines::_kyberAddPoly_3 = generate_kyberAddPoly_3(); + StubRoutines::_kyber12To16 = generate_kyber12To16(); + StubRoutines::_kyberBarrettReduce = generate_kyberBarrettReduce(); + } + if (UseDilithiumIntrinsics) { StubRoutines::_dilithiumAlmostNtt = generate_dilithiumAlmostNtt(); StubRoutines::_dilithiumAlmostInverseNtt = generate_dilithiumAlmostInverseNtt(); diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp index 536583ff40c0b..fab76c41303c7 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp @@ -48,6 +48,17 @@ STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT) bool StubRoutines::aarch64::_completed = false; +ATTRIBUTE_ALIGNED(64) uint16_t StubRoutines::aarch64::_kyberConsts[] = +{ + // Because we sometimes load these in pairs, montQInvModR, kyber_q + // and kyberBarrettMultiplier should stay together and in this order. + 0xF301, 0xF301, 0xF301, 0xF301, 0xF301, 0xF301, 0xF301, 0xF301, // montQInvModR + 0x0D01, 0x0D01, 0x0D01, 0x0D01, 0x0D01, 0x0D01, 0x0D01, 0x0D01, // kyber_q + 0x4EBF, 0x4EBF, 0x4EBF, 0x4EBF, 0x4EBF, 0x4EBF, 0x4EBF, 0x4EBF, // kyberBarrettMultiplier + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, // toMont((kyber_n / 2)^-1 (mod kyber_q)) + 0x0549, 0x0549, 0x0549, 0x0549, 0x0549, 0x0549, 0x0549, 0x0549 // montRSquareModQ +}; + ATTRIBUTE_ALIGNED(64) uint32_t StubRoutines::aarch64::_dilithiumConsts[] = { 58728449, 58728449, 58728449, 58728449, // montQInvModR diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp index 857bb2ff10a91..4c942b9f8d81d 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp @@ -110,6 +110,7 @@ class aarch64 { } private: + static uint16_t _kyberConsts[]; static uint32_t _dilithiumConsts[]; static juint _crc_table[]; static jubyte _adler_table[]; diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 0f04fee79220a..6bf300ced42ab 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -414,13 +414,24 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false); } + if (_features & CPU_ASIMD) { + if (FLAG_IS_DEFAULT(UseKyberIntrinsics)) { + UseKyberIntrinsics = true; + } + } else if (UseKyberIntrinsics) { + if (!FLAG_IS_DEFAULT(UseKyberIntrinsics)) { + warning("Kyber intrinsics require ASIMD instructions"); + } + FLAG_SET_DEFAULT(UseKyberIntrinsics, false); + } + if (_features & CPU_ASIMD) { if (FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) { UseDilithiumIntrinsics = true; } } else if (UseDilithiumIntrinsics) { if (!FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) { - warning("Dilithium intrinsic requires ASIMD instructions"); + warning("Dilithium intrinsics require ASIMD instructions"); } FLAG_SET_DEFAULT(UseDilithiumIntrinsics, false); } @@ -703,6 +714,7 @@ void VM_Version::initialize_cpu_information(void) { get_compatible_board(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len); desc_len = (int)strlen(_cpu_desc); snprintf(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len, " %s", _features_string); + fprintf(stderr, "_features_string = \"%s\"", _features_string); _initialized = true; } diff --git a/src/hotspot/share/classfile/vmIntrinsics.cpp b/src/hotspot/share/classfile/vmIntrinsics.cpp index 8011b05969724..e23720f3ae049 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.cpp +++ b/src/hotspot/share/classfile/vmIntrinsics.cpp @@ -488,6 +488,14 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { case vmIntrinsics::_chacha20Block: if (!UseChaCha20Intrinsics) return true; break; + case vmIntrinsics::_kyberNtt: + case vmIntrinsics::_kyberInverseNtt: + case vmIntrinsics::_kyberNttMult: + case vmIntrinsics::_kyberAddPoly_2: + case vmIntrinsics::_kyberAddPoly_3: + case vmIntrinsics::_kyber12To16: + case vmIntrinsics::_kyberBarrettReduce: + if (!UseKyberIntrinsics) return true; case vmIntrinsics::_dilithiumAlmostNtt: case vmIntrinsics::_dilithiumAlmostInverseNtt: case vmIntrinsics::_dilithiumNttMult: diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 49446b53b98bb..68de40f1788c6 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -569,6 +569,27 @@ class methodHandle; do_name(chacha20Block_name, "implChaCha20Block") \ do_signature(chacha20Block_signature, "([I[B)I") \ \ + /* support for com.sun.crypto.provider.ML_KEM */ \ + do_class(com_sun_crypto_provider_ML_KEM, "com/sun/crypto/provider/ML_KEM") \ + do_signature(SaSaSaSaI_signature, "([S[S[S[S)I") \ + do_signature(BaISaII_signature, "([BI[SI)I") \ + do_signature(SaSaSaI_signature, "([S[S[S)I") \ + do_signature(SaSaI_signature, "([S[S)I") \ + do_signature(SaI_signature, "([S)I") \ + do_name(kyberAddPoly_name, "implKyberAddPoly") \ + do_intrinsic(_kyberNtt, com_sun_crypto_provider_ML_KEM, kyberNtt_name, SaSaI_signature, F_S) \ + do_name(kyberNtt_name, "implKyberNtt") \ + do_intrinsic(_kyberInverseNtt, com_sun_crypto_provider_ML_KEM, kyberInverseNtt_name, SaSaI_signature, F_S) \ + do_name(kyberInverseNtt_name, "implKyberInverseNtt") \ + do_intrinsic(_kyberNttMult, com_sun_crypto_provider_ML_KEM, kyberNttMult_name, SaSaSaSaI_signature, F_S) \ + do_name(kyberNttMult_name, "implKyberNttMult") \ + do_intrinsic(_kyberAddPoly_2, com_sun_crypto_provider_ML_KEM, kyberAddPoly_name, SaSaSaI_signature, F_S) \ + do_intrinsic(_kyberAddPoly_3, com_sun_crypto_provider_ML_KEM, kyberAddPoly_name, SaSaSaSaI_signature, F_S) \ + do_intrinsic(_kyber12To16, com_sun_crypto_provider_ML_KEM, kyber12To16_name, BaISaII_signature, F_S) \ + do_name(kyber12To16_name, "implKyber12To16") \ + do_intrinsic(_kyberBarrettReduce, com_sun_crypto_provider_ML_KEM, kyberBarrettReduce_name, SaI_signature, F_S) \ + do_name(kyberBarrettReduce_name, "implKyberBarrettReduce") \ + \ /* support for sun.security.provider.ML_DSA */ \ do_class(sun_security_provider_ML_DSA, "sun/security/provider/ML_DSA") \ do_signature(IaII_signature, "([II)I") \ diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 3cbb1512cd06a..4fe2b286e155a 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -395,6 +395,13 @@ static_field(StubRoutines, _sha3_implCompress, address) \ static_field(StubRoutines, _double_keccak, address) \ static_field(StubRoutines, _sha3_implCompressMB, address) \ + static_field(StubRoutines, _kyberNtt, address) \ + static_field(StubRoutines, _kyberInverseNtt, address) \ + static_field(StubRoutines, _kyberNttMult, address) \ + static_field(StubRoutines, _kyberAddPoly_2, address) \ + static_field(StubRoutines, _kyberAddPoly_3, address) \ + static_field(StubRoutines, _kyber12To16, address) \ + static_field(StubRoutines, _kyberBarrettReduce, address) \ static_field(StubRoutines, _dilithiumAlmostNtt, address) \ static_field(StubRoutines, _dilithiumAlmostInverseNtt, address) \ static_field(StubRoutines, _dilithiumNttMult, address) \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index 3effa8eee0498..f39937b9cdd3b 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -792,6 +792,13 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_vectorizedMismatch: case vmIntrinsics::_ghash_processBlocks: case vmIntrinsics::_chacha20Block: + case vmIntrinsics::_kyberNtt: + case vmIntrinsics::_kyberInverseNtt: + case vmIntrinsics::_kyberNttMult: + case vmIntrinsics::_kyberAddPoly_2: + case vmIntrinsics::_kyberAddPoly_3: + case vmIntrinsics::_kyber12To16: + case vmIntrinsics::_kyberBarrettReduce: case vmIntrinsics::_dilithiumAlmostNtt: case vmIntrinsics::_dilithiumAlmostInverseNtt: case vmIntrinsics::_dilithiumNttMult: diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 23cf8a67be7b6..decc43a212a21 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -2192,6 +2192,13 @@ void ConnectionGraph::process_call_arguments(CallNode *call) { strcmp(call->as_CallLeaf()->_name, "intpoly_assign") == 0 || strcmp(call->as_CallLeaf()->_name, "ghash_processBlocks") == 0 || strcmp(call->as_CallLeaf()->_name, "chacha20Block") == 0 || + strcmp(call->as_CallLeaf()->_name, "kyberNtt") == 0 || + strcmp(call->as_CallLeaf()->_name, "kyberInverseNtt") == 0 || + strcmp(call->as_CallLeaf()->_name, "kyberNttMult") == 0 || + strcmp(call->as_CallLeaf()->_name, "kyberAddPoly_2") == 0 || + strcmp(call->as_CallLeaf()->_name, "kyberAddPoly_3") == 0 || + strcmp(call->as_CallLeaf()->_name, "kyber12To16") == 0 || + strcmp(call->as_CallLeaf()->_name, "kyberBarrettReduce") == 0 || strcmp(call->as_CallLeaf()->_name, "dilithiumAlmostNtt") == 0 || strcmp(call->as_CallLeaf()->_name, "dilithiumAlmostInverseNtt") == 0 || strcmp(call->as_CallLeaf()->_name, "dilithiumNttMult") == 0 || diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 783631bf08d89..017564173a847 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -626,6 +626,20 @@ bool LibraryCallKit::try_to_inline(int predicate) { return inline_ghash_processBlocks(); case vmIntrinsics::_chacha20Block: return inline_chacha20Block(); + case vmIntrinsics::_kyberNtt: + return inline_kyberNtt(); + case vmIntrinsics::_kyberInverseNtt: + return inline_kyberInverseNtt(); + case vmIntrinsics::_kyberNttMult: + return inline_kyberNttMult(); + case vmIntrinsics::_kyberAddPoly_2: + return inline_kyberAddPoly_2(); + case vmIntrinsics::_kyberAddPoly_3: + return inline_kyberAddPoly_3(); + case vmIntrinsics::_kyber12To16: + return inline_kyber12To16(); + case vmIntrinsics::_kyberBarrettReduce: + return inline_kyberBarrettReduce(); case vmIntrinsics::_dilithiumAlmostNtt: return inline_dilithiumAlmostNtt(); case vmIntrinsics::_dilithiumAlmostInverseNtt: @@ -7640,6 +7654,245 @@ bool LibraryCallKit::inline_chacha20Block() { return true; } +//------------------------------inline_kyberNtt +bool LibraryCallKit::inline_kyberNtt() { + address stubAddr; + const char *stubName; + assert(UseKyberIntrinsics, "need Kyber intrinsics support"); + assert(callee()->signature()->size() == 2, "kyberNtt has 2 parameters"); + + stubAddr = StubRoutines::kyberNtt(); + stubName = "kyberNtt"; + if (!stubAddr) return false; + + Node* coeffs = argument(0); + Node* ntt_zetas = argument(1); + + coeffs = must_be_not_null(coeffs, true); + ntt_zetas = must_be_not_null(ntt_zetas, true); + + Node* coeffs_start = array_element_address(coeffs, intcon(0), T_SHORT); + assert(coeffs_start, "coeffs is null"); + Node* ntt_zetas_start = array_element_address(ntt_zetas, intcon(0), T_SHORT); + assert(ntt_zetas_start, "ntt_zetas is null"); + Node* kyberNtt = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::kyberNtt_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + coeffs_start, ntt_zetas_start); + // return an int + Node* retvalue = _gvn.transform(new ProjNode(kyberNtt, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + +//------------------------------inline_kyberInverseNtt +bool LibraryCallKit::inline_kyberInverseNtt() { + address stubAddr; + const char *stubName; + assert(UseKyberIntrinsics, "need Kyber intrinsics support"); + assert(callee()->signature()->size() == 2, "kyberInverseNtt has 2 parameters"); + + stubAddr = StubRoutines::kyberInverseNtt(); + stubName = "kyberInverseNtt"; + if (!stubAddr) return false; + + Node* coeffs = argument(0); + Node* zetas = argument(1); + + coeffs = must_be_not_null(coeffs, true); + zetas = must_be_not_null(zetas, true); + + Node* coeffs_start = array_element_address(coeffs, intcon(0), T_SHORT); + assert(coeffs_start, "coeffs is null"); + Node* zetas_start = array_element_address(zetas, intcon(0), T_SHORT); + assert(zetas_start, "inverseNtt_zetas is null"); + Node* kyberInverseNtt = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::kyberInverseNtt_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + coeffs_start, zetas_start); + + // return an int + Node* retvalue = _gvn.transform(new ProjNode(kyberInverseNtt, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + +//------------------------------inline_kyberNttMult +bool LibraryCallKit::inline_kyberNttMult() { + address stubAddr; + const char *stubName; + assert(UseKyberIntrinsics, "need Kyber intrinsics support"); + assert(callee()->signature()->size() == 4, "kyberNttMult has 4 parameters"); + + stubAddr = StubRoutines::kyberNttMult(); + stubName = "kyberNttMult"; + if (!stubAddr) return false; + + Node* result = argument(0); + Node* ntta = argument(1); + Node* nttb = argument(2); + Node* zetas = argument(3); + + result = must_be_not_null(result, true); + ntta = must_be_not_null(ntta, true); + nttb = must_be_not_null(nttb, true); + zetas = must_be_not_null(zetas, true); + Node* result_start = array_element_address(result, intcon(0), T_SHORT); + assert(result_start, "result is null"); + Node* ntta_start = array_element_address(ntta, intcon(0), T_SHORT); + assert(ntta_start, "ntta is null"); + Node* nttb_start = array_element_address(nttb, intcon(0), T_SHORT); + assert(nttb_start, "nttb is null"); + Node* zetas_start = array_element_address(zetas, intcon(0), T_SHORT); + assert(zetas_start, "nttMult_zetas is null"); + Node* kyberNttMult = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::kyberNttMult_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + result_start, ntta_start, nttb_start, + zetas_start); + + // return an int + Node* retvalue = _gvn.transform(new ProjNode(kyberNttMult, TypeFunc::Parms)); + set_result(retvalue); + + return true; +} + +//------------------------------inline_kyberAddPoly_2 +bool LibraryCallKit::inline_kyberAddPoly_2() { + address stubAddr; + const char *stubName; + assert(UseKyberIntrinsics, "need Kyber intrinsics support"); + assert(callee()->signature()->size() == 3, "kyberAddPoly_2 has 3 parameters"); + + stubAddr = StubRoutines::kyberAddPoly_2(); + stubName = "kyberAddPoly_2"; + if (!stubAddr) return false; + + Node* result = argument(0); + Node* a = argument(1); + Node* b = argument(2); + + result = must_be_not_null(result, true); + a = must_be_not_null(a, true); + b = must_be_not_null(b, true); + + Node* result_start = array_element_address(result, intcon(0), T_SHORT); + assert(result_start, "result is null"); + Node* a_start = array_element_address(a, intcon(0), T_SHORT); + assert(a_start, "a is null"); + Node* b_start = array_element_address(b, intcon(0), T_SHORT); + assert(b_start, "b is null"); + Node* kyberAddPoly_2 = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::kyberAddPoly_2_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + result_start, a_start, b_start); + // return an int + Node* retvalue = _gvn.transform(new ProjNode(kyberAddPoly_2, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + +//------------------------------inline_kyberAddPoly_3 +bool LibraryCallKit::inline_kyberAddPoly_3() { + address stubAddr; + const char *stubName; + assert(UseKyberIntrinsics, "need Kyber intrinsics support"); + assert(callee()->signature()->size() == 4, "kyberAddPoly_3 has 4 parameters"); + + stubAddr = StubRoutines::kyberAddPoly_3(); + stubName = "kyberAddPoly_3"; + if (!stubAddr) return false; + + Node* result = argument(0); + Node* a = argument(1); + Node* b = argument(2); + Node* c = argument(3); + + result = must_be_not_null(result, true); + a = must_be_not_null(a, true); + b = must_be_not_null(b, true); + c = must_be_not_null(c, true); + + Node* result_start = array_element_address(result, intcon(0), T_SHORT); + assert(result_start, "result is null"); + Node* a_start = array_element_address(a, intcon(0), T_SHORT); + assert(a_start, "a is null"); + Node* b_start = array_element_address(b, intcon(0), T_SHORT); + assert(b_start, "b is null"); + Node* c_start = array_element_address(c, intcon(0), T_SHORT); + assert(c_start, "c is null"); + Node* kyberAddPoly_3 = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::kyberAddPoly_3_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + result_start, a_start, b_start, c_start); + // return an int + Node* retvalue = _gvn.transform(new ProjNode(kyberAddPoly_3, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + +//------------------------------inline_kyber12To16 +bool LibraryCallKit::inline_kyber12To16() { + address stubAddr; + const char *stubName; + assert(UseKyberIntrinsics, "need Kyber intrinsics support"); + assert(callee()->signature()->size() == 4, "kyber12To16 has 4 parameters"); + + stubAddr = StubRoutines::kyber12To16(); + stubName = "kyber12To16"; + if (!stubAddr) return false; + + Node* condensed = argument(0); + Node* condensedOffs = argument(1); + Node* parsed = argument(2); + Node* parsedLength = argument(3); + + condensed = must_be_not_null(condensed, true); + parsed = must_be_not_null(parsed, true); + + Node* condensed_start = array_element_address(condensed, intcon(0), T_BYTE); + assert(condensed_start, "condensed is null"); + Node* parsed_start = array_element_address(parsed, intcon(0), T_SHORT); + assert(parsed_start, "parsed is null"); + Node* kyber12To16 = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::kyber12To16_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + condensed_start, condensedOffs, parsed_start, parsedLength); + // return an int + Node* retvalue = _gvn.transform(new ProjNode(kyber12To16, TypeFunc::Parms)); + set_result(retvalue); + return true; + +} + +//------------------------------inline_kyberBarrettReduce +bool LibraryCallKit::inline_kyberBarrettReduce() { + address stubAddr; + const char *stubName; + assert(UseKyberIntrinsics, "need Kyber intrinsics support"); + assert(callee()->signature()->size() == 1, "kyberBarrettReduce has 1 parameters"); + + stubAddr = StubRoutines::kyberBarrettReduce(); + stubName = "kyberBarrettReduce"; + if (!stubAddr) return false; + + Node* coeffs = argument(0); + + coeffs = must_be_not_null(coeffs, true); + + Node* coeffs_start = array_element_address(coeffs, intcon(0), T_SHORT); + assert(coeffs_start, "coeffs is null"); + Node* kyberBarrettReduce = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::kyberBarrettReduce_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + coeffs_start); + // return an int + Node* retvalue = _gvn.transform(new ProjNode(kyberBarrettReduce, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + //------------------------------inline_dilithiumAlmostNtt bool LibraryCallKit::inline_dilithiumAlmostNtt() { address stubAddr; @@ -7696,7 +7949,6 @@ bool LibraryCallKit::inline_dilithiumAlmostInverseNtt() { OptoRuntime::dilithiumAlmostInverseNtt_Type(), stubAddr, stubName, TypePtr::BOTTOM, coeffs_start, zetas_start); - // return an int Node* retvalue = _gvn.transform(new ProjNode(dilithiumAlmostInverseNtt, TypeFunc::Parms)); set_result(retvalue); @@ -7717,10 +7969,12 @@ bool LibraryCallKit::inline_dilithiumNttMult() { Node* result = argument(0); Node* ntta = argument(1); Node* nttb = argument(2); + Node* zetas = argument(3); result = must_be_not_null(result, true); ntta = must_be_not_null(ntta, true); nttb = must_be_not_null(nttb, true); + zetas = must_be_not_null(zetas, true); Node* result_start = array_element_address(result, intcon(0), T_INT); assert(result_start, "result is null"); diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index ad1ce71c374bf..cb755267ec57e 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -314,6 +314,13 @@ class LibraryCallKit : public GraphKit { Node* get_key_start_from_aescrypt_object(Node* aescrypt_object); bool inline_ghash_processBlocks(); bool inline_chacha20Block(); + bool inline_kyberNtt(); + bool inline_kyberInverseNtt(); + bool inline_kyberNttMult(); + bool inline_kyberAddPoly_2(); + bool inline_kyberAddPoly_3(); + bool inline_kyber12To16(); + bool inline_kyberBarrettReduce(); bool inline_dilithiumAlmostNtt(); bool inline_dilithiumAlmostInverseNtt(); bool inline_dilithiumNttMult(); diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index e32cedf6cee15..74d7eb42ebcf6 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -242,13 +242,18 @@ const TypeFunc* OptoRuntime::_bigIntegerShift_Type = nullptr; const TypeFunc* OptoRuntime::_vectorizedMismatch_Type = nullptr; const TypeFunc* OptoRuntime::_ghash_processBlocks_Type = nullptr; const TypeFunc* OptoRuntime::_chacha20Block_Type = nullptr; - +const TypeFunc* OptoRuntime::_kyberNtt_Type = nullptr; +const TypeFunc* OptoRuntime::_kyberInverseNtt_Type = nullptr; +const TypeFunc* OptoRuntime::_kyberNttMult_Type = nullptr; +const TypeFunc* OptoRuntime::_kyberAddPoly_2_Type = nullptr; +const TypeFunc* OptoRuntime::_kyberAddPoly_3_Type = nullptr; +const TypeFunc* OptoRuntime::_kyber12To16_Type = nullptr; +const TypeFunc* OptoRuntime::_kyberBarrettReduce_Type = nullptr; const TypeFunc* OptoRuntime::_dilithiumAlmostNtt_Type = nullptr; const TypeFunc* OptoRuntime::_dilithiumAlmostInverseNtt_Type = nullptr; const TypeFunc* OptoRuntime::_dilithiumNttMult_Type = nullptr; const TypeFunc* OptoRuntime::_dilithiumMontMulByConstant_Type = nullptr; const TypeFunc* OptoRuntime::_dilithiumDecomposePoly_Type = nullptr; - const TypeFunc* OptoRuntime::_base64_encodeBlock_Type = nullptr; const TypeFunc* OptoRuntime::_base64_decodeBlock_Type = nullptr; const TypeFunc* OptoRuntime::_string_IndexOf_Type = nullptr; @@ -1409,6 +1414,146 @@ static const TypeFunc* make_chacha20Block_Type() { return TypeFunc::make(domain, range); } +// Kyber NTT function +static const TypeFunc* make_kyberNtt_Type() { + int argcnt = 2; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // coeffs + fields[argp++] = TypePtr::NOTNULL; // NTT zetas + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Kyber inverse NTT function +static const TypeFunc* make_kyberInverseNtt_Type() { + int argcnt = 2; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // coeffs + fields[argp++] = TypePtr::NOTNULL; // inverse NTT zetas + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Kyber NTT multiply function +static const TypeFunc* make_kyberNttMult_Type() { + int argcnt = 4; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // result + fields[argp++] = TypePtr::NOTNULL; // ntta + fields[argp++] = TypePtr::NOTNULL; // nttb + fields[argp++] = TypePtr::NOTNULL; // NTT multiply zetas + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} +// Kyber add 2 polynomials function +static const TypeFunc* make_kyberAddPoly_2_Type() { + int argcnt = 3; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // result + fields[argp++] = TypePtr::NOTNULL; // a + fields[argp++] = TypePtr::NOTNULL; // b + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + + +// Kyber add 3 polynomials function +static const TypeFunc* make_kyberAddPoly_3_Type() { + int argcnt = 4; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // result + fields[argp++] = TypePtr::NOTNULL; // a + fields[argp++] = TypePtr::NOTNULL; // b + fields[argp++] = TypePtr::NOTNULL; // c + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + + +// Kyber XOF output parsing into polynomial coefficients candidates +// or decompress(12,...) function +static const TypeFunc* make_kyber12To16_Type() { + int argcnt = 4; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // condensed + fields[argp++] = TypeInt::INT; // condensedOffs + fields[argp++] = TypePtr::NOTNULL; // parsed + fields[argp++] = TypeInt::INT; // parsedLength + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Kyber Barrett reduce function +static const TypeFunc* make_kyberBarrettReduce_Type() { + int argcnt = 1; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // coeffs + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + // Dilithium NTT function except for the final "normalization" to |coeff| < Q static const TypeFunc* make_dilithiumAlmostNtt_Type() { int argcnt = 2; @@ -2120,13 +2265,18 @@ void OptoRuntime::initialize_types() { _vectorizedMismatch_Type = make_vectorizedMismatch_Type(); _ghash_processBlocks_Type = make_ghash_processBlocks_Type(); _chacha20Block_Type = make_chacha20Block_Type(); - + _kyberNtt_Type = make_kyberNtt_Type(); + _kyberInverseNtt_Type = make_kyberInverseNtt_Type(); + _kyberNttMult_Type = make_kyberNttMult_Type(); + _kyberAddPoly_2_Type = make_kyberAddPoly_2_Type(); + _kyberAddPoly_3_Type = make_kyberAddPoly_3_Type(); + _kyber12To16_Type = make_kyber12To16_Type(); + _kyberBarrettReduce_Type = make_kyberBarrettReduce_Type(); _dilithiumAlmostNtt_Type = make_dilithiumAlmostNtt_Type(); _dilithiumAlmostInverseNtt_Type = make_dilithiumAlmostInverseNtt_Type(); _dilithiumNttMult_Type = make_dilithiumNttMult_Type(); _dilithiumMontMulByConstant_Type = make_dilithiumMontMulByConstant_Type(); _dilithiumDecomposePoly_Type = make_dilithiumDecomposePoly_Type(); - _base64_encodeBlock_Type = make_base64_encodeBlock_Type(); _base64_decodeBlock_Type = make_base64_decodeBlock_Type(); _string_IndexOf_Type = make_string_IndexOf_Type(); diff --git a/src/hotspot/share/opto/runtime.hpp b/src/hotspot/share/opto/runtime.hpp index 96b7e9297d637..fd7fc796aa4b5 100644 --- a/src/hotspot/share/opto/runtime.hpp +++ b/src/hotspot/share/opto/runtime.hpp @@ -180,6 +180,13 @@ class OptoRuntime : public AllStatic { static const TypeFunc* _vectorizedMismatch_Type; static const TypeFunc* _ghash_processBlocks_Type; static const TypeFunc* _chacha20Block_Type; + static const TypeFunc* _kyberNtt_Type; + static const TypeFunc* _kyberInverseNtt_Type; + static const TypeFunc* _kyberNttMult_Type; + static const TypeFunc* _kyberAddPoly_2_Type; + static const TypeFunc* _kyberAddPoly_3_Type; + static const TypeFunc* _kyber12To16_Type; + static const TypeFunc* _kyberBarrettReduce_Type; static const TypeFunc* _dilithiumAlmostNtt_Type; static const TypeFunc* _dilithiumAlmostInverseNtt_Type; static const TypeFunc* _dilithiumNttMult_Type; @@ -468,6 +475,10 @@ class OptoRuntime : public AllStatic { return _unsafe_setmemory_Type; } +// static const TypeFunc* digestBase_implCompress_Type(bool is_sha3); +// static const TypeFunc* digestBase_implCompressMB_Type(bool is_sha3); +// static const TypeFunc* double_keccak_Type(); + static inline const TypeFunc* array_fill_Type() { assert(_array_fill_Type != nullptr, "should be initialized"); return _array_fill_Type; @@ -584,6 +595,41 @@ class OptoRuntime : public AllStatic { return _chacha20Block_Type; } + static const TypeFunc* kyberNtt_Type() { + assert(_kyberNtt_Type != nullptr, "should be initialized"); + return _kyberNtt_Type; + } + + static const TypeFunc* kyberInverseNtt_Type() { + assert(_kyberInverseNtt_Type != nullptr, "should be initialized"); + return _kyberInverseNtt_Type; + } + + static const TypeFunc* kyberNttMult_Type() { + assert(_kyberNttMult_Type != nullptr, "should be initialized"); + return _kyberNttMult_Type; + } + + static const TypeFunc* kyberAddPoly_2_Type() { + assert(_kyberAddPoly_2_Type != nullptr, "should be initialized"); + return _kyberAddPoly_2_Type; + } + + static const TypeFunc* kyberAddPoly_3_Type() { + assert(_kyberAddPoly_3_Type != nullptr, "should be initialized"); + return _kyberAddPoly_3_Type; + } + + static const TypeFunc* kyber12To16_Type() { + assert(_kyber12To16_Type != nullptr, "should be initialized"); + return _kyber12To16_Type; + } + + static const TypeFunc* kyberBarrettReduce_Type() { + assert(_kyberBarrettReduce_Type != nullptr, "should be initialized"); + return _kyberBarrettReduce_Type; + } + static inline const TypeFunc* dilithiumAlmostNtt_Type() { assert(_dilithiumAlmostNtt_Type != nullptr, "should be initialized"); return _dilithiumAlmostNtt_Type; diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 9edd95b9cdc08..29f0948276ada 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -325,6 +325,8 @@ const int ObjectAlignmentInBytes = 8; product(bool, UseChaCha20Intrinsics, false, DIAGNOSTIC, \ "Use intrinsics for the vectorized version of ChaCha20") \ \ + product(bool, UseKyberIntrinsics, false, DIAGNOSTIC, \ + "Use intrinsics for the vectorized version of Kyber") \ product(bool, UseDilithiumIntrinsics, false, DIAGNOSTIC, \ "Use intrinsics for the vectorized version of Dilithium") \ \ diff --git a/src/hotspot/share/runtime/stubDeclarations.hpp b/src/hotspot/share/runtime/stubDeclarations.hpp index c061d0b5daf8c..46feaaf017586 100644 --- a/src/hotspot/share/runtime/stubDeclarations.hpp +++ b/src/hotspot/share/runtime/stubDeclarations.hpp @@ -678,6 +678,21 @@ ghash_processBlocks) \ do_stub(compiler, chacha20Block) \ do_entry(compiler, chacha20Block, chacha20Block, chacha20Block) \ + do_stub(compiler, kyberNtt) \ + do_entry(compiler, kyberNtt, kyberNtt, kyberNtt) \ + do_stub(compiler, kyberInverseNtt) \ + do_entry(compiler, kyberInverseNtt, kyberInverseNtt, kyberInverseNtt) \ + do_stub(compiler, kyberNttMult) \ + do_entry(compiler, kyberNttMult, kyberNttMult, kyberNttMult) \ + do_stub(compiler, kyberAddPoly_2) \ + do_entry(compiler, kyberAddPoly_2, kyberAddPoly_2, kyberAddPoly_2) \ + do_stub(compiler, kyberAddPoly_3) \ + do_entry(compiler, kyberAddPoly_3, kyberAddPoly_3, kyberAddPoly_3) \ + do_stub(compiler, kyber12To16) \ + do_entry(compiler, kyber12To16, kyber12To16, kyber12To16) \ + do_stub(compiler, kyberBarrettReduce) \ + do_entry(compiler, kyberBarrettReduce, kyberBarrettReduce, \ + kyberBarrettReduce) \ do_stub(compiler, dilithiumAlmostNtt) \ do_entry(compiler, dilithiumAlmostNtt, \ dilithiumAlmostNtt, dilithiumAlmostNtt) \ diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java b/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java index 9808a0133032e..b45b655e1f3e0 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java @@ -28,6 +28,7 @@ import java.security.*; import java.util.Arrays; import javax.crypto.DecapsulateException; +import jdk.internal.vm.annotation.IntrinsicCandidate; import sun.security.provider.SHA3.SHAKE256; import sun.security.provider.SHA3Parallel.Shake128Parallel; @@ -71,6 +72,268 @@ public final class ML_KEM { -1599, -709, -789, -1317, -57, 1049, -584 }; + private static final short[] montZetasForVectorNttArr = new short[]{ + // level 0 + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + -758, -758, -758, -758, -758, -758, -758, -758, + // level 1 + -359, -359, -359, -359, -359, -359, -359, -359, + -359, -359, -359, -359, -359, -359, -359, -359, + -359, -359, -359, -359, -359, -359, -359, -359, + -359, -359, -359, -359, -359, -359, -359, -359, + -359, -359, -359, -359, -359, -359, -359, -359, + -359, -359, -359, -359, -359, -359, -359, -359, + -359, -359, -359, -359, -359, -359, -359, -359, + -359, -359, -359, -359, -359, -359, -359, -359, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + -1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517, + // level 2 + 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, + 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, + 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, + 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, + 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, + 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, + 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, + 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, + 287, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, + 202, 202, 202, 202, 202, 202, 202, 202, + 202, 202, 202, 202, 202, 202, 202, 202, + 202, 202, 202, 202, 202, 202, 202, 202, + 202, 202, 202, 202, 202, 202, 202, 202, + // level 3 + -171, -171, -171, -171, -171, -171, -171, -171, + -171, -171, -171, -171, -171, -171, -171, -171, + 622, 622, 622, 622, 622, 622, 622, 622, + 622, 622, 622, 622, 622, 622, 622, 622, + 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, + 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, + 182, 182, 182, 182, 182, 182, 182, 182, + 182, 182, 182, 182, 182, 182, 182, 182, + 962, 962, 962, 962, 962, 962, 962, 962, + 962, 962, 962, 962, 962, 962, 962, 962, + -1202, -1202, -1202, -1202, -1202, -1202, -1202, -1202, + -1202, -1202, -1202, -1202, -1202, -1202, -1202, -1202, + -1474, -1474, -1474, -1474, -1474, -1474, -1474, -1474, + -1474, -1474, -1474, -1474, -1474, -1474, -1474, -1474, + 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, + 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, + // level 4 + 573, 573, 573, 573, 573, 573, 573, 573, + -1325, -1325, -1325, -1325, -1325, -1325, -1325, -1325, + 264, 264, 264, 264, 264, 264, 264, 264, + 383, 383, 383, 383, 383, 383, 383, 383, + -829, -829, -829, -829, -829, -829, -829, -829, + 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + -1602, -1602, -1602, -1602, -1602, -1602, -1602, -1602, + -130, -130, -130, -130, -130, -130, -130, -130, + -681, -681, -681, -681, -681, -681, -681, -681, + 1017, 1017, 1017, 1017, 1017, 1017, 1017, 1017, + 732, 732, 732, 732, 732, 732, 732, 732, + 608, 608, 608, 608, 608, 608, 608, 608, + -1542, -1542, -1542, -1542, -1542, -1542, -1542, -1542, + 411, 411, 411, 411, 411, 411, 411, 411, + -205, -205, -205, -205, -205, -205, -205, -205, + -1571, -1571, -1571, -1571, -1571, -1571, -1571, -1571, + // level 5 + 1223, 1223, 1223, 1223, 652, 652, 652, 652, + -552, -552, -552, -552, 1015, 1015, 1015, 1015, + -1293, -1293, -1293, -1293, 1491, 1491, 1491, 1491, + -282, -282, -282, -282, -1544, -1544, -1544, -1544, + 516, 516, 516, 516, -8, -8, -8, -8, + -320, -320, -320, -320, -666, -666, -666, -666, + 1711, 1711, 1711, 1711, -1162, -1162, -1162, -1162, + 126, 126, 126, 126, 1469, 1469, 1469, 1469, + -853, -853, -853, -853, -90, -90, -90, -90, + -271, -271, -271, -271, 830, 830, 830, 830, + 107, 107, 107, 107, -1421, -1421, -1421, -1421, + -247, -247, -247, -247, -951, -951, -951, -951, + -398, -398, -398, -398, 961, 961, 961, 961, + -1508, -1508, -1508, -1508, -725, -725, -725, -725, + 448, 448, 448, 448, -1065, -1065, -1065, -1065, + 677, 677, 677, 677, -1275, -1275, -1275, -1275, + // level 6 + -1103, -1103, 430, 430, 555, 555, 843, 843, + -1251, -1251, 871, 871, 1550, 1550, 105, 105, + 422, 422, 587, 587, 177, 177, -235, -235, + -291, -291, -460, -460, 1574, 1574, 1653, 1653, + -246, -246, 778, 778, 1159, 1159, -147, -147, + -777, -777, 1483, 1483, -602, -602, 1119, 1119, + -1590, -1590, 644, 644, -872, -872, 349, 349, + 418, 418, 329, 329, -156, -156, -75, -75, + 817, 817, 1097, 1097, 603, 603, 610, 610, + 1322, 1322, -1285, -1285, -1465, -1465, 384, 384, + -1215, -1215, -136, -136, 1218, 1218, -1335, -1335, + -874, -874, 220, 220, -1187, -1187, 1670, 1670, + -1185, -1185, -1530, -1530, -1278, -1278, 794, 794, + -1510, -1510, -854, -854, -870, -870, 478, 478, + -108, -108, -308, -308, 996, 996, 991, 991, + 958, 958, -1460, -1460, 1522, 1522, 1628, 1628 + }; + private static final int[] MONT_ZETAS_FOR_INVERSE_NTT = new int[]{ + 584, -1049, 57, 1317, 789, 709, 1599, -1601, + -990, 604, 348, 857, 612, 474, 1177, -1014, + -88, -982, -191, 668, 1386, 486, -1153, -534, + 514, 137, 586, -1178, 227, 339, -907, 244, + 1200, -833, 1394, -30, 1074, 636, -317, -1192, + -1259, -355, -425, -884, -977, 1430, 868, 607, + 184, 1448, 702, 1327, 431, 497, 595, -94, + 1649, -1497, -620, 42, -172, 1107, -222, 1003, + 426, -845, 395, -510, 1613, 825, 1269, -290, + -1429, 623, -567, 1617, 36, 1007, 1440, 332, + -201, 1313, -1382, -744, 669, -1538, 128, -1598, + 1401, 1183, -553, 714, 405, -1155, -445, 406, + -1496, -49, 82, 1369, 259, 1604, 373, 909, + -1249, -1000, -25, -52, 530, -895, 1226, 819, + -185, 281, -742, 1253, 417, 1400, 35, -593, + 97, -1263, 551, -585, 969, -914, -1188 + }; + + private static final short[] montZetasForVectorInverseNttArr = new short[]{ + // level 0 + -1628, -1628, -1522, -1522, 1460, 1460, -958, -958, + -991, -991, -996, -996, 308, 308, 108, 108, + -478, -478, 870, 870, 854, 854, 1510, 1510, + -794, -794, 1278, 1278, 1530, 1530, 1185, 1185, + 1659, 1659, 1187, 1187, -220, -220, 874, 874, + 1335, 1335, -1218, -1218, 136, 136, 1215, 1215, + -384, -384, 1465, 1465, 1285, 1285, -1322, -1322, + -610, -610, -603, -603, -1097, -1097, -817, -817, + 75, 75, 156, 156, -329, -329, -418, -418, + -349, -349, 872, 872, -644, -644, 1590, 1590, + -1119, -1119, 602, 602, -1483, -1483, 777, 777, + 147, 147, -1159, -1159, -778, -778, 246, 246, + -1653, -1653, -1574, -1574, 460, 460, 291, 291, + 235, 235, -177, -177, -587, -587, -422, -422, + -105, -105, -1550, -1550, -871, -871, 1251, 1251, + -843, -843, -555, -555, -430, -430, 1103, 1103, + // level 1 + 1275, 1275, 1275, 1275, -677, -677, -677, -677, + 1065, 1065, 1065, 1065, -448, -448, -448, -448, + 725, 725, 725, 725, 1508, 1508, 1508, 1508, + -961, -961, -961, -961, 398, 398, 398, 398, + 951, 951, 951, 951, 247, 247, 247, 247, + 1421, 1421, 1421, 1421, -107, -107, -107, -107, + -830, -830, -830, -830, 271, 271, 271, 271, + 90, 90, 90, 90, 853, 853, 853, 853, + -1469, -1469, -1469, -1469, -126, -126, -126, -126, + 1162, 1162, 1162, 1162, 1618, 1618, 1618, 1618, + 666, 666, 666, 666, 320, 320, 320, 320, + 8, 8, 8, 8, -516, -516, -516, -516, + 1544, 1544, 1544, 1544, 282, 282, 282, 282, + -1491, -1491, -1491, -1491, 1293, 1293, 1293, 1293, + -1015, -1015, -1015, -1015, 552, 552, 552, 552, + -652, -652, -652, -652, -1223, -1223, -1223, -1223, + // level 2 + 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, + 205, 205, 205, 205, 205, 205, 205, 205, + -411, -411, -411, -411, -411, -411, -411, -411, + 1542, 1542, 1542, 1542, 1542, 1542, 1542, 1542, + -608, -608, -608, -608, -608, -608, -608, -608, + -732, -732, -732, -732, -732, -732, -732, -732, + -1017, -1017, -1017, -1017, -1017, -1017, -1017, -1017, + 681, 681, 681, 681, 681, 681, 681, 681, + 130, 130, 130, 130, 130, 130, 130, 130, + 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, + -1458, -1458, -1458, -1458, -1458, -1458, -1458, -1458, + 829, 829, 829, 829, 829, 829, 829, 829, + -383, -383, -383, -383, -383, -383, -383, -383, + -264, -264, -264, -264, -264, -264, -264, -264, + 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, + -573, -573, -573, -573, -573, -573, -573, -573, + // level 3 + -1468, -1468, -1468, -1468, -1468, -1468, -1468, -1468, + -1468, -1468, -1468, -1468, -1468, -1468, -1468, -1468, + 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, + 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, + 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, + 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, + -962, -962, -962, -962, -962, -962, -962, -962, + -962, -962, -962, -962, -962, -962, -962, -962, + -182, -182, -182, -182, -182, -182, -182, -182, + -182, -182, -182, -182, -182, -182, -182, -182, + -1577, -1577, -1577, -1577, -1577, -1577, -1577, -1577, + -1577, -1577, -1577, -1577, -1577, -1577, -1577, -1577, + -622, -622, -622, -622, -622, -622, -622, -622, + -622, -622, -622, -622, -622, -622, -622, -622, + 171, 171, 171, 171, 171, 171, 171, 171, + 171, 171, 171, 171, 171, 171, 171, 171, + // level 4 + -202, -202, -202, -202, -202, -202, -202, -202, + -202, -202, -202, -202, -202, -202, -202, -202, + -202, -202, -202, -202, -202, -202, -202, -202, + -202, -202, -202, -202, -202, -202, -202, -202, + -287, -287, -287, -287, -287, -287, -287, -287, + -287, -287, -287, -287, -287, -287, -287, -287, + -287, -287, -287, -287, -287, -287, -287, -287, + -287, -287, -287, -287, -287, -287, -287, -287, + -1422, -1422, -1422, -1422, -1422, -1422, -1422, -1422, + -1422, -1422, -1422, -1422, -1422, -1422, -1422, -1422, + -1422, -1422, -1422, -1422, -1422, -1422, -1422, -1422, + -1422, -1422, -1422, -1422, -1422, -1422, -1422, -1422, + -1493, -1493, -1493, -1493, -1493, -1493, -1493, -1493, + -1493, -1493, -1493, -1493, -1493, -1493, -1493, -1493, + -1493, -1493, -1493, -1493, -1493, -1493, -1493, -1493, + -1493, -1493, -1493, -1493, -1493, -1493, -1493, -1493, + // level 5 + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, + 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, + // level 6 + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758 + }; + private static final int[] MONT_ZETAS_FOR_NTT_MULT = new int[]{ -1003, 1003, 222, -222, -1107, 1107, 172, -172, -42, 42, 620, -620, 1497, -1497, -1649, 1649, @@ -89,6 +352,24 @@ public final class ML_KEM { 1601, -1601, -1599, 1599, -709, 709, -789, 789, -1317, 1317, -57, 57, 1049, -1049, -584, 584 }; + private static final short[] montZetasForVectorNttMultArr = new short[]{ + -1103, 1103, 430, -430, 555, -555, 843, -843, + -1251, 1251, 871, -871, 1550, -1550, 105, -105, + 422, -422, 587, -587, 177, -177, -235, 235, + -291, 291, -460, 460, 1574, -1574, 1653, -1653, + -246, 246, 778, -778, 1159, -1159, -147, 147, + -777, 777, 1483, -1483, -602, 602, 1119, -1119, + -1590, 1590, 644, -644, -872, 872, 349, -349, + 418, -418, 329, -329, -156, 156, -75, 75, + 817, -817, 1097, -1097, 603, -603, 610, -610, + 1322, -1322, -1285, 1285, -1465, 1465, 384, -384, + -1215, 1215, -136, 136, 1218, -1218, -1335, 1335, + -874, 874, 220, -220, -1187, 1187, 1670, 1659, + -1185, 1185, -1530, 1530, -1278, 1278, 794, -794, + -1510, 1510, -854, 854, -870, 870, 478, -478, + -108, 108, -308, 308, 996, -996, 991, -991, + 958, -958, -1460, 1460, 1522, -1522, 1628, -1628 + }; private final int mlKem_k; private final int mlKem_eta1; @@ -261,7 +542,7 @@ protected ML_KEM_EncapsulateResult encapsulate( try { mlKemH = MessageDigest.getInstance(HASH_H_NAME); mlKemG = MessageDigest.getInstance(HASH_G_NAME); - } catch (NoSuchAlgorithmException e){ + } catch (NoSuchAlgorithmException e) { // This should never happen. throw new RuntimeException(e); } @@ -527,7 +808,7 @@ private short[][][] generateA(byte[] rho, Boolean transposed) { for (int i = 0; i < mlKem_k; i++) { for (int j = 0; j < mlKem_k; j++) { - xofBufArr[parInd] = seedBuf.clone(); + System.arraycopy(seedBuf, 0, xofBufArr[parInd], 0, seedBuf.length); if (transposed) { xofBufArr[parInd][rhoLen] = (byte) i; xofBufArr[parInd][rhoLen + 1] = (byte) j; @@ -707,9 +988,13 @@ private short[][] mlKemVectorInverseNTT(short[][] vector) { return vector; } - // The elements of poly should be in the range [-ML_KEM_Q, ML_KEM_Q] - // The elements of poly at return will be in the range of [0, ML_KEM_Q] - private void mlKemNTT(short[] poly) { + @IntrinsicCandidate + static int implKyberNtt(short[] poly, short[] ntt_zetas) { + implKyberNttJava(poly); + return 1; + } + + static void implKyberNttJava(short[] poly) { int[] coeffs = new int[ML_KEM_N]; for (int m = 0; m < ML_KEM_N; m++) { coeffs[m] = poly[m]; @@ -718,12 +1003,23 @@ private void mlKemNTT(short[] poly) { for (int m = 0; m < ML_KEM_N; m++) { poly[m] = (short) coeffs[m]; } + } + + // The elements of poly should be in the range [-mlKem_q, mlKem_q] + // The elements of poly at return will be in the range of [0, mlKem_q] + private void mlKemNTT(short[] poly) { + assert poly.length == ML_KEM_N; + implKyberNtt(poly, montZetasForVectorNttArr); mlKemBarrettReduce(poly); } - // Works in place, but also returns its (modified) input so that it can - // be used in expressions - private short[] mlKemInverseNTT(short[] poly) { + @IntrinsicCandidate + static int implKyberInverseNtt(short[] poly, short[] zetas) { + implKyberInverseNttJava(poly); + return 1; + } + + static void implKyberInverseNttJava(short[] poly) { int[] coeffs = new int[ML_KEM_N]; for (int m = 0; m < ML_KEM_N; m++) { coeffs[m] = poly[m]; @@ -732,6 +1028,13 @@ private short[] mlKemInverseNTT(short[] poly) { for (int m = 0; m < ML_KEM_N; m++) { poly[m] = (short) coeffs[m]; } + } + + // Works in place, but also returns its (modified) input so that it can + // be used in expressions + private short[] mlKemInverseNTT(short[] poly) { + assert poly.length == ML_KEM_N; + implKyberInverseNtt(poly, montZetasForVectorInverseNttArr); return poly; } @@ -822,11 +1125,16 @@ private short[] mlKemVectorScalarMult(short[][] a, short[][] b) { return result; } - // Multiplies two polynomials represented in the NTT domain. - // The result is a representation of the product still in the NTT domain. - // The coefficients in the result are in the range (-ML_KEM_Q, ML_KEM_Q). - private void nttMult(short[] result, short[] ntta, short[] nttb) { + @IntrinsicCandidate + static int implKyberNttMult(short[] result, short[] ntta, short[] nttb, + short[] zetas) { + implKyberNttMultJava(result, ntta, nttb); + return 1; + } + + static void implKyberNttMultJava(short[] result, short[] ntta, short[] nttb) { for (int m = 0; m < ML_KEM_N / 2; m++) { + int a0 = ntta[2 * m]; int a1 = ntta[2 * m + 1]; int b0 = nttb[2 * m]; @@ -839,6 +1147,15 @@ private void nttMult(short[] result, short[] ntta, short[] nttb) { } } + // Multiplies two polynomials represented in the NTT domain. + // The result is a representation of the product still in the NTT domain. + // The coefficients in the result are in the range (-mlKem_q, mlKem_q). + private void nttMult(short[] result, short[] ntta, short[] nttb) { + assert (result.length == ML_KEM_N) && (ntta.length == ML_KEM_N) && + (nttb.length == ML_KEM_N); + implKyberNttMult(result, ntta, nttb, montZetasForVectorNttMultArr); + } + // Adds the vector of polynomials b to a in place, i.e. a will hold // the result. It also returns (the modified) a so that it can be used // in an expression. @@ -853,15 +1170,41 @@ private short[][] mlKemAddVec(short[][] a, short[][] b) { return a; } + @IntrinsicCandidate + static int implKyberAddPoly(short[] result, short[] a, short[] b) { + implKyberAddPolyJava(result, a, b); + return 1; + } + + static void implKyberAddPolyJava(short[] result, short[] a, short[] b) { + for (int m = 0; m < ML_KEM_N; m++) { + int r = a[m] + b[m] + ML_KEM_Q; // This makes r > - ML_KEM_Q + a[m] = (short) r; + } + mlKemBarrettReduce(a); + } + // Adds the polynomial b to a in place, i.e. (the modified) a will hold // the result. // The coefficients are supposed be greater than -ML_KEM_Q in a and // greater than -ML_KEM_Q and less than ML_KEM_Q in b. // The coefficients in the result are greater than -ML_KEM_Q. - private void mlKemAddPoly(short[] a, short[] b) { + private short[] mlKemAddPoly(short[] a, short[] b) { + assert (a.length == ML_KEM_N) && (b.length == ML_KEM_N); + implKyberAddPoly(a, a, b); + return a; + } + + @IntrinsicCandidate + static int implKyberAddPoly(short[] result, short[] a, short[] b, short[] c) { + implKyberAddPolyJava(result, a, b, c); + return 1; + } + + static void implKyberAddPolyJava(short[] result, short[] a, short[] b, short[] c) { for (int m = 0; m < ML_KEM_N; m++) { - int r = a[m] + b[m] + ML_KEM_Q; // This makes r > -ML_KEM_Q - a[m] = (short) r; + int r = a[m] + b[m] + c[m] + 2 * ML_KEM_Q; // This makes r > - ML_KEM_Q + result[m] = (short) r; } } @@ -871,10 +1214,9 @@ private void mlKemAddPoly(short[] a, short[] b) { // greater than -ML_KEM_Q and less than ML_KEM_Q. // The coefficients in the result are nonnegative and less than ML_KEM_Q. private short[] mlKemAddPoly(short[] a, short[] b, short[] c) { - for (int m = 0; m < ML_KEM_N; m++) { - int r = a[m] + b[m] + c[m] + 2 * ML_KEM_Q; // This makes r > - ML_KEM_Q - a[m] = (short) r; - } + assert (a.length == ML_KEM_N) && (b.length == ML_KEM_N) && + (c.length == ML_KEM_N); + implKyberAddPoly(a, a, b, c); mlKemBarrettReduce(a); return a; } @@ -997,15 +1339,13 @@ private short[][] decodeVector(int l, byte[] encodedVector) { return result; } - // The intrinsic implementations assume that the input and output buffers - // are such that condensed can be read in 192-byte chunks and - // parsed can be written in 128 shorts chunks. In other words, - // if (i - 1) * 128 < parsedLengths <= i * 128 then - // parsed.size should be at least i * 128 and - // condensed.size should be at least index + i * 192 - private void twelve2Sixteen(byte[] condensed, int index, - short[] parsed, int parsedLength) { + @IntrinsicCandidate + private static int implKyber12To16(byte[] condensed, int index, short[] parsed, int parsedLength) { + implKyber12To16Java(condensed, index, parsed, parsedLength); + return 1; + } + private static void implKyber12To16Java(byte[] condensed, int index, short[] parsed, int parsedLength) { for (int i = 0; i < parsedLength * 3 / 2; i += 3) { parsed[(i / 3) * 2] = (short) ((condensed[i + index] & 0xff) + 256 * (condensed[i + index + 1] & 0xf)); @@ -1014,6 +1354,25 @@ private void twelve2Sixteen(byte[] condensed, int index, } } + // The intrinsic implementations assume that the input and output buffers + // are such that condensed can be read in 96-byte chunks and + // parsed can be written in 64 shorts chunks except for the last chunk + // that can be either 48 or 64 shorts. In other words, + // if (i - 1) * 64 < parsedLengths <= i * 64 then + // parsed.length should be either i * 64 or (i-1) * 64 + 48 and + // condensed.length should be at least index + i * 96. + private void twelve2Sixteen(byte[] condensed, int index, + short[] parsed, int parsedLength) { + int i = parsedLength / 64; + int remainder = parsedLength - i * 64; + if (remainder != 0) { + i++; + } + assert ((remainder == 0) || (remainder == 48)) && + (index + i * 96 <= condensed.length); + implKyber12To16(condensed, index, parsed, parsedLength); + } + private static void decodePoly5(byte[] condensed, int index, short[] parsed) { int j = index; for (int i = 0; i < ML_KEM_N; i += 8) { @@ -1152,6 +1511,19 @@ private static short[] decompressDecode(byte[] input) { return result; } + @IntrinsicCandidate + static int implKyberBarrettReduce(short[] coeffs) { + implKyberBarrettReduceJava(coeffs); + return 1; + } + + static void implKyberBarrettReduceJava(short[] poly) { + for (int m = 0; m < ML_KEM_N; m++) { + int tmp = ((int) poly[m] * BARRETT_MULTIPLIER) >> BARRETT_SHIFT; + poly[m] = (short) (poly[m] - tmp * ML_KEM_Q); + } + } + // The input elements can have any short value. // Modifies poly such that upon return poly[i] will be // in the range [0, ML_KEM_Q] and will be congruent with the original @@ -1161,11 +1533,9 @@ private static short[] decompressDecode(byte[] input) { // That means that if the original poly[i] > -ML_KEM_Q then at return it // will be in the range [0, ML_KEM_Q), i.e. it will be the canonical // representative of its residue class. - private void mlKemBarrettReduce(short[] poly) { - for (int m = 0; m < ML_KEM_N; m++) { - int tmp = ((int) poly[m] * BARRETT_MULTIPLIER) >> BARRETT_SHIFT; - poly[m] = (short) (poly[m] - tmp * ML_KEM_Q); - } + private static void mlKemBarrettReduce(short[] poly) { + assert poly.length == ML_KEM_N; + implKyberBarrettReduce(poly); } // Precondition: -(2^MONT_R_BITS -1) * MONT_Q <= b * c < (2^MONT_R_BITS - 1) * MONT_Q diff --git a/src/java.base/share/classes/sun/security/provider/ML_DSA.java b/src/java.base/share/classes/sun/security/provider/ML_DSA.java index 238b5e9d46a0a..ff25eb527efdb 100644 --- a/src/java.base/share/classes/sun/security/provider/ML_DSA.java +++ b/src/java.base/share/classes/sun/security/provider/ML_DSA.java @@ -1554,7 +1554,7 @@ boolean vectorNormBound(int[][] vec, int bound) { // precondition: -2^31 * MONT_Q <= a, b < 2^31, -2^31 < a * b < 2^31 * MONT_Q // computes a * b * 2^-32 mod MONT_Q // the result is greater than -MONT_Q and less than MONT_Q - // see e.g. Algorithm 3 in https://eprint.iacr.org/2018/039.pdf + // See e.g. Algorithm 3 in https://eprint.iacr.org/2018/039.pdf private static int montMul(int b, int c) { long a = (long) b * (long) c; int aHigh = (int) (a >> MONT_R_BITS); From c3de94cee12471a11c457c11dd55c547633de5cb Mon Sep 17 00:00:00 2001 From: KIRIYAMA Takuya Date: Wed, 16 Apr 2025 15:42:40 +0000 Subject: [PATCH 0614/1101] 8352942: jdk/jfr/startupargs/TestMemoryOptions.java fails with 32-bit build Reviewed-by: phh --- test/jdk/jdk/jfr/startupargs/TestMemoryOptions.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/jdk/jdk/jfr/startupargs/TestMemoryOptions.java b/test/jdk/jdk/jfr/startupargs/TestMemoryOptions.java index 6827c663ee37b..100b0d74a075f 100644 --- a/test/jdk/jdk/jfr/startupargs/TestMemoryOptions.java +++ b/test/jdk/jdk/jfr/startupargs/TestMemoryOptions.java @@ -485,6 +485,7 @@ private static void launchTestVM(TestCase tc) throws Exception { if (flightRecorderOptions != null) { pb = ProcessTools.createTestJavaProcessBuilder("--add-exports=jdk.jfr/jdk.jfr.internal=ALL-UNNAMED", "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", + "-Xmx256m", flightRecorderOptions, "-XX:StartFlightRecording", SUT.class.getName(), @@ -493,6 +494,7 @@ private static void launchTestVM(TestCase tc) throws Exception { // default, no FlightRecorderOptions passed pb = ProcessTools.createTestJavaProcessBuilder("--add-exports=jdk.jfr/jdk.jfr.internal=ALL-UNNAMED", "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", + "-Xmx256m", "-XX:StartFlightRecording", SUT.class.getName(), tc.getTestName()); From 84458ec18ce33295636f7b26b8e3ff25ecb349f2 Mon Sep 17 00:00:00 2001 From: Rohitash Kumar Date: Wed, 16 Apr 2025 16:08:31 +0000 Subject: [PATCH 0615/1101] 8353013: java.net.URI.create(String) may have low performance to scan the host/domain name from URI string when the hostname starts with number Reviewed-by: michaelm, xpeng --- src/java.base/share/classes/java/net/URI.java | 15 ++++- test/jdk/java/net/URI/Test.java | 38 +++++++++++- .../net/URIAuthorityParsingBenchmark.java | 62 +++++++++++++++++++ 3 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/net/URIAuthorityParsingBenchmark.java diff --git a/src/java.base/share/classes/java/net/URI.java b/src/java.base/share/classes/java/net/URI.java index 2e6f2409bf42a..cd116f3877bcb 100644 --- a/src/java.base/share/classes/java/net/URI.java +++ b/src/java.base/share/classes/java/net/URI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3426,6 +3426,19 @@ private int scanByte(int start, int n) int p = start; int q = scan(p, n, L_DIGIT, H_DIGIT); if (q <= p) return q; + + // Handle leading zeros + int i = p, j; + while ((j = scan(i, q, '0')) > i) i = j; + + // Calculate the number of significant digits (after leading zeros) + int significantDigitsNum = q - i; + + if (significantDigitsNum < 3) return q; // definitely < 255 + + // If more than 3 significant digits, it's definitely > 255 + if (significantDigitsNum > 3) return p; + if (Integer.parseInt(input, p, q, 10) > 255) return p; return q; } diff --git a/test/jdk/java/net/URI/Test.java b/test/jdk/java/net/URI/Test.java index 00d473f87beff..95dd49ea34fbb 100644 --- a/test/jdk/java/net/URI/Test.java +++ b/test/jdk/java/net/URI/Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* @test * @summary Unit test for java.net.URI * @bug 4464135 4505046 4503239 4438319 4991359 4866303 7023363 7041800 - * 7171415 6339649 6933879 8037396 8272072 8051627 8297687 + * 7171415 6339649 6933879 8037396 8272072 8051627 8297687 8353013 * @author Mark Reinhold */ @@ -1620,6 +1620,7 @@ static void bugs() { b8051627(); b8272072(); b8297687(); + b8353013(); } private static void b8297687() { @@ -1786,6 +1787,39 @@ private static void b8272072() { } } + // 8353013 - Increase test coverage for cases where the authority component of a hierarchical + // URI has a host component that starts with a number. + private static void b8353013() { + testCreate("https://0.0.0.1").s("https").h("0.0.0.1").p("").z(); + testCreate("https://00.0.0.2").s("https").h("00.0.0.2").p("").z(); + testCreate("https://000.0.0.3").s("https").h("000.0.0.3").p("").z(); + testCreate("https://0000.0.0.4").s("https").h("0000.0.0.4").p("").z(); + + testCreate("https://00000.0.0.5").s("https").h("00000.0.0.5").p("").z(); + testCreate("https://00001.0.0.6").s("https").h("00001.0.0.6").p("").z(); + + testCreate("https://01.0.0.1").s("https").h("01.0.0.1").p("").z(); + + testCreate("https://111111.2.3.com").s("https").h("111111.2.3.com").p("").z(); + + testCreate("https://1.example.com").s("https").h("1.example.com").p("").z(); + testCreate("https://12.example.com").s("https").h("12.example.com").p("").z(); + testCreate("https://123.example.com").s("https").h("123.example.com").p("").z(); + testCreate("https://1234.example.com").s("https").h("1234.example.com").p("").z(); + testCreate("https://12345.example.com").s("https").h("12345.example.com").p("").z(); + + testCreate("https://98765432101.example.com").s("https").h("98765432101.example.com").p("").z(); + testCreate("https://98765432101.www.example.com/").s("https").h("98765432101.www.example.com").p("/").z(); + testCreate("https://98765432101.www.example.com").s("https").h("98765432101.www.example.com").p("").z(); + + testCreate("https://9223372036854775808.example.com").s("https").h("9223372036854775808.example.com").p("").z(); + testCreate("https://9223372036854775808.www.example.com").s("https").h("9223372036854775808.www.example.com").p("").z(); + testCreate("https://9223372036854775808.xyz.abc.com").s("https").h("9223372036854775808.xyz.abc.com").p("").z(); + testCreate("https://9223372036854775808.xyz.abc.pqr.com").s("https").h("9223372036854775808.xyz.abc.pqr.com").p("").z(); + + testCreate("https://256.example.com").s("https").h("256.example.com").p("").z(); + } + public static void main(String[] args) throws Exception { switch (args.length) { diff --git a/test/micro/org/openjdk/bench/java/net/URIAuthorityParsingBenchmark.java b/test/micro/org/openjdk/bench/java/net/URIAuthorityParsingBenchmark.java new file mode 100644 index 0000000000000..8e75b9e35ac60 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/net/URIAuthorityParsingBenchmark.java @@ -0,0 +1,62 @@ +/* + * 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. + */ +package org.openjdk.bench.java.net; + +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +import java.net.URI; +import java.util.concurrent.TimeUnit; + +/** + * Tests Java.net.URI.create performance on various URI types. + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(value = 3) +public class URIAuthorityParsingBenchmark { + + @Param({ + "https://98765432101.abc.xyz.com", + "https://ABCDEFGHIJK.abc.xyz.com" + }) + private String uri; + + @Benchmark + public void create(Blackhole blackhole) { + blackhole.consume(URI.create(uri)); + } + +} From 7a107e2fc4b0ea5c6d82fd047a631aff37bf3e74 Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Wed, 16 Apr 2025 16:28:12 +0000 Subject: [PATCH 0616/1101] 8351603: Change to GCC 14.2.0 for building on Linux at Oracle 8344272: gcc devkit doesn't have lto-plugin where needed Reviewed-by: ihse, erikj --- doc/building.html | 4 ++-- doc/building.md | 4 ++-- make/conf/jib-profiles.js | 10 +++++----- make/devkit/Tools.gmk | 42 +++++++++++++++++++++++++++++++++------ 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/doc/building.html b/doc/building.html index 7157848f561ae..95cda58e82853 100644 --- a/doc/building.html +++ b/doc/building.html @@ -586,7 +586,7 @@

Native Compiler Linux -gcc 13.2.0 +gcc 14.2.0 macOS @@ -604,7 +604,7 @@

gcc

The minimum accepted version of gcc is 10.0. Older versions will not be accepted by configure.

The JDK is currently known to compile successfully with gcc version -13.2 or newer.

+14.2 or newer.

In general, any version between these two should be usable.

clang

The minimum accepted version of clang is 13. Older versions will not diff --git a/doc/building.md b/doc/building.md index 04db6e94d1c12..914473916b417 100644 --- a/doc/building.md +++ b/doc/building.md @@ -392,7 +392,7 @@ issues. | Operating system | Toolchain version | | ------------------ | ------------------------------------------- | -| Linux | gcc 13.2.0 | +| Linux | gcc 14.2.0 | | macOS | Apple Xcode 14.3.1 (using clang 14.0.3) | | Windows | Microsoft Visual Studio 2022 version 17.6.5 | @@ -404,7 +404,7 @@ C, and C++14 for C++. The minimum accepted version of gcc is 10.0. Older versions will not be accepted by `configure`. -The JDK is currently known to compile successfully with gcc version 13.2 or +The JDK is currently known to compile successfully with gcc version 14.2 or newer. In general, any version between these two should be usable. diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 02474f3dccb73..aa4d846280ed3 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -1088,14 +1088,14 @@ var getJibProfilesProfiles = function (input, common, data) { var getJibProfilesDependencies = function (input, common) { var devkit_platform_revisions = { - linux_x64: "gcc13.2.0-OL6.4+1.0", + linux_x64: "gcc14.2.0-OL6.4+1.0", macosx: "Xcode14.3.1+1.0", windows_x64: "VS2022-17.6.5+1.0", - linux_aarch64: "gcc13.2.0-OL7.6+1.0", + linux_aarch64: "gcc14.2.0-OL7.6+1.0", linux_arm: "gcc8.2.0-Fedora27+1.0", - linux_ppc64le: "gcc13.2.0-Fedora_41+1.0", - linux_s390x: "gcc13.2.0-Fedora_41+1.0", - linux_riscv64: "gcc13.2.0-Fedora_41+1.0" + linux_ppc64le: "gcc14.2.0-Fedora_41+1.0", + linux_s390x: "gcc14.2.0-Fedora_41+1.0", + linux_riscv64: "gcc14.2.0-Fedora_41+1.0" }; var devkit_platform = (input.target_cpu == "x86" diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index 249eaa6624715..f4323f58638be 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -92,8 +92,18 @@ endif # Define external dependencies # Latest that could be made to work. -GCC_VER := 13.2.0 -ifeq ($(GCC_VER), 13.2.0) +GCC_VER := 14.2.0 +ifeq ($(GCC_VER), 14.2.0) + gcc_ver := gcc-14.2.0 + binutils_ver := binutils-2.43 + ccache_ver := ccache-4.10.2 + CCACHE_CMAKE_BASED := 1 + mpfr_ver := mpfr-4.2.1 + gmp_ver := gmp-6.3.0 + mpc_ver := mpc-1.3.1 + gdb_ver := gdb-15.2 + REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 +else ifeq ($(GCC_VER), 13.2.0) gcc_ver := gcc-13.2.0 binutils_ver := binutils-2.41 ccache_ver := ccache-3.7.12 @@ -262,10 +272,18 @@ define Download # Allow override $(1)_DIRNAME ?= $(basename $(basename $(notdir $($(1))))) $(1)_DIR = $(abspath $(SRCDIR)/$$($(1)_DIRNAME)) - $(1)_CFG = $$($(1)_DIR)/configure + ifeq ($$($(1)_CMAKE_BASED),) + $(1)_CFG = $$($(1)_DIR)/configure + $(1)_SRC_MARKER = $$($(1)_DIR)/configure + $(1)_CONFIG = $(CONFIG) + else + $(1)_CFG = cmake + $(1)_SRC_MARKER = $$($(1)_DIR)/CMakeLists.txt + $(1)_CONFIG = $$(CMAKE_CONFIG) $$($(1)_DIR) + endif $(1)_FILE = $(DOWNLOAD)/$(notdir $($(1))) - $$($(1)_CFG) : $$($(1)_FILE) + $$($(1)_SRC_MARKER) : $$($(1)_FILE) mkdir -p $$(SRCDIR) tar -C $$(SRCDIR) -xf $$< $$(foreach p,$$(abspath $$(wildcard patches/$$(ARCH)-$$(notdir $$($(1)_DIR)).patch)), \ @@ -365,6 +383,8 @@ CONFIG = --target=$(TARGET) \ --host=$(HOST) --build=$(BUILD) \ --prefix=$(PREFIX) +CMAKE_CONFIG = -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$(PREFIX) + PATHEXT = $(PREFIX)/bin: PATHPRE = PATH=$(PATHEXT)$(PATH) @@ -576,6 +596,8 @@ ifeq ($(HOST), $(TARGET)) $(PATHPRE) $(ENVS) CFLAGS="$(CFLAGS)" $(GDB_CFG) \ $(CONFIG) \ --with-sysroot=$(SYSROOT) \ + --with-mpfr=$(PREFIX) \ + --with-gmp=$(PREFIX) \ ) > $(@D)/log.config 2>&1 @echo 'done' @@ -591,13 +613,13 @@ endif ################################################################################ # very straightforward. just build a ccache. it is only for host. $(BUILDDIR)/$(ccache_ver)/Makefile \ - : $(CCACHE_CFG) + : $(CCACHE_SRC_MARKER) $(info Configuring $@. Log in $(@D)/log.config) @mkdir -p $(@D) @( \ cd $(@D) ; \ $(PATHPRE) $(ENVS) $(CCACHE_CFG) \ - $(CONFIG) \ + $(CCACHE_CONFIG) \ ) > $(@D)/log.config 2>&1 @echo 'done' @@ -703,6 +725,14 @@ ifeq ($(TARGET), $(HOST)) ld.gold nm objcopy objdump ranlib readelf size strings strip) endif +# Add link to work around "plugin needed to handle lto object" (JDK-8344272) +$(PREFIX)/lib/bfd-plugins/liblto_plugin.so: $(PREFIX)/libexec/gcc/$(TARGET)/$(GCC_VER)/liblto_plugin.so + @echo 'Creating missing $(@F) soft link' + @mkdir -p $(@D) + ln -s $$(realpath -s --relative-to=$(@D) $<) $@ + +missing-links += $(PREFIX)/lib/bfd-plugins/liblto_plugin.so + ################################################################################ bfdlib : $(bfdlib) From d80db00f8221b95ab767bb84d06b83a83ba4cd4c Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Wed, 16 Apr 2025 17:19:47 +0000 Subject: [PATCH 0617/1101] 8354873: javax/swing/plaf/metal/MetalIconFactory/bug4952462.java failing on CI Reviewed-by: honkar --- .../metal/MetalIconFactory/bug4952462.java | 64 ++++++++----------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/test/jdk/javax/swing/plaf/metal/MetalIconFactory/bug4952462.java b/test/jdk/javax/swing/plaf/metal/MetalIconFactory/bug4952462.java index f3562108314d2..65c5c510fc3f7 100644 --- a/test/jdk/javax/swing/plaf/metal/MetalIconFactory/bug4952462.java +++ b/test/jdk/javax/swing/plaf/metal/MetalIconFactory/bug4952462.java @@ -29,7 +29,7 @@ * @modules java.desktop/sun.awt * @library /test/lib * @key headful - * @run main bug4952462 + * @run main/othervm -Dsun.java2d.uiScale=1 bug4952462 */ import java.awt.Color; @@ -41,10 +41,8 @@ import javax.swing.JRadioButton; import javax.swing.SwingUtilities; import javax.swing.UIManager; -import javax.swing.plaf.metal.MetalTheme; - -import jtreg.SkippedException; -import sun.awt.AppContext; +import javax.swing.plaf.metal.MetalLookAndFeel; +import javax.swing.plaf.metal.OceanTheme; public class bug4952462 { private static JFrame frame; @@ -52,41 +50,35 @@ public class bug4952462 { public static void main(String[] args) throws Exception { try { + MetalLookAndFeel.setCurrentTheme(new OceanTheme()); UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + Robot r = new Robot(); + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("Metal JRadioButton Foreground Color Test"); + frame.getContentPane().setLayout(new FlowLayout()); + rb = new JRadioButton("RadioButton", true); + rb.setEnabled(false); + rb.setForeground(Color.RED); + frame.getContentPane().add(rb); + frame.setSize(250, 100); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); - MetalTheme theme = (MetalTheme) AppContext.getAppContext().get("currentMetalTheme"); - if (theme == null || !"Ocean".equals(theme.getName())) { - throw new SkippedException("Current theme is not Ocean. Test is " + - "only for Metal's Ocean theme. Skipping test."); - } else { - Robot r = new Robot(); - SwingUtilities.invokeAndWait(() -> { - frame = new JFrame("Metal JRadioButton Foreground Color Test"); - frame.getContentPane().setLayout(new FlowLayout()); - rb = new JRadioButton("RadioButton", true); - rb.setEnabled(false); - rb.setForeground(Color.RED); - frame.getContentPane().add(rb); - frame.setSize(250, 100); - frame.setLocationRelativeTo(null); - frame.setVisible(true); - }); - - r.waitForIdle(); - r.delay(500); + r.waitForIdle(); + r.delay(500); - SwingUtilities.invokeAndWait(() -> { - Point p = rb.getLocationOnScreen(); - for (int i = 0; i < 50; i++) { - Color c = r.getPixelColor(p.x + 10 + i, p.y + (rb.getHeight() / 2)); - System.out.println(c); - if (c.getRed() > 200 && c.getBlue() < 200 && c.getGreen() < 200) { - throw new RuntimeException("Test failed. Radiobutton is red " + - "and not grey."); - } + SwingUtilities.invokeAndWait(() -> { + Point p = rb.getLocationOnScreen(); + for (int i = 0; i < 50; i++) { + Color c = r.getPixelColor(p.x + 10 + i, p.y + (rb.getHeight() / 2)); + System.out.println(c); + if (c.getRed() > 200 && c.getBlue() < 80 && c.getGreen() < 80) { + throw new RuntimeException("Test failed. Radiobutton is red " + + "and not grey."); } - }); - } + } + }); } finally { SwingUtilities.invokeAndWait(() -> { if (frame != null) { From e433fa2719917cff6cb373e9a60981a7418e2f4f Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 16 Apr 2025 17:52:53 +0000 Subject: [PATCH 0618/1101] 8352001: AOT cache should not contain classes injected into built-in class loaders Reviewed-by: ccheung, matsaave --- src/hotspot/share/cds/aotClassLocation.cpp | 31 ++++ src/hotspot/share/cds/aotClassLocation.hpp | 5 + src/hotspot/share/classfile/classLoader.cpp | 14 ++ src/hotspot/share/classfile/classLoader.hpp | 1 + .../share/classfile/classLoaderExt.cpp | 10 +- .../share/classfile/classLoaderExt.hpp | 2 +- src/hotspot/share/utilities/zipLibrary.cpp | 9 + src/hotspot/share/utilities/zipLibrary.hpp | 3 +- src/java.base/share/native/libzip/zip_util.c | 4 +- src/java.base/share/native/libzip/zip_util.h | 4 +- .../aotClassLinking/FakeCodeLocation.java | 170 ++++++++++++++++++ 11 files changed, 246 insertions(+), 7 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/FakeCodeLocation.java diff --git a/src/hotspot/share/cds/aotClassLocation.cpp b/src/hotspot/share/cds/aotClassLocation.cpp index 656d7551b0330..8471d04b57215 100644 --- a/src/hotspot/share/cds/aotClassLocation.cpp +++ b/src/hotspot/share/cds/aotClassLocation.cpp @@ -47,6 +47,7 @@ #include #include +Array* AOTClassLocationConfig::_dumptime_jar_files = nullptr; AOTClassLocationConfig* AOTClassLocationConfig::_dumptime_instance = nullptr; const AOTClassLocationConfig* AOTClassLocationConfig::_runtime_instance = nullptr; @@ -479,6 +480,13 @@ void AOTClassLocationConfig::dumptime_init_helper(TRAPS) { _class_locations->at_put(i, tmp_array.at(i)); } + _dumptime_jar_files = MetadataFactory::new_array(ClassLoaderData::the_null_class_loader_data(), + tmp_array.length(), CHECK); + for (int i = 1; i < tmp_array.length(); i++) { + ClassPathZipEntry* jar_file = ClassLoader::create_class_path_zip_entry(tmp_array.at(i)->path()); + _dumptime_jar_files->at_put(i, jar_file); // may be null if the path is not a valid JAR file + } + const char* lcp = find_lcp(all_css.boot_and_app_cp(), _dumptime_lcp_len); if (_dumptime_lcp_len > 0) { os::free((void*)lcp); @@ -693,6 +701,29 @@ void AOTClassLocationConfig::check_nonempty_dirs() const { } } +// It's possible to use reflection+setAccessible to call into ClassLoader::defineClass() to +// pretend that a dynamically generated class comes from a JAR file in the classpath. +// Detect such classes so that they can be excluded from the archive. +bool AOTClassLocationConfig::is_valid_classpath_index(int classpath_index, InstanceKlass* ik) { + if (1 <= classpath_index && classpath_index < length()) { + ClassPathZipEntry *zip = _dumptime_jar_files->at(classpath_index); + if (zip != nullptr) { + JavaThread* current = JavaThread::current(); + ResourceMark rm(current); + const char* const class_name = ik->name()->as_C_string(); + const char* const file_name = ClassLoader::file_name_for_class_name(class_name, + ik->name()->utf8_length()); + if (!zip->has_entry(current, file_name)) { + log_warning(cds)("class %s cannot be archived because it was not defined from %s as claimed", + class_name, zip->name()); + return false; + } + } + } + + return true; +} + AOTClassLocationConfig* AOTClassLocationConfig::write_to_archive() const { Array* archived_copy = ArchiveBuilder::new_ro_array(_class_locations->length()); for (int i = 0; i < _class_locations->length(); i++) { diff --git a/src/hotspot/share/cds/aotClassLocation.hpp b/src/hotspot/share/cds/aotClassLocation.hpp index cb53e9c96e9d4..47f4dc86c9896 100644 --- a/src/hotspot/share/cds/aotClassLocation.hpp +++ b/src/hotspot/share/cds/aotClassLocation.hpp @@ -34,6 +34,7 @@ class AllClassLocationStreams; class ClassLocationStream; +class ClassPathZipEntry; class LogStream; // An AOTClassLocation is a location where the application is configured to load Java classes @@ -139,6 +140,8 @@ class AOTClassLocationConfig : public CHeapObj { static const AOTClassLocationConfig* _runtime_instance; Array* _class_locations; // jrt -> -Xbootclasspath/a -> -classpath -> --module_path + static Array* _dumptime_jar_files; + int _boot_classpath_end; int _app_classpath_end; int _module_end; @@ -263,6 +266,8 @@ class AOTClassLocationConfig : public CHeapObj { // Functions used only during runtime bool validate(bool has_aot_linked_classes, bool* has_extra_module_paths) const; + + bool is_valid_classpath_index(int classpath_index, InstanceKlass* ik); }; diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index 3ca1ec237e866..a7d6cc39614c7 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -305,6 +305,20 @@ ClassPathZipEntry::~ClassPathZipEntry() { FREE_C_HEAP_ARRAY(char, _zip_name); } +bool ClassPathZipEntry::has_entry(JavaThread* current, const char* name) { + ThreadToNativeFromVM ttn(current); + // check whether zip archive contains name + jint name_len; + jint filesize; + jzentry* entry = ZipLibrary::find_entry(_zip, name, &filesize, &name_len); + if (entry == nullptr) { + return false; + } else { + ZipLibrary::free_entry(_zip, entry); + return true; + } +} + u1* ClassPathZipEntry::open_entry(JavaThread* current, const char* name, jint* filesize, bool nul_terminate) { // enable call to C land ThreadToNativeFromVM ttn(current); diff --git a/src/hotspot/share/classfile/classLoader.hpp b/src/hotspot/share/classfile/classLoader.hpp index 7827b6066e5b3..d762e6caca7d0 100644 --- a/src/hotspot/share/classfile/classLoader.hpp +++ b/src/hotspot/share/classfile/classLoader.hpp @@ -93,6 +93,7 @@ class ClassPathZipEntry: public ClassPathEntry { const char* name() const { return _zip_name; } ClassPathZipEntry(jzfile* zip, const char* zip_name); virtual ~ClassPathZipEntry(); + bool has_entry(JavaThread* current, const char* name); u1* open_entry(JavaThread* current, const char* name, jint* filesize, bool nul_terminate); ClassFileStream* open_stream(JavaThread* current, const char* name); }; diff --git a/src/hotspot/share/classfile/classLoaderExt.cpp b/src/hotspot/share/classfile/classLoaderExt.cpp index 3a6fd0d933c45..fb63513353798 100644 --- a/src/hotspot/share/classfile/classLoaderExt.cpp +++ b/src/hotspot/share/classfile/classLoaderExt.cpp @@ -67,7 +67,7 @@ int ClassLoaderExt::compare_module_names(const char** p1, const char** p2) { return strcmp(*p1, *p2); } -void ClassLoaderExt::record_result(const s2 classpath_index, InstanceKlass* result, bool redefined) { +void ClassLoaderExt::record_result(s2 classpath_index, InstanceKlass* result, bool redefined) { assert(CDSConfig::is_dumping_archive(), "sanity"); // We need to remember where the class comes from during dumping. @@ -80,9 +80,17 @@ void ClassLoaderExt::record_result(const s2 classpath_index, InstanceKlass* resu classloader_type = ClassLoader::PLATFORM_LOADER; AOTClassLocationConfig::dumptime_set_has_platform_classes(); } + + if (CDSConfig::is_dumping_preimage_static_archive() || CDSConfig::is_dumping_dynamic_archive()) { + if (!AOTClassLocationConfig::dumptime()->is_valid_classpath_index(classpath_index, result)) { + classpath_index = -1; + } + } + AOTClassLocationConfig::dumptime_update_max_used_index(classpath_index); result->set_shared_classpath_index(classpath_index); result->set_shared_class_loader_type(classloader_type); + #if INCLUDE_CDS_JAVA_HEAP if (CDSConfig::is_dumping_heap() && AllowArchivingWithJavaAgent && classloader_type == ClassLoader::BOOT_LOADER && classpath_index < 0 && redefined) { diff --git a/src/hotspot/share/classfile/classLoaderExt.hpp b/src/hotspot/share/classfile/classLoaderExt.hpp index 86bd5cce7baa7..f4a1cf1a9c72c 100644 --- a/src/hotspot/share/classfile/classLoaderExt.hpp +++ b/src/hotspot/share/classfile/classLoaderExt.hpp @@ -40,7 +40,7 @@ class ClassLoaderExt: public ClassLoader { // AllStatic static void append_boot_classpath(ClassPathEntry* new_entry); static int compare_module_names(const char** p1, const char** p2); - static void record_result(const s2 classpath_index, InstanceKlass* result, bool redefined); + static void record_result(s2 classpath_index, InstanceKlass* result, bool redefined); #endif // INCLUDE_CDS }; diff --git a/src/hotspot/share/utilities/zipLibrary.cpp b/src/hotspot/share/utilities/zipLibrary.cpp index f56e311ec2eee..ae68fb9ef7703 100644 --- a/src/hotspot/share/utilities/zipLibrary.cpp +++ b/src/hotspot/share/utilities/zipLibrary.cpp @@ -35,6 +35,7 @@ typedef void**(*ZIP_Open_t)(const char* name, char** pmsg); typedef void(*ZIP_Close_t)(jzfile* zip); typedef jzentry* (*ZIP_FindEntry_t)(jzfile* zip, const char* name, jint* sizeP, jint* nameLen); typedef jboolean(*ZIP_ReadEntry_t)(jzfile* zip, jzentry* entry, unsigned char* buf, char* namebuf); +typedef void(*ZIP_FreeEntry_t)(jzfile *zip, jzentry *entry); typedef jint(*ZIP_CRC32_t)(jint crc, const jbyte* buf, jint len); typedef const char* (*ZIP_GZip_InitParams_t)(size_t, size_t*, size_t*, int); typedef size_t(*ZIP_GZip_Fully_t)(char*, size_t, char*, size_t, char*, size_t, int, char*, char const**); @@ -43,6 +44,7 @@ static ZIP_Open_t ZIP_Open = nullptr; static ZIP_Close_t ZIP_Close = nullptr; static ZIP_FindEntry_t ZIP_FindEntry = nullptr; static ZIP_ReadEntry_t ZIP_ReadEntry = nullptr; +static ZIP_FreeEntry_t ZIP_FreeEntry = nullptr; static ZIP_CRC32_t ZIP_CRC32 = nullptr; static ZIP_GZip_InitParams_t ZIP_GZip_InitParams = nullptr; static ZIP_GZip_Fully_t ZIP_GZip_Fully = nullptr; @@ -79,6 +81,7 @@ static void store_function_pointers(const char* path, bool vm_exit_on_failure) { ZIP_Close = CAST_TO_FN_PTR(ZIP_Close_t, dll_lookup("ZIP_Close", path, vm_exit_on_failure)); ZIP_FindEntry = CAST_TO_FN_PTR(ZIP_FindEntry_t, dll_lookup("ZIP_FindEntry", path, vm_exit_on_failure)); ZIP_ReadEntry = CAST_TO_FN_PTR(ZIP_ReadEntry_t, dll_lookup("ZIP_ReadEntry", path, vm_exit_on_failure)); + ZIP_FreeEntry = CAST_TO_FN_PTR(ZIP_FreeEntry_t, dll_lookup("ZIP_FreeEntry", path, vm_exit_on_failure)); ZIP_CRC32 = CAST_TO_FN_PTR(ZIP_CRC32_t, dll_lookup("ZIP_CRC32", path, vm_exit_on_failure)); // The following entry points are most likely optional from a zip library implementation perspective. // Hence no vm_exit on a resolution failure. Further refactorings should investigate this, @@ -176,6 +179,12 @@ jboolean ZipLibrary::read_entry(jzfile* zip, jzentry* entry, unsigned char* buf, return ZIP_ReadEntry(zip, entry, buf, namebuf); } +void ZipLibrary::free_entry(jzfile* zip, jzentry* entry) { + initialize(); + assert(ZIP_FreeEntry != nullptr, "invariant"); + ZIP_FreeEntry(zip, entry); +} + jint ZipLibrary::crc32(jint crc, const jbyte* buf, jint len) { initialize(); assert(ZIP_CRC32 != nullptr, "invariant"); diff --git a/src/hotspot/share/utilities/zipLibrary.hpp b/src/hotspot/share/utilities/zipLibrary.hpp index 73745aca2e206..90f55c24c192b 100644 --- a/src/hotspot/share/utilities/zipLibrary.hpp +++ b/src/hotspot/share/utilities/zipLibrary.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,6 +46,7 @@ class ZipLibrary : AllStatic { static void close(jzfile* zip); static jzentry* find_entry(jzfile* zip, const char* name, jint* sizeP, jint* nameLen); static jboolean read_entry(jzfile* zip, jzentry* entry, unsigned char* buf, char* namebuf); + static void free_entry(jzfile* zip, jzentry* entry); static jint crc32(jint crc, const jbyte* buf, jint len); static const char* init_params(size_t block_size, size_t* needed_out_size, size_t* needed_tmp_size, int level); static size_t compress(char* in, size_t in_size, char* out, size_t out_size, char* tmp, size_t tmp_size, int level, char* buf, const char** pmsg); diff --git a/src/java.base/share/native/libzip/zip_util.c b/src/java.base/share/native/libzip/zip_util.c index c327d3376597d..86223f22a438f 100644 --- a/src/java.base/share/native/libzip/zip_util.c +++ b/src/java.base/share/native/libzip/zip_util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1116,7 +1116,7 @@ newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint) * jzentry for each zip. This optimizes a common access pattern. */ -void +JNIEXPORT void ZIP_FreeEntry(jzfile *jz, jzentry *ze) { jzentry *last; diff --git a/src/java.base/share/native/libzip/zip_util.h b/src/java.base/share/native/libzip/zip_util.h index eef52b38b051c..9825202fc7bdc 100644 --- a/src/java.base/share/native/libzip/zip_util.h +++ b/src/java.base/share/native/libzip/zip_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -276,7 +276,7 @@ void ZIP_Unlock(jzfile *zip); jint ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len); -void +JNIEXPORT void ZIP_FreeEntry(jzfile *zip, jzentry *ze); jlong ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry); jzentry * ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/FakeCodeLocation.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/FakeCodeLocation.java new file mode 100644 index 0000000000000..5bec6623a08d8 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/FakeCodeLocation.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test Do not cache classes that are loaded from a fake location. + * @bug 8352001 + * @requires vm.cds.supports.aot.class.linking + * @comment work around JDK-8345635 + * @requires !vm.jvmci.enabled + * @library /test/jdk/lib/testlibrary /test/lib + * @build FakeCodeLocation + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar FakeCodeLocationApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller ClassNotInJar1 ClassNotInJar2 + * @run driver FakeCodeLocation + */ + +import java.lang.invoke.MethodHandles; +import java.lang.reflect.InaccessibleObjectException; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.ProtectionDomain; + +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.StringArrayUtils; + +public class FakeCodeLocation { + static final String appJar = "app.jar"; + static final String mainClass = FakeCodeLocationApp.class.getName(); + + public static void main(String[] args) throws Exception { + (new Tester(false)).run(new String[] {"STATIC"}); + (new Tester(true )).run(new String[] {"STATIC"}); + (new Tester(false)).run(new String[] {"AOT"}); + (new Tester(true )).run(new String[] {"AOT"}); + } + + static class Tester extends CDSAppTester { + boolean addOpen;; + public Tester(boolean addOpen) { + super(mainClass); + this.addOpen = addOpen; + } + + @Override + public String classpath(RunMode runMode) { + return appJar; + } + + @Override + public String[] vmArgs(RunMode runMode) { + String[] args = new String[] { + "-Xlog:cds", + "-Xlog:cds+class=debug", + "-Xlog:class+load", + }; + if (addOpen) { + args = StringArrayUtils.concat(args, "--add-opens", "java.base/java.lang=ALL-UNNAMED", "-XX:-AOTClassLinking"); + } + return args; + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] { + mainClass, + addOpen ? "hasAddedOpen" : "hasNotAddedOpen", + }; + } + + @Override + public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { + if (isDumping(runMode)) { + out.shouldMatch("cds,class.* FakeCodeLocationApp"); + out.shouldNotMatch("cds,class.* ClassNotInJar1"); + out.shouldNotMatch("cds,class.* ClassNotInJar2"); + } + + if (runMode.isProductionRun()) { + out.shouldMatch("class,load.* FakeCodeLocationApp .*source: shared objects file"); + out.shouldNotMatch("class,load.* ClassNotInJar1 .*source: shared objects file"); + out.shouldNotMatch("class,load.* ClassNotInJar2 .*source: shared objects file"); + } + } + } +} + +class FakeCodeLocationApp { + static boolean hasAddedOpen; + + public static void main(String args[]) throws Exception { + hasAddedOpen = args[0].equals("hasAddedOpen"); + testWithLookup(); + testWithSetAccessible(); + } + + // Define a class using Lookup.defineClass(). The ClassFileParser should see "__JVM_DefineClass__" + // as the source location, so this class will be excluded, as the location is not supported. + static void testWithLookup() throws Exception { + byte[] data = Files.readAllBytes(Paths.get("ClassNotInJar1.class")); + Class c = MethodHandles.lookup().defineClass(data); + System.out.println(c.getProtectionDomain()); + System.out.println(c.getProtectionDomain().getCodeSource()); + } + + // Use setAccessible to call into ClassLoader.defineClass(). In this case, the ClassFileParser + // sees "app.jar" as the source location, but the app.jar doesn't contain this class file, so we + // should exclude this class. + static void testWithSetAccessible() throws Exception { + Method m = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class, ProtectionDomain.class); + System.out.println(m); + try { + m.setAccessible(true); + if (!hasAddedOpen) { + throw new RuntimeException("setAccessible() should have failed because '--add-opens java.base/java.lang=ALL-UNNAMED' was not specified"); + } + } catch (InaccessibleObjectException t) { + if (hasAddedOpen) { + throw new RuntimeException("setAccessible() failed even though '--add-opens java.base/java.lang=ALL-UNNAMED' was specified"); + } else { + System.out.println("\n\nExpected: " + t); + t.printStackTrace(System.out); + return; + } + } + + ProtectionDomain pd = FakeCodeLocationApp.class.getProtectionDomain(); + ClassLoader appLoader = FakeCodeLocationApp.class.getClassLoader(); + byte[] data = Files.readAllBytes(Paths.get("ClassNotInJar2.class")); + Class c = null; + try { + c = (Class)m.invoke(appLoader, "ClassNotInJar2", data, 0, data.length, pd); + } catch (Throwable t) { + System.out.println(t); + t.printStackTrace(System.out); + return; + } + + System.out.println(c); + System.out.println(c.getProtectionDomain()); + System.out.println(c.getProtectionDomain().getCodeSource()); + } +} + +class ClassNotInJar1 {} + +class ClassNotInJar2 {} From 98dac46aac2cea9790c1275208cc4c92e8e9a98a Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 16 Apr 2025 18:05:07 +0000 Subject: [PATCH 0619/1101] 8353589: Open source a few Swing menu-related tests Reviewed-by: jdv, honkar --- .../javax/swing/JPopupMenu/bug4119993.java | 112 ++++++++++++++++++ .../javax/swing/JPopupMenu/bug4187004.java | 97 +++++++++++++++ .../javax/swing/JPopupMenu/bug4530303.java | 85 +++++++++++++ 3 files changed, 294 insertions(+) create mode 100644 test/jdk/javax/swing/JPopupMenu/bug4119993.java create mode 100644 test/jdk/javax/swing/JPopupMenu/bug4187004.java create mode 100644 test/jdk/javax/swing/JPopupMenu/bug4530303.java diff --git a/test/jdk/javax/swing/JPopupMenu/bug4119993.java b/test/jdk/javax/swing/JPopupMenu/bug4119993.java new file mode 100644 index 0000000000000..1fe72ea29d6ba --- /dev/null +++ b/test/jdk/javax/swing/JPopupMenu/bug4119993.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4119993 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Check that mouse button 3 is reserved for popup invocation not selection. + * @run main/manual bug4119993 + */ + +import java.awt.BorderLayout; +import java.awt.Dimension; +import javax.swing.BoxLayout; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTextArea; +import javax.swing.border.BevelBorder; + +/* + * This is a sort of negative test. Mouse Button 3 is not supposed to cause selections. + * If it did, then it would not be useable to invoke popup menus. + * So this popup menu test .. does not popup menus. + */ + +public class bug4119993 { + + static final String INSTRUCTIONS = """ + + The test window contains a text area, a table, and a list. +

+ For each component, try to select text/cells/rows/items as appropriate + using the RIGHT mouse button (Mouse Button 3). +

+ If the selection changes, then press FAIL. +

+ If the selection does not change, press PASS + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(bug4119993::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("bug4119993"); + JPanel p = new JPanel(); + p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); + frame.add(p); + + String text = "This is some text that you should try to select using the right mouse button"; + JTextArea area = new JTextArea(text, 5, 40); + JScrollPane scrollpane0 = new JScrollPane(area); + scrollpane0.setBorder(new BevelBorder(BevelBorder.LOWERED)); + scrollpane0.setPreferredSize(new Dimension(430, 200)); + p.add(scrollpane0); + + String[][] data = new String[5][5]; + String[] cols = new String[5]; + for (int r = 0; r < 5; r ++) { + cols[r] = "col " + r; + for (int c = 0; c < 5; c ++) { + data[r][c] = "(" + r + "," + c + ")"; + } + } + + JTable tableView = new JTable(data, cols); + JScrollPane scrollpane = new JScrollPane(tableView); + scrollpane.setBorder(new BevelBorder(BevelBorder.LOWERED)); + scrollpane.setPreferredSize(new Dimension(430, 200)); + p.add(scrollpane); + + String[] s = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}; + JList listView = new JList(s); + JScrollPane scrollpane2 = new JScrollPane(listView); + scrollpane2.setBorder(new BevelBorder(BevelBorder.LOWERED)); + scrollpane2.setPreferredSize(new Dimension(430, 200)); + p.add(scrollpane2); + + frame.pack(); + return frame; + } +} diff --git a/test/jdk/javax/swing/JPopupMenu/bug4187004.java b/test/jdk/javax/swing/JPopupMenu/bug4187004.java new file mode 100644 index 0000000000000..40a6633c13006 --- /dev/null +++ b/test/jdk/javax/swing/JPopupMenu/bug4187004.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 4187004 + @summary test that title/label is show on menu for Motif L&F + @key headful +*/ + +import java.awt.Dimension; +import java.awt.Robot; +import javax.swing.JFrame; +import javax.swing.JPopupMenu; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class bug4187004 { + + static volatile JPopupMenu m; + static volatile Dimension d1, d2; + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(bug4187004::createUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(1000); + d1 = m.getSize(); + SwingUtilities.invokeAndWait(bug4187004::hideMenu); + robot.waitForIdle(); + robot.delay(1000); + SwingUtilities.invokeAndWait(bug4187004::updateUI); + robot.waitForIdle(); + robot.delay(1000); + SwingUtilities.invokeAndWait(bug4187004::showMenu); + robot.waitForIdle(); + robot.delay(1000); + d2 = m.getSize(); + } finally { + SwingUtilities.invokeAndWait(bug4187004::hideMenu); + } + System.out.println(d1); + System.out.println(d2); + if (d1.width <= d2.width) { + throw new RuntimeException("Menu not updated"); + } + } + + static void createUI() { + try { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); + } catch (Exception e) { + throw new RuntimeException(e); + } + m = new JPopupMenu("One really long menu title"); + m.add("Item 1"); + m.add("Item 2"); + m.add("Item 3"); + m.add("Item 4"); + m.pack(); + m.setVisible(true); + } + + static void hideMenu() { + m.setVisible(false); + } + + static void showMenu() { + m.setVisible(true); + } + + static void updateUI() { + m.setLabel("short"); + m.pack(); + } +} diff --git a/test/jdk/javax/swing/JPopupMenu/bug4530303.java b/test/jdk/javax/swing/JPopupMenu/bug4530303.java new file mode 100644 index 0000000000000..c99dacc7cff3c --- /dev/null +++ b/test/jdk/javax/swing/JPopupMenu/bug4530303.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4530303 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Tests JPopupMenu.pack() + * @run main/manual bug4530303 + */ + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; + +public class bug4530303 { + + static final String INSTRUCTIONS = """ + The test window has a menu bar. + Open the menu "Menu" and place the mouse pointer over the first menu item, "Point here". + The second menu item, "Ghost", should be replaced with another item, "Fixed!". + If the item just disappears and no new item appears in the empty space, the test FAILS. + """; + + static volatile JMenu menu; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(bug4530303::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("bug4530303"); + menu = new JMenu("Menu"); + JMenuItem item = new JMenuItem("Point here"); + item.addMouseListener(new MenuBuilder()); + menu.add(item); + menu.add(new JMenuItem("Ghost")); + + JMenuBar mbar = new JMenuBar(); + mbar.add(menu); + frame.setJMenuBar(mbar); + frame.setSize(300, 300); + return frame; + } + + static class MenuBuilder extends MouseAdapter { + public void mouseEntered(MouseEvent ev) { + menu.remove(1); + menu.add(new JMenuItem("Fixed!")); + + JPopupMenu pm = menu.getPopupMenu(); + pm.pack(); + pm.paintImmediately(pm.getBounds()); + } + } +} From 0c34bf047615ad57c91cd49844f9d34f9a8329a2 Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Wed, 16 Apr 2025 19:57:42 +0000 Subject: [PATCH 0620/1101] 8354471: Assertion failure with -XX:-EnableX86ECoreOpts Reviewed-by: sviswanathan, jbhateja --- .../x86/stubGenerator_x86_64_poly_mont.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp index a897fe2e6942d..d142414be5ec2 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp @@ -564,7 +564,16 @@ address StubGenerator::generate_intpoly_montgomeryMult_P256() { address start = __ pc(); __ enter(); - if (EnableX86ECoreOpts && UseAVX > 1) { + if (VM_Version::supports_avx512ifma() && VM_Version::supports_avx512vlbw()) { + // Register Map + const Register aLimbs = c_rarg0; // rdi | rcx + const Register bLimbs = c_rarg1; // rsi | rdx + const Register rLimbs = c_rarg2; // rdx | r8 + const Register tmp = r9; + + montgomeryMultiply(aLimbs, bLimbs, rLimbs, tmp, _masm); + } else { + assert(VM_Version::supports_avxifma(), "Require AVX_IFMA support"); __ push(r12); __ push(r13); __ push(r14); @@ -607,14 +616,6 @@ address StubGenerator::generate_intpoly_montgomeryMult_P256() { __ pop(r14); __ pop(r13); __ pop(r12); - } else { - // Register Map - const Register aLimbs = c_rarg0; // rdi | rcx - const Register bLimbs = c_rarg1; // rsi | rdx - const Register rLimbs = c_rarg2; // rdx | r8 - const Register tmp = r9; - - montgomeryMultiply(aLimbs, bLimbs, rLimbs, tmp, _masm); } __ leave(); From a2d7f441b8616e0cd8c231f3358b1b508e76686d Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Wed, 16 Apr 2025 20:11:26 +0000 Subject: [PATCH 0621/1101] 8295651: JFR: 'jfr scrub' should summarize what was removed Reviewed-by: mgronlun --- .../jdk/jfr/consumer/RecordedObject.java | 10 +++- .../jdk/jfr/consumer/RecordingFile.java | 9 +++- .../classes/jdk/jfr/internal/LongMap.java | 15 +++++- .../jfr/internal/consumer/JdkJfrConsumer.java | 6 ++- .../internal/consumer/filter/ChunkWriter.java | 48 ++++++++++++++++++- .../jdk/jfr/internal/tool/Command.java | 4 ++ .../classes/jdk/jfr/internal/tool/Scrub.java | 24 ++++++++-- .../jdk/jfr/internal/tool/Summary.java | 2 +- test/jdk/jdk/jfr/tool/TestScrub.java | 33 +++++++++++-- 9 files changed, 136 insertions(+), 15 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java index 21bd30a8248d1..8d4a69a92d772 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.nio.file.Path; import java.time.Duration; import java.time.Instant; import java.time.OffsetDateTime; @@ -35,6 +36,7 @@ import java.util.Comparator; import java.util.List; import java.util.Objects; +import java.util.function.Predicate; import jdk.jfr.Configuration; import jdk.jfr.EventType; @@ -46,6 +48,7 @@ import jdk.jfr.internal.consumer.JdkJfrConsumer; import jdk.jfr.internal.consumer.ObjectContext; import jdk.jfr.internal.consumer.ObjectFactory; +import jdk.jfr.internal.consumer.filter.ChunkWriter.RemovedEvents; import jdk.jfr.internal.tool.PrettyWriter; /** @@ -148,6 +151,11 @@ public MetadataEvent newMetadataEvent(List previous, List List configurations) { return new MetadataEvent(previous, current, configurations); } + + @Override + public List write(RecordingFile file, Path output, Predicate filter) throws IOException { + return file.write(output, filter, true); + } }; JdkJfrConsumer.setAccess(access); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java index 0e51da0411925..a3880da33fad9 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java @@ -46,6 +46,7 @@ import jdk.jfr.internal.consumer.ParserState; import jdk.jfr.internal.consumer.RecordingInput; import jdk.jfr.internal.consumer.filter.ChunkWriter; +import jdk.jfr.internal.consumer.filter.ChunkWriter.RemovedEvents; /** * A recording file. @@ -229,12 +230,18 @@ public void close() throws IOException { public void write(Path destination, Predicate filter) throws IOException { Objects.requireNonNull(destination, "destination"); Objects.requireNonNull(filter, "filter"); - try (ChunkWriter cw = new ChunkWriter(file.toPath(), destination, filter)) { + write(destination, filter, false); + } + + // package private + List write(Path destination, Predicate filter, boolean collectResults) throws IOException { + try (ChunkWriter cw = new ChunkWriter(file.toPath(), destination, filter, collectResults)) { try (RecordingFile rf = new RecordingFile(cw)) { while (rf.hasMoreEvents()) { rf.readEvent(); } } + return cw.getRemovedEventTypes(); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/LongMap.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/LongMap.java index 3a3539df4b12b..dfb549b57784a 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/LongMap.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/LongMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,9 @@ package jdk.jfr.internal; +import java.util.ArrayList; import java.util.BitSet; +import java.util.List; import java.util.function.Consumer; import java.util.function.LongConsumer; @@ -265,4 +267,15 @@ public String toString() { } return sb.toString(); } + + public List values() { + List list = new ArrayList<>(count); + for (int i = 0; i < keys.length; i++) { + T o = objects[i]; + if (o != null) { + list.add(o); + } + } + return list; + } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/JdkJfrConsumer.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/JdkJfrConsumer.java index cc5dc4f5d7405..9690cc1684b4f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/JdkJfrConsumer.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/JdkJfrConsumer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,10 @@ package jdk.jfr.internal.consumer; import java.io.IOException; +import java.nio.file.Path; import java.util.Comparator; import java.util.List; +import java.util.function.Predicate; import jdk.jfr.Configuration; import jdk.jfr.EventType; @@ -43,6 +45,7 @@ import jdk.jfr.consumer.RecordedThreadGroup; import jdk.jfr.consumer.RecordingFile; import jdk.jfr.internal.Type; +import jdk.jfr.internal.consumer.filter.ChunkWriter.RemovedEvents;; /* * Purpose of this class is to give package private access to @@ -105,4 +108,5 @@ public static JdkJfrConsumer instance() { public abstract MetadataEvent newMetadataEvent(List previous, List current, List configuration); + public abstract List write(RecordingFile file, Path output, Predicate filter) throws IOException; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/ChunkWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/ChunkWriter.java index 5e3940e7d11d1..06a415c35613a 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/ChunkWriter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/ChunkWriter.java @@ -32,6 +32,7 @@ import java.util.Deque; import java.util.Map; import java.util.HashMap; +import java.util.List; import java.util.function.Predicate; import jdk.jfr.consumer.RecordedEvent; @@ -51,6 +52,28 @@ * All positional values are relative to file start, not the chunk. */ public final class ChunkWriter implements Closeable { + public static class RemovedEvents implements Comparable { + public final String name; + private long count; + private long removed; + + private RemovedEvents(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public String share() { + return removed + "/" + count; + } + + @Override + public int compareTo(RemovedEvents that) { + return this.getName().compareTo(that.getName()); + } + } private LongMap pools = new LongMap<>(); private final Deque checkpoints = new ArrayDeque<>(); private final Path destination; @@ -58,16 +81,19 @@ public final class ChunkWriter implements Closeable { private final RecordingOutput output; private final Predicate filter; private final Map waste = new HashMap<>(); + private final LongMap removedEvents = new LongMap<>(); + private final boolean collectResults; private long chunkStartPosition; private boolean chunkComplete; private long lastCheckpoint; - public ChunkWriter(Path source, Path destination, Predicate filter) throws IOException { + public ChunkWriter(Path source, Path destination, Predicate filter, boolean collectResults) throws IOException { this.destination = destination; this.output = new RecordingOutput(destination.toFile()); this.input = new RecordingInput(source.toFile()); this.filter = filter; + this.collectResults = collectResults; } Constants getPool(Type type) { @@ -87,7 +113,25 @@ public CheckpointEvent newCheckpointEvent(long startPosition) { } public boolean accept(RecordedEvent event) { - return filter.test(event); + if (!collectResults) { + return filter.test(event); + } + long id = event.getEventType().getId(); + RemovedEvents r = removedEvents.get(id); + if (r == null) { + r = new RemovedEvents(event.getEventType().getName()); + removedEvents.put(id, r); + } + r.count++; + if (filter.test(event)) { + return true; + } + r.removed++; + return false; + } + + public List getRemovedEventTypes() { + return removedEvents.values().stream().filter(r -> r.removed > 0).sorted().toList(); } public void touch(Object object) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Command.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Command.java index 38c6bb4285e52..066b528d950b8 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Command.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Command.java @@ -318,6 +318,10 @@ protected final void println(String text) { System.out.println(text); } + protected final void printf(String text, Object ... args) { + System.out.printf(text, args); + } + public static void checkCommonError(Deque options, String typo, String correct) throws UserSyntaxException { if (typo.equals(options.peek())) { throw new UserSyntaxException("unknown option " + typo + ", did you mean " + correct + "?"); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Scrub.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Scrub.java index a17662af88d57..8a02ded11258d 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Scrub.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Scrub.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,8 @@ import jdk.jfr.EventType; import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordingFile; +import jdk.jfr.internal.consumer.JdkJfrConsumer; +import jdk.jfr.internal.consumer.filter.ChunkWriter.RemovedEvents; import jdk.jfr.internal.util.UserDataException; import jdk.jfr.internal.util.UserSyntaxException; @@ -141,12 +143,26 @@ public void execute(Deque options) throws UserSyntaxException, UserDataE try (RecordingFile rf = new RecordingFile(input)) { List types = rf.readEventTypes(); Predicate filter = createFilter(options, types); - rf.write(output, filter); + List result = JdkJfrConsumer.instance().write(rf, output, filter); + println("Scrubbed recording file written to:"); + println(output.toRealPath().toString()); + if (result.isEmpty()) { + println("No events removed."); + return; + } + int maxName = 0; + int maxShare = 0; + for (RemovedEvents re : result) { + maxName = Math.max(maxName, re.getName().length()); + maxShare = Math.max(maxShare, re.share().length()); + } + println("Removed events:"); + for (RemovedEvents re : result) { + printf("%-" + maxName + "s %" + maxShare + "s\n", re.getName(), re.share()); + } } catch (IOException ioe) { couldNotReadError(input, ioe); } - println("Scrubbed recording file written to:"); - println(output.toAbsolutePath().toString()); } private Predicate createFilter(Deque options, List types) throws UserSyntaxException, UserDataException { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java index 08ab475fa680b..31b8d807ba0f8 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java @@ -152,7 +152,7 @@ private void printInformation(Path p) throws IOException { println(typeHeader + " ".repeat(minWidth - typeHeader.length()) + header); println("=".repeat(minWidth + header.length())); for (Statistics s : statsList) { - System.out.printf(" %-" + minWidth + "s%10d %12d\n", s.name, s.count, s.size); + printf(" %-" + minWidth + "s%10d %12d\n", s.name, s.count, s.size); } } } diff --git a/test/jdk/jdk/jfr/tool/TestScrub.java b/test/jdk/jdk/jfr/tool/TestScrub.java index 43b9fca7ee4c0..23a87452ff96b 100644 --- a/test/jdk/jdk/jfr/tool/TestScrub.java +++ b/test/jdk/jdk/jfr/tool/TestScrub.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,9 +69,16 @@ public static void main(String[] args) throws Throwable { try (Recording r = new Recording()) { r.start(); - emit(100, "India", TigerEvent.class); - emit(100, "Namibia", ZebraEvent.class); - emit(10000, "Lake Tanganyika", TigerfishEvent.class); + emit(50, "India", TigerEvent.class); + emit(50, "Namibia", ZebraEvent.class); + emit(5000, "Lake Tanganyika", TigerfishEvent.class); + // Force rotation + try (Recording s = new Recording()) { + s.start(); + } + emit(50, "India", TigerEvent.class); + emit(50, "Namibia", ZebraEvent.class); + emit(5000, "Lake Tanganyika", TigerfishEvent.class); r.stop(); r.dump(file); } @@ -89,6 +96,7 @@ public static void main(String[] args) throws Throwable { testThreadInclude(file); testMissingEventType(file); + testSummary(file); } private static void testInputOutput(Path file) throws Throwable { @@ -275,6 +283,23 @@ private static void testMissingEventType(Path input) throws Throwable { Files.delete(output); } + + private static void testSummary(Path file) throws Throwable { + String inputFile = file.toAbsolutePath().toString(); + + String removedZebras = Path.of("removed-zebras.jfr").toAbsolutePath().toString(); + var outp = ExecuteHelper.jfr("scrub", "--exclude-events", "Zebra", inputFile, removedZebras); + outp.shouldContain("Removed events:"); + outp.shouldContain("example.Zebra 100/100"); + outp.shouldNotContain("Tiger"); + outp.shouldNotContain("No events removed"); + + String noneRemoved = Path.of("none-removed.jfr").toAbsolutePath().toString(); + outp = ExecuteHelper.jfr("scrub", "--exclude-events", "jdk.JVMInformation", inputFile, noneRemoved); + outp.shouldContain("No events removed"); + outp.shouldNotContain("jdk.JVMInformation"); + } + private static void assertNotThread(RecordedEvent event, String... threadNames) { String s = event.getThread().getJavaName(); for (String threadName : threadNames) { From db2dffb6e5fed3773080581350f7f5c0bcff8f35 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Wed, 16 Apr 2025 23:04:37 +0000 Subject: [PATCH 0622/1101] 8354559: gc/g1/TestAllocationFailure.java doesn't need WB API Reviewed-by: ayang, kbarrett --- test/hotspot/jtreg/gc/g1/TestAllocationFailure.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/gc/g1/TestAllocationFailure.java b/test/hotspot/jtreg/gc/g1/TestAllocationFailure.java index cd4c991de263c..a0aabf359b429 100644 --- a/test/hotspot/jtreg/gc/g1/TestAllocationFailure.java +++ b/test/hotspot/jtreg/gc/g1/TestAllocationFailure.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,10 +31,7 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.management - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * gc.g1.TestAllocationFailure + * @run driver gc.g1.TestAllocationFailure */ import jdk.test.lib.process.OutputAnalyzer; From 07aad68c17ba8d95aee914f3bd9705301477acf6 Mon Sep 17 00:00:00 2001 From: Anjian-Wen Date: Thu, 17 Apr 2025 02:16:24 +0000 Subject: [PATCH 0623/1101] 8329887: RISC-V: C2: Support Zvbb Vector And-Not instruction Reviewed-by: fyang, fjiang --- src/hotspot/cpu/riscv/riscv_v.ad | 68 +++++++++++++++++++ .../compiler/lib/ir_framework/IRNode.java | 10 +++ .../AllBitsSetVectorMatchRuleTest.java | 64 ++++++++++++++++- 3 files changed, 139 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 1e99b2ece2914..9b135215b3d0f 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -1117,6 +1117,74 @@ instruct vxor_regL_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} +// ------------------------------ Vector and not ----------------------------------- + +// vector and not + +instruct vand_notI(vReg dst, vReg src1, vReg src2, immI_M1 m1) %{ + predicate(UseZvbb); + predicate(Matcher::vector_element_basic_type(n) == T_INT || + Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT); + match(Set dst (AndV src1 (XorV src2 (Replicate m1)))); + format %{ "vand_notI $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vandn_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notL(vReg dst, vReg src1, vReg src2, immL_M1 m1) %{ + predicate(UseZvbb); + predicate(Matcher::vector_element_basic_type(n) == T_LONG); + match(Set dst (AndV src1 (XorV src2 (Replicate m1)))); + format %{ "vand_notL $dst, $src1, $src2" %} + ins_encode %{ + __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); + __ vandn_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notI_masked(vReg dst_src1, vReg src2, immI_M1 m1, vRegMask_V0 v0) %{ + predicate(UseZvbb); + predicate(Matcher::vector_element_basic_type(n) == T_INT || + Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (Replicate m1))) v0)); + format %{ "vand_notI_masked $dst_src1, $dst_src1, $src2, $v0" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vandn_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), + Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notL_masked(vReg dst_src1, vReg src2, immL_M1 m1, vRegMask_V0 v0) %{ + predicate(UseZvbb); + predicate(Matcher::vector_element_basic_type(n) == T_LONG); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (Replicate m1))) v0)); + format %{ "vand_notL_masked $dst_src1, $dst_src1, $src2, $v0" %} + ins_encode %{ + __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); + __ vandn_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), + Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + // ------------------------------ Vector not ----------------------------------- // vector not diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 57e4d413fea07..6d58b35f53c91 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -2116,6 +2116,16 @@ public class IRNode { machOnlyNameRegex(VAND_NOT_L, "vand_notL"); } + public static final String VAND_NOT_I_MASKED = PREFIX + "VAND_NOT_I_MASKED" + POSTFIX; + static { + machOnlyNameRegex(VAND_NOT_I_MASKED, "vand_notI_masked"); + } + + public static final String VAND_NOT_L_MASKED = PREFIX + "VAND_NOT_L_MASKED" + POSTFIX; + static { + machOnlyNameRegex(VAND_NOT_L_MASKED, "vand_notL_masked"); + } + public static final String VECTOR_BLEND_B = VECTOR_PREFIX + "VECTOR_BLEND_B" + POSTFIX; static { vectorNode(VECTOR_BLEND_B, "VectorBlend", TYPE_BYTE); diff --git a/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java b/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java index e490174e380de..f33dd24e726a8 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java @@ -42,7 +42,7 @@ * @key randomness * @library /test/lib / * @requires vm.compiler2.enabled - * @requires vm.cpu.features ~= ".*asimd.*" + * @requires (os.simpleArch == "aarch64" & vm.cpu.features ~= ".*asimd.*") | (os.simpleArch == "riscv64" & vm.cpu.features ~= ".*zvbb.*") * @summary AArch64: [vector] Make all bits set vector sharable for match rules * @modules jdk.incubator.vector * @@ -59,6 +59,9 @@ public class AllBitsSetVectorMatchRuleTest { private static int[] ia; private static int[] ib; private static int[] ir; + private static long[] la; + private static long[] lb; + private static long[] lr; private static boolean[] ma; private static boolean[] mb; private static boolean[] mc; @@ -68,6 +71,9 @@ public class AllBitsSetVectorMatchRuleTest { ia = new int[LENGTH]; ib = new int[LENGTH]; ir = new int[LENGTH]; + la = new long[LENGTH]; + lb = new long[LENGTH]; + lr = new long[LENGTH]; ma = new boolean[LENGTH]; mb = new boolean[LENGTH]; mc = new boolean[LENGTH]; @@ -76,6 +82,8 @@ public class AllBitsSetVectorMatchRuleTest { for (int i = 0; i < LENGTH; i++) { ia[i] = RD.nextInt(25); ib[i] = RD.nextInt(25); + la[i] = RD.nextLong(25); + lb[i] = RD.nextLong(25); ma[i] = RD.nextBoolean(); mb[i] = RD.nextBoolean(); mc[i] = RD.nextBoolean(); @@ -98,8 +106,58 @@ public static void testAllBitsSetVector() { @Test @Warmup(10000) - @IR(counts = { IRNode.VAND_NOT_L, " >= 1" }, applyIf = {"UseSVE", "0"}) - @IR(counts = { IRNode.VMASK_AND_NOT_L, " >= 1" }, applyIf = {"UseSVE", "> 0"}) + @IR(counts = { IRNode.VAND_NOT_L, " >= 1" }) + public static void testVectorVAndNotL() { + LongVector av = LongVector.fromArray(L_SPECIES, la, 0); + LongVector bv = LongVector.fromArray(L_SPECIES, lb, 0); + av.not().lanewise(VectorOperators.AND_NOT, bv).intoArray(lr, 0); + + // Verify results + for (int i = 0; i < L_SPECIES.length(); i++) { + Asserts.assertEquals((~la[i]) & (~lb[i]), lr[i]); + } + } + + @Test + @Warmup(10000) + @IR(counts = { IRNode.VAND_NOT_I_MASKED, " >= 1" }, applyIfPlatform = {"aarch64", "true"}, applyIf = {"UseSVE", "> 0"}) + @IR(counts = { IRNode.VAND_NOT_I_MASKED, " >= 1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testVectorVAndNotIMasked() { + VectorMask avm = VectorMask.fromArray(I_SPECIES, ma, 0); + IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); + IntVector bv = IntVector.fromArray(I_SPECIES, ib, 0); + av.not().lanewise(VectorOperators.AND_NOT, bv, avm).intoArray(ir, 0); + + // Verify results + for (int i = 0; i < I_SPECIES.length(); i++) { + if (ma[i] == true) { + Asserts.assertEquals((~ia[i]) & (~ib[i]), ir[i]); + } + } + } + + @Test + @Warmup(10000) + @IR(counts = { IRNode.VAND_NOT_L_MASKED, " >= 1" }, applyIfPlatform = {"aarch64", "true"}, applyIf = {"UseSVE", "> 0"}) + @IR(counts = { IRNode.VAND_NOT_L_MASKED, " >= 1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testVectorVAndNotLMasked() { + VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); + LongVector av = LongVector.fromArray(L_SPECIES, la, 0); + LongVector bv = LongVector.fromArray(L_SPECIES, lb, 0); + av.not().lanewise(VectorOperators.AND_NOT, bv, avm).intoArray(lr, 0); + + // Verify results + for (int i = 0; i < L_SPECIES.length(); i++) { + if (ma[i] == true) { + Asserts.assertEquals((~la[i]) & (~lb[i]), lr[i]); + } + } + } + + @Test + @Warmup(10000) + @IR(counts = { IRNode.VAND_NOT_L, " >= 1" }, applyIfPlatform = {"aarch64", "true"}, applyIf = {"UseSVE", "0"}) + @IR(counts = { IRNode.VMASK_AND_NOT_L, " >= 1" }, applyIfPlatform = {"aarch64", "true"}, applyIf = {"UseSVE", "> 0"}) public static void testAllBitsSetMask() { VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); VectorMask bvm = VectorMask.fromArray(L_SPECIES, mb, 0); From a71f621a3248320e8a7a78f1652a7750271ed4ef Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 17 Apr 2025 03:10:58 +0000 Subject: [PATCH 0624/1101] 8353694: Resolved Class/Field/Method CP entries missing from AOT Configuration Reviewed-by: shade, vlivanov --- src/hotspot/share/cds/archiveUtils.inline.hpp | 2 +- src/hotspot/share/cds/finalImageRecipes.cpp | 153 ++++++++++++------ src/hotspot/share/cds/finalImageRecipes.hpp | 19 ++- src/hotspot/share/runtime/mutexLocker.cpp | 2 + src/hotspot/share/runtime/mutexLocker.hpp | 1 + 5 files changed, 120 insertions(+), 57 deletions(-) diff --git a/src/hotspot/share/cds/archiveUtils.inline.hpp b/src/hotspot/share/cds/archiveUtils.inline.hpp index 9388bca18c72e..72de48743f3f1 100644 --- a/src/hotspot/share/cds/archiveUtils.inline.hpp +++ b/src/hotspot/share/cds/archiveUtils.inline.hpp @@ -78,7 +78,7 @@ Array* ArchiveUtils::archive_ptr_array(GrowableArray* tmp_array) { Array* archived_array = ArchiveBuilder::new_ro_array(tmp_array->length()); for (int i = 0; i < tmp_array->length(); i++) { T ptr = tmp_array->at(i); - if (!builder->is_in_buffer_space(ptr)) { + if (ptr != nullptr && !builder->is_in_buffer_space(ptr)) { if (is_dynamic_dump && MetaspaceShared::is_in_shared_metaspace(ptr)) { // We have a pointer that lives in the dynamic archive but points into // the static archive. diff --git a/src/hotspot/share/cds/finalImageRecipes.cpp b/src/hotspot/share/cds/finalImageRecipes.cpp index bdfd261355bf3..f0ce8ceb020bb 100644 --- a/src/hotspot/share/cds/finalImageRecipes.cpp +++ b/src/hotspot/share/cds/finalImageRecipes.cpp @@ -36,6 +36,7 @@ #include "memory/resourceArea.hpp" #include "oops/constantPool.inline.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/mutexLocker.hpp" static FinalImageRecipes* _final_image_recipes = nullptr; @@ -43,56 +44,126 @@ void* FinalImageRecipes::operator new(size_t size) throw() { return ArchiveBuilder::current()->ro_region_alloc(size); } -void FinalImageRecipes::record_recipes_impl() { - assert(CDSConfig::is_dumping_preimage_static_archive(), "must be"); +void FinalImageRecipes::record_all_classes() { + _all_klasses = ArchiveUtils::archive_array(ArchiveBuilder::current()->klasses()); + ArchivePtrMarker::mark_pointer(&_all_klasses); +} + +void FinalImageRecipes::record_recipes_for_constantpool() { ResourceMark rm; - GrowableArray* klasses = ArchiveBuilder::current()->klasses(); - // Record the indys that have been resolved in the training run. These indys will be - // resolved during the final image assembly. + // The recipes are recorded regardless of CDSConfig::is_dumping_{invokedynamic,dynamic_proxies,reflection_data}(). + // If some of these options are not enabled, the corresponding recipes will be + // ignored during the final image assembly. + + GrowableArray*> tmp_cp_recipes; + GrowableArray tmp_cp_flags; - GrowableArray tmp_indy_klasses; - GrowableArray*> tmp_indy_cp_indices; - int total_indys_to_resolve = 0; + GrowableArray* klasses = ArchiveBuilder::current()->klasses(); for (int i = 0; i < klasses->length(); i++) { + GrowableArray cp_indices; + int flags = 0; + Klass* k = klasses->at(i); if (k->is_instance_klass()) { InstanceKlass* ik = InstanceKlass::cast(k); - GrowableArray indices; + ConstantPool* cp = ik->constants(); + ConstantPoolCache* cp_cache = cp->cache(); + + for (int cp_index = 1; cp_index < cp->length(); cp_index++) { // Index 0 is unused + if (cp->tag_at(cp_index).value() == JVM_CONSTANT_Class) { + Klass* k = cp->resolved_klass_at(cp_index); + if (k->is_instance_klass()) { + cp_indices.append(cp_index); + flags |= HAS_CLASS; + } + } + } + + if (cp_cache != nullptr) { + Array* field_entries = cp_cache->resolved_field_entries(); + if (field_entries != nullptr) { + for (int i = 0; i < field_entries->length(); i++) { + ResolvedFieldEntry* rfe = field_entries->adr_at(i); + if (rfe->is_resolved(Bytecodes::_getfield) || + rfe->is_resolved(Bytecodes::_putfield)) { + cp_indices.append(rfe->constant_pool_index()); + flags |= HAS_FIELD_AND_METHOD; + } + } + } - if (ik->constants()->cache() != nullptr) { - Array* tmp_indy_entries = ik->constants()->cache()->resolved_indy_entries(); - if (tmp_indy_entries != nullptr) { - for (int i = 0; i < tmp_indy_entries->length(); i++) { - ResolvedIndyEntry* rie = tmp_indy_entries->adr_at(i); + Array* method_entries = cp_cache->resolved_method_entries(); + if (method_entries != nullptr) { + for (int i = 0; i < method_entries->length(); i++) { + ResolvedMethodEntry* rme = method_entries->adr_at(i); + if (rme->is_resolved(Bytecodes::_invokevirtual) || + rme->is_resolved(Bytecodes::_invokespecial) || + rme->is_resolved(Bytecodes::_invokeinterface) || + rme->is_resolved(Bytecodes::_invokestatic) || + rme->is_resolved(Bytecodes::_invokehandle)) { + cp_indices.append(rme->constant_pool_index()); + flags |= HAS_FIELD_AND_METHOD; + } + } + } + + Array* indy_entries = cp_cache->resolved_indy_entries(); + if (indy_entries != nullptr) { + for (int i = 0; i < indy_entries->length(); i++) { + ResolvedIndyEntry* rie = indy_entries->adr_at(i); int cp_index = rie->constant_pool_index(); if (rie->is_resolved()) { - indices.append(cp_index); + cp_indices.append(cp_index); + flags |= HAS_INDY; } } } } + } - if (indices.length() > 0) { - tmp_indy_klasses.append(ArchiveBuilder::current()->get_buffered_addr(ik)); - tmp_indy_cp_indices.append(ArchiveUtils::archive_array(&indices)); - total_indys_to_resolve += indices.length(); - } + if (cp_indices.length() > 0) { + tmp_cp_recipes.append(ArchiveUtils::archive_array(&cp_indices)); + } else { + tmp_cp_recipes.append(nullptr); } + tmp_cp_flags.append(flags); } - _all_klasses = ArchiveUtils::archive_array(klasses); - ArchivePtrMarker::mark_pointer(&_all_klasses); + _cp_recipes = ArchiveUtils::archive_array(&tmp_cp_recipes); + ArchivePtrMarker::mark_pointer(&_cp_recipes); + + _cp_flags = ArchiveUtils::archive_array(&tmp_cp_flags); + ArchivePtrMarker::mark_pointer(&_cp_flags); +} - assert(tmp_indy_klasses.length() == tmp_indy_cp_indices.length(), "must be"); - if (tmp_indy_klasses.length() > 0) { - _indy_klasses = ArchiveUtils::archive_array(&tmp_indy_klasses); - _indy_cp_indices = ArchiveUtils::archive_array(&tmp_indy_cp_indices); +void FinalImageRecipes::apply_recipes_for_constantpool(JavaThread* current) { + assert(CDSConfig::is_dumping_final_static_archive(), "must be"); - ArchivePtrMarker::mark_pointer(&_indy_klasses); - ArchivePtrMarker::mark_pointer(&_indy_cp_indices); + for (int i = 0; i < _all_klasses->length(); i++) { + Array* cp_indices = _cp_recipes->at(i); + int flags = _cp_flags->at(i); + if (cp_indices != nullptr) { + InstanceKlass* ik = InstanceKlass::cast(_all_klasses->at(i)); + if (ik->is_loaded()) { + ResourceMark rm(current); + ConstantPool* cp = ik->constants(); + GrowableArray preresolve_list(cp->length(), cp->length(), false); + for (int j = 0; j < cp_indices->length(); j++) { + preresolve_list.at_put(cp_indices->at(j), true); + } + if ((flags & HAS_CLASS) != 0) { + AOTConstantPoolResolver::preresolve_class_cp_entries(current, ik, &preresolve_list); + } + if ((flags & HAS_FIELD_AND_METHOD) != 0) { + AOTConstantPoolResolver::preresolve_field_and_method_cp_entries(current, ik, &preresolve_list); + } + if ((flags & HAS_INDY) != 0) { + AOTConstantPoolResolver::preresolve_indy_cp_entries(current, ik, &preresolve_list); + } + } + } } - log_info(cds)("%d indies in %d classes will be resolved in final CDS image", total_indys_to_resolve, tmp_indy_klasses.length()); } void FinalImageRecipes::load_all_classes(TRAPS) { @@ -122,27 +193,11 @@ void FinalImageRecipes::load_all_classes(TRAPS) { } } -void FinalImageRecipes::apply_recipes_for_invokedynamic(TRAPS) { - assert(CDSConfig::is_dumping_final_static_archive(), "must be"); - - if (CDSConfig::is_dumping_invokedynamic() && _indy_klasses != nullptr) { - assert(_indy_cp_indices != nullptr, "must be"); - for (int i = 0; i < _indy_klasses->length(); i++) { - InstanceKlass* ik = _indy_klasses->at(i); - ConstantPool* cp = ik->constants(); - Array* cp_indices = _indy_cp_indices->at(i); - GrowableArray preresolve_list(cp->length(), cp->length(), false); - for (int j = 0; j < cp_indices->length(); j++) { - preresolve_list.at_put(cp_indices->at(j), true); - } - AOTConstantPoolResolver::preresolve_indy_cp_entries(THREAD, ik, &preresolve_list); - } - } -} - void FinalImageRecipes::record_recipes() { + assert(CDSConfig::is_dumping_preimage_static_archive(), "must be"); _final_image_recipes = new FinalImageRecipes(); - _final_image_recipes->record_recipes_impl(); + _final_image_recipes->record_all_classes(); + _final_image_recipes->record_recipes_for_constantpool(); } void FinalImageRecipes::apply_recipes(TRAPS) { @@ -163,7 +218,7 @@ void FinalImageRecipes::apply_recipes(TRAPS) { void FinalImageRecipes::apply_recipes_impl(TRAPS) { load_all_classes(CHECK); - apply_recipes_for_invokedynamic(CHECK); + apply_recipes_for_constantpool(THREAD); } void FinalImageRecipes::serialize(SerializeClosure* soc) { diff --git a/src/hotspot/share/cds/finalImageRecipes.hpp b/src/hotspot/share/cds/finalImageRecipes.hpp index f07d9787af970..3af1e70772c6b 100644 --- a/src/hotspot/share/cds/finalImageRecipes.hpp +++ b/src/hotspot/share/cds/finalImageRecipes.hpp @@ -42,26 +42,31 @@ template class Array; // - The list of all classes that are stored in the AOTConfiguration file. // - The list of all classes that require AOT resolution of invokedynamic call sites. class FinalImageRecipes { + static constexpr int HAS_CLASS = 0x1; + static constexpr int HAS_FIELD_AND_METHOD = 0x2; + static constexpr int HAS_INDY = 0x4; + // A list of all the archived classes from the preimage. We want to transfer all of these // into the final image. Array* _all_klasses; - // The classes who have resolved at least one indy CP entry during the training run. - // _indy_cp_indices[i] is a list of all resolved CP entries for _indy_klasses[i]. - Array* _indy_klasses; - Array*>* _indy_cp_indices; + // For each klass k _all_klasses->at(i), _cp_recipes->at(i) lists all the {klass,field,method,indy} + // cp indices that were resolved for k during the training run. + Array*>* _cp_recipes; + Array* _cp_flags; - FinalImageRecipes() : _indy_klasses(nullptr), _indy_cp_indices(nullptr) {} + FinalImageRecipes() : _all_klasses(nullptr), _cp_recipes(nullptr), _cp_flags(nullptr) {} void* operator new(size_t size) throw(); // Called when dumping preimage - void record_recipes_impl(); + void record_all_classes(); + void record_recipes_for_constantpool(); // Called when dumping final image void apply_recipes_impl(TRAPS); void load_all_classes(TRAPS); - void apply_recipes_for_invokedynamic(TRAPS); + void apply_recipes_for_constantpool(JavaThread* current); public: static void serialize(SerializeClosure* soc); diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 3db53d038b669..faed0d5f95299 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -147,6 +147,7 @@ Mutex* ClassListFile_lock = nullptr; Mutex* UnregisteredClassesTable_lock= nullptr; Mutex* LambdaFormInvokers_lock = nullptr; Mutex* ScratchObjects_lock = nullptr; +Mutex* FinalImageRecipes_lock = nullptr; #endif // INCLUDE_CDS Mutex* Bootclasspath_lock = nullptr; @@ -299,6 +300,7 @@ void mutex_init() { MUTEX_DEFN(UnregisteredClassesTable_lock , PaddedMutex , nosafepoint-1); MUTEX_DEFN(LambdaFormInvokers_lock , PaddedMutex , safepoint); MUTEX_DEFN(ScratchObjects_lock , PaddedMutex , nosafepoint-1); // Holds DumpTimeTable_lock + MUTEX_DEFN(FinalImageRecipes_lock , PaddedMutex , nosafepoint); #endif // INCLUDE_CDS MUTEX_DEFN(Bootclasspath_lock , PaddedMutex , nosafepoint); diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index bd2073dfe882b..3bd01b575c4ea 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -129,6 +129,7 @@ extern Mutex* ClassListFile_lock; // ClassListWriter() extern Mutex* UnregisteredClassesTable_lock; // UnregisteredClassesTableTable extern Mutex* LambdaFormInvokers_lock; // Protecting LambdaFormInvokers::_lambdaform_lines extern Mutex* ScratchObjects_lock; // Protecting _scratch_xxx_table in heapShared.cpp +extern Mutex* FinalImageRecipes_lock; // Protecting the tables used by FinalImageRecipes. #endif // INCLUDE_CDS #if INCLUDE_JFR extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table From 055b750d999e52569094bffa7dc0364a50771853 Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Thu, 17 Apr 2025 06:08:36 +0000 Subject: [PATCH 0625/1101] 8354543: Set more meaningful names for "get_vm_result" and "get_vm_result_2" Reviewed-by: shade, coleenp --- .../cpu/aarch64/c1_Runtime1_aarch64.cpp | 12 +++--- .../cpu/aarch64/macroAssembler_aarch64.cpp | 14 +++---- .../cpu/aarch64/macroAssembler_aarch64.hpp | 4 +- .../cpu/aarch64/sharedRuntime_aarch64.cpp | 4 +- .../templateInterpreterGenerator_aarch64.cpp | 4 +- .../cpu/aarch64/templateTable_aarch64.cpp | 8 ++-- src/hotspot/cpu/arm/c1_Runtime1_arm.cpp | 4 +- src/hotspot/cpu/arm/macroAssembler_arm.cpp | 14 +++---- src/hotspot/cpu/arm/macroAssembler_arm.hpp | 4 +- src/hotspot/cpu/arm/sharedRuntime_arm.cpp | 4 +- .../arm/templateInterpreterGenerator_arm.cpp | 4 +- src/hotspot/cpu/arm/templateTable_arm.cpp | 8 ++-- src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp | 8 ++-- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 22 +++++------ src/hotspot/cpu/ppc/macroAssembler_ppc.hpp | 4 +- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 4 +- .../ppc/templateInterpreterGenerator_ppc.cpp | 4 +- src/hotspot/cpu/ppc/templateTable_ppc_64.cpp | 6 +-- src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp | 12 +++--- .../cpu/riscv/macroAssembler_riscv.cpp | 14 +++---- .../cpu/riscv/macroAssembler_riscv.hpp | 4 +- src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp | 4 +- .../templateInterpreterGenerator_riscv.cpp | 4 +- src/hotspot/cpu/riscv/templateTable_riscv.cpp | 8 ++-- src/hotspot/cpu/s390/c1_Runtime1_s390.cpp | 12 +++--- src/hotspot/cpu/s390/macroAssembler_s390.cpp | 16 ++++---- src/hotspot/cpu/s390/macroAssembler_s390.hpp | 4 +- src/hotspot/cpu/s390/sharedRuntime_s390.cpp | 4 +- .../templateInterpreterGenerator_s390.cpp | 2 +- src/hotspot/cpu/s390/templateTable_s390.cpp | 6 +-- src/hotspot/cpu/x86/c1_Runtime1_x86.cpp | 12 +++--- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 14 +++---- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 4 +- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 4 +- .../x86/templateInterpreterGenerator_x86.cpp | 4 +- src/hotspot/cpu/x86/templateTable_x86.cpp | 8 ++-- src/hotspot/share/c1/c1_Runtime1.cpp | 10 ++--- .../share/interpreter/interpreterRuntime.cpp | 38 +++++++++---------- .../interpreter/zero/bytecodeInterpreter.cpp | 34 ++++++++--------- .../leakprofiler/checkpoint/rootResolver.cpp | 2 +- src/hotspot/share/jvmci/jvmciRuntime.cpp | 20 +++++----- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 2 +- src/hotspot/share/opto/generateOptoStub.cpp | 2 +- src/hotspot/share/opto/runtime.cpp | 20 +++++----- src/hotspot/share/runtime/javaCalls.cpp | 6 +-- src/hotspot/share/runtime/javaThread.cpp | 6 +-- src/hotspot/share/runtime/javaThread.hpp | 14 +++---- src/hotspot/share/runtime/sharedRuntime.cpp | 14 +++---- src/hotspot/share/runtime/vmStructs.cpp | 4 +- 49 files changed, 215 insertions(+), 225 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp index 063918ee20b7b..a6aab24349a1f 100644 --- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp @@ -91,10 +91,10 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre // exception pending => remove activation and forward to exception handler // make sure that the vm_results are cleared if (oop_result1->is_valid()) { - str(zr, Address(rthread, JavaThread::vm_result_offset())); + str(zr, Address(rthread, JavaThread::vm_result_oop_offset())); } if (metadata_result->is_valid()) { - str(zr, Address(rthread, JavaThread::vm_result_2_offset())); + str(zr, Address(rthread, JavaThread::vm_result_metadata_offset())); } if (frame_size() == no_frame_size) { leave(); @@ -108,10 +108,10 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre } // get oop results if there are any and reset the values in the thread if (oop_result1->is_valid()) { - get_vm_result(oop_result1, rthread); + get_vm_result_oop(oop_result1, rthread); } if (metadata_result->is_valid()) { - get_vm_result_2(metadata_result, rthread); + get_vm_result_metadata(metadata_result, rthread); } return call_offset; } @@ -406,8 +406,8 @@ OopMapSet* Runtime1::generate_handle_exception(C1StubId id, StubAssembler *sasm) __ authenticate_return_address(exception_pc); // make sure that the vm_results are cleared (may be unnecessary) - __ str(zr, Address(rthread, JavaThread::vm_result_offset())); - __ str(zr, Address(rthread, JavaThread::vm_result_2_offset())); + __ str(zr, Address(rthread, JavaThread::vm_result_oop_offset())); + __ str(zr, Address(rthread, JavaThread::vm_result_metadata_offset())); break; case C1StubId::handle_exception_nofpu_id: case C1StubId::handle_exception_id: diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index b6472b1b94812..1e226c70420de 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -849,7 +849,7 @@ void MacroAssembler::call_VM_base(Register oop_result, // get oop result if there is one and reset the value in the thread if (oop_result->is_valid()) { - get_vm_result(oop_result, java_thread); + get_vm_result_oop(oop_result, java_thread); } } @@ -1145,15 +1145,15 @@ void MacroAssembler::call_VM(Register oop_result, } -void MacroAssembler::get_vm_result(Register oop_result, Register java_thread) { - ldr(oop_result, Address(java_thread, JavaThread::vm_result_offset())); - str(zr, Address(java_thread, JavaThread::vm_result_offset())); +void MacroAssembler::get_vm_result_oop(Register oop_result, Register java_thread) { + ldr(oop_result, Address(java_thread, JavaThread::vm_result_oop_offset())); + str(zr, Address(java_thread, JavaThread::vm_result_oop_offset())); verify_oop_msg(oop_result, "broken oop in call_VM_base"); } -void MacroAssembler::get_vm_result_2(Register metadata_result, Register java_thread) { - ldr(metadata_result, Address(java_thread, JavaThread::vm_result_2_offset())); - str(zr, Address(java_thread, JavaThread::vm_result_2_offset())); +void MacroAssembler::get_vm_result_metadata(Register metadata_result, Register java_thread) { + ldr(metadata_result, Address(java_thread, JavaThread::vm_result_metadata_offset())); + str(zr, Address(java_thread, JavaThread::vm_result_metadata_offset())); } void MacroAssembler::align(int modulus) { diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index bd537af59e471..11d1985e50bf4 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -823,8 +823,8 @@ class MacroAssembler: public Assembler { Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true); - void get_vm_result (Register oop_result, Register thread); - void get_vm_result_2(Register metadata_result, Register thread); + void get_vm_result_oop(Register oop_result, Register thread); + void get_vm_result_metadata(Register metadata_result, Register thread); // These always tightly bind to MacroAssembler::call_VM_base // bypassing the virtual implementation diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index b0b299876018a..967984b882166 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -2783,7 +2783,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti __ cbnz(rscratch1, pending); // get the returned Method* - __ get_vm_result_2(rmethod, rthread); + __ get_vm_result_metadata(rmethod, rthread); __ str(rmethod, Address(sp, reg_save.reg_offset_in_bytes(rmethod))); // r0 is where we want to jump, overwrite rscratch1 which is saved and scratch @@ -2802,7 +2802,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti // exception pending => remove activation and forward to exception handler - __ str(zr, Address(rthread, JavaThread::vm_result_offset())); + __ str(zr, Address(rthread, JavaThread::vm_result_oop_offset())); __ ldr(r0, Address(rthread, Thread::pending_exception_offset())); __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index 80c9437de6b7a..2db3b435abbc9 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -1978,11 +1978,11 @@ void TemplateInterpreterGenerator::generate_throw_exception() { // preserve exception over this code sequence __ pop_ptr(r0); - __ str(r0, Address(rthread, JavaThread::vm_result_offset())); + __ str(r0, Address(rthread, JavaThread::vm_result_oop_offset())); // remove the activation (without doing throws on illegalMonitorExceptions) __ remove_activation(vtos, false, true, false); // restore exception - __ get_vm_result(r0, rthread); + __ get_vm_result_oop(r0, rthread); // In between activations - previous activation type unknown yet // compute continuation point - the continuation point expects the diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp index e50810486c80d..2cc9b39983ac1 100644 --- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp @@ -484,7 +484,7 @@ void TemplateTable::condy_helper(Label& Done) __ mov(rarg, (int) bytecode()); __ call_VM(obj, entry, rarg); - __ get_vm_result_2(flags, rthread); + __ get_vm_result_metadata(flags, rthread); // VMr = obj = base address to find primitive value to push // VMr2 = flags = (tos, off) using format of CPCE::_flags @@ -3723,8 +3723,7 @@ void TemplateTable::checkcast() __ push(atos); // save receiver for result, and for GC call_VM(r0, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); - // vm_result_2 has metadata result - __ get_vm_result_2(r0, rthread); + __ get_vm_result_metadata(r0, rthread); __ pop(r3); // restore receiver __ b(resolved); @@ -3777,8 +3776,7 @@ void TemplateTable::instanceof() { __ push(atos); // save receiver for result, and for GC call_VM(r0, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); - // vm_result_2 has metadata result - __ get_vm_result_2(r0, rthread); + __ get_vm_result_metadata(r0, rthread); __ pop(r3); // restore receiver __ verify_oop(r3); __ load_klass(r3, r3); diff --git a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp index 949e985ab1eea..021b47148fa8c 100644 --- a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp +++ b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp @@ -70,11 +70,11 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre if (oop_result1->is_valid()) { assert_different_registers(oop_result1, R3, Rtemp); - get_vm_result(oop_result1, Rtemp); + get_vm_result_oop(oop_result1, Rtemp); } if (metadata_result->is_valid()) { assert_different_registers(metadata_result, R3, Rtemp); - get_vm_result_2(metadata_result, Rtemp); + get_vm_result_metadata(metadata_result, Rtemp); } // Check for pending exception diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.cpp b/src/hotspot/cpu/arm/macroAssembler_arm.cpp index 638b3a5404c25..3dcde7d898d08 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp @@ -424,7 +424,7 @@ void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, in // get oop result if there is one and reset the value in the thread if (oop_result->is_valid()) { - get_vm_result(oop_result, tmp); + get_vm_result_oop(oop_result, tmp); } } @@ -528,17 +528,17 @@ void MacroAssembler::call_VM_leaf(address entry_point, Register arg_1, Register call_VM_leaf_helper(entry_point, 4); } -void MacroAssembler::get_vm_result(Register oop_result, Register tmp) { +void MacroAssembler::get_vm_result_oop(Register oop_result, Register tmp) { assert_different_registers(oop_result, tmp); - ldr(oop_result, Address(Rthread, JavaThread::vm_result_offset())); - str(zero_register(tmp), Address(Rthread, JavaThread::vm_result_offset())); + ldr(oop_result, Address(Rthread, JavaThread::vm_result_oop_offset())); + str(zero_register(tmp), Address(Rthread, JavaThread::vm_result_oop_offset())); verify_oop(oop_result); } -void MacroAssembler::get_vm_result_2(Register metadata_result, Register tmp) { +void MacroAssembler::get_vm_result_metadata(Register metadata_result, Register tmp) { assert_different_registers(metadata_result, tmp); - ldr(metadata_result, Address(Rthread, JavaThread::vm_result_2_offset())); - str(zero_register(tmp), Address(Rthread, JavaThread::vm_result_2_offset())); + ldr(metadata_result, Address(Rthread, JavaThread::vm_result_metadata_offset())); + str(zero_register(tmp), Address(Rthread, JavaThread::vm_result_metadata_offset())); } void MacroAssembler::add_rc(Register dst, Register arg1, RegisterOrConstant arg2) { diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.hpp b/src/hotspot/cpu/arm/macroAssembler_arm.hpp index 621f0101432e7..d60b38e42dbea 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.hpp @@ -257,8 +257,8 @@ class MacroAssembler: public Assembler { void call_VM_leaf(address entry_point, Register arg_1, Register arg_2, Register arg_3); void call_VM_leaf(address entry_point, Register arg_1, Register arg_2, Register arg_3, Register arg_4); - void get_vm_result(Register oop_result, Register tmp); - void get_vm_result_2(Register metadata_result, Register tmp); + void get_vm_result_oop(Register oop_result, Register tmp); + void get_vm_result_metadata(Register metadata_result, Register tmp); // Always sets/resets sp, which default to SP if (last_sp == noreg) // Optionally sets/resets fp (use noreg to avoid setting it) diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index c63d72920a5b6..6dde82daaf975 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -1717,7 +1717,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti // Overwrite saved register values // Place metadata result of VM call into Rmethod - __ get_vm_result_2(R1, Rtemp); + __ get_vm_result_metadata(R1, Rtemp); __ str(R1, Address(SP, RegisterSaver::Rmethod_offset * wordSize)); // Place target address (VM call result) into Rtemp @@ -1730,7 +1730,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti RegisterSaver::restore_live_registers(masm); const Register Rzero = __ zero_register(Rtemp); - __ str(Rzero, Address(Rthread, JavaThread::vm_result_2_offset())); + __ str(Rzero, Address(Rthread, JavaThread::vm_result_metadata_offset())); __ mov(Rexception_pc, LR); __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp); diff --git a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp index da226c09f3cd6..30d88a4db91fd 100644 --- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp @@ -1467,11 +1467,11 @@ void TemplateInterpreterGenerator::generate_throw_exception() { // preserve exception over this code sequence __ pop_ptr(R0_tos); - __ str(R0_tos, Address(Rthread, JavaThread::vm_result_offset())); + __ str(R0_tos, Address(Rthread, JavaThread::vm_result_oop_offset())); // remove the activation (without doing throws on illegalMonitorExceptions) __ remove_activation(vtos, Rexception_pc, false, true, false); // restore exception - __ get_vm_result(Rexception_obj, Rtemp); + __ get_vm_result_oop(Rexception_obj, Rtemp); // In between activations - previous activation type unknown yet // compute continuation point - the continuation point expects diff --git a/src/hotspot/cpu/arm/templateTable_arm.cpp b/src/hotspot/cpu/arm/templateTable_arm.cpp index bbe5713090af5..50e3761dcb917 100644 --- a/src/hotspot/cpu/arm/templateTable_arm.cpp +++ b/src/hotspot/cpu/arm/templateTable_arm.cpp @@ -538,7 +538,7 @@ void TemplateTable::condy_helper(Label& Done) __ mov(rtmp, (int) bytecode()); __ call_VM(obj, CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc), rtmp); - __ get_vm_result_2(flags, rtmp); + __ get_vm_result_metadata(flags, rtmp); // VMr = obj = base address to find primitive value to push // VMr2 = flags = (tos, off) using format of CPCE::_flags @@ -4143,8 +4143,7 @@ void TemplateTable::checkcast() { __ push(atos); call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); - // vm_result_2 has metadata result - __ get_vm_result_2(Rsuper, Robj); + __ get_vm_result_metadata(Rsuper, Robj); __ pop_ptr(Robj); __ b(resolved); @@ -4214,8 +4213,7 @@ void TemplateTable::instanceof() { __ push(atos); call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); - // vm_result_2 has metadata result - __ get_vm_result_2(Rsuper, Robj); + __ get_vm_result_metadata(Rsuper, Robj); __ pop_ptr(Robj); __ b(resolved); diff --git a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp index 11c01dcdc60e6..79b129c08ae22 100644 --- a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp @@ -82,10 +82,10 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, if (oop_result1->is_valid() || metadata_result->is_valid()) { li(R0, 0); if (oop_result1->is_valid()) { - std(R0, in_bytes(JavaThread::vm_result_offset()), R16_thread); + std(R0, in_bytes(JavaThread::vm_result_oop_offset()), R16_thread); } if (metadata_result->is_valid()) { - std(R0, in_bytes(JavaThread::vm_result_2_offset()), R16_thread); + std(R0, in_bytes(JavaThread::vm_result_metadata_offset()), R16_thread); } } @@ -112,10 +112,10 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, // Get oop results if there are any and reset the values in the thread. if (oop_result1->is_valid()) { - get_vm_result(oop_result1); + get_vm_result_oop(oop_result1); } if (metadata_result->is_valid()) { - get_vm_result_2(metadata_result); + get_vm_result_metadata(metadata_result); } return (int)(return_pc - code_section()->start()); diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 40019ef9f4bb3..f82395b14fb35 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -1337,7 +1337,7 @@ void MacroAssembler::call_VM_base(Register oop_result, // Get oop result if there is one and reset the value in the thread. if (oop_result->is_valid()) { - get_vm_result(oop_result); + get_vm_result_oop(oop_result); } _last_calls_return_pc = return_pc; @@ -3425,34 +3425,34 @@ void MacroAssembler::set_top_ijava_frame_at_SP_as_last_Java_frame(Register sp, R set_last_Java_frame(/*sp=*/sp, /*pc=*/tmp1); } -void MacroAssembler::get_vm_result(Register oop_result) { +void MacroAssembler::get_vm_result_oop(Register oop_result) { // Read: // R16_thread - // R16_thread->in_bytes(JavaThread::vm_result_offset()) + // R16_thread->in_bytes(JavaThread::vm_result_oop_offset()) // // Updated: // oop_result - // R16_thread->in_bytes(JavaThread::vm_result_offset()) + // R16_thread->in_bytes(JavaThread::vm_result_oop_offset()) - ld(oop_result, in_bytes(JavaThread::vm_result_offset()), R16_thread); + ld(oop_result, in_bytes(JavaThread::vm_result_oop_offset()), R16_thread); li(R0, 0); - std(R0, in_bytes(JavaThread::vm_result_offset()), R16_thread); + std(R0, in_bytes(JavaThread::vm_result_oop_offset()), R16_thread); verify_oop(oop_result, FILE_AND_LINE); } -void MacroAssembler::get_vm_result_2(Register metadata_result) { +void MacroAssembler::get_vm_result_metadata(Register metadata_result) { // Read: // R16_thread - // R16_thread->in_bytes(JavaThread::vm_result_2_offset()) + // R16_thread->in_bytes(JavaThread::vm_result_metadata_offset()) // // Updated: // metadata_result - // R16_thread->in_bytes(JavaThread::vm_result_2_offset()) + // R16_thread->in_bytes(JavaThread::vm_result_metadata_offset()) - ld(metadata_result, in_bytes(JavaThread::vm_result_2_offset()), R16_thread); + ld(metadata_result, in_bytes(JavaThread::vm_result_metadata_offset()), R16_thread); li(R0, 0); - std(R0, in_bytes(JavaThread::vm_result_2_offset()), R16_thread); + std(R0, in_bytes(JavaThread::vm_result_metadata_offset()), R16_thread); } Register MacroAssembler::encode_klass_not_null(Register dst, Register src) { diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index b709cf16713b0..7e2925ace26c8 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -745,8 +745,8 @@ class MacroAssembler: public Assembler { void set_top_ijava_frame_at_SP_as_last_Java_frame(Register sp, Register tmp1, Label* jpc = nullptr); // Read vm result from thread: oop_result = R16_thread->result; - void get_vm_result (Register oop_result); - void get_vm_result_2(Register metadata_result); + void get_vm_result_oop(Register oop_result); + void get_vm_result_metadata(Register metadata_result); static bool needs_explicit_null_check(intptr_t offset); static bool uses_implicit_null_check(void* address); diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 0d0e004c92383..5a94d46943425 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -3404,7 +3404,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti RegisterSaver::restore_live_registers_and_pop_frame(masm, frame_size_in_bytes, /*restore_ctr*/ false); // Get the returned method. - __ get_vm_result_2(R19_method); + __ get_vm_result_metadata(R19_method); __ bctr(); @@ -3418,7 +3418,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti __ li(R11_scratch1, 0); __ ld(R3_ARG1, thread_(pending_exception)); - __ std(R11_scratch1, in_bytes(JavaThread::vm_result_offset()), R16_thread); + __ std(R11_scratch1, in_bytes(JavaThread::vm_result_oop_offset()), R16_thread); __ b64_patchable(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type); // ------------- diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index b1ad3cd48bcc6..a8f5dbda484d6 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -2160,12 +2160,12 @@ void TemplateInterpreterGenerator::generate_throw_exception() { { __ pop_ptr(Rexception); __ verify_oop(Rexception); - __ std(Rexception, in_bytes(JavaThread::vm_result_offset()), R16_thread); + __ std(Rexception, in_bytes(JavaThread::vm_result_oop_offset()), R16_thread); __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false, true); __ notify_method_exit(false, vtos, InterpreterMacroAssembler::SkipNotifyJVMTI, false); - __ get_vm_result(Rexception); + __ get_vm_result_oop(Rexception); // We are done with this activation frame; find out where to go next. // The continuation point will be an exception handler, which expects diff --git a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp index 934bb1bd52918..8be6080e3d1c0 100644 --- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp @@ -386,7 +386,7 @@ void TemplateTable::condy_helper(Label& Done) { const Register rarg = R4_ARG2; __ li(rarg, (int)bytecode()); call_VM(obj, CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc), rarg); - __ get_vm_result_2(flags); + __ get_vm_result_metadata(flags); // VMr = obj = base address to find primitive value to push // VMr2 = flags = (tos, off) using format of CPCE::_flags @@ -3964,7 +3964,7 @@ void TemplateTable::checkcast() { // Call into the VM to "quicken" instanceof. __ push_ptr(); // for GC call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); - __ get_vm_result_2(RspecifiedKlass); + __ get_vm_result_metadata(RspecifiedKlass); __ pop_ptr(); // Restore receiver. __ b(Lresolved); @@ -4026,7 +4026,7 @@ void TemplateTable::instanceof() { // Call into the VM to "quicken" instanceof. __ push_ptr(); // for GC call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); - __ get_vm_result_2(RspecifiedKlass); + __ get_vm_result_metadata(RspecifiedKlass); __ pop_ptr(); // Restore receiver. __ b(Lresolved); diff --git a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp index 0f1f1dd891c51..849417725a70d 100644 --- a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp @@ -89,10 +89,10 @@ int StubAssembler::call_RT(Register oop_result, Register metadata_result, addres // exception pending => remove activation and forward to exception handler // make sure that the vm_results are cleared if (oop_result->is_valid()) { - sd(zr, Address(xthread, JavaThread::vm_result_offset())); + sd(zr, Address(xthread, JavaThread::vm_result_oop_offset())); } if (metadata_result->is_valid()) { - sd(zr, Address(xthread, JavaThread::vm_result_2_offset())); + sd(zr, Address(xthread, JavaThread::vm_result_metadata_offset())); } if (frame_size() == no_frame_size) { leave(); @@ -106,10 +106,10 @@ int StubAssembler::call_RT(Register oop_result, Register metadata_result, addres } // get oop results if there are any and reset the values in the thread if (oop_result->is_valid()) { - get_vm_result(oop_result, xthread); + get_vm_result_oop(oop_result, xthread); } if (metadata_result->is_valid()) { - get_vm_result_2(metadata_result, xthread); + get_vm_result_metadata(metadata_result, xthread); } return call_offset; } @@ -427,8 +427,8 @@ OopMapSet* Runtime1::generate_handle_exception(C1StubId id, StubAssembler *sasm) __ ld(exception_pc, Address(fp, frame::return_addr_offset * BytesPerWord)); // make sure that the vm_results are cleared (may be unnecessary) - __ sd(zr, Address(xthread, JavaThread::vm_result_offset())); - __ sd(zr, Address(xthread, JavaThread::vm_result_2_offset())); + __ sd(zr, Address(xthread, JavaThread::vm_result_oop_offset())); + __ sd(zr, Address(xthread, JavaThread::vm_result_metadata_offset())); break; case C1StubId::handle_exception_nofpu_id: case C1StubId::handle_exception_id: diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 71481565fc73d..b5c311c341db4 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -498,19 +498,19 @@ void MacroAssembler::call_VM_base(Register oop_result, // get oop result if there is one and reset the value in the thread if (oop_result->is_valid()) { - get_vm_result(oop_result, java_thread); + get_vm_result_oop(oop_result, java_thread); } } -void MacroAssembler::get_vm_result(Register oop_result, Register java_thread) { - ld(oop_result, Address(java_thread, JavaThread::vm_result_offset())); - sd(zr, Address(java_thread, JavaThread::vm_result_offset())); +void MacroAssembler::get_vm_result_oop(Register oop_result, Register java_thread) { + ld(oop_result, Address(java_thread, JavaThread::vm_result_oop_offset())); + sd(zr, Address(java_thread, JavaThread::vm_result_oop_offset())); verify_oop_msg(oop_result, "broken oop in call_VM_base"); } -void MacroAssembler::get_vm_result_2(Register metadata_result, Register java_thread) { - ld(metadata_result, Address(java_thread, JavaThread::vm_result_2_offset())); - sd(zr, Address(java_thread, JavaThread::vm_result_2_offset())); +void MacroAssembler::get_vm_result_metadata(Register metadata_result, Register java_thread) { + ld(metadata_result, Address(java_thread, JavaThread::vm_result_metadata_offset())); + sd(zr, Address(java_thread, JavaThread::vm_result_metadata_offset())); } void MacroAssembler::clinit_barrier(Register klass, Register tmp, Label* L_fast_path, Label* L_slow_path) { diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index e145639bbe731..b390fb236c273 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -122,8 +122,8 @@ class MacroAssembler: public Assembler { Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true); - void get_vm_result(Register oop_result, Register java_thread); - void get_vm_result_2(Register metadata_result, Register java_thread); + void get_vm_result_oop(Register oop_result, Register java_thread); + void get_vm_result_metadata(Register metadata_result, Register java_thread); // These always tightly bind to MacroAssembler::call_VM_leaf_base // bypassing the virtual implementation diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index 49e630bbfdf91..1079084149042 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -2646,7 +2646,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti __ bnez(t1, pending); // get the returned Method* - __ get_vm_result_2(xmethod, xthread); + __ get_vm_result_metadata(xmethod, xthread); __ sd(xmethod, Address(sp, reg_saver.reg_offset_in_bytes(xmethod))); // x10 is where we want to jump, overwrite t1 which is saved and temporary @@ -2664,7 +2664,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti // exception pending => remove activation and forward to exception handler - __ sd(zr, Address(xthread, JavaThread::vm_result_offset())); + __ sd(zr, Address(xthread, JavaThread::vm_result_oop_offset())); __ ld(x10, Address(xthread, Thread::pending_exception_offset())); __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index e96bd2e1f2a73..72e1180164b77 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -1725,11 +1725,11 @@ void TemplateInterpreterGenerator::generate_throw_exception() { // preserve exception over this code sequence __ pop_ptr(x10); - __ sd(x10, Address(xthread, JavaThread::vm_result_offset())); + __ sd(x10, Address(xthread, JavaThread::vm_result_oop_offset())); // remove the activation (without doing throws on illegalMonitorExceptions) __ remove_activation(vtos, false, true, false); // restore exception - __ get_vm_result(x10, xthread); + __ get_vm_result_oop(x10, xthread); // In between activations - previous activation type unknown yet // compute continuation point - the continuation point expects the diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index 216cfdeed7930..a035326be0130 100644 --- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp @@ -460,7 +460,7 @@ void TemplateTable::condy_helper(Label& Done) { __ mv(rarg, (int) bytecode()); __ call_VM(obj, entry, rarg); - __ get_vm_result_2(flags, xthread); + __ get_vm_result_metadata(flags, xthread); // VMr = obj = base address to find primitive value to push // VMr2 = flags = (tos, off) using format of CPCE::_flags @@ -3657,8 +3657,7 @@ void TemplateTable::checkcast() { __ push(atos); // save receiver for result, and for GC call_VM(x10, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); - // vm_result_2 has metadata result - __ get_vm_result_2(x10, xthread); + __ get_vm_result_metadata(x10, xthread); __ pop_reg(x13); // restore receiver __ j(resolved); @@ -3712,8 +3711,7 @@ void TemplateTable::instanceof() { __ push(atos); // save receiver for result, and for GC call_VM(x10, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); - // vm_result_2 has metadata result - __ get_vm_result_2(x10, xthread); + __ get_vm_result_metadata(x10, xthread); __ pop_reg(x13); // restore receiver __ verify_oop(x13); __ load_klass(x13, x13); diff --git a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp index b5d804d283e4f..db04703ceb02e 100644 --- a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp +++ b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp @@ -86,10 +86,10 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre // Make sure that the vm_results are cleared. if (oop_result1->is_valid()) { - clear_mem(Address(Z_thread, JavaThread::vm_result_offset()), sizeof(jlong)); + clear_mem(Address(Z_thread, JavaThread::vm_result_oop_offset()), sizeof(jlong)); } if (metadata_result->is_valid()) { - clear_mem(Address(Z_thread, JavaThread::vm_result_2_offset()), sizeof(jlong)); + clear_mem(Address(Z_thread, JavaThread::vm_result_metadata_offset()), sizeof(jlong)); } if (frame_size() == no_frame_size) { // Pop the stub frame. @@ -109,10 +109,10 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre // Get oop results if there are any and reset the values in the thread. if (oop_result1->is_valid()) { - get_vm_result(oop_result1); + get_vm_result_oop(oop_result1); } if (metadata_result->is_valid()) { - get_vm_result_2(metadata_result); + get_vm_result_metadata(metadata_result); } return call_offset; @@ -886,8 +886,8 @@ OopMapSet* Runtime1::generate_handle_exception(C1StubId id, StubAssembler *sasm) DEBUG_ONLY(__ z_lay(reg_fp, Address(Z_SP, frame_size_in_bytes));) // Make sure that the vm_results are cleared (may be unnecessary). - __ clear_mem(Address(Z_thread, JavaThread::vm_result_offset()), sizeof(oop)); - __ clear_mem(Address(Z_thread, JavaThread::vm_result_2_offset()), sizeof(Metadata*)); + __ clear_mem(Address(Z_thread, JavaThread::vm_result_oop_offset()), sizeof(oop)); + __ clear_mem(Address(Z_thread, JavaThread::vm_result_metadata_offset()), sizeof(Metadata*)); break; } case C1StubId::handle_exception_nofpu_id: diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index 54370a4959b64..88aedd1b5c00f 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -2304,7 +2304,7 @@ void MacroAssembler::call_VM_base(Register oop_result, // Get oop result if there is one and reset the value in the thread. if (oop_result->is_valid()) { - get_vm_result(oop_result); + get_vm_result_oop(oop_result); } _last_calls_return_pc = return_pc; // Wipe out other (error handling) calls. @@ -4067,22 +4067,22 @@ void MacroAssembler::set_thread_state(JavaThreadState new_state) { store_const(Address(Z_thread, JavaThread::thread_state_offset()), new_state, Z_R0, false); } -void MacroAssembler::get_vm_result(Register oop_result) { - z_lg(oop_result, Address(Z_thread, JavaThread::vm_result_offset())); - clear_mem(Address(Z_thread, JavaThread::vm_result_offset()), sizeof(void*)); +void MacroAssembler::get_vm_result_oop(Register oop_result) { + z_lg(oop_result, Address(Z_thread, JavaThread::vm_result_oop_offset())); + clear_mem(Address(Z_thread, JavaThread::vm_result_oop_offset()), sizeof(void*)); verify_oop(oop_result, FILE_AND_LINE); } -void MacroAssembler::get_vm_result_2(Register result) { - z_lg(result, Address(Z_thread, JavaThread::vm_result_2_offset())); - clear_mem(Address(Z_thread, JavaThread::vm_result_2_offset()), sizeof(void*)); +void MacroAssembler::get_vm_result_metadata(Register result) { + z_lg(result, Address(Z_thread, JavaThread::vm_result_metadata_offset())); + clear_mem(Address(Z_thread, JavaThread::vm_result_metadata_offset()), sizeof(void*)); } // We require that C code which does not return a value in vm_result will // leave it undisturbed. void MacroAssembler::set_vm_result(Register oop_result) { - z_stg(oop_result, Address(Z_thread, JavaThread::vm_result_offset())); + z_stg(oop_result, Address(Z_thread, JavaThread::vm_result_oop_offset())); } // Explicit null checks (used for method handle code). diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp index 3f7744588d6ec..4aa7bb56f3ad4 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp @@ -816,8 +816,8 @@ class MacroAssembler: public Assembler { void set_thread_state(JavaThreadState new_state); // Read vm result from thread. - void get_vm_result (Register oop_result); - void get_vm_result_2(Register result); + void get_vm_result_oop (Register oop_result); + void get_vm_result_metadata(Register result); // Vm result is currently getting hijacked to for oop preservation. void set_vm_result(Register oop_result); diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 7b6735eabccc6..f4487ccabec14 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -3043,7 +3043,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti RegisterSaver::restore_live_registers(masm, RegisterSaver::all_registers); // get the returned method - __ get_vm_result_2(Z_method); + __ get_vm_result_metadata(Z_method); // We are back to the original state on entry and ready to go. __ z_br(Z_R1_scratch); @@ -3057,7 +3057,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti // exception pending => remove activation and forward to exception handler __ z_lgr(Z_R2, Z_R0); // pending_exception - __ clear_mem(Address(Z_thread, JavaThread::vm_result_offset()), sizeof(jlong)); + __ clear_mem(Address(Z_thread, JavaThread::vm_result_oop_offset()), sizeof(jlong)); __ load_const_optimized(Z_R1_scratch, StubRoutines::forward_exception_entry()); __ z_br(Z_R1_scratch); diff --git a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp index 841f4f9ca4bd2..a52d20e32a340 100644 --- a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp @@ -2228,7 +2228,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() { __ remove_activation(vtos, noreg/*ret.pc already loaded*/, false/*throw exc*/, true/*install exc*/, false/*notify jvmti*/); __ z_lg(Z_fp, _z_abi(callers_sp), Z_SP); // Restore frame pointer. - __ get_vm_result(Z_ARG1); // Restore exception. + __ get_vm_result_oop(Z_ARG1); // Restore exception. __ verify_oop(Z_ARG1); __ z_lgr(Z_ARG2, return_pc); // Restore return address. diff --git a/src/hotspot/cpu/s390/templateTable_s390.cpp b/src/hotspot/cpu/s390/templateTable_s390.cpp index e6c0c7781a3ba..4262c77ecd73c 100644 --- a/src/hotspot/cpu/s390/templateTable_s390.cpp +++ b/src/hotspot/cpu/s390/templateTable_s390.cpp @@ -540,7 +540,7 @@ void TemplateTable::condy_helper(Label& Done) { const Register rarg = Z_ARG2; __ load_const_optimized(rarg, (int)bytecode()); call_VM(obj, CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc), rarg); - __ get_vm_result_2(flags); + __ get_vm_result_metadata(flags); // VMr = obj = base address to find primitive value to push // VMr2 = flags = (tos, off) using format of CPCE::_flags @@ -4063,7 +4063,7 @@ void TemplateTable::checkcast() { __ push(atos); // Save receiver for result, and for GC. call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); - __ get_vm_result_2(Z_tos); + __ get_vm_result_metadata(Z_tos); Register receiver = Z_ARG4; Register klass = Z_tos; @@ -4135,7 +4135,7 @@ void TemplateTable::instanceof() { __ push(atos); // Save receiver for result, and for GC. call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); - __ get_vm_result_2(Z_tos); + __ get_vm_result_metadata(Z_tos); Register receiver = Z_tmp_2; Register klass = Z_tos; diff --git a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp index db6614686a2a1..726574e69e8e6 100644 --- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp +++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp @@ -103,10 +103,10 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre movptr(rax, Address(thread, Thread::pending_exception_offset())); // make sure that the vm_results are cleared if (oop_result1->is_valid()) { - movptr(Address(thread, JavaThread::vm_result_offset()), NULL_WORD); + movptr(Address(thread, JavaThread::vm_result_oop_offset()), NULL_WORD); } if (metadata_result->is_valid()) { - movptr(Address(thread, JavaThread::vm_result_2_offset()), NULL_WORD); + movptr(Address(thread, JavaThread::vm_result_metadata_offset()), NULL_WORD); } if (frame_size() == no_frame_size) { leave(); @@ -120,10 +120,10 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre } // get oop results if there are any and reset the values in the thread if (oop_result1->is_valid()) { - get_vm_result(oop_result1); + get_vm_result_oop(oop_result1); } if (metadata_result->is_valid()) { - get_vm_result_2(metadata_result); + get_vm_result_metadata(metadata_result); } assert(call_offset >= 0, "Should be set"); @@ -532,8 +532,8 @@ OopMapSet* Runtime1::generate_handle_exception(C1StubId id, StubAssembler *sasm) __ movptr(exception_pc, Address(rbp, 1*BytesPerWord)); // make sure that the vm_results are cleared (may be unnecessary) - __ movptr(Address(thread, JavaThread::vm_result_offset()), NULL_WORD); - __ movptr(Address(thread, JavaThread::vm_result_2_offset()), NULL_WORD); + __ movptr(Address(thread, JavaThread::vm_result_oop_offset()), NULL_WORD); + __ movptr(Address(thread, JavaThread::vm_result_metadata_offset()), NULL_WORD); break; case C1StubId::handle_exception_nofpu_id: case C1StubId::handle_exception_id: diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 6093ad6951921..25de76a7e4008 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -1226,7 +1226,7 @@ void MacroAssembler::call_VM_base(Register oop_result, // get oop result if there is one and reset the value in the thread if (oop_result->is_valid()) { - get_vm_result(oop_result); + get_vm_result_oop(oop_result); } } @@ -1316,15 +1316,15 @@ void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Reg MacroAssembler::call_VM_leaf_base(entry_point, 4); } -void MacroAssembler::get_vm_result(Register oop_result) { - movptr(oop_result, Address(r15_thread, JavaThread::vm_result_offset())); - movptr(Address(r15_thread, JavaThread::vm_result_offset()), NULL_WORD); +void MacroAssembler::get_vm_result_oop(Register oop_result) { + movptr(oop_result, Address(r15_thread, JavaThread::vm_result_oop_offset())); + movptr(Address(r15_thread, JavaThread::vm_result_oop_offset()), NULL_WORD); verify_oop_msg(oop_result, "broken oop in call_VM_base"); } -void MacroAssembler::get_vm_result_2(Register metadata_result) { - movptr(metadata_result, Address(r15_thread, JavaThread::vm_result_2_offset())); - movptr(Address(r15_thread, JavaThread::vm_result_2_offset()), NULL_WORD); +void MacroAssembler::get_vm_result_metadata(Register metadata_result) { + movptr(metadata_result, Address(r15_thread, JavaThread::vm_result_metadata_offset())); + movptr(Address(r15_thread, JavaThread::vm_result_metadata_offset()), NULL_WORD); } void MacroAssembler::check_and_handle_earlyret() { diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index bc25138f82151..efd1a4c154f1c 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -282,8 +282,8 @@ class MacroAssembler: public Assembler { Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true); - void get_vm_result (Register oop_result); - void get_vm_result_2(Register metadata_result); + void get_vm_result_oop(Register oop_result); + void get_vm_result_metadata(Register metadata_result); // These always tightly bind to MacroAssembler::call_VM_base // bypassing the virtual implementation diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 09c102aa5d16a..621340964ac4b 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -3233,7 +3233,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti __ jcc(Assembler::notEqual, pending); // get the returned Method* - __ get_vm_result_2(rbx); + __ get_vm_result_metadata(rbx); __ movptr(Address(rsp, RegisterSaver::rbx_offset_in_bytes()), rbx); __ movptr(Address(rsp, RegisterSaver::rax_offset_in_bytes()), rax); @@ -3252,7 +3252,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti // exception pending => remove activation and forward to exception handler - __ movptr(Address(r15_thread, JavaThread::vm_result_offset()), NULL_WORD); + __ movptr(Address(r15_thread, JavaThread::vm_result_oop_offset()), NULL_WORD); __ movptr(rax, Address(r15_thread, Thread::pending_exception_offset())); __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index bdc2ca908bd41..45e30a8b4fb52 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -1543,11 +1543,11 @@ void TemplateInterpreterGenerator::generate_throw_exception() { // preserve exception over this code sequence __ pop_ptr(rax); - __ movptr(Address(thread, JavaThread::vm_result_offset()), rax); + __ movptr(Address(thread, JavaThread::vm_result_oop_offset()), rax); // remove the activation (without doing throws on illegalMonitorExceptions) __ remove_activation(vtos, rdx, false, true, false); // restore exception - __ get_vm_result(rax); + __ get_vm_result_oop(rax); // In between activations - previous activation type unknown yet // compute continuation point - the continuation point expects the diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index 226b8b1c65597..43da80f408261 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -470,7 +470,7 @@ void TemplateTable::condy_helper(Label& Done) { const Register rarg = c_rarg1; __ movl(rarg, (int)bytecode()); call_VM(obj, CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc), rarg); - __ get_vm_result_2(flags); + __ get_vm_result_metadata(flags); // VMr = obj = base address to find primitive value to push // VMr2 = flags = (tos, off) using format of CPCE::_flags __ movl(off, flags); @@ -3680,8 +3680,7 @@ void TemplateTable::checkcast() { __ push(atos); // save receiver for result, and for GC call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); - // vm_result_2 has metadata result - __ get_vm_result_2(rax); + __ get_vm_result_metadata(rax); __ pop_ptr(rdx); // restore receiver __ jmpb(resolved); @@ -3737,8 +3736,7 @@ void TemplateTable::instanceof() { __ push(atos); // save receiver for result, and for GC call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); - // vm_result_2 has metadata result - __ get_vm_result_2(rax); + __ get_vm_result_metadata(rax); __ pop_ptr(rdx); // restore receiver __ verify_oop(rdx); diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index d7a9c8d56d430..9d4b35024ed05 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -370,7 +370,7 @@ JRT_ENTRY(void, Runtime1::new_instance(JavaThread* current, Klass* klass)) h->initialize(CHECK); // allocate instance and return via TLS oop obj = h->allocate_instance(CHECK); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); JRT_END @@ -386,7 +386,7 @@ JRT_ENTRY(void, Runtime1::new_type_array(JavaThread* current, Klass* klass, jint assert(klass->is_klass(), "not a class"); BasicType elt_type = TypeArrayKlass::cast(klass)->element_type(); oop obj = oopFactory::new_typeArray(elt_type, length, CHECK); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); // This is pretty rare but this runtime patch is stressful to deoptimization // if we deoptimize here so force a deopt to stress the path. if (DeoptimizeALot) { @@ -409,7 +409,7 @@ JRT_ENTRY(void, Runtime1::new_object_array(JavaThread* current, Klass* array_kla Handle holder(current, array_klass->klass_holder()); // keep the klass alive Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass(); objArrayOop obj = oopFactory::new_objArray(elem_klass, length, CHECK); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); // This is pretty rare but this runtime patch is stressful to deoptimization // if we deoptimize here so force a deopt to stress the path. if (DeoptimizeALot) { @@ -428,7 +428,7 @@ JRT_ENTRY(void, Runtime1::new_multi_array(JavaThread* current, Klass* klass, int assert(rank >= 1, "rank must be nonzero"); Handle holder(current, klass->klass_holder()); // keep the klass alive oop obj = ArrayKlass::cast(klass)->multi_allocate(rank, dims, CHECK); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); JRT_END @@ -642,7 +642,7 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c } } - current->set_vm_result(exception()); + current->set_vm_result_oop(exception()); // Set flag if return address is a method handle call site. current->set_is_method_handle_return(nm->is_method_handle_return(pc)); diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 52eab4f796e6b..0f16b17e99e00 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -150,7 +150,7 @@ JRT_ENTRY(void, InterpreterRuntime::ldc(JavaThread* current, bool wide)) assert (tag.is_unresolved_klass() || tag.is_klass(), "wrong ldc call"); Klass* klass = pool->klass_at(cp_index, CHECK); oop java_class = klass->java_mirror(); - current->set_vm_result(java_class); + current->set_vm_result_oop(java_class); JRT_END JRT_ENTRY(void, InterpreterRuntime::resolve_ldc(JavaThread* current, Bytecodes::Code bytecode)) { @@ -193,14 +193,14 @@ JRT_ENTRY(void, InterpreterRuntime::resolve_ldc(JavaThread* current, Bytecodes:: } } #endif - current->set_vm_result(result); + current->set_vm_result_oop(result); if (!is_fast_aldc) { // Tell the interpreter how to unbox the primitive. guarantee(java_lang_boxing_object::is_instance(result, type), ""); int offset = java_lang_boxing_object::value_offset(type); intptr_t flags = ((as_TosState(type) << ConstantPoolCache::tos_state_shift) | (offset & ConstantPoolCache::field_index_mask)); - current->set_vm_result_2((Metadata*)flags); + current->set_vm_result_metadata((Metadata*)flags); } } JRT_END @@ -220,20 +220,20 @@ JRT_ENTRY(void, InterpreterRuntime::_new(JavaThread* current, ConstantPool* pool klass->initialize(CHECK); oop obj = klass->allocate_instance(CHECK); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); JRT_END JRT_ENTRY(void, InterpreterRuntime::newarray(JavaThread* current, BasicType type, jint size)) oop obj = oopFactory::new_typeArray(type, size, CHECK); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); JRT_END JRT_ENTRY(void, InterpreterRuntime::anewarray(JavaThread* current, ConstantPool* pool, int index, jint size)) Klass* klass = pool->klass_at(index, CHECK); objArrayOop obj = oopFactory::new_objArray(klass, size, CHECK); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); JRT_END @@ -261,7 +261,7 @@ JRT_ENTRY(void, InterpreterRuntime::multianewarray(JavaThread* current, jint* fi dims[index] = first_size_address[n]; } oop obj = ArrayKlass::cast(klass)->multi_allocate(nof_dims, dims, CHECK); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); JRT_END @@ -283,7 +283,7 @@ JRT_ENTRY(void, InterpreterRuntime::quicken_io_cc(JavaThread* current)) // thread quicken the bytecode before we get here. // assert( cpool->tag_at(which).is_unresolved_klass(), "should only come here to quicken bytecodes" ); Klass* klass = cpool->klass_at(which, CHECK); - current->set_vm_result_2(klass); + current->set_vm_result_metadata(klass); JRT_END @@ -383,7 +383,7 @@ JRT_ENTRY(void, InterpreterRuntime::create_exception(JavaThread* current, char* } // create exception Handle exception = Exceptions::new_exception(current, s, message); - current->set_vm_result(exception()); + current->set_vm_result_oop(exception()); JRT_END @@ -402,7 +402,7 @@ JRT_ENTRY(void, InterpreterRuntime::create_klass_exception(JavaThread* current, } // create exception, with klass name as detail message Handle exception = Exceptions::new_exception(current, s, klass_name); - current->set_vm_result(exception()); + current->set_vm_result_oop(exception()); JRT_END JRT_ENTRY(void, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException(JavaThread* current, arrayOopDesc* a, jint index)) @@ -461,7 +461,7 @@ JRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea // Allocation of scalar replaced object used in this frame // failed. Unconditionally pop the frame. current->dec_frames_to_pop_failed_realloc(); - current->set_vm_result(h_exception()); + current->set_vm_result_oop(h_exception()); // If the method is synchronized we already unlocked the monitor // during deoptimization so the interpreter needs to skip it when // the frame is popped. @@ -476,7 +476,7 @@ JRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea if (current->do_not_unlock_if_synchronized()) { ResourceMark rm; assert(current_bci == 0, "bci isn't zero for do_not_unlock_if_synchronized"); - current->set_vm_result(exception); + current->set_vm_result_oop(exception); return Interpreter::remove_activation_entry(); } @@ -577,7 +577,7 @@ JRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea JvmtiExport::notice_unwind_due_to_exception(current, h_method(), handler_pc, h_exception(), (handler_pc != nullptr)); } - current->set_vm_result(h_exception()); + current->set_vm_result_oop(h_exception()); return continuation; JRT_END @@ -765,11 +765,11 @@ JRT_ENTRY(void, InterpreterRuntime::new_illegal_monitor_state_exception(JavaThre // method will be called during an exception unwind. assert(!HAS_PENDING_EXCEPTION, "no pending exception"); - Handle exception(current, current->vm_result()); + Handle exception(current, current->vm_result_oop()); assert(exception() != nullptr, "vm result should be set"); - current->set_vm_result(nullptr); // clear vm result before continuing (may cause memory leaks and assert failures) + current->set_vm_result_oop(nullptr); // clear vm result before continuing (may cause memory leaks and assert failures) exception = get_preinitialized_exception(vmClasses::IllegalMonitorStateException_klass(), CATCH); - current->set_vm_result(exception()); + current->set_vm_result_oop(exception()); JRT_END @@ -1474,7 +1474,7 @@ JRT_END #if INCLUDE_JVMTI // This is a support of the JVMTI PopFrame interface. // Make sure it is an invokestatic of a polymorphic intrinsic that has a member_name argument -// and return it as a vm_result so that it can be reloaded in the list of invokestatic parameters. +// and return it as a vm_result_oop so that it can be reloaded in the list of invokestatic parameters. // The member_name argument is a saved reference (in local#0) to the member_name. // For backward compatibility with some JDK versions (7, 8) it can also be a direct method handle. // FIXME: remove DMH case after j.l.i.InvokerBytecodeGenerator code shape is updated. @@ -1495,9 +1495,9 @@ JRT_ENTRY(void, InterpreterRuntime::member_name_arg_or_null(JavaThread* current, // FIXME: remove after j.l.i.InvokerBytecodeGenerator code shape is updated. member_name_oop = java_lang_invoke_DirectMethodHandle::member(member_name_oop); } - current->set_vm_result(member_name_oop); + current->set_vm_result_oop(member_name_oop); } else { - current->set_vm_result(nullptr); + current->set_vm_result_oop(nullptr); } JRT_END #endif // INCLUDE_JVMTI diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp index 43b618dcc1e13..401953a170f77 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp @@ -2033,8 +2033,8 @@ void BytecodeInterpreter::run(interpreterState istate) { // Must prevent reordering of stores for object initialization // with stores that publish the new object. OrderAccess::storestore(); - SET_STACK_OBJECT(THREAD->vm_result(), 0); - THREAD->set_vm_result(nullptr); + SET_STACK_OBJECT(THREAD->vm_result_oop(), 0); + THREAD->set_vm_result_oop(nullptr); UPDATE_PC_AND_TOS_AND_CONTINUE(3, 1); } CASE(_anewarray): { @@ -2045,8 +2045,8 @@ void BytecodeInterpreter::run(interpreterState istate) { // Must prevent reordering of stores for object initialization // with stores that publish the new object. OrderAccess::storestore(); - SET_STACK_OBJECT(THREAD->vm_result(), -1); - THREAD->set_vm_result(nullptr); + SET_STACK_OBJECT(THREAD->vm_result_oop(), -1); + THREAD->set_vm_result_oop(nullptr); UPDATE_PC_AND_CONTINUE(3); } CASE(_multianewarray): { @@ -2062,8 +2062,8 @@ void BytecodeInterpreter::run(interpreterState istate) { // Must prevent reordering of stores for object initialization // with stores that publish the new object. OrderAccess::storestore(); - SET_STACK_OBJECT(THREAD->vm_result(), -dims); - THREAD->set_vm_result(nullptr); + SET_STACK_OBJECT(THREAD->vm_result_oop(), -dims); + THREAD->set_vm_result_oop(nullptr); UPDATE_PC_AND_TOS_AND_CONTINUE(4, -(dims-1)); } CASE(_checkcast): @@ -2144,8 +2144,8 @@ void BytecodeInterpreter::run(interpreterState istate) { oop result = constants->resolved_reference_at(index); if (result == nullptr) { CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode), handle_exception); - SET_STACK_OBJECT(THREAD->vm_result(), 0); - THREAD->set_vm_result(nullptr); + SET_STACK_OBJECT(THREAD->vm_result_oop(), 0); + THREAD->set_vm_result_oop(nullptr); } else { VERIFY_OOP(result); SET_STACK_OBJECT(result, 0); @@ -2161,15 +2161,15 @@ void BytecodeInterpreter::run(interpreterState istate) { case JVM_CONSTANT_UnresolvedClass: case JVM_CONSTANT_UnresolvedClassInError: CALL_VM(InterpreterRuntime::ldc(THREAD, wide), handle_exception); - SET_STACK_OBJECT(THREAD->vm_result(), 0); - THREAD->set_vm_result(nullptr); + SET_STACK_OBJECT(THREAD->vm_result_oop(), 0); + THREAD->set_vm_result_oop(nullptr); break; case JVM_CONSTANT_Dynamic: case JVM_CONSTANT_DynamicInError: { CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode), handle_exception); - oop result = THREAD->vm_result(); + oop result = THREAD->vm_result_oop(); VERIFY_OOP(result); jvalue value; @@ -2211,7 +2211,7 @@ void BytecodeInterpreter::run(interpreterState istate) { case JVM_CONSTANT_DynamicInError: { CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode), handle_exception); - oop result = THREAD->vm_result(); + oop result = THREAD->vm_result_oop(); VERIFY_OOP(result); jvalue value; @@ -2250,7 +2250,7 @@ void BytecodeInterpreter::run(interpreterState istate) { if (result == nullptr) { CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode), handle_exception); - result = THREAD->vm_result(); + result = THREAD->vm_result_oop(); } if (result == Universe::the_null_sentinel()) result = nullptr; @@ -2518,8 +2518,8 @@ void BytecodeInterpreter::run(interpreterState istate) { // Must prevent reordering of stores for object initialization // with stores that publish the new object. OrderAccess::storestore(); - SET_STACK_OBJECT(THREAD->vm_result(), -1); - THREAD->set_vm_result(nullptr); + SET_STACK_OBJECT(THREAD->vm_result_oop(), -1); + THREAD->set_vm_result_oop(nullptr); UPDATE_PC_AND_CONTINUE(2); } @@ -2959,8 +2959,8 @@ void BytecodeInterpreter::run(interpreterState istate) { CALL_VM(continuation_bci = (intptr_t)InterpreterRuntime::exception_handler_for_exception(THREAD, except_oop()), handle_exception); - except_oop = Handle(THREAD, THREAD->vm_result()); - THREAD->set_vm_result(nullptr); + except_oop = Handle(THREAD, THREAD->vm_result_oop()); + THREAD->set_vm_result_oop(nullptr); if (continuation_bci >= 0) { // Place exception on top of stack SET_STACK_OBJECT(except_oop(), 0); diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp index d1ae48e4a75c9..cf94293f0a31d 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp @@ -277,7 +277,7 @@ bool ReferenceToThreadRootClosure::do_thread_stack_detailed(JavaThread* jt) { // around using this function /* * // can't reach these oop* from the outside - f->do_oop((oop*) &_vm_result); + f->do_oop((oop*) &_vm_result_oop); f->do_oop((oop*) &_exception_oop); f->do_oop((oop*) &_pending_async_exception); */ diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index 8e885e5f7f9bf..6f1fa52576e41 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -96,7 +96,7 @@ static void deopt_caller() { // call is of the variety where allocation failure returns null without an // exception, the following action is taken: // 1. The pending OutOfMemoryError is cleared -// 2. null is written to JavaThread::_vm_result +// 2. null is written to JavaThread::_vm_result_oop class RetryableAllocationMark { private: InternalOOMEMark _iom; @@ -107,7 +107,7 @@ class RetryableAllocationMark { if (THREAD != nullptr) { if (HAS_PENDING_EXCEPTION) { oop ex = PENDING_EXCEPTION; - THREAD->set_vm_result(nullptr); + THREAD->set_vm_result_oop(nullptr); if (ex->is_a(vmClasses::OutOfMemoryError_klass())) { CLEAR_PENDING_EXCEPTION; } @@ -127,12 +127,12 @@ JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_instance_or_null(JavaThread* current, Kl if (!h->is_initialized()) { // Cannot re-execute class initialization without side effects // so return without attempting the initialization - current->set_vm_result(nullptr); + current->set_vm_result_oop(nullptr); return; } // allocate instance and return via TLS oop obj = h->allocate_instance(CHECK); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); } JRT_BLOCK_END; SharedRuntime::on_slowpath_allocation_exit(current); @@ -166,7 +166,7 @@ JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array_or_null(JavaThread* current, Klass deopt_caller(); } } - current->set_vm_result(obj); + current->set_vm_result_oop(obj); JRT_BLOCK_END; SharedRuntime::on_slowpath_allocation_exit(current); JRT_END @@ -177,13 +177,13 @@ JRT_ENTRY(void, JVMCIRuntime::new_multi_array_or_null(JavaThread* current, Klass Handle holder(current, klass->klass_holder()); // keep the klass alive RetryableAllocationMark ram(current); oop obj = ArrayKlass::cast(klass)->multi_allocate(rank, dims, CHECK); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); JRT_END JRT_ENTRY(void, JVMCIRuntime::dynamic_new_array_or_null(JavaThread* current, oopDesc* element_mirror, jint length)) RetryableAllocationMark ram(current); oop obj = Reflection::reflect_new_array(element_mirror, length, CHECK); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); JRT_END JRT_ENTRY(void, JVMCIRuntime::dynamic_new_instance_or_null(JavaThread* current, oopDesc* type_mirror)) @@ -201,12 +201,12 @@ JRT_ENTRY(void, JVMCIRuntime::dynamic_new_instance_or_null(JavaThread* current, if (!klass->is_initialized()) { // Cannot re-execute class initialization without side effects // so return without attempting the initialization - current->set_vm_result(nullptr); + current->set_vm_result_oop(nullptr); return; } oop obj = klass->allocate_instance(CHECK); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); JRT_END extern void vm_exit(int code); @@ -533,7 +533,7 @@ JRT_ENTRY(jlong, JVMCIRuntime::invoke_static_method_one_arg(JavaThread* current, if (return_type == T_VOID) { return 0; } else if (return_type == T_OBJECT || return_type == T_ARRAY) { - current->set_vm_result(result.get_oop()); + current->set_vm_result_oop(result.get_oop()); return 0; } else { jvalue *value = (jvalue *) result.get_value_addr(); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 4fe2b286e155a..8ca13a3a6c376 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -227,7 +227,7 @@ nonstatic_field(JavaThread, _scopedValueCache, OopHandle) \ nonstatic_field(JavaThread, _anchor, JavaFrameAnchor) \ nonstatic_field(JavaThread, _monitor_owner_id, int64_t) \ - nonstatic_field(JavaThread, _vm_result, oop) \ + nonstatic_field(JavaThread, _vm_result_oop, oop) \ nonstatic_field(JavaThread, _stack_overflow_state._stack_overflow_limit, address) \ volatile_nonstatic_field(JavaThread, _exception_oop, oop) \ volatile_nonstatic_field(JavaThread, _exception_pc, address) \ diff --git a/src/hotspot/share/opto/generateOptoStub.cpp b/src/hotspot/share/opto/generateOptoStub.cpp index b13504ab10e56..77633857cdf87 100644 --- a/src/hotspot/share/opto/generateOptoStub.cpp +++ b/src/hotspot/share/opto/generateOptoStub.cpp @@ -228,7 +228,7 @@ void GraphKit::gen_stub(address C_function, Node* target = map()->in(TypeFunc::Parms); // Runtime call returning oop in TLS? Fetch it out if( pass_tls ) { - Node* adr = basic_plus_adr(top(), thread, in_bytes(JavaThread::vm_result_offset())); + Node* adr = basic_plus_adr(top(), thread, in_bytes(JavaThread::vm_result_oop_offset())); Node* vm_result = make_load(nullptr, adr, TypeOopPtr::BOTTOM, T_OBJECT, MemNode::unordered); map()->set_req(TypeFunc::Parms, vm_result); // vm_result passed as result // clear thread-local-storage(tls) diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 74d7eb42ebcf6..6d24fb26cd2f4 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -347,7 +347,7 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::new_instance_C(Klass* klass, JavaThread* curr // Scavenge and allocate an instance. Handle holder(current, klass->klass_holder()); // keep the klass alive oop result = InstanceKlass::cast(klass)->allocate_instance(THREAD); - current->set_vm_result(result); + current->set_vm_result_oop(result); // Pass oops back through thread local storage. Our apparent type to Java // is that we return an oop, but we can block on exit from this routine and @@ -393,7 +393,7 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::new_array_C(Klass* array_type, int len, JavaT // a GC can trash the oop in C's return register. The generated stub will // fetch the oop from TLS after any possible GC. deoptimize_caller_frame(current, HAS_PENDING_EXCEPTION); - current->set_vm_result(result); + current->set_vm_result_oop(result); JRT_BLOCK_END; // inform GC that we won't do card marks for initializing writes. @@ -421,14 +421,14 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::new_array_nozero_C(Klass* array_type, int len // a GC can trash the oop in C's return register. The generated stub will // fetch the oop from TLS after any possible GC. deoptimize_caller_frame(current, HAS_PENDING_EXCEPTION); - current->set_vm_result(result); + current->set_vm_result_oop(result); JRT_BLOCK_END; // inform GC that we won't do card marks for initializing writes. SharedRuntime::on_slowpath_allocation_exit(current); - oop result = current->vm_result(); + oop result = current->vm_result_oop(); if ((len > 0) && (result != nullptr) && is_deoptimized_caller_frame(current)) { // Zero array here if the caller is deoptimized. @@ -465,7 +465,7 @@ JRT_ENTRY(void, OptoRuntime::multianewarray2_C(Klass* elem_type, int len1, int l Handle holder(current, elem_type->klass_holder()); // keep the klass alive oop obj = ArrayKlass::cast(elem_type)->multi_allocate(2, dims, THREAD); deoptimize_caller_frame(current, HAS_PENDING_EXCEPTION); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); JRT_END // multianewarray for 3 dimensions @@ -482,7 +482,7 @@ JRT_ENTRY(void, OptoRuntime::multianewarray3_C(Klass* elem_type, int len1, int l Handle holder(current, elem_type->klass_holder()); // keep the klass alive oop obj = ArrayKlass::cast(elem_type)->multi_allocate(3, dims, THREAD); deoptimize_caller_frame(current, HAS_PENDING_EXCEPTION); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); JRT_END // multianewarray for 4 dimensions @@ -500,7 +500,7 @@ JRT_ENTRY(void, OptoRuntime::multianewarray4_C(Klass* elem_type, int len1, int l Handle holder(current, elem_type->klass_holder()); // keep the klass alive oop obj = ArrayKlass::cast(elem_type)->multi_allocate(4, dims, THREAD); deoptimize_caller_frame(current, HAS_PENDING_EXCEPTION); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); JRT_END // multianewarray for 5 dimensions @@ -519,7 +519,7 @@ JRT_ENTRY(void, OptoRuntime::multianewarray5_C(Klass* elem_type, int len1, int l Handle holder(current, elem_type->klass_holder()); // keep the klass alive oop obj = ArrayKlass::cast(elem_type)->multi_allocate(5, dims, THREAD); deoptimize_caller_frame(current, HAS_PENDING_EXCEPTION); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); JRT_END JRT_ENTRY(void, OptoRuntime::multianewarrayN_C(Klass* elem_type, arrayOopDesc* dims, JavaThread* current)) @@ -537,7 +537,7 @@ JRT_ENTRY(void, OptoRuntime::multianewarrayN_C(Klass* elem_type, arrayOopDesc* d Handle holder(current, elem_type->klass_holder()); // keep the klass alive oop obj = ArrayKlass::cast(elem_type)->multi_allocate(len, c_dims, THREAD); deoptimize_caller_frame(current, HAS_PENDING_EXCEPTION); - current->set_vm_result(obj); + current->set_vm_result_oop(obj); JRT_END JRT_BLOCK_ENTRY(void, OptoRuntime::monitor_notify_C(oopDesc* obj, JavaThread* current)) @@ -2012,7 +2012,7 @@ address OptoRuntime::rethrow_C(oopDesc* exception, JavaThread* thread, address r } #endif - thread->set_vm_result(exception); + thread->set_vm_result_oop(exception); // Frame not compiled (handles deoptimization blob) return SharedRuntime::raw_exception_handler_for_return_address(thread, ret_pc); } diff --git a/src/hotspot/share/runtime/javaCalls.cpp b/src/hotspot/share/runtime/javaCalls.cpp index e9b0a11917aaa..012cea19bb0f4 100644 --- a/src/hotspot/share/runtime/javaCalls.cpp +++ b/src/hotspot/share/runtime/javaCalls.cpp @@ -427,7 +427,7 @@ void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaC result = link.result(); // circumvent MS C++ 5.0 compiler bug (result is clobbered across call) // Preserve oop return value across possible gc points if (oop_result_flag) { - thread->set_vm_result(result->get_oop()); + thread->set_vm_result_oop(result->get_oop()); } } } // Exit JavaCallWrapper (can block - potential return oop must be preserved) @@ -438,8 +438,8 @@ void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaC // Restore possible oop return if (oop_result_flag) { - result->set_oop(thread->vm_result()); - thread->set_vm_result(nullptr); + result->set_oop(thread->vm_result_oop()); + thread->set_vm_result_oop(nullptr); } } diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index b5c7709ac88f1..e4f377a121799 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -423,8 +423,8 @@ JavaThread::JavaThread(MemTag mem_tag) : _vframe_array_last(nullptr), _jvmti_deferred_updates(nullptr), _callee_target(nullptr), - _vm_result(nullptr), - _vm_result_2(nullptr), + _vm_result_oop(nullptr), + _vm_result_metadata(nullptr), _current_pending_monitor(nullptr), _current_pending_monitor_is_from_java(true), @@ -1412,7 +1412,7 @@ void JavaThread::oops_do_no_frames(OopClosure* f, NMethodClosure* cf) { // Traverse instance variables at the end since the GC may be moving things // around using this function - f->do_oop((oop*) &_vm_result); + f->do_oop((oop*) &_vm_result_oop); f->do_oop((oop*) &_exception_oop); #if INCLUDE_JVMCI f->do_oop((oop*) &_jvmci_reserved_oop0); diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 25d3b7906e69b..01da26a97e841 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -145,8 +145,8 @@ class JavaThread: public Thread { Method* _callee_target; // Used to pass back results to the interpreter or generated code running Java code. - oop _vm_result; // oop result is GC-preserved - Metadata* _vm_result_2; // non-oop result + oop _vm_result_oop; // oop result is GC-preserved + Metadata* _vm_result_metadata; // non-oop result // See ReduceInitialCardMarks: this holds the precise space interval of // the most recent slow path allocation for which compiled code has @@ -784,10 +784,10 @@ class JavaThread: public Thread { void set_callee_target (Method* x) { _callee_target = x; } // Oop results of vm runtime calls - oop vm_result() const { return _vm_result; } - void set_vm_result (oop x) { _vm_result = x; } + oop vm_result_oop() const { return _vm_result_oop; } + void set_vm_result_oop(oop x) { _vm_result_oop = x; } - void set_vm_result_2 (Metadata* x) { _vm_result_2 = x; } + void set_vm_result_metadata(Metadata* x) { _vm_result_metadata = x; } MemRegion deferred_card_mark() const { return _deferred_card_mark; } void set_deferred_card_mark(MemRegion mr) { _deferred_card_mark = mr; } @@ -853,8 +853,8 @@ class JavaThread: public Thread { return byte_offset_of(JavaThread, _anchor); } static ByteSize callee_target_offset() { return byte_offset_of(JavaThread, _callee_target); } - static ByteSize vm_result_offset() { return byte_offset_of(JavaThread, _vm_result); } - static ByteSize vm_result_2_offset() { return byte_offset_of(JavaThread, _vm_result_2); } + static ByteSize vm_result_oop_offset() { return byte_offset_of(JavaThread, _vm_result_oop); } + static ByteSize vm_result_metadata_offset() { return byte_offset_of(JavaThread, _vm_result_metadata); } static ByteSize thread_state_offset() { return byte_offset_of(JavaThread, _thread_state); } static ByteSize saved_exception_pc_offset() { return byte_offset_of(JavaThread, _saved_exception_pc); } static ByteSize osthread_offset() { return byte_offset_of(JavaThread, _osthread); } diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 2f29ce9b1fc6d..3695d9dfe76dc 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -1439,7 +1439,7 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method_ic_miss(JavaThread* JRT_BLOCK callee_method = SharedRuntime::handle_ic_miss_helper(CHECK_NULL); // Return Method* through TLS - current->set_vm_result_2(callee_method()); + current->set_vm_result_metadata(callee_method()); JRT_BLOCK_END // return compiled code entry point after potential safepoints return get_resolved_entry(current, callee_method); @@ -1470,7 +1470,7 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method(JavaThread* current) caller_frame.is_upcall_stub_frame()) { Method* callee = current->callee_target(); guarantee(callee != nullptr && callee->is_method(), "bad handshake"); - current->set_vm_result_2(callee); + current->set_vm_result_metadata(callee); current->set_callee_target(nullptr); if (caller_frame.is_entry_frame() && VM_Version::supports_fast_class_init_checks()) { // Bypass class initialization checks in c2i when caller is in native. @@ -1492,7 +1492,7 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method(JavaThread* current) JRT_BLOCK // Force resolving of caller (if we called from compiled frame) callee_method = SharedRuntime::reresolve_call_site(CHECK_NULL); - current->set_vm_result_2(callee_method()); + current->set_vm_result_metadata(callee_method()); JRT_BLOCK_END // return compiled code entry point after potential safepoints return get_resolved_entry(current, callee_method); @@ -1550,7 +1550,7 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::resolve_static_call_C(JavaThread* curren bool enter_special = false; JRT_BLOCK callee_method = SharedRuntime::resolve_helper(false, false, CHECK_NULL); - current->set_vm_result_2(callee_method()); + current->set_vm_result_metadata(callee_method()); JRT_BLOCK_END // return compiled code entry point after potential safepoints return get_resolved_entry(current, callee_method); @@ -1561,7 +1561,7 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::resolve_virtual_call_C(JavaThread* curre methodHandle callee_method; JRT_BLOCK callee_method = SharedRuntime::resolve_helper(true, false, CHECK_NULL); - current->set_vm_result_2(callee_method()); + current->set_vm_result_metadata(callee_method()); JRT_BLOCK_END // return compiled code entry point after potential safepoints return get_resolved_entry(current, callee_method); @@ -1574,7 +1574,7 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::resolve_opt_virtual_call_C(JavaThread* c methodHandle callee_method; JRT_BLOCK callee_method = SharedRuntime::resolve_helper(true, true, CHECK_NULL); - current->set_vm_result_2(callee_method()); + current->set_vm_result_metadata(callee_method()); JRT_BLOCK_END // return compiled code entry point after potential safepoints return get_resolved_entry(current, callee_method); @@ -3168,7 +3168,7 @@ void SharedRuntime::on_slowpath_allocation_exit(JavaThread* current) { // this object in the future without emitting card-marks, so // GC may take any compensating steps. - oop new_obj = current->vm_result(); + oop new_obj = current->vm_result_oop(); if (new_obj == nullptr) return; BarrierSet *bs = BarrierSet::barrier_set(); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index c95dd709c844e..f865380fdb7de 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -604,10 +604,8 @@ nonstatic_field(JavaThread, _threadObj, OopHandle) \ nonstatic_field(JavaThread, _vthread, OopHandle) \ nonstatic_field(JavaThread, _jvmti_vthread, OopHandle) \ - nonstatic_field(JavaThread, _scopedValueCache, OopHandle) \ + nonstatic_field(JavaThread, _scopedValueCache, OopHandle) \ nonstatic_field(JavaThread, _anchor, JavaFrameAnchor) \ - nonstatic_field(JavaThread, _vm_result, oop) \ - nonstatic_field(JavaThread, _vm_result_2, Metadata*) \ volatile_nonstatic_field(JavaThread, _current_pending_monitor, ObjectMonitor*) \ nonstatic_field(JavaThread, _current_pending_monitor_is_from_java, bool) \ volatile_nonstatic_field(JavaThread, _current_waiting_monitor, ObjectMonitor*) \ From af7a19a8cfba8d7016de94d6ffc86d201ab4a884 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 17 Apr 2025 06:34:43 +0000 Subject: [PATCH 0626/1101] 8354802: MAX_SECS definition is unused in os_linux Reviewed-by: kbarrett, dholmes --- src/hotspot/os/linux/os_linux.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 4e26797cd5b3a..1afece719cbb9 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -139,8 +139,6 @@ #define MAX_PATH (2 * K) -#define MAX_SECS 100000000 - // for timer info max values which include all bits #define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) From 3d0feba00a1c1ef7627880859a093bb00eb8fc4c Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Thu, 17 Apr 2025 06:39:50 +0000 Subject: [PATCH 0627/1101] 8352865: Open source several AWT TextComponent tests - Batch 2 Reviewed-by: prr, serb, jdv --- test/jdk/ProblemList.txt | 2 + .../AltPlusNumberKeyCombinationsTest.java | 74 ++++++++ .../CorrectTextComponentSelectionTest.java | 139 +++++++++++++++ .../TextComponent/SelectionAndCaretColor.java | 162 ++++++++++++++++++ .../java/awt/TextComponent/SelectionTest.java | 73 ++++++++ 5 files changed, 450 insertions(+) create mode 100644 test/jdk/java/awt/TextComponent/AltPlusNumberKeyCombinationsTest.java create mode 100644 test/jdk/java/awt/TextComponent/CorrectTextComponentSelectionTest.java create mode 100644 test/jdk/java/awt/TextComponent/SelectionAndCaretColor.java create mode 100644 test/jdk/java/awt/TextComponent/SelectionTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 4ff6ea1fe74fd..a0d9f6586ba69 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -799,6 +799,8 @@ java/awt/TrayIcon/DragEventSource/DragEventSource.java 8252242 macosx-all java/awt/FileDialog/DefaultFocusOwner/DefaultFocusOwner.java 7187728 macosx-all,linux-all java/awt/print/PageFormat/Orient.java 8016055 macosx-all java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.java 8024986 macosx-all,linux-all +java/awt/TextComponent/CorrectTextComponentSelectionTest.java 8237220 macosx-all +java/awt/TextComponent/SelectionAndCaretColor.java 7017622 linux-all java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter.java 8254841 macosx-all java/awt/Focus/AppletInitialFocusTest/AppletInitialFocusTest1.java 8256289 windows-x64 java/awt/FullScreen/TranslucentWindow/TranslucentWindow.java 8258103 linux-all diff --git a/test/jdk/java/awt/TextComponent/AltPlusNumberKeyCombinationsTest.java b/test/jdk/java/awt/TextComponent/AltPlusNumberKeyCombinationsTest.java new file mode 100644 index 0000000000000..27599b0a91c9c --- /dev/null +++ b/test/jdk/java/awt/TextComponent/AltPlusNumberKeyCombinationsTest.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4737679 4623376 4501485 4740906 4708221 + * @requires (os.family == "windows") + * @summary Alt+Left/right/up/down generate characters in JTextArea + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AltPlusNumberKeyCombinationsTest + */ + +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.TextArea; +import java.awt.TextField; + +public class AltPlusNumberKeyCombinationsTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + [WINDOWS PLATFORM ONLY] + Please do the following steps for both TextField and TextArea: + 1. Hold down ALT and press a NON-NUMPAD right arrow, then release + ALT key. If any symbol is typed the test failed. + 2. Hold down ALT and press one after another the following + NUMPAD keys: 0, 1, 2, 8. Release ALT key. If the Euro symbol + is not typed the test failed + 3. Hold down ALT and press one after another the following + NUMPAD keys: 0, 2, 2, 7. Release ALT key. If nothing or + the blank symbol is typed the test failed + If all the steps are done successfully the test PASSed, + else test FAILS. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + Frame f = new Frame("key combination test"); + f.setLayout(new FlowLayout()); + TextField tf = new TextField("TextField"); + f.add(tf); + TextArea ta = new TextArea("TextArea"); + f.add(ta); + f.setSize(200, 200); + return f; + } +} diff --git a/test/jdk/java/awt/TextComponent/CorrectTextComponentSelectionTest.java b/test/jdk/java/awt/TextComponent/CorrectTextComponentSelectionTest.java new file mode 100644 index 0000000000000..9d3e6d8563733 --- /dev/null +++ b/test/jdk/java/awt/TextComponent/CorrectTextComponentSelectionTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5100806 + * @summary TextArea.select(0,0) does not de-select the selected text properly + * @key headful + * @run main CorrectTextComponentSelectionTest + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.TextArea; +import java.awt.TextComponent; +import java.awt.TextField; +import java.lang.reflect.InvocationTargetException; + +public class CorrectTextComponentSelectionTest { + static TextField tf = new TextField("TextField"); + static TextArea ta = new TextArea("TextArea"); + static Robot r; + static Frame frame; + static volatile Color color_center; + static volatile Point loc; + + public static void main(String[] args) throws Exception { + try { + r = new Robot(); + EventQueue.invokeAndWait(() -> { + initialize(); + }); + r.waitForIdle(); + r.delay(1000); + + test(tf); + test(ta); + System.out.println("Test Passed!"); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static void initialize() { + frame = new Frame("TextComponent Selection Test"); + frame.setLayout(new BorderLayout()); + + // We should place to the text components the long strings in order to + // cover the components by the selection completely + String sf = ""; + for (int i = 0; i < 50; i++) { + sf = sf + " "; + } + tf.setText(sf); + // We check the color of the text component in order to find out the + // bug reproducible situation + tf.setForeground(Color.WHITE); + tf.setBackground(Color.WHITE); + + String sa = ""; + for (int i = 0; i < 50; i++) { + for (int j = 0; j < 50; j++) { + sa = sa + " "; + } + sa = sa + "\n"; + } + ta.setText(sa); + ta.setForeground(Color.WHITE); + ta.setBackground(Color.WHITE); + + frame.add(tf, "North"); + frame.add(ta, "South"); + frame.setSize(200, 200); + frame.setVisible(true); + } + + private static void test(TextComponent tc) throws Exception { + if (tc instanceof TextField) { + System.out.println("TextField testing ..."); + } else if (tc instanceof TextArea) { + System.out.println("TextArea testing ..."); + } + + r.waitForIdle(); + r.delay(100); + EventQueue.invokeAndWait(() -> { + tc.requestFocus(); + tc.selectAll(); + tc.select(0, 0); + }); + + r.waitForIdle(); + r.delay(100); + EventQueue.invokeAndWait(() -> { + loc = tc.getLocationOnScreen(); + }); + r.waitForIdle(); + r.delay(100); + + EventQueue.invokeAndWait(() -> { + color_center = r.getPixelColor(loc.x + tc.getWidth() / 2, loc.y + tc.getHeight() / 2); + }); + + System.out.println("Color of the text component (CENTER) =" + color_center); + System.out.println("White color=" + Color.WHITE); + + if (color_center.getRGB() != Color.WHITE.getRGB()) { + throw new RuntimeException("Test Failed"); + } + } +} diff --git a/test/jdk/java/awt/TextComponent/SelectionAndCaretColor.java b/test/jdk/java/awt/TextComponent/SelectionAndCaretColor.java new file mode 100644 index 0000000000000..60b932e4be8df --- /dev/null +++ b/test/jdk/java/awt/TextComponent/SelectionAndCaretColor.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6287895 + * @requires (os.family == "linux") + * @summary Test cursor and selected text incorrectly colored in TextField + * @key headful + * @run main SelectionAndCaretColor + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.TextArea; +import java.awt.TextComponent; +import java.awt.TextField; +import java.awt.image.BufferedImage; + +public class SelectionAndCaretColor { + static TextField tf = new TextField(20); + static TextArea ta = new TextArea("", 1, 20, TextArea.SCROLLBARS_NONE); + static Robot r; + static Frame frame; + static volatile int flips; + + public static void main(String[] args) throws Exception { + try { + frame = new Frame("Selection and Caret color test"); + r = new Robot(); + + EventQueue.invokeAndWait(() -> { + frame.setLayout(new BorderLayout()); + tf.setFont(new Font("Monospaced", Font.PLAIN, 15)); + ta.setFont(new Font("Monospaced", Font.PLAIN, 15)); + + frame.add(tf, BorderLayout.NORTH); + frame.add(ta, BorderLayout.SOUTH); + frame.setSize(200, 200); + frame.setVisible(true); + }); + r.waitForIdle(); + r.delay(1000); + test(tf); + test(ta); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static int countFlips(TextComponent tc) { + int y = tc.getLocationOnScreen().y + tc.getHeight() / 2; + int x1 = tc.getLocationOnScreen().x + 5; + int x2 = tc.getLocationOnScreen().x + tc.getWidth() - 5; + + int[] fb = {tc.getBackground().getRGB(), tc.getForeground().getRGB()}; + int i = 0; + int flips = 0; + + BufferedImage img = r.createScreenCapture(new Rectangle(x1, y, x2 - x1, 1)); + for (int x = 0; x < x2 - x1; x++) { + int c = img.getRGB(x, 0); + if (c == fb[i]) { + ; + } else if (c == fb[1 - i]) { + flips++; + i = 1 - i; + } else { + throw new RuntimeException("Invalid color detected: " + + Integer.toString(c, 16) + " instead of " + + Integer.toString(fb[i], 16)); + } + } + return flips; + } + + private static void test(TextComponent tc) throws Exception { + if (tc instanceof TextField) { + System.out.println("TextField testing ..."); + } else if (tc instanceof TextArea) { + System.out.println("TextArea testing ..."); + } + + // now passing along the component's vertical center, + // skipping 5px from both sides, + // we should see bg - textcolor - bg - selcolor - + // seltextcolor - selcolor - bg + // that is bg-fg-bg-fg-bg-fg-bg, 6 flips + + EventQueue.invokeAndWait(() -> { + tc.setForeground(Color.green); + tc.setBackground(Color.magenta); + + tc.setText(" I I "); + tc.select(5, 10); + tc.requestFocus(); + }); + r.waitForIdle(); + r.delay(200); + EventQueue.invokeAndWait(() -> { + flips = countFlips(tc); + }); + if (flips != 6) { + throw new RuntimeException("Invalid number of flips: " + + flips + " instead of 6"); + } + EventQueue.invokeAndWait(() -> { + // same for caret: spaces in the tc, caret in the middle + // bg-fg-bg - 2 flips + + tc.select(0, 0); + tc.setText(" "); + tc.setCaretPosition(5); + }); + r.waitForIdle(); + r.delay(200); + + for (int i = 0; i < 10; i++) { + EventQueue.invokeAndWait(() -> { + flips = countFlips(tc); + }); + + if (flips == 2) { + break; + } + if (flips == 0) { + continue; + } + throw new RuntimeException("Invalid number of flips: " + + flips + " instead of 2"); + } + } +} diff --git a/test/jdk/java/awt/TextComponent/SelectionTest.java b/test/jdk/java/awt/TextComponent/SelectionTest.java new file mode 100644 index 0000000000000..d29818d762176 --- /dev/null +++ b/test/jdk/java/awt/TextComponent/SelectionTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4056231 + * @summary Checks that TextComponents don't grab the global CDE selection + * upon construction if their own selection is null. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SelectionTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Frame; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class SelectionTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. "Select some text in another window, then click the button.", + 2. "If the text in the other window is de-selected, the test FAILS.", + "If the text remains selected, the test PASSES." + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + Frame frame = new Frame("Selection Test"); + frame.setLayout(new BorderLayout()); + Button b = new Button("Select some text in another window, then" + + " click me"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + frame.add(new TextField("text field test")); + frame.add(new TextArea("text area test")); + } + }); + frame.add(b); + frame.setSize(400, 400); + return frame; + } +} From e00355a036936c5290cf8d85fd3c4f743b0ad23a Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Thu, 17 Apr 2025 06:40:54 +0000 Subject: [PATCH 0628/1101] 8353958: Open source several AWT ScrollPane tests - Batch 2 Reviewed-by: prr, psadhukhan --- test/jdk/ProblemList.txt | 1 + .../ScrollPane/ScrollPaneAsNeededTest.java | 67 ++++++++ .../ScrollPane/ScrollPaneComponentTest.java | 125 +++++++++++++++ .../awt/ScrollPane/ScrollPaneEventType.java | 81 ++++++++++ .../java/awt/ScrollPane/ScrollPaneSize.java | 97 ++++++++++++ .../ScrollPanechildViewportTest.java | 146 ++++++++++++++++++ 6 files changed, 517 insertions(+) create mode 100644 test/jdk/java/awt/ScrollPane/ScrollPaneAsNeededTest.java create mode 100644 test/jdk/java/awt/ScrollPane/ScrollPaneComponentTest.java create mode 100644 test/jdk/java/awt/ScrollPane/ScrollPaneEventType.java create mode 100644 test/jdk/java/awt/ScrollPane/ScrollPaneSize.java create mode 100644 test/jdk/java/awt/ScrollPane/ScrollPanechildViewportTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index a0d9f6586ba69..ac4828eadcaf8 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -441,6 +441,7 @@ java/awt/Focus/TranserFocusToWindow/TranserFocusToWindow.java 6848810 macosx-all java/awt/FileDialog/ModalFocus/FileDialogModalFocusTest.java 8194751 linux-all java/awt/image/VolatileImage/BitmaskVolatileImage.java 8133102 linux-all java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java 8203004 linux-all +java/awt/ScrollPane/ScrollPaneScrollType/ScrollPaneEventType.java 8296516 macosx-all java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java 7107528 linux-all,macosx-all java/awt/Mouse/MouseDragEvent/MouseDraggedTest.java 8080676 linux-all java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersInKeyEvent.java 8157147 linux-all,windows-all,macosx-all diff --git a/test/jdk/java/awt/ScrollPane/ScrollPaneAsNeededTest.java b/test/jdk/java/awt/ScrollPane/ScrollPaneAsNeededTest.java new file mode 100644 index 0000000000000..e4be90fae311d --- /dev/null +++ b/test/jdk/java/awt/ScrollPane/ScrollPaneAsNeededTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4152524 + * @summary ScrollPane AS_NEEDED always places scrollbars first time component + * is laid out + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ScrollPaneAsNeededTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Frame; +import java.awt.ScrollPane; + +public class ScrollPaneAsNeededTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. You will see a frame titled 'ScrollPane as needed' + of minimum possible size in the middle of the screen. + 2. If for the first resize of frame(using mouse) to + a very big size(may be, to half the area of the screen) + the scrollbars(any - horizontal, vertical or both) + appear, click FAIL else, click PASS. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(ScrollPaneAsNeededTest::initialize) + .build() + .awaitAndCheck(); + } + + static Frame initialize() { + Frame f = new Frame("ScrollPane as needed"); + f.setLayout(new BorderLayout()); + ScrollPane sp = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED); + sp.add(new Button("TEST")); + f.add("Center", sp); + f.setSize(200, 200); + return f; + } +} diff --git a/test/jdk/java/awt/ScrollPane/ScrollPaneComponentTest.java b/test/jdk/java/awt/ScrollPane/ScrollPaneComponentTest.java new file mode 100644 index 0000000000000..b2fc4c77b6321 --- /dev/null +++ b/test/jdk/java/awt/ScrollPane/ScrollPaneComponentTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4100671 + * @summary removing and adding back ScrollPane component does not work + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ScrollPaneComponentTest + */ + +import java.awt.Adjustable; +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Panel; +import java.awt.ScrollPane; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class ScrollPaneComponentTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Notice the scrollbars (horizontal and vertical) + in the Frame titled 'ScrollPane Component Test' + 2. Click the button labeled 'Remove and add back + ScrollPane Contents' + 3. If the Scrollbars (horizontal or vertical or both) + disappears in the Frame, then press FAIL, else press PASS. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(ScrollPaneComponentTest::initialize) + .build() + .awaitAndCheck(); + } + + static Frame initialize() { + Frame fr = new Frame("ScrollPane Component Test"); + fr.setLayout(new BorderLayout()); + ScrollTester test = new ScrollTester(); + + fr.add(test); + fr.pack(); + fr.setSize(200, 200); + + Adjustable vadj = test.pane.getVAdjustable(); + Adjustable hadj = test.pane.getHAdjustable(); + vadj.setUnitIncrement(5); + hadj.setUnitIncrement(5); + return fr; + } +} + +class Box extends Component { + public Dimension getPreferredSize() { + System.out.println("asked for size"); + return new Dimension(300, 300); + } + + public void paint(Graphics gr) { + super.paint(gr); + gr.setColor(Color.red); + gr.drawLine(5, 5, 295, 5); + gr.drawLine(295, 5, 295, 295); + gr.drawLine(295, 295, 5, 295); + gr.drawLine(5, 295, 5, 5); + System.out.println("Painted!!"); + } +} + +class ScrollTester extends Panel { + public ScrollPane pane; + private final Box child; + + class Handler implements ActionListener { + public void actionPerformed(ActionEvent e) { + System.out.println("Removing scrollable component"); + pane.remove(child); + System.out.println("Adding back scrollable component"); + pane.add(child); + System.out.println("Done Adding back scrollable component"); + } + } + + public ScrollTester() { + pane = new ScrollPane(); + pane.setSize(200, 200); + child = new Box(); + pane.add(child); + setLayout(new BorderLayout()); + Button changeScrollContents = new Button("Remove and add back ScrollPane Contents"); + changeScrollContents.setBackground(Color.red); + changeScrollContents.addActionListener(new Handler()); + add("North", changeScrollContents); + add("Center", pane); + } +} diff --git a/test/jdk/java/awt/ScrollPane/ScrollPaneEventType.java b/test/jdk/java/awt/ScrollPane/ScrollPaneEventType.java new file mode 100644 index 0000000000000..47b4ae416c128 --- /dev/null +++ b/test/jdk/java/awt/ScrollPane/ScrollPaneEventType.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4075484 + * @summary Tests that events of different types are generated for the + * corresponding scroll actions. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ScrollPaneEventType + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.ScrollPane; +import java.awt.event.AdjustmentListener; + +public class ScrollPaneEventType { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. This test verifies that when user performs some scrolling operation on + ScrollPane the correct AdjustmentEvent is being generated. + 2. To test this, press on: + - scrollbar's arrows and verify that UNIT event is generated, + - scrollbar's grey area(non-thumb) and verify that BLOCK event is + generated, + - drag scrollbar's thumb and verify that TRACK event is generated + If you see correct events for both scroll bars then test is PASSED. + Otherwise it is FAILED. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(ScrollPaneEventType::initialize) + .logArea() + .build() + .awaitAndCheck(); + } + + static Frame initialize() { + Frame frame = new Frame("ScrollPane event type test"); + frame.setLayout(new BorderLayout()); + ScrollPane pane = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS); + pane.add(new Button("press") { + public Dimension getPreferredSize() { + return new Dimension(1000, 1000); + } + }); + + AdjustmentListener listener = e -> PassFailJFrame.log(e.toString()); + pane.getHAdjustable().addAdjustmentListener(listener); + pane.getVAdjustable().addAdjustmentListener(listener); + frame.add(pane); + frame.setSize(200, 200); + return frame; + } +} diff --git a/test/jdk/java/awt/ScrollPane/ScrollPaneSize.java b/test/jdk/java/awt/ScrollPane/ScrollPaneSize.java new file mode 100644 index 0000000000000..3130563d4a97c --- /dev/null +++ b/test/jdk/java/awt/ScrollPane/ScrollPaneSize.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4117404 + * @summary Tests that child component is always at least large as scrollpane + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ScrollPaneSize + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.Panel; +import java.awt.ScrollPane; +import java.util.List; + +public class ScrollPaneSize { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Three frames representing the three different ScrollPane scrollbar + policies will appear. + 2. Verify that when you resize the windows, the child component in the + scrollpane always expands to fill the scrollpane. The scrollpane + background is colored red to show any improper bleed through. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(ScrollPaneSize::initialize) + .positionTestUIRightColumn() + .build() + .awaitAndCheck(); + } + + static List initialize() { + return List.of(new ScrollFrame("SCROLLBARS_AS_NEEDED", ScrollPane.SCROLLBARS_AS_NEEDED), + new ScrollFrame("SCROLLBARS_ALWAYS", ScrollPane.SCROLLBARS_ALWAYS), + new ScrollFrame("SCROLLBARS_NEVER", ScrollPane.SCROLLBARS_NEVER)); + } +} + +class ScrollFrame extends Frame { + ScrollFrame(String title, int policy) { + super(title); + setLayout(new GridLayout(1, 1)); + ScrollPane c = new ScrollPane(policy); + c.setBackground(Color.red); + Panel panel = new TestPanel(); + c.add(panel); + add(c); + pack(); + Dimension size = panel.getPreferredSize(); + Insets insets = getInsets(); + setSize(size.width + 45 + insets.right + insets.left, + size.height + 20 + insets.top + insets.bottom); + } +} + +class TestPanel extends Panel { + TestPanel() { + setLayout(new FlowLayout()); + setBackground(Color.white); + + Button b1, b2, b3; + add(b1 = new Button("Button1")); + add(b2 = new Button("Button2")); + add(b3 = new Button("Button3")); + } +} diff --git a/test/jdk/java/awt/ScrollPane/ScrollPanechildViewportTest.java b/test/jdk/java/awt/ScrollPane/ScrollPanechildViewportTest.java new file mode 100644 index 0000000000000..0dc0772aebafd --- /dev/null +++ b/test/jdk/java/awt/ScrollPane/ScrollPanechildViewportTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4094581 + * @summary ScrollPane does not refresh properly when child is just smaller than viewport + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ScrollPanechildViewportTest + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.ScrollPane; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class ScrollPanechildViewportTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Click "Slightly Large" and ensure scrollbars are VISIBLE + 2. Click "Slightly Small" and ensure there are NO scrollbars + 3. Click "Smaller" and ensure there are NO scrollbars + 4. If everything is ok, click PASS, else click FAIL. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(ScrollPanechildViewportTest::initialize) + .build() + .awaitAndCheck(); + } + + static Frame initialize() { + return new Test(); + } +} + +class Test extends Frame implements ActionListener { + Button b1, b2, b3; + MyPanel p; + int state; // 0 = slightly large, 1 = slightly smaller, 2 = smaller + + public Test() { + ScrollPane sp = new ScrollPane(); + p = new MyPanel(); + p.setBackground(Color.yellow); + state = 1; + sp.add(p); + add(sp, "Center"); + + Panel p1 = new Panel(); + b1 = new Button("Slightly Large"); + b1.addActionListener(this); + p1.add(b1); + b2 = new Button("Slightly Small"); + b2.addActionListener(this); + p1.add(b2); + b3 = new Button("Smaller"); + b3.addActionListener(this); + p1.add(b3); + + add(p1, "South"); + + setSize(400, 200); + //added to test to move test frame away from instructions + setLocation(0, 350); + } + + public void actionPerformed(ActionEvent e) { + Object source = e.getSource(); + + // set size to small and re-validate the panel to get correct size of + // scrollpane viewport without scrollbars + + state = 2; + p.invalidate(); + validate(); + + Dimension pd = ((ScrollPane) p.getParent()).getViewportSize(); + + if (source.equals(b1)) { + p.setBackground(Color.green); + state = 0; + } else if (source.equals(b2)) { + p.setBackground(Color.yellow); + state = 1; + } else if (source.equals(b3)) { + p.setBackground(Color.red); + state = 2; + } + + p.invalidate(); + validate(); + System.out.println("Panel Size = " + p.getSize()); + System.out.println("ScrollPane Viewport Size = " + pd); + System.out.println(" "); + } + + class MyPanel extends Panel { + public Dimension getPreferredSize() { + Dimension d = null; + Dimension pd = ((ScrollPane) getParent()).getViewportSize(); + switch (state) { + case 0 -> { + d = new Dimension(pd.width + 2, pd.height + 2); + System.out.println("Preferred size: " + d); + } + case 1 -> { + d = new Dimension(pd.width - 2, pd.height - 2); + System.out.println("Preferred size: " + d); + } + case 2 -> { + d = new Dimension(50, 50); + System.out.println("Preferred size: " + d); + } + } + return d; + } + } +} From a4e9da3747fe0a3c27e414787eaa97f80b24f5de Mon Sep 17 00:00:00 2001 From: Maxim Kartashev Date: Thu, 17 Apr 2025 06:59:01 +0000 Subject: [PATCH 0629/1101] 8354191: GTK LaF should use pre-multiplied alpha same as cairo Reviewed-by: avu, prr --- .../sun/java/swing/plaf/gtk/GTKEngine.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java index f9f6307678108..2540f6e788095 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java @@ -532,14 +532,7 @@ public void paintBackground(Graphics g, SynthContext context, native_paint_background(widget, state, x - x0, y - y0, w, h); } - private static final ColorModel[] COLOR_MODELS = { - // Transparency.OPAQUE - new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000), - // Transparency.BITMASK - new DirectColorModel(25, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x01000000), - // Transparency.TRANSLUCENT - ColorModel.getRGBdefault(), - }; + private static final ColorModel[] COLOR_MODELS = new ColorModel[3]; private static final int[][] BAND_OFFSETS = { { 0x00ff0000, 0x0000ff00, 0x000000ff }, // OPAQUE @@ -609,8 +602,8 @@ public BufferedImage finishPainting(boolean useCache) { WritableRaster raster = Raster.createPackedRaster( dataBuffer, w0, h0, w0, bands, null); - ColorModel cm = COLOR_MODELS[transparency - 1]; - BufferedImage img = new BufferedImage(cm, raster, false, null); + ColorModel cm = colorModelFor(transparency); + BufferedImage img = new BufferedImage(cm, raster, true, null); if (useCache) { cache.setImage(getClass(), null, w0, h0, cacheArgs, img); } @@ -618,6 +611,18 @@ public BufferedImage finishPainting(boolean useCache) { return img; } + private ColorModel colorModelFor(int transparency) { + synchronized (COLOR_MODELS) { + int index = transparency - 1; + if (COLOR_MODELS[index] == null) { + COLOR_MODELS[index] = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration() + .getColorModel(transparency); + } + return COLOR_MODELS[index]; + } + } + /** * Notify native layer of theme change, and flush cache */ From fabf67c376708a3be80d2a4e67d30d226d6e6af8 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 17 Apr 2025 07:21:34 +0000 Subject: [PATCH 0630/1101] 8354625: Compile::igv_print_graph_to_network doesn't use its second parameter Reviewed-by: rcastanedalo, thartmann --- src/hotspot/share/opto/compile.cpp | 4 ++-- src/hotspot/share/opto/compile.hpp | 2 +- src/hotspot/share/opto/node.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 9e29ecb7616d6..e4e82cbddabeb 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -5265,10 +5265,10 @@ void Compile::igv_print_method_to_file(const char* phase_name, bool append) { void Compile::igv_print_method_to_network(const char* phase_name) { ResourceMark rm; GrowableArray empty_list; - igv_print_graph_to_network(phase_name, (Node*) C->root(), empty_list); + igv_print_graph_to_network(phase_name, empty_list); } -void Compile::igv_print_graph_to_network(const char* name, Node* node, GrowableArray& visible_nodes) { +void Compile::igv_print_graph_to_network(const char* name, GrowableArray& visible_nodes) { if (_debug_network_printer == nullptr) { _debug_network_printer = new IdealGraphPrinter(C); } else { diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 271013f29c5cc..6f505e502b54d 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -680,7 +680,7 @@ class Compile : public Phase { void igv_print_method_to_file(const char* phase_name = "Debug", bool append = false); void igv_print_method_to_network(const char* phase_name = "Debug"); - void igv_print_graph_to_network(const char* name, Node* node, GrowableArray& visible_nodes); + void igv_print_graph_to_network(const char* name, GrowableArray& visible_nodes); static IdealGraphPrinter* debug_file_printer() { return _debug_file_printer; } static IdealGraphPrinter* debug_network_printer() { return _debug_network_printer; } #endif diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index d00bd3d394371..76e193609101c 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -2057,7 +2057,7 @@ void PrintBFS::print() { if (_print_igv) { Compile* C = Compile::current(); C->init_igv(); - C->igv_print_graph_to_network("PrintBFS", (Node*) C->root(), _print_list); + C->igv_print_graph_to_network("PrintBFS", _print_list); } } else { _output->print_cr("No nodes to print."); From 1138a186eb670e2c0662bda69c35680b41f4d66c Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 17 Apr 2025 07:24:14 +0000 Subject: [PATCH 0631/1101] 8344251: C2: remove blackholes with dead control input Reviewed-by: shade, thartmann, kvn --- src/hotspot/share/opto/cfgnode.cpp | 4 ++ src/hotspot/share/opto/cfgnode.hpp | 1 + .../compiler/blackhole/DeadBhElimination.java | 70 +++++++++++++++++++ .../compiler/lib/ir_framework/IRNode.java | 12 ++++ 4 files changed, 87 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/blackhole/DeadBhElimination.java diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 5bf0d6facc13b..4885d44a13df7 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -3109,6 +3109,10 @@ void NeverBranchNode::format( PhaseRegAlloc *ra_, outputStream *st) const { } #endif +Node* BlackholeNode::Ideal(PhaseGVN* phase, bool can_reshape) { + return remove_dead_region(phase, can_reshape) ? this : nullptr; +} + #ifndef PRODUCT void BlackholeNode::format(PhaseRegAlloc* ra, outputStream* st) const { st->print("blackhole "); diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 6786089a20327..a0e780c0e5742 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -735,6 +735,7 @@ class BlackholeNode : public MultiNode { virtual int Opcode() const; virtual uint ideal_reg() const { return 0; } // not matched in the AD file virtual const Type* bottom_type() const { return TypeTuple::MEMBAR; } + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); const RegMask &in_RegMask(uint idx) const { // Fake the incoming arguments mask for blackholes: accept all registers diff --git a/test/hotspot/jtreg/compiler/blackhole/DeadBhElimination.java b/test/hotspot/jtreg/compiler/blackhole/DeadBhElimination.java new file mode 100644 index 0000000000000..0fb503d2c44d3 --- /dev/null +++ b/test/hotspot/jtreg/compiler/blackhole/DeadBhElimination.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, Red Hat and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8344251 + * @summary Test that blackhole without control input are removed + * @library /test/lib / + * @run driver compiler.blackhole.DeadBhElimination + */ + +package compiler.blackhole; + +import compiler.lib.ir_framework.*; + +public class DeadBhElimination { + public static void main(String[] args) { + TestFramework.runWithFlags( + "-XX:-TieredCompilation", + "-XX:+UnlockExperimentalVMOptions", + // Prevent the dead branches to be compiled into an uncommon trap + // instead of generating a BlackholeNode. + "-XX:PerMethodTrapLimit=0", + "-XX:PerMethodSpecTrapLimit=0", + "-XX:CompileCommand=blackhole,compiler.blackhole.DeadBhElimination::iAmABlackhole" + ); + } + + static public void iAmABlackhole(int x) {} + + @Test + @IR(counts = {IRNode.BLACKHOLE, "1"}, phase = CompilePhase.AFTER_PARSING) + @IR(failOn = {IRNode.BLACKHOLE}, phase = CompilePhase.FINAL_CODE) + static void removalAfterLoopOpt() { + int a = 77; + int b = 0; + do { + a--; + b++; + } while (a > 0); + // b == 77, known after first loop opts round + // loop is detected as empty loop + + if (b == 78) { // dead + iAmABlackhole(a); + } + } + + +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 6d58b35f53c91..e7340dd0d8fbf 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -2717,6 +2717,11 @@ public class IRNode { macroNodes(MOD_D, regex); } + public static final String BLACKHOLE = PREFIX + "BLACKHOLE" + POSTFIX; + static { + fromBeforeRemoveUselessToFinalCode(BLACKHOLE, "Blackhole"); + } + /* * Utility methods to set up IR_NODE_MAPPINGS. */ @@ -2843,6 +2848,13 @@ private static void storeOfNodes(String irNodePlaceholder, String irNodeRegex) { beforeMatching(irNodePlaceholder, regex); } + private static void fromBeforeRemoveUselessToFinalCode(String irNodePlaceholder, String irNodeRegex) { + String regex = START + irNodeRegex + MID + END; + IR_NODE_MAPPINGS.put(irNodePlaceholder, new SinglePhaseRangeEntry(CompilePhase.PRINT_IDEAL, regex, + CompilePhase.BEFORE_REMOVEUSELESS, + CompilePhase.FINAL_CODE)); + } + /** * Apply {@code regex} on all ideal graph phases starting from {@link CompilePhase#PHASEIDEALLOOP1} which is the * first phase that could contain vector nodes from super word. From 5125ceb922540ef695d2fa4b3c7880e00dd078c3 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 17 Apr 2025 11:47:21 +0000 Subject: [PATCH 0632/1101] 8349405: Redundant and confusing null checks on data from CP::resolved_klasses Reviewed-by: dholmes, iklam --- src/hotspot/share/oops/constantPool.cpp | 26 +++++++++---------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index f6a94a984cef6..0d3b44351f806 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -589,8 +589,9 @@ void ConstantPool::remove_resolved_klass_if_non_deterministic(int cp_index) { if (!can_archive) { int resolved_klass_index = klass_slot_at(cp_index).resolved_klass_index(); - resolved_klasses()->at_put(resolved_klass_index, nullptr); + // This might be at a safepoint but do this in the right order. tag_at_put(cp_index, JVM_CONSTANT_UnresolvedClass); + resolved_klasses()->at_put(resolved_klass_index, nullptr); } LogStreamHandle(Trace, cds, resolve) log; @@ -669,9 +670,8 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int cp_ind // the unresolved_klasses() array. if (this_cp->tag_at(cp_index).is_klass()) { Klass* klass = this_cp->resolved_klasses()->at(resolved_klass_index); - if (klass != nullptr) { - return klass; - } + assert(klass != nullptr, "must be resolved"); + return klass; } // This tag doesn't change back to unresolved class unless at a safepoint. @@ -724,12 +724,12 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int cp_ind trace_class_resolution(this_cp, k); } - Klass** adr = this_cp->resolved_klasses()->adr_at(resolved_klass_index); - Atomic::release_store(adr, k); // The interpreter assumes when the tag is stored, the klass is resolved // and the Klass* stored in _resolved_klasses is non-null, so we need // hardware store ordering here. // We also need to CAS to not overwrite an error from a racing thread. + Klass** adr = this_cp->resolved_klasses()->adr_at(resolved_klass_index); + Atomic::release_store(adr, k); jbyte old_tag = Atomic::cmpxchg((jbyte*)this_cp->tag_addr_at(cp_index), (jbyte)JVM_CONSTANT_UnresolvedClass, @@ -738,7 +738,7 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int cp_ind // We need to recheck exceptions from racing thread and return the same. if (old_tag == JVM_CONSTANT_UnresolvedClassInError) { // Remove klass. - this_cp->resolved_klasses()->at_put(resolved_klass_index, nullptr); + Atomic::store(adr, (Klass*)nullptr); throw_resolution_error(this_cp, cp_index, CHECK_NULL); } @@ -758,7 +758,7 @@ Klass* ConstantPool::klass_at_if_loaded(const constantPoolHandle& this_cp, int w if (this_cp->tag_at(which).is_klass()) { Klass* k = this_cp->resolved_klasses()->at(resolved_klass_index); - assert(k != nullptr, "should be resolved"); + assert(k != nullptr, "must be resolved"); return k; } else if (this_cp->tag_at(which).is_unresolved_klass_in_error()) { return nullptr; @@ -1147,16 +1147,8 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, // don't trigger resolution if the constant might need it switch (tag.value()) { case JVM_CONSTANT_Class: - { - CPKlassSlot kslot = this_cp->klass_slot_at(cp_index); - int resolved_klass_index = kslot.resolved_klass_index(); - if (this_cp->resolved_klasses()->at(resolved_klass_index) == nullptr) { - (*status_return) = false; - return nullptr; - } - // the klass is waiting in the CP; go get it + assert(this_cp->resolved_klass_at(cp_index) != nullptr, "must be resolved"); break; - } case JVM_CONSTANT_String: case JVM_CONSTANT_Integer: case JVM_CONSTANT_Float: From 9502ab0bf5ce8623776d295ff5260d717dfb9467 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 17 Apr 2025 12:26:15 +0000 Subject: [PATCH 0633/1101] 8354766: Test TestUnexported.java javac build fails Reviewed-by: nbenalla, jpai --- .../jdk/javadoc/doclet/testUnexported/TestUnexported.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/langtools/jdk/javadoc/doclet/testUnexported/TestUnexported.java b/test/langtools/jdk/javadoc/doclet/testUnexported/TestUnexported.java index aae257a0b558e..798a034ae13ec 100644 --- a/test/langtools/jdk/javadoc/doclet/testUnexported/TestUnexported.java +++ b/test/langtools/jdk/javadoc/doclet/testUnexported/TestUnexported.java @@ -27,6 +27,8 @@ * @summary Hide superclasses from conditionally exported packages * @library /tools/lib ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main * @build javadoc.tester.* toolbox.ToolBox * @run main TestUnexported */ From e9c8986a65df534ee2a396cb3b49fe3dbcaf6a44 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 17 Apr 2025 12:31:30 +0000 Subject: [PATCH 0634/1101] 8354493: Opensource Several MultiScreen and Insets related tests Reviewed-by: psadhukhan, tr --- test/jdk/java/awt/Multiscreen/DialogTest.java | 236 ++++++++++++++++++ .../java/awt/Multiscreen/FillThisScreen.java | 140 +++++++++++ .../Multiscreen/IMCandidateWindowTest.java | 104 ++++++++ 3 files changed, 480 insertions(+) create mode 100644 test/jdk/java/awt/Multiscreen/DialogTest.java create mode 100644 test/jdk/java/awt/Multiscreen/FillThisScreen.java create mode 100644 test/jdk/java/awt/Multiscreen/IMCandidateWindowTest.java diff --git a/test/jdk/java/awt/Multiscreen/DialogTest.java b/test/jdk/java/awt/Multiscreen/DialogTest.java new file mode 100644 index 0000000000000..fbd72bfd6f0a1 --- /dev/null +++ b/test/jdk/java/awt/Multiscreen/DialogTest.java @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.Panel; +import java.awt.Point; +import java.awt.ScrollPane; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.WindowConstants; + +import jtreg.SkippedException; + +/* + * @test + * @bug 4368500 + * @key multimon + * @summary Dialog needs a constructor with GraphicsConfiguration + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame + * @run main/manual DialogTest + */ + +public class DialogTest { + static GraphicsDevice[] gds; + + private static Frame f; + private static Frame dummyFrame = new Frame(); + private static Dialog dummyDialog = new Dialog(dummyFrame); + + public static void main(String[] args) throws Exception { + gds = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(); + if (gds.length < 2) { + throw new SkippedException("You have only one monitor in your system" + + " - test skipped"); + } + + String INSTRUCTIONS = """ + This test tests the multiscreen functionality of Dialogs and JDialogs. + You should see the message "X screens detected", where X + is the number of screens on your system. If X is incorrect, press Fail. + + In the test window, there are a list of buttons representing each + type of dialog for each screen. + If there aren't buttons for every screen in your system, press Fail. + + Press each button, and the indicated type of dialog should appear + on the indicated screen. + Modal dialogs should not allow to click on the Instructions or + DialogTest windows. + + The buttons turn yellow once they have been pressed, to keep track + of test progress. + + If all Dialogs appear correctly, press Pass. + If Dialogs appear on the wrong screen or don't behave in + proper modality, press Fail."""; + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .logArea(5) + .testUI(DialogTest::init) + .build() + .awaitAndCheck(); + } + + public static Frame init() { + PassFailJFrame.log(gds.length + " screens detected."); + f = new Frame("DialogTest UI"); + f.setSize(400, 400); + MyScrollPane sp = new MyScrollPane(); + + Panel p = new Panel(); + p.setLayout(new GridLayout(0, 1)); + + for (int i = 0; i < gds.length; i++) { + Button btn; + + //screen # , modal, frame-owned, swing + btn = new MyButton(new DialogInfo(i, false, false, false)); + p.add(btn); + + btn = new MyButton(new DialogInfo(i, true, false, false)); + p.add(btn); + + btn = new MyButton(new DialogInfo(i, false, true, false)); + p.add(btn); + + btn = new MyButton(new DialogInfo(i, true, true, false)); + p.add(btn); + + btn = new MyButton(new DialogInfo(i, false, false, true)); + p.add(btn); + + btn = new MyButton(new DialogInfo(i, true, false, true)); + p.add(btn); + + btn = new MyButton(new DialogInfo(i, false, true, true)); + p.add(btn); + + btn = new MyButton(new DialogInfo(i, true, true, true)); + p.add(btn); + + } + sp.add(p); + f.add(sp); + return f; + } + + static class MyScrollPane extends ScrollPane { + @Override + public Dimension getPreferredSize() { + return f.getSize(); + } + } + + static class MyButton extends Button { + public MyButton(DialogInfo info) { + setLabel(info.toString()); + addActionListener(new PutupDialog(info)); + } + } + + static class PutupDialog implements ActionListener { + DialogInfo info; + + public PutupDialog(DialogInfo info) { + this.info = info; + } + + @Override + public void actionPerformed(ActionEvent e) { + ((Button) (e.getSource())).setBackground(Color.yellow); + Dialog d = info.createDialog(); + d.show(); + } + } + + static class DialogInfo { + int num; + boolean modal; + boolean frameOwned; + boolean swing; + + public DialogInfo(int num, boolean modal, boolean frameOwned, boolean swing) { + this.num = num; + this.modal = modal; + this.frameOwned = frameOwned; + this.swing = swing; + } + + public Dialog createDialog() { + GraphicsConfiguration gc = gds[num].getDefaultConfiguration(); + + Dialog d; + + if (swing) { + if (frameOwned) { + d = new JDialog(dummyFrame, toString(), modal, gc); + } else { + d = new JDialog(dummyDialog, toString(), modal, gc); + } + + ((JDialog) d).setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); + if (modal) { + ((JDialog) d).getContentPane().add(new JLabel("Check that I am modal!")); + } + } else { + if (frameOwned) { + d = new Dialog(dummyFrame, toString(), modal, gc); + } else { + d = new Dialog(dummyDialog, toString(), modal, gc); + } + + d.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + e.getComponent().hide(); + } + }); + if (modal) { + d.add(new Label("Check that I am modal!")); + } + } + + d.setLocation(new Point((int) (gc.getBounds().getX() + 20) + , (int) (gc.getBounds().getY() + 20))); + d.setSize(300, 100); + + return d; + } + + public String toString() { + return "Screen " + num + (frameOwned ? " Frame-owned" : " Dialog-owned") + + (modal ? " modal " : " non-modal ") + + (swing ? "JDialog" : "Dialog"); + } + } +} + + diff --git a/test/jdk/java/awt/Multiscreen/FillThisScreen.java b/test/jdk/java/awt/Multiscreen/FillThisScreen.java new file mode 100644 index 0000000000000..542127827ecd8 --- /dev/null +++ b/test/jdk/java/awt/Multiscreen/FillThisScreen.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.GridLayout; +import java.awt.Rectangle; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import jtreg.SkippedException; + +/* + * @test + * @bug 4356756 + * @key multimon + * @summary Return all screen devices for physical and virtual display devices + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame + * @run main/manual FillThisScreen + */ + +public class FillThisScreen { + private static Frame f; + private static Button b; + private static Rectangle oldSize; + private static boolean fillmode = true; + static GraphicsDevice[] gs; + + public static void main(String[] args) throws Exception { + gs = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(); + if (gs.length < 2) { + throw new SkippedException("You have only one monitor in your system" + + " - test skipped"); + } + + String INSTRUCTIONS = """ + This test is for testing the bounds of a multimonitor system. + You will see a Frame with several buttons: one marked 'Fill + This Screen' and an additional button for each display on your system. + + First, drag the Frame onto each display and click the + 'Fill This Screen' button. + + The Frame should resize to take up the entire display area + of the screen it is on, and the button text changes to say, + 'Get Smaller'. + + Click the button again to restore the Frame. + + Next, use the 'Move to screen' buttons to move the Frame to + each display and again click the 'Fill This Screen' button. + + If the number of 'Move to Screen' buttons is not equals to + the number of screens on your system, the test fails. + + If the Frame always correctly resizes to take up ONLY the + entire screen it is on (and not a different screen, or all + screens), the test passes else it fails."""; + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(FillThisScreen::init) + .build() + .awaitAndCheck(); + } + + public static Frame init() { + Button tempBtn; + + f = new Frame("Drag Me Around"); + f.setLayout(new GridLayout(0, 1)); + + b = new Button("Fill This Screen"); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (fillmode) { + oldSize = f.getBounds(); + Rectangle r = f.getGraphicsConfiguration().getBounds(); + f.setBounds(r); + b.setLabel("Get Smaller"); + } else { + f.setBounds(oldSize); + b.setLabel("Fill This Screen"); + } + fillmode = !fillmode; + } + }); + f.add(b); + + for (int i = 0; i < gs.length; i++) { + tempBtn = new Button("Move to screen:" + i); + tempBtn.addActionListener(new WinMover(i)); + f.add(tempBtn); + } + f.setSize(300, 100); + return f; + } + + private static class WinMover implements ActionListener { + int scrNum; + + public WinMover(int scrNum) { + this.scrNum = scrNum; + } + + public void actionPerformed(ActionEvent e) { + Rectangle newBounds = gs[scrNum].getDefaultConfiguration().getBounds(); + f.setLocation(newBounds.x + newBounds.width / 2, + newBounds.y + newBounds.height / 2); + } + + } +} diff --git a/test/jdk/java/awt/Multiscreen/IMCandidateWindowTest.java b/test/jdk/java/awt/Multiscreen/IMCandidateWindowTest.java new file mode 100644 index 0000000000000..6af3188156db9 --- /dev/null +++ b/test/jdk/java/awt/Multiscreen/IMCandidateWindowTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.FlowLayout; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Rectangle; + +import javax.swing.JFrame; +import javax.swing.JTextField; + +import jtreg.SkippedException; + +/* + * @test + * @bug 4805862 + * @key multimon + * @requires (os.family == "windows") + * @summary Tests IM candidate window is positioned correctly for the + * text components inside a window in multiscreen configurations, if + * this window has negative coordinates + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame + * @run main/manual IMCandidateWindowTest + */ + +public class IMCandidateWindowTest { + static GraphicsConfiguration gc; + + public static void main(String[] args) throws Exception { + GraphicsDevice[] gds = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getScreenDevices(); + if (gds.length < 2) { + throw new SkippedException("You have only one monitor in your system" + + " - test skipped"); + } + + GraphicsDevice gd = null; + + for (int i = 0; i < gds.length; i++) { + gc = gds[i].getDefaultConfiguration(); + if ((gc.getBounds().x < 0) || (gc.getBounds().y < 0)) { + gd = gds[i]; + break; + } + } + + if (gd == null) { + // no screens with negative coords + throw new SkippedException("No screens with negative coords - test skipped"); + } + + String INSTRUCTIONS = """ + This test is for windows + Test requirements: installed support for asian languages + Chinese (PRC) w/ Chinese QuanPing input method. + Multiscreen environment where one of the monitors has negative coords + Go to the text field in the opened Frame. Switch to Chinese language and + start typing "ka". + Note, that IM helper window is appeared. + If this window is appeared near the text field, press PASS button. + If this window is appeared at the edge of the screen or on another + screen, press FAIL button"""; + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(IMCandidateWindowTest::createUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createUI() { + Rectangle b = gc.getBounds(); + + JFrame f = new JFrame("Frame", gc); + f.setBounds(b.x + b.width / 2 - 150, b.y + b.height / 2 - 100, 300, 200); + f.getContentPane().setLayout(new FlowLayout()); + JTextField tf = new JTextField(10); + f.getContentPane().add(tf); + return f; + } +} From 4c99489420bd73159eca6bae22442f7b29156c1d Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Thu, 17 Apr 2025 13:07:19 +0000 Subject: [PATCH 0635/1101] 8354285: Open source Swing tests Batch 3 Reviewed-by: abhiscxk --- .../MotifLAFMenuAcceleratorDelimiter.java | 95 +++++++++++++++++++ .../motif/SplitPane/4141400/bug4141400.java | 71 ++++++++++++++ .../windows/MenuItem/4685843/bug4685843.java | 87 +++++++++++++++++ 3 files changed, 253 insertions(+) create mode 100644 test/jdk/com/sun/java/swing/plaf/motif/MenuItem/AcceleratorDelimiter/MotifLAFMenuAcceleratorDelimiter.java create mode 100644 test/jdk/com/sun/java/swing/plaf/motif/SplitPane/4141400/bug4141400.java create mode 100644 test/jdk/com/sun/java/swing/plaf/windows/MenuItem/4685843/bug4685843.java diff --git a/test/jdk/com/sun/java/swing/plaf/motif/MenuItem/AcceleratorDelimiter/MotifLAFMenuAcceleratorDelimiter.java b/test/jdk/com/sun/java/swing/plaf/motif/MenuItem/AcceleratorDelimiter/MotifLAFMenuAcceleratorDelimiter.java new file mode 100644 index 0000000000000..3d1d9cadd8ac7 --- /dev/null +++ b/test/jdk/com/sun/java/swing/plaf/motif/MenuItem/AcceleratorDelimiter/MotifLAFMenuAcceleratorDelimiter.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4210461 + * @summary Tests that Motif Look & Feel's MenuItem Accelerator Delimiter is + * shown properly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MotifLAFMenuAcceleratorDelimiter + */ + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.KeyStroke; +import javax.swing.UIManager; + +public class MotifLAFMenuAcceleratorDelimiter { + public static void main(String[] args) throws Exception { + try { + UIManager.setLookAndFeel( + "com.sun.java.swing.plaf.motif.MotifLookAndFeel"); + } catch (Exception e) { + throw new RuntimeException("The Motif LAF failed to instantiate"); + } + + String INSTRUCTIONS = """ + The visual design specification for the Motif LAF asks for + a "+" to delimit the other two entities in a menu item's + accelerator. + + As a point of reference, the visual design specifications for the + L&Fs are as follows: JLF/Metal = "-", Mac = "-", Motif = "+", + Windows = "+". + + Click on "Menu" of "MotifLAFMenuAcceleratorDelimiter" window, + make sure it shows MenuItem with label "Hi There! ^+H" or + "Hi There! Ctrl+H". + + If it shows same label test passed otherwise failed. + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(MotifLAFMenuAcceleratorDelimiter::initialize) + .build() + .awaitAndCheck(); + } + + private static JFrame initialize() { + JFrame fr = new JFrame("MotifLAFMenuAcceleratorDelimiter"); + JPanel menuPanel = new JPanel(); + JMenuBar menuBar = new JMenuBar(); + menuBar.setOpaque(true); + JMenu exampleMenu = new JMenu("Menu"); + JMenuItem hiMenuItem = new JMenuItem("Hi There!"); + hiMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, + ActionEvent.CTRL_MASK)); + exampleMenu.add(hiMenuItem); + menuBar.add(exampleMenu); + menuPanel.add(menuBar); + + fr.setLayout(new BorderLayout()); + fr.add(menuPanel, BorderLayout.CENTER); + fr.setSize(250,100); + return fr; + } +} diff --git a/test/jdk/com/sun/java/swing/plaf/motif/SplitPane/4141400/bug4141400.java b/test/jdk/com/sun/java/swing/plaf/motif/SplitPane/4141400/bug4141400.java new file mode 100644 index 0000000000000..2202c7726a3d9 --- /dev/null +++ b/test/jdk/com/sun/java/swing/plaf/motif/SplitPane/4141400/bug4141400.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4141400 + * @summary Tests that the divider of JSplitPane can be moved only by + * dragging its thumb under Motif LAF + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4141400 + */ + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JSplitPane; +import javax.swing.UIManager; + +public class bug4141400 { + public static void main(String[] args) throws Exception { + try { + UIManager.setLookAndFeel( + "com.sun.java.swing.plaf.motif.MotifLookAndFeel"); + } catch (Exception e) { + throw new RuntimeException("Failed to set Motif LAF"); + } + + String INSTRUCTIONS = """ + Place mouse cursor somewhere on the split pane divider, but outside + its thumb. Then try to move the divider. It should not move. If it + does not move, the test passes, otherwise it fails. + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(70) + .testUI(bug4141400::initialize) + .build() + .awaitAndCheck(); + } + + private static JFrame initialize() { + JFrame fr = new JFrame("bug4141400"); + JSplitPane pane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, + true, + new JButton("Button 1"), + new JButton("Button 2")); + fr.add(pane); + fr.setSize(250, 300); + return fr; + } +} diff --git a/test/jdk/com/sun/java/swing/plaf/windows/MenuItem/4685843/bug4685843.java b/test/jdk/com/sun/java/swing/plaf/windows/MenuItem/4685843/bug4685843.java new file mode 100644 index 0000000000000..dbab77aca3f9a --- /dev/null +++ b/test/jdk/com/sun/java/swing/plaf/windows/MenuItem/4685843/bug4685843.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4685843 + * @requires (os.family == "windows") + * @summary Tests that disabled JCheckBoxMenuItem's are drawn properly in + * Windows LAF + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4685843 + */ + +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.UIManager; + +public class bug4685843 { + public static void main(String[] args) throws Exception { + try { + UIManager.setLookAndFeel ( + "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + } catch (Exception e) { + throw new RuntimeException("Failed to set Windows LAF"); + } + + String INSTRUCTIONS = """ + In the window named "bug4685843" open File menu. + If all three disabled items are drawn properly press "Pass". + Otherwise press "Fail". + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(bug4685843::initialize) + .build() + .awaitAndCheck(); + } + + private static JFrame initialize() { + JMenuBar jMenuBar = new JMenuBar(); + JMenu jMenu = new JMenu("File"); + JMenuItem jMenuItem = new JMenuItem("JMenuItem"); + JCheckBoxMenuItem jCheckBoxMenuItem = + new JCheckBoxMenuItem("JCheckBoxMenuItem"); + JRadioButtonMenuItem jRadioButtonMenuItem = + new JRadioButtonMenuItem("JRadioButtonMenuItem"); + + jMenuItem.setEnabled(false); + jMenu.add(jMenuItem); + jCheckBoxMenuItem.setEnabled(false); + jMenu.add(jCheckBoxMenuItem); + jRadioButtonMenuItem.setEnabled(false); + jMenu.add(jRadioButtonMenuItem); + jMenuBar.add(jMenu); + + JFrame mainFrame = new JFrame("bug4685843"); + mainFrame.setJMenuBar(jMenuBar); + mainFrame.setSize(200, 200); + return mainFrame; + } +} From e21387e0454e821e5720e781138dcc4c24a14ec7 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 17 Apr 2025 13:08:49 +0000 Subject: [PATCH 0636/1101] 8354365: Opensource few Modal and Full Screen related tests Reviewed-by: jdv, tr --- test/jdk/ProblemList.txt | 1 + .../NonfocusableFrameFullScreenTest.java | 139 ++++++++++++++++++ .../awt/Modal/AddRemoveTransientForsTest.java | 123 ++++++++++++++++ .../java/awt/Modal/DialogLosesFocusTest.java | 107 ++++++++++++++ .../Modal/NativeDialogToFrontBackTest.java | 118 +++++++++++++++ 5 files changed, 488 insertions(+) create mode 100644 test/jdk/java/awt/FullScreen/NonfocusableFrameFullScreenTest.java create mode 100644 test/jdk/java/awt/Modal/AddRemoveTransientForsTest.java create mode 100644 test/jdk/java/awt/Modal/DialogLosesFocusTest.java create mode 100644 test/jdk/java/awt/Modal/NativeDialogToFrontBackTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index ac4828eadcaf8..4a00130d3aa40 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -391,6 +391,7 @@ java/awt/Modal/MultipleDialogs/MultipleDialogs2Test.java 8198665 macosx-all java/awt/Modal/MultipleDialogs/MultipleDialogs3Test.java 8198665 macosx-all java/awt/Modal/MultipleDialogs/MultipleDialogs4Test.java 8198665 macosx-all java/awt/Modal/MultipleDialogs/MultipleDialogs5Test.java 8198665 macosx-all +java/awt/Modal/NativeDialogToFrontBackTest.java 7188049 windows-all,linux-all java/awt/Mouse/EnterExitEvents/DragWindowOutOfFrameTest.java 8177326 macosx-all java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java 8005021 macosx-all java/awt/Mouse/EnterExitEvents/FullscreenEnterEventTest.java 8051455 macosx-all diff --git a/test/jdk/java/awt/FullScreen/NonfocusableFrameFullScreenTest.java b/test/jdk/java/awt/FullScreen/NonfocusableFrameFullScreenTest.java new file mode 100644 index 0000000000000..a273adff6ccc7 --- /dev/null +++ b/test/jdk/java/awt/FullScreen/NonfocusableFrameFullScreenTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.GraphicsEnvironment; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JPanel; + +/* + * @test + * @bug 6225472 6682536 + * @requires (os.family != "linux") + * @summary Tests that non-focusable Frame in full-screen mode overlaps the task bar. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual NonfocusableFrameFullScreenTest + */ + +public class NonfocusableFrameFullScreenTest extends JPanel { + boolean fullscreen = false; + + public static void main(String[] args) throws Exception { + final String INSTRUCTIONS = """ + 1. Press "Show Frame" button to show a Frame with two buttons. + + 2. Press the button "To Full Screen" to bring the frame to + full-screen mode: + + The frame should overlap the taskbar + + 3. Press "To Windowed" button: + The frame should return to its original size. + The frame shouldn't be alwaysOnTop. + + 4. Press "Set Always On Top" button and make sure the frame + is alwaysOnTop, then press "To Full Screen" button + and then "To Windowed" button: + + The frame should return to its original size keeping alwaysOnTop + state on. + + Press Pass if everything is as expected."""; + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(NonfocusableFrameFullScreenTest::new) + .build() + .awaitAndCheck(); + } + + private NonfocusableFrameFullScreenTest() { + Button b = new Button("Show Frame"); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showFrame(); + } + }); + setLayout(new BorderLayout()); + add(b, BorderLayout.CENTER); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(200, 100); + } + + public void showFrame() { + Frame frame = new Frame("Test Frame"); + + Button button = new Button("To Full Screen"); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (fullscreen) { + GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(). + setFullScreenWindow(null); + button.setLabel("To Full Screen"); + fullscreen = false; + } else { + GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(). + setFullScreenWindow(frame); + button.setLabel("To Windowed"); + fullscreen = true; + } + frame.validate(); + } + }); + + Button button2 = new Button("Set Always On Top"); + button2.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (frame.isAlwaysOnTop()) { + button2.setLabel("Set Always On Top"); + frame.setAlwaysOnTop(false); + } else { + button2.setLabel("Set Not Always On Top"); + frame.setAlwaysOnTop(true); + } + frame.validate(); + } + }); + + frame.setLayout(new BorderLayout()); + frame.add(button, BorderLayout.WEST); + frame.add(button2, BorderLayout.EAST); + frame.setBounds(400, 200, 350, 100); + frame.setFocusableWindowState(false); + frame.setVisible(true); + } +} diff --git a/test/jdk/java/awt/Modal/AddRemoveTransientForsTest.java b/test/jdk/java/awt/Modal/AddRemoveTransientForsTest.java new file mode 100644 index 0000000000000..65b66e8ce8df5 --- /dev/null +++ b/test/jdk/java/awt/Modal/AddRemoveTransientForsTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Button; +import java.awt.Dialog; +import java.awt.Frame; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; + +/* + * @test + * @bug 6271779 + * @summary This test shows and hides a modal dialog several times without destroying its + * peer. Without the fix this may lead to application (or even WM) hang. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AddRemoveTransientForsTest + */ + +public class AddRemoveTransientForsTest { + + private static Dialog d1; + private static Dialog d2; + + public static void main(String[] args) throws Exception { + final String INSTRUCTIONS = """ + When the test starts, a frame is shown with a button 'Show Dialog D1'. + + 1. Press the button 'Show Dialog D1' to show a modal dialog D1 with a button + 'Show dialog D2'. + + 2. Press the button 'Show dialog D2' to show another modal dialog D2 with a button + 'Close'. + + 3. Press the button 'Close' to close dialog D2. + + 4. Repeat steps 2 and 3 several times (at least 3-4 times). + + If the application is not hung, press Pass. + + NOTE: all the modal dialogs must be closed before pressing Pass button."""; + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(AddRemoveTransientForsTest::init) + .build() + .awaitAndCheck(); + } + + public static Frame init() { + Frame f = new Frame("AddRemoveTransientForsTest Frame"); + Button b = new Button("Show dialog D1"); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) + { + d1.setVisible(true); + } + }); + f.add(b); + f.setSize(200, 100); + + WindowListener wl = new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) + { + e.getWindow().dispose(); + } + }; + + d1 = new Dialog(f, "D1", true); + d1.setBounds(200, 200, 200, 100); + d1.addWindowListener(wl); + Button b1 = new Button("Show dialog D2"); + b1.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) + { + d2.setVisible(true); + } + }); + d1.add(b1); + + d2 = new Dialog(d1, "D2", true); + d2.setBounds(300, 300, 200, 100); + Button b2 = new Button("Close"); + b2.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) + { + d2.setVisible(false); + } + }); + d2.add(b2); + + return f; + } +} diff --git a/test/jdk/java/awt/Modal/DialogLosesFocusTest.java b/test/jdk/java/awt/Modal/DialogLosesFocusTest.java new file mode 100644 index 0000000000000..738c2c29ee2b2 --- /dev/null +++ b/test/jdk/java/awt/Modal/DialogLosesFocusTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.Frame; + +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; + +/* + * @test + * @bug 6278150 + * @key headful + * @summary Initially modal blocked window causes modal dialog to lose focus + * @run main DialogLosesFocusTest + */ + +public class DialogLosesFocusTest { + private static Frame parent; + private static Dialog dialog; + private static Frame blocked; + private static volatile boolean failed; + + public static void main(String[] args) throws Exception { + try { + createAndShowUI(); + + sleepForMsecs(10000); + + if (failed) { + throw new RuntimeException("Test Failed"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (parent != null) { + parent.dispose(); + } + if (dialog != null) { + dialog.dispose(); + } + if (blocked != null) { + blocked.dispose(); + } + }); + } + } + + public static void createAndShowUI() throws Exception { + EventQueue.invokeAndWait(() -> { + parent = new Frame("Parent frame"); + parent.setBounds(0, 0, 300, 100); + parent.setVisible(true); + }); + + sleepForMsecs(1000); + + EventQueue.invokeLater(() -> { + dialog = new Dialog(parent, "Modal dialog", Dialog.ModalityType.APPLICATION_MODAL); + dialog.setBounds(100, 120, 300, 100); + dialog.setVisible(true); + }); + + sleepForMsecs(1000); + + EventQueue.invokeAndWait(() -> { + blocked = new Frame("Blocked frame"); + blocked.setBounds(200, 240, 300, 100); + blocked.addWindowListener(new WindowAdapter() { + @Override + public void windowActivated(WindowEvent we) { + if (dialog.isVisible()) { + failed = true; + } + } + }); + blocked.setVisible(true); + }); + } + + private static void sleepForMsecs(int t) { + try { + Thread.sleep(t); + } catch (Exception z) {} + } +} diff --git a/test/jdk/java/awt/Modal/NativeDialogToFrontBackTest.java b/test/jdk/java/awt/Modal/NativeDialogToFrontBackTest.java new file mode 100644 index 0000000000000..6c41ef73b1e7b --- /dev/null +++ b/test/jdk/java/awt/Modal/NativeDialogToFrontBackTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Dialog; +import java.awt.FileDialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.util.List; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.print.PageFormat; +import java.awt.print.PrinterJob; + +/* + * @test + * @bug 6393608 + * @summary Tests that toBack/toFront methods works correctly for native dialogs + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual NativeDialogToFrontBackTest + */ + +public class NativeDialogToFrontBackTest { + public static void main(String[] args) throws Exception { + final String INSTRUCTIONS = """ + When the test starts two frames appear: 'Control' and 'Blocked' + 1. Click on the 'Show file dialog' button + 2. Drag the file dialog so it partially overlaps the 'Blocked' frame + 3. 'Blocked' frame must be below the file dialog, if not - press Fail + 3. Click on the 'Blocked to front' button + 4. 'Blocked' frame must still be below the file dialog, if not - press Fail + 5. Close the file dialog + 6. Repeat steps 2 to 4 with print and page dialogs using the corresponding button + 7. If 'Blocked' frame is always below File/Print/Page dialog, press Pass"""; + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(NativeDialogToFrontBackTest::init) + .positionTestUI(WindowLayouts::rightOneColumn) + .build() + .awaitAndCheck(); + } + + public static List init() { + Frame blocked = new Frame("Blocked"); + blocked.setSize(200, 200); + + Frame control = new Frame("Control"); + control.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE); + control.setLayout(new FlowLayout()); + + Button showFileDialog = new Button("Show file dialog"); + showFileDialog.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) + { + new FileDialog(control, "File dialog").setVisible(true); + } + }); + control.add(showFileDialog); + + Button showPrintDialog = new Button("Show print dialog"); + showPrintDialog.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) + { + PrinterJob.getPrinterJob().printDialog(); + } + }); + control.add(showPrintDialog); + + Button showPageDialog = new Button("Show page dialog"); + showPageDialog.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) + { + PrinterJob.getPrinterJob().pageDialog(new PageFormat()); + } + }); + control.add(showPageDialog); + + Button blockedToFront = new Button("Blocked to front"); + blockedToFront.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) + { + blocked.toFront(); + } + }); + control.add(blockedToFront); + + control.setSize(200, 200); + return List.of(control, blocked); + } +} From dda4b5a4ade2e5d7225117e58fce4038bb0e0f1b Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Thu, 17 Apr 2025 13:36:05 +0000 Subject: [PATCH 0637/1101] 8354418: Open source Swing tests Batch 4 Reviewed-by: abhiscxk --- .../WindowsLAFMenuAcceleratorDelimiter.java | 95 ++++++++++++++++++ .../4227768/bug4227768.java | 99 +++++++++++++++++++ .../4305725/bug4305725.java | 97 ++++++++++++++++++ 3 files changed, 291 insertions(+) create mode 100644 test/jdk/com/sun/java/swing/plaf/windows/MenuItem/AcceleratorDelimiter/WindowsLAFMenuAcceleratorDelimiter.java create mode 100644 test/jdk/com/sun/java/swing/plaf/windows/WindowsDesktopManager/4227768/bug4227768.java create mode 100644 test/jdk/com/sun/java/swing/plaf/windows/WindowsDesktopManager/4305725/bug4305725.java diff --git a/test/jdk/com/sun/java/swing/plaf/windows/MenuItem/AcceleratorDelimiter/WindowsLAFMenuAcceleratorDelimiter.java b/test/jdk/com/sun/java/swing/plaf/windows/MenuItem/AcceleratorDelimiter/WindowsLAFMenuAcceleratorDelimiter.java new file mode 100644 index 0000000000000..adb1d93c9fe91 --- /dev/null +++ b/test/jdk/com/sun/java/swing/plaf/windows/MenuItem/AcceleratorDelimiter/WindowsLAFMenuAcceleratorDelimiter.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4210461 + * @requires (os.family == "windows") + * @summary Tests that Windows Look & Feel's MenuItem Accelerator Delimiter is + * shown properly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual WindowsLAFMenuAcceleratorDelimiter + */ + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.KeyStroke; +import javax.swing.UIManager; + +public class WindowsLAFMenuAcceleratorDelimiter { + public static void main(String[] args) throws Exception { + try { + UIManager.setLookAndFeel( + "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + } catch (Exception e) { + throw new RuntimeException("The Windows LAF failed to instantiate"); + } + + String INSTRUCTIONS = """ + The visual design specification for the Windows LAF asks for + a "+" to delimit the other two entities in a menuitem's + accelerator. + + As a point of reference, the visual design specifications for the + L&Fs are as follows: JLF/Metal = "-", Mac = "-", Motif = "+", + Windows = "+". + + Click on "Menu" of "WindowsLAFMenuAcceleratorDelimiter" window, + make sure it shows MenuItem with label "Hi There! Ctrl+H". + + If it shows same label test passed otherwise failed. + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(WindowsLAFMenuAcceleratorDelimiter::initialize) + .build() + .awaitAndCheck(); + } + + private static JFrame initialize() { + JFrame fr = new JFrame("WindowsLAFMenuAcceleratorDelimiter"); + JPanel menuPanel = new JPanel(); + JMenuBar menuBar = new JMenuBar(); + menuBar.setOpaque(true); + JMenu exampleMenu = new JMenu("Menu"); + JMenuItem hiMenuItem = new JMenuItem("Hi There!"); + hiMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, + ActionEvent.CTRL_MASK)); + exampleMenu.add(hiMenuItem); + menuBar.add(exampleMenu); + menuPanel.add(menuBar); + + fr.setLayout(new BorderLayout()); + fr.add(menuPanel, BorderLayout.CENTER); + fr.setSize(250, 100); + return fr; + } +} diff --git a/test/jdk/com/sun/java/swing/plaf/windows/WindowsDesktopManager/4227768/bug4227768.java b/test/jdk/com/sun/java/swing/plaf/windows/WindowsDesktopManager/4227768/bug4227768.java new file mode 100644 index 0000000000000..ef9cc90bea066 --- /dev/null +++ b/test/jdk/com/sun/java/swing/plaf/windows/WindowsDesktopManager/4227768/bug4227768.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4227768 + * @requires (os.family == "windows") + * @summary Tests Z-ordering of Windows Look-and-Feel JInternalFrames + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4227768 + */ + +import java.awt.Dimension; +import java.awt.Toolkit; +import java.beans.PropertyVetoException; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.UIManager; + +public class bug4227768 { + private static JDesktopPane desktop ; + private static JFrame frame; + private static int openFrameCount = 0; + private static final int xOffset = 30; + private static final int yOffset = 30; + + public static void main(String[] args) throws Exception { + try { + UIManager.setLookAndFeel + ("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + } catch (Exception e) { + throw new RuntimeException("Failed to set Windows LAF"); + } + + String INSTRUCTIONS = """ + Close the internal frame titled "Document #4". The internal frame + titled "Document #3" should get active. Now close the internal + frame titled "Document #2". The internal frame titled "Document #3" + should remain active. If something is not like this, then test + failed. Otherwise test succeeded. + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4227768::initialize) + .build() + .awaitAndCheck(); + } + + private static JFrame initialize() { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + frame = new JFrame("bug4227768"); + frame.setSize(screenSize.width / 3, screenSize.height / 3); + frame.add(desktop = new JDesktopPane()); + createFrame(); + createFrame(); + createFrame(); + createFrame(); + desktop.putClientProperty("JDesktopPane.dragMode", "outline"); + return frame; + } + + protected static void createFrame() { + JInternalFrame internalFrame = new JInternalFrame + ("Document #" + (++openFrameCount), true, true, true, true); + internalFrame.setSize(frame.getWidth() / 2, frame.getHeight() / 2); + internalFrame.setLocation(xOffset * openFrameCount, + yOffset * openFrameCount); + desktop.add(internalFrame); + internalFrame.setVisible(true); + try { + internalFrame.setSelected(true); + } catch (PropertyVetoException e) { + throw new RuntimeException(e); + } + } +} diff --git a/test/jdk/com/sun/java/swing/plaf/windows/WindowsDesktopManager/4305725/bug4305725.java b/test/jdk/com/sun/java/swing/plaf/windows/WindowsDesktopManager/4305725/bug4305725.java new file mode 100644 index 0000000000000..4b9a462c47261 --- /dev/null +++ b/test/jdk/com/sun/java/swing/plaf/windows/WindowsDesktopManager/4305725/bug4305725.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4305725 + * @requires (os.family == "windows") + * @summary Tests if in Win LAF the JOptionPane.showInternalMessageDialog() is + * not maximized to match background maximized internal frame. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4305725 + */ + +import java.awt.Dimension; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.UIManager; + +public class bug4305725 implements ActionListener { + private static JDesktopPane desktop ; + + public static void main(String[] args) throws Exception { + try { + UIManager.setLookAndFeel + ("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + } catch (Exception e) { + throw new RuntimeException("Failed to set Windows LAF"); + } + + String INSTRUCTIONS = """ + Maximize the internal frame, then call Exit from File menu. + You will see a message box. If message box is also the size of + internal frame, then test failed. If it is of usual size, + then test is passed. + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4305725::initialize) + .build() + .awaitAndCheck(); + } + + private static JFrame initialize() { + JFrame frame = new JFrame("bug4305725"); + frame.add(desktop = new JDesktopPane()); + JMenuBar mb = new JMenuBar() ; + JMenu menu = new JMenu("File"); + mb.add(menu) ; + JMenuItem menuItem = menu.add(new JMenuItem("Exit")); + menuItem.addActionListener(new bug4305725()) ; + frame.setJMenuBar(mb) ; + Dimension sDim = Toolkit.getDefaultToolkit().getScreenSize(); + frame.setSize(sDim.width / 2, sDim.height / 2) ; + JInternalFrame internalFrame = new JInternalFrame + ("Internal", true, true, true, true); + internalFrame.setSize(frame.getWidth(), frame.getHeight() / 2); + internalFrame.setVisible(true); + desktop.add(internalFrame, JLayeredPane.FRAME_CONTENT_LAYER); + return frame; + } + + @Override + public void actionPerformed(ActionEvent aEvent) { + JOptionPane.showInternalMessageDialog(desktop, "Exiting test app"); + } +} From abb23828f9dc5f4cdb75d5b924dd6f45925102cd Mon Sep 17 00:00:00 2001 From: Artur Barashev Date: Thu, 17 Apr 2025 13:45:47 +0000 Subject: [PATCH 0638/1101] 8350807: Certificates using MD5 algorithm that are disabled by default are incorrectly allowed in TLSv1.3 when re-enabled Reviewed-by: mullan --- .../security/ssl/CertSignAlgsExtension.java | 19 +- .../sun/security/ssl/CertificateMessage.java | 120 ++++----- .../sun/security/ssl/CertificateRequest.java | 18 +- .../classes/sun/security/ssl/ClientHello.java | 6 +- .../security/ssl/PreSharedKeyExtension.java | 9 +- .../classes/sun/security/ssl/ServerHello.java | 43 +--- .../security/ssl/SessionTicketExtension.java | 9 +- .../ssl/SignatureAlgorithmsExtension.java | 22 +- .../sun/security/ssl/SignatureScheme.java | 33 ++- .../CriticalSubjectAltName.java | 3 +- .../net/ssl/templates/SSLSocketTemplate.java | 6 +- .../HttpsURLConnection/DNSIdentities.java | 4 +- .../IPAddressIPIdentities.java | 4 +- .../HttpsURLConnection/IPIdentities.java | 4 +- .../https/HttpsURLConnection/Identities.java | 4 +- ...NotAllowedInTLS13CertificateSignature.java | 231 ++++++++++++++++++ 16 files changed, 352 insertions(+), 183 deletions(-) create mode 100644 test/jdk/sun/security/ssl/SignatureScheme/MD5NotAllowedInTLS13CertificateSignature.java diff --git a/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java b/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java index 2772ecff337fd..b975290d09d85 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java @@ -99,13 +99,7 @@ public byte[] produce(ConnectionContext context, } // Produce the extension. - if (chc.localSupportedCertSignAlgs == null) { - chc.localSupportedCertSignAlgs = - SignatureScheme.getSupportedAlgorithms( - chc.sslConfig, - chc.algorithmConstraints, chc.activeProtocols, - CERTIFICATE_SCOPE); - } + SignatureScheme.updateHandshakeLocalSupportedAlgs(chc); int vectorLen = SignatureScheme.sizeInRecord() * chc.localSupportedCertSignAlgs.size(); @@ -245,15 +239,8 @@ public byte[] produce(ConnectionContext context, } // Produce the extension. - if (shc.localSupportedCertSignAlgs == null) { - shc.localSupportedCertSignAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, - List.of(shc.negotiatedProtocol), - CERTIFICATE_SCOPE); - } - + // localSupportedCertSignAlgs has been already updated when we set + // the negotiated protocol. int vectorLen = SignatureScheme.sizeInRecord() * shc.localSupportedCertSignAlgs.size(); byte[] extData = new byte[vectorLen + 2]; diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java index cdb65bd329a14..c055673b45ba2 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -697,46 +697,6 @@ private static void checkClientCerts(ServerHandshakeContext shc, } } - /** - * When a failure happens during certificate checking from an - * {@link X509TrustManager}, determine what TLS alert description - * to use. - * - * @param cexc The exception thrown by the {@link X509TrustManager} - * - * @return A byte value corresponding to a TLS alert description number. - */ - private static Alert getCertificateAlert( - ClientHandshakeContext chc, CertificateException cexc) { - // The specific reason for the failure will determine how to - // set the alert description value - Alert alert = Alert.CERTIFICATE_UNKNOWN; - - Throwable baseCause = cexc.getCause(); - if (baseCause instanceof CertPathValidatorException cpve) { - Reason reason = cpve.getReason(); - if (reason == BasicReason.REVOKED) { - alert = chc.staplingActive ? - Alert.BAD_CERT_STATUS_RESPONSE : - Alert.CERTIFICATE_REVOKED; - } else if ( - reason == BasicReason.UNDETERMINED_REVOCATION_STATUS) { - alert = chc.staplingActive ? - Alert.BAD_CERT_STATUS_RESPONSE : - Alert.CERTIFICATE_UNKNOWN; - } else if (reason == BasicReason.ALGORITHM_CONSTRAINED) { - alert = Alert.UNSUPPORTED_CERTIFICATE; - } else if (reason == BasicReason.EXPIRED) { - alert = Alert.CERTIFICATE_EXPIRED; - } else if (reason == BasicReason.INVALID_SIGNATURE || - reason == BasicReason.NOT_YET_VALID) { - alert = Alert.BAD_CERTIFICATE; - } - } - - return alert; - } - } /** @@ -1329,37 +1289,57 @@ private static X509Certificate[] checkServerCerts( return certs; } - /** - * When a failure happens during certificate checking from an - * {@link X509TrustManager}, determine what TLS alert description - * to use. - * - * @param cexc The exception thrown by the {@link X509TrustManager} - * - * @return A byte value corresponding to a TLS alert description number. - */ - private static Alert getCertificateAlert( - ClientHandshakeContext chc, CertificateException cexc) { - // The specific reason for the failure will determine how to - // set the alert description value - Alert alert = Alert.CERTIFICATE_UNKNOWN; - - Throwable baseCause = cexc.getCause(); - if (baseCause instanceof CertPathValidatorException cpve) { - Reason reason = cpve.getReason(); - if (reason == BasicReason.REVOKED) { - alert = chc.staplingActive ? - Alert.BAD_CERT_STATUS_RESPONSE : - Alert.CERTIFICATE_REVOKED; - } else if ( - reason == BasicReason.UNDETERMINED_REVOCATION_STATUS) { - alert = chc.staplingActive ? - Alert.BAD_CERT_STATUS_RESPONSE : - Alert.CERTIFICATE_UNKNOWN; + } + + /** + * When a failure happens during certificate checking from an + * {@link X509TrustManager}, determine what TLS alert description + * to use. + * + * @param cexc The exception thrown by the {@link X509TrustManager} + * @return A byte value corresponding to a TLS alert description number. + */ + private static Alert getCertificateAlert( + ClientHandshakeContext chc, CertificateException cexc) { + // The specific reason for the failure will determine how to + // set the alert description value + Alert alert = Alert.CERTIFICATE_UNKNOWN; + + Throwable baseCause = cexc.getCause(); + if (baseCause instanceof CertPathValidatorException cpve) { + Reason reason = cpve.getReason(); + if (reason == BasicReason.REVOKED) { + alert = chc.staplingActive ? + Alert.BAD_CERT_STATUS_RESPONSE : + Alert.CERTIFICATE_REVOKED; + } else if (reason == BasicReason.UNDETERMINED_REVOCATION_STATUS) { + alert = chc.staplingActive ? + Alert.BAD_CERT_STATUS_RESPONSE : + Alert.CERTIFICATE_UNKNOWN; + } else if (reason == BasicReason.EXPIRED) { + alert = Alert.CERTIFICATE_EXPIRED; + } else if (reason == BasicReason.INVALID_SIGNATURE + || reason == BasicReason.NOT_YET_VALID) { + alert = Alert.BAD_CERTIFICATE; + } else if (reason == BasicReason.ALGORITHM_CONSTRAINED) { + alert = Alert.UNSUPPORTED_CERTIFICATE; + + // Per TLSv1.3 RFC we MUST abort the handshake with a + // "bad_certificate" alert if we reject certificate + // because of the signature using MD5 or SHA1 algorithm. + if (chc.negotiatedProtocol != null + && chc.negotiatedProtocol.useTLS13PlusSpec()) { + final String exMsg = cexc.getMessage().toUpperCase(); + + if (exMsg.contains("MD5WITH") + || exMsg.contains("SHA1WITH")) { + alert = Alert.BAD_CERTIFICATE; + } } } - - return alert; } + + return alert; } + } diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java index 062d4d77a5851..66b8c0487032f 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java @@ -636,25 +636,11 @@ public byte[] produce(ConnectionContext context, // The producing happens in server side only. ServerHandshakeContext shc = (ServerHandshakeContext) context; - if (shc.localSupportedSignAlgs == null) { - shc.localSupportedSignAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols, - HANDSHAKE_SCOPE); - } - - if (shc.localSupportedCertSignAlgs == null) { - shc.localSupportedCertSignAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols, - CERTIFICATE_SCOPE); - } - // According to TLSv1.2 RFC, CertificateRequest message must // contain signature schemes supported for both: // handshake signatures and certificate signatures. + // localSupportedSignAlgs and localSupportedCertSignAlgs have been + // already updated when we set the negotiated protocol. List certReqSignAlgs = new ArrayList<>(shc.localSupportedSignAlgs); certReqSignAlgs.retainAll(shc.localSupportedCertSignAlgs); diff --git a/src/java.base/share/classes/sun/security/ssl/ClientHello.java b/src/java.base/share/classes/sun/security/ssl/ClientHello.java index e75076b11d64f..3e43921520df0 100644 --- a/src/java.base/share/classes/sun/security/ssl/ClientHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ClientHello.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -825,6 +825,10 @@ private void onClientHello(ServerHandshakeContext context, "Negotiated protocol version: " + negotiatedProtocol.name); } + // Protocol version is negotiated, update locally supported + // signature schemes according to the protocol being used. + SignatureScheme.updateHandshakeLocalSupportedAlgs(context); + // Consume the handshake message for the specific protocol version. if (negotiatedProtocol.isDTLS) { if (negotiatedProtocol.useTLS13PlusSpec()) { diff --git a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java index 9e843a0e4a564..4751708e5dc88 100644 --- a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java @@ -42,7 +42,6 @@ import sun.security.util.HexDumpEncoder; import static sun.security.ssl.SSLExtension.*; -import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE; /** * Pack of the "pre_shared_key" extension. @@ -445,13 +444,7 @@ private static boolean canRejoin(ClientHelloMessage clientHello, // localSupportedCertSignAlgs field is populated. This is particularly // important when client authentication was used in an initial session, // and it is now being resumed. - if (shc.localSupportedCertSignAlgs == null) { - shc.localSupportedCertSignAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols, - CERTIFICATE_SCOPE); - } + SignatureScheme.updateHandshakeLocalSupportedAlgs(shc); // Validate the required client authentication. if (result && diff --git a/src/java.base/share/classes/sun/security/ssl/ServerHello.java b/src/java.base/share/classes/sun/security/ssl/ServerHello.java index f19964dd5c7b8..303095a072290 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerHello.java @@ -25,9 +25,6 @@ package sun.security.ssl; -import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE; -import static sun.security.ssl.SignatureScheme.HANDSHAKE_SCOPE; - import java.io.IOException; import java.nio.ByteBuffer; import java.security.AlgorithmConstraints; @@ -272,22 +269,6 @@ public byte[] produce(ConnectionContext context, "Not resumption, and no new session is allowed"); } - if (shc.localSupportedSignAlgs == null) { - shc.localSupportedSignAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols, - HANDSHAKE_SCOPE); - } - - if (shc.localSupportedCertSignAlgs == null) { - shc.localSupportedCertSignAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols, - CERTIFICATE_SCOPE); - } - SSLSessionImpl session = new SSLSessionImpl(shc, CipherSuite.C_NULL); session.setMaximumPacketSize(shc.sslConfig.maximumPacketSize); @@ -522,22 +503,6 @@ public byte[] produce(ConnectionContext context, "Not resumption, and no new session is allowed"); } - if (shc.localSupportedSignAlgs == null) { - shc.localSupportedSignAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols, - HANDSHAKE_SCOPE); - } - - if (shc.localSupportedCertSignAlgs == null) { - shc.localSupportedCertSignAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols, - CERTIFICATE_SCOPE); - } - SSLSessionImpl session = new SSLSessionImpl(shc, CipherSuite.C_NULL); session.setMaximumPacketSize(shc.sslConfig.maximumPacketSize); @@ -959,6 +924,10 @@ private void onHelloRetryRequest(ClientHandshakeContext chc, "Negotiated protocol version: " + serverVersion.name); } + // Protocol version is negotiated, update locally supported + // signature schemes according to the protocol being used. + SignatureScheme.updateHandshakeLocalSupportedAlgs(chc); + // TLS 1.3 key share extension may have produced client // possessions for TLS 1.3 key exchanges. // @@ -1010,6 +979,10 @@ private void onServerHello(ClientHandshakeContext chc, "Negotiated protocol version: " + serverVersion.name); } + // Protocol version is negotiated, update locally supported + // signature schemes according to the protocol being used. + SignatureScheme.updateHandshakeLocalSupportedAlgs(chc); + if (serverHello.serverRandom.isVersionDowngrade(chc)) { throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, "A potential protocol version downgrade attack"); diff --git a/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java b/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java index 60f630ccbd2a4..6cf930619f7a3 100644 --- a/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java @@ -40,7 +40,6 @@ import static sun.security.ssl.SSLExtension.CH_SESSION_TICKET; import static sun.security.ssl.SSLExtension.SH_SESSION_TICKET; -import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE; import sun.security.ssl.SSLExtension.ExtensionConsumer; import sun.security.ssl.SSLExtension.SSLExtensionSpec; @@ -353,13 +352,7 @@ public byte[] produce(ConnectionContext context, return new byte[0]; } - if (chc.localSupportedCertSignAlgs == null) { - chc.localSupportedCertSignAlgs = - SignatureScheme.getSupportedAlgorithms( - chc.sslConfig, - chc.algorithmConstraints, chc.activeProtocols, - CERTIFICATE_SCOPE); - } + SignatureScheme.updateHandshakeLocalSupportedAlgs(chc); return chc.resumingSession.getPskIdentity(); } diff --git a/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java b/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java index 2b36d35e78d5a..80029e73afb18 100644 --- a/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java @@ -187,13 +187,7 @@ public byte[] produce(ConnectionContext context, } // Produce the extension. - if (chc.localSupportedSignAlgs == null) { - chc.localSupportedSignAlgs = - SignatureScheme.getSupportedAlgorithms( - chc.sslConfig, - chc.algorithmConstraints, chc.activeProtocols, - HANDSHAKE_SCOPE); - } + SignatureScheme.updateHandshakeLocalSupportedAlgs(chc); int vectorLen = SignatureScheme.sizeInRecord() * chc.localSupportedSignAlgs.size(); @@ -417,18 +411,14 @@ public byte[] produce(ConnectionContext context, } // Produce the extension. - List sigAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, - List.of(shc.negotiatedProtocol), - HANDSHAKE_SCOPE); - - int vectorLen = SignatureScheme.sizeInRecord() * sigAlgs.size(); + // localSupportedSignAlgs has been already updated when we + // set the negotiated protocol. + int vectorLen = SignatureScheme.sizeInRecord() + * shc.localSupportedSignAlgs.size(); byte[] extData = new byte[vectorLen + 2]; ByteBuffer m = ByteBuffer.wrap(extData); Record.putInt16(m, vectorLen); - for (SignatureScheme ss : sigAlgs) { + for (SignatureScheme ss : shc.localSupportedSignAlgs) { Record.putInt16(m, ss.id); } diff --git a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java index b817cc3fb9d5b..b3ed5810c56b3 100644 --- a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java +++ b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java @@ -374,9 +374,40 @@ private boolean isPermitted( && (namedGroup == null || namedGroup.isPermitted(constraints)); } + // Helper method to update all locally supported signature schemes for + // a given HandshakeContext. + static void updateHandshakeLocalSupportedAlgs(HandshakeContext hc) { + // To improve performance we only update when necessary. + // No need to do anything if we already computed the local supported + // algorithms and either there is no negotiated protocol yet or the + // only active protocol ends up to be the negotiated protocol. + if (hc.localSupportedSignAlgs != null + && hc.localSupportedCertSignAlgs != null + && (hc.negotiatedProtocol == null + || hc.activeProtocols.size() == 1)) { + return; + } + + List protocols = hc.negotiatedProtocol != null ? + List.of(hc.negotiatedProtocol) : + hc.activeProtocols; + + hc.localSupportedSignAlgs = getSupportedAlgorithms( + hc.sslConfig, + hc.algorithmConstraints, + protocols, + HANDSHAKE_SCOPE); + + hc.localSupportedCertSignAlgs = getSupportedAlgorithms( + hc.sslConfig, + hc.algorithmConstraints, + protocols, + CERTIFICATE_SCOPE); + } + // Get local supported algorithm collection complying to algorithm // constraints and SSL scopes. - static List getSupportedAlgorithms( + private static List getSupportedAlgorithms( SSLConfiguration config, SSLAlgorithmConstraints constraints, List activeProtocols, diff --git a/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java b/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java index d4eca8b577646..cb11b17ebb5f3 100644 --- a/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java +++ b/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -105,6 +105,7 @@ void doServerSide() throws Exception { (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); SSLServerSocket sslServerSocket = (SSLServerSocket) sslssf.createServerSocket(serverPort); + sslServerSocket.setEnabledProtocols(new String[]{"TLSv1.2"}); serverPort = sslServerSocket.getLocalPort(); /* diff --git a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java index b67f897830473..ce1a99a7f1efa 100644 --- a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java +++ b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -245,7 +245,7 @@ protected void doClientSide() throws Exception { // // The server side takes care of the issue if the server cannot // get started in 90 seconds. The client side would just ignore - // the test case if the serer is not ready. + // the test case if the server is not ready. boolean serverIsReady = serverCondition.await(90L, TimeUnit.SECONDS); if (!serverIsReady) { @@ -378,7 +378,7 @@ private void bootup() throws Exception { * Check various exception conditions. */ if ((local != null) && (remote != null)) { - // If both failed, return the curthread's exception. + // If both failed, return the current thread's exception. local.addSuppressed(remote); exception = local; } else if (local != null) { diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java index 0d479d60fd271..4b2dece0c75a7 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -893,7 +893,7 @@ private static SSLContext getSSLContext(String trusedCertStr, TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); tmf.init(ks); - SSLContext ctx = SSLContext.getInstance("TLS"); + SSLContext ctx = SSLContext.getInstance("TLSv1.2"); if (keyCertStr != null) { KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java index bd6c62c603ca1..a15093c821ece 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -901,7 +901,7 @@ private static SSLContext getSSLContext(String trusedCertStr, TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); tmf.init(ks); - SSLContext ctx = SSLContext.getInstance("TLS"); + SSLContext ctx = SSLContext.getInstance("TLSv1.2"); if (keyCertStr != null) { KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java index 91f0020f7d124..6ea6252656623 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -900,7 +900,7 @@ private static SSLContext getSSLContext(String trusedCertStr, TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); tmf.init(ks); - SSLContext ctx = SSLContext.getInstance("TLS"); + SSLContext ctx = SSLContext.getInstance("TLSv1.2"); if (keyCertStr != null) { KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Identities.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Identities.java index 3764b3de68819..53960c058959c 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Identities.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Identities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -893,7 +893,7 @@ private static SSLContext getSSLContext(String trusedCertStr, TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); tmf.init(ks); - SSLContext ctx = SSLContext.getInstance("TLS"); + SSLContext ctx = SSLContext.getInstance("TLSv1.2"); if (keyCertStr != null) { KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); diff --git a/test/jdk/sun/security/ssl/SignatureScheme/MD5NotAllowedInTLS13CertificateSignature.java b/test/jdk/sun/security/ssl/SignatureScheme/MD5NotAllowedInTLS13CertificateSignature.java new file mode 100644 index 0000000000000..ed61aace3f476 --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/MD5NotAllowedInTLS13CertificateSignature.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8350807 + * @summary Certificates using MD5 algorithm that are disabled by default are + * incorrectly allowed in TLSv1.3 when re-enabled. + * @modules java.base/sun.security.x509 + * java.base/sun.security.util + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm MD5NotAllowedInTLS13CertificateSignature + */ + +import static jdk.test.lib.Asserts.assertEquals; +import static jdk.test.lib.Asserts.assertTrue; +import static jdk.test.lib.Utils.runAndCheckException; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import java.util.List; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.TrustManagerFactory; +import jdk.test.lib.security.CertificateBuilder; +import jdk.test.lib.security.SecurityUtils; +import sun.security.x509.AuthorityKeyIdentifierExtension; +import sun.security.x509.GeneralName; +import sun.security.x509.GeneralNames; +import sun.security.x509.KeyIdentifier; +import sun.security.x509.SerialNumber; +import sun.security.x509.X500Name; + +public class MD5NotAllowedInTLS13CertificateSignature extends + SSLSocketTemplate { + + private final String protocol; + private X509Certificate trustedCert; + private X509Certificate serverCert; + private X509Certificate clientCert; + private KeyPair serverKeys; + private KeyPair clientKeys; + + protected MD5NotAllowedInTLS13CertificateSignature(String protocol) + throws Exception { + super(); + this.protocol = protocol; + setupCertificates(); + } + + public static void main(String[] args) throws Exception { + // MD5 is disabled by default in java.security config file, + // re-enable it for our test. + SecurityUtils.removeFromDisabledAlgs( + "jdk.certpath.disabledAlgorithms", List.of("MD5")); + SecurityUtils.removeFromDisabledAlgs( + "jdk.tls.disabledAlgorithms", List.of("MD5withRSA")); + + // Should fail on TLSv1.3 and up. + runAndCheckException( + // The conditions to reproduce the bug being fixed only met when + // 'TLS' is specified, i.e. when older versions of protocol are + // supported besides TLSv1.3. + () -> new MD5NotAllowedInTLS13CertificateSignature("TLS").run(), + serverEx -> { + Throwable clientEx = serverEx.getSuppressed()[0]; + assertTrue(clientEx instanceof SSLHandshakeException); + assertEquals(clientEx.getMessage(), "(bad_certificate) " + + "PKIX path validation failed: " + + "java.security.cert.CertPathValidatorException: " + + "Algorithm constraints check failed on signature" + + " algorithm: MD5withRSA"); + }); + + // Should run fine on TLSv1.2. + new MD5NotAllowedInTLS13CertificateSignature("TLSv1.2").run(); + } + + @Override + public SSLContext createServerSSLContext() throws Exception { + return getSSLContext( + trustedCert, serverCert, serverKeys.getPrivate(), protocol); + } + + @Override + public SSLContext createClientSSLContext() throws Exception { + return getSSLContext( + trustedCert, clientCert, clientKeys.getPrivate(), protocol); + } + + private static SSLContext getSSLContext( + X509Certificate trustedCertificate, X509Certificate keyCertificate, + PrivateKey privateKey, String protocol) + throws Exception { + + // create a key store + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(null, null); + + // import the trusted cert + ks.setCertificateEntry("TLS Signer", trustedCertificate); + + // generate certificate chain + Certificate[] chain = new Certificate[2]; + chain[0] = keyCertificate; + chain[1] = trustedCertificate; + + // import the key entry. + final char[] passphrase = "passphrase".toCharArray(); + ks.setKeyEntry("Whatever", privateKey, passphrase, chain); + + // Using PKIX TrustManager - this is where MD5 signature check is done. + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + tmf.init(ks); + + // create SSL context + SSLContext ctx = SSLContext.getInstance(protocol); + + // Using "SunX509" which doesn't check peer supported signature + // algorithms, so we check against local supported signature + // algorithms which constitutes the fix being tested. + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, passphrase); + + ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + return ctx; + } + + // Certificate-building helper methods. + // Certificates are signed with signature using MD5WithRSA algorithm. + + private void setupCertificates() throws Exception { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); + kpg.initialize(1024); + KeyPair caKeys = kpg.generateKeyPair(); + this.serverKeys = kpg.generateKeyPair(); + this.clientKeys = kpg.generateKeyPair(); + + this.trustedCert = createTrustedCert(caKeys); + + this.serverCert = customCertificateBuilder( + "O=Some-Org, L=Some-City, ST=Some-State, C=US", + serverKeys.getPublic(), caKeys.getPublic()) + .addBasicConstraintsExt(false, false, -1) + .build(trustedCert, caKeys.getPrivate(), "MD5WithRSA"); + + this.clientCert = customCertificateBuilder( + "CN=localhost, OU=SSL-Client, O=Some-Org, L=Some-City, ST=Some-State, C=US", + clientKeys.getPublic(), caKeys.getPublic()) + .addBasicConstraintsExt(false, false, -1) + .build(trustedCert, caKeys.getPrivate(), "MD5WithRSA"); + } + + private static X509Certificate createTrustedCert(KeyPair caKeys) + throws Exception { + SecureRandom random = new SecureRandom(); + + KeyIdentifier kid = new KeyIdentifier(caKeys.getPublic()); + GeneralNames gns = new GeneralNames(); + GeneralName name = new GeneralName(new X500Name( + "O=Some-Org, L=Some-City, ST=Some-State, C=US")); + gns.add(name); + BigInteger serialNumber = BigInteger.valueOf( + random.nextLong(1000000) + 1); + return customCertificateBuilder( + "O=Some-Org, L=Some-City, ST=Some-State, C=US", + caKeys.getPublic(), caKeys.getPublic()) + .setSerialNumber(serialNumber) + .addExtension(new AuthorityKeyIdentifierExtension(kid, gns, + new SerialNumber(serialNumber))) + .addBasicConstraintsExt(true, true, -1) + .build(null, caKeys.getPrivate(), "MD5WithRSA"); + } + + private static CertificateBuilder customCertificateBuilder( + String subjectName, PublicKey publicKey, PublicKey caKey) + throws CertificateException, IOException { + SecureRandom random = new SecureRandom(); + + CertificateBuilder builder = new CertificateBuilder() + .setSubjectName(subjectName) + .setPublicKey(publicKey) + .setNotAfter( + Date.from(Instant.now().minus(1, ChronoUnit.HOURS))) + .setNotAfter(Date.from(Instant.now().plus(1, ChronoUnit.HOURS))) + .setSerialNumber( + BigInteger.valueOf(random.nextLong(1000000) + 1)) + .addSubjectKeyIdExt(publicKey) + .addAuthorityKeyIdExt(caKey); + builder.addKeyUsageExt( + new boolean[]{true, true, true, true, true, true}); + + return builder; + } + +} From 86f3eafade20bd901b0657ab9ad1bdf12d1143c2 Mon Sep 17 00:00:00 2001 From: Saint Wesonga Date: Thu, 17 Apr 2025 13:59:44 +0000 Subject: [PATCH 0639/1101] 8353009: Improve documentation for Windows AArch64 builds Reviewed-by: erikj, ihse --- doc/building.html | 14 ++++++++++++++ doc/building.md | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/doc/building.html b/doc/building.html index 95cda58e82853..1e6f99e97c93d 100644 --- a/doc/building.html +++ b/doc/building.html @@ -1722,6 +1722,20 @@

Building for musl

--with-devkit=$DEVKIT \ --with-sysroot=$SYSROOT

and run make normally.

+

Building for Windows AArch64

+

The Visual Studio Build Tools can be used for building the JDK +without a full Visual Studio installation. To set up the Visual Studio +2022 Build Tools on a Windows AArch64 machine for a native build, launch +the installer as follows in a Windows command prompt:

+
vs_buildtools.exe --quiet --wait --norestart --nocache ^
+--installPath "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools" ^
+--add Microsoft.VisualStudio.Component.VC.CoreBuildTools ^
+--add Microsoft.VisualStudio.Component.VC.Tools.ARM64 ^
+--add Microsoft.VisualStudio.Component.Windows11SDK.22621
+

To generate Windows AArch64 builds using Cygwin on a Windows x64 +machine, you must set the proper target platform by adding +--openjdk-target=aarch64-unknown-cygwin to your configure +command line.

Build Performance

Building the JDK requires a lot of horsepower. Some of the build tools can be adjusted to utilize more or less of resources such as diff --git a/doc/building.md b/doc/building.md index 914473916b417..18e030baa9e29 100644 --- a/doc/building.md +++ b/doc/building.md @@ -1457,6 +1457,24 @@ sh ./configure --with-jvm-variants=server \ and run `make` normally. +#### Building for Windows AArch64 +The Visual Studio Build Tools can be used for building the JDK without a full +Visual Studio installation. To set up the Visual Studio 2022 Build Tools on a +Windows AArch64 machine for a native build, launch the installer as follows +in a Windows command prompt: + +``` +vs_buildtools.exe --quiet --wait --norestart --nocache ^ +--installPath "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools" ^ +--add Microsoft.VisualStudio.Component.VC.CoreBuildTools ^ +--add Microsoft.VisualStudio.Component.VC.Tools.ARM64 ^ +--add Microsoft.VisualStudio.Component.Windows11SDK.22621 +``` + +To generate Windows AArch64 builds using Cygwin on a Windows x64 machine, +you must set the proper target platform by adding +`--openjdk-target=aarch64-unknown-cygwin` to your configure command line. + ## Build Performance Building the JDK requires a lot of horsepower. Some of the build tools can be From cd8adf13ed6579fad9e777aa291146fa653288b0 Mon Sep 17 00:00:00 2001 From: Ferenc Rakoczi Date: Thu, 17 Apr 2025 14:01:46 +0000 Subject: [PATCH 0640/1101] 8354926: Remove remnants of debugging in the fix for JDK-8348561 and JDK-8349721 Reviewed-by: adinn --- src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp | 2 +- src/hotspot/cpu/aarch64/vm_version_aarch64.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp b/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp index 1107ec0a8f82a..c8b215b6eb4fe 100644 --- a/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp @@ -44,7 +44,7 @@ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(compiler, 75000 ZGC_ONLY(+5000)) \ + do_arch_blob(compiler, 65000 ZGC_ONLY(+5000)) \ do_stub(compiler, vector_iota_indices) \ do_arch_entry(aarch64, compiler, vector_iota_indices, \ vector_iota_indices, vector_iota_indices) \ diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 6bf300ced42ab..c555e393ca57c 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -714,7 +714,6 @@ void VM_Version::initialize_cpu_information(void) { get_compatible_board(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len); desc_len = (int)strlen(_cpu_desc); snprintf(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len, " %s", _features_string); - fprintf(stderr, "_features_string = \"%s\"", _features_string); _initialized = true; } From d1d81dd01ca6f3fc1e4710e6055c5a3185f43d9a Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Thu, 17 Apr 2025 15:37:05 +0000 Subject: [PATCH 0641/1101] 8353953: con/sun/jdi tests should be fixed to not always require includevirtualthreads=y Reviewed-by: sspitsyn, amenkov --- test/jdk/com/sun/jdi/EventQueueDisconnectTest.java | 4 ++-- .../jdi/RedefineNestmateAttr/TestNestmateAttr.java | 3 ++- test/jdk/com/sun/jdi/TestScaffold.java | 12 ++++++++++-- test/jdk/com/sun/jdi/VMConnection.java | 6 +++--- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/test/jdk/com/sun/jdi/EventQueueDisconnectTest.java b/test/jdk/com/sun/jdi/EventQueueDisconnectTest.java index c050cb792eb62..848046186efaf 100644 --- a/test/jdk/com/sun/jdi/EventQueueDisconnectTest.java +++ b/test/jdk/com/sun/jdi/EventQueueDisconnectTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ public class EventQueueDisconnectTest { public static void main(String args[]) throws Exception { VMConnection connection = new VMConnection( "com.sun.jdi.CommandLineLaunch:", - VirtualMachine.TRACE_NONE); + VirtualMachine.TRACE_NONE, false); connection.setConnectorArg("main", "EventQueueDisconnectTarg"); String debuggeeVMOptions = VMConnection.getDebuggeeVMOptions(); if (!debuggeeVMOptions.equals("")) { diff --git a/test/jdk/com/sun/jdi/RedefineNestmateAttr/TestNestmateAttr.java b/test/jdk/com/sun/jdi/RedefineNestmateAttr/TestNestmateAttr.java index 76bd3bf5dc15b..21ea9f3892174 100644 --- a/test/jdk/com/sun/jdi/RedefineNestmateAttr/TestNestmateAttr.java +++ b/test/jdk/com/sun/jdi/RedefineNestmateAttr/TestNestmateAttr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -213,6 +213,7 @@ public class TestNestmateAttr extends TestScaffold { TestNestmateAttr (String[] args) { super(args); + enableIncludeVirtualthreads(); // need to run debug agent with includevirtualthreads=y } public static void main(String[] args) throws Throwable { diff --git a/test/jdk/com/sun/jdi/TestScaffold.java b/test/jdk/com/sun/jdi/TestScaffold.java index e410ae2c76d78..92779738998c5 100644 --- a/test/jdk/com/sun/jdi/TestScaffold.java +++ b/test/jdk/com/sun/jdi/TestScaffold.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,9 @@ abstract public class TestScaffold extends TargetAdapter { private boolean redefineAsynchronously = false; private ReferenceType mainStartClass = null; + // Set true by tests that need the debug agent to be run with includevirtualthreads=y. + private boolean includeVThreads = false; + ThreadReference mainThread; /** * We create a VMDeathRequest, SUSPEND_ALL, to sync the BE and FE. @@ -84,6 +87,10 @@ public void mySleep(int millis) { } } + void enableIncludeVirtualthreads() { + includeVThreads = true; + } + boolean getExceptionCaught() { return exceptionCaught; } @@ -588,7 +595,8 @@ public void connect(String args[]) { argInfo.targetVMArgs = VMConnection.getDebuggeeVMOptions() + " " + argInfo.targetVMArgs; connection = new VMConnection(argInfo.connectorSpec, - argInfo.traceFlags); + argInfo.traceFlags, + includeVThreads); addListener(new TargetAdapter() { public void eventSetComplete(EventSet set) { diff --git a/test/jdk/com/sun/jdi/VMConnection.java b/test/jdk/com/sun/jdi/VMConnection.java index 1444393e46b31..64eef3c38f73d 100644 --- a/test/jdk/com/sun/jdi/VMConnection.java +++ b/test/jdk/com/sun/jdi/VMConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -123,9 +123,9 @@ private Map parseConnectorArgs(Connector connector, String argString) { return arguments; } - VMConnection(String connectSpec, int traceFlags) { + VMConnection(String connectSpec, int traceFlags, boolean includeVThreads) { String nameString; - String argString = "includevirtualthreads=y"; + String argString = "includevirtualthreads=" + (includeVThreads ? 'y' : 'n'); int index = connectSpec.indexOf(':'); if (index == -1) { nameString = connectSpec; From e639cd6a775fabb057b684c70f85b94f84fa5d04 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Thu, 17 Apr 2025 16:18:56 +0000 Subject: [PATCH 0642/1101] 8353213: Open source several swing tests batch3 Reviewed-by: prr --- .../bug4331515.java | 68 +++++++++++++++ .../AddMouseListenerTest.java | 68 +++++++++++++++ .../plaf/basic/BasicToolBarUI/bug4305622.java | 87 +++++++++++++++++++ .../plaf/basic/BasicToolBarUI/bug4331392.java | 73 ++++++++++++++++ 4 files changed, 296 insertions(+) create mode 100644 test/jdk/javax/swing/plaf/basic/BasicInternalFrameTitlePane/bug4331515.java create mode 100644 test/jdk/javax/swing/plaf/basic/BasicSplitPaneDivider/AddMouseListenerTest.java create mode 100644 test/jdk/javax/swing/plaf/basic/BasicToolBarUI/bug4305622.java create mode 100644 test/jdk/javax/swing/plaf/basic/BasicToolBarUI/bug4331392.java diff --git a/test/jdk/javax/swing/plaf/basic/BasicInternalFrameTitlePane/bug4331515.java b/test/jdk/javax/swing/plaf/basic/BasicInternalFrameTitlePane/bug4331515.java new file mode 100644 index 0000000000000..3129148b362d1 --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicInternalFrameTitlePane/bug4331515.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4331515 + * @requires (os.family == "windows") + * @summary System menu of an internal frame shouldn't have duplicated items in Win L&F + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4331515 + */ + +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.UIManager; + +public class bug4331515 { + static final String INSTRUCTIONS = """ + Open the system menu of internal frame "JIF" placed in the frame "Test". + If this menu contains duplicates of some items then test FAILS, else + test PASSES. + """; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + PassFailJFrame.builder() + .title("bug4331515 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4331515::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame fr = new JFrame("System Menu in JIF Test"); + JDesktopPane dp = new JDesktopPane(); + fr.setContentPane(dp); + JInternalFrame jif = new JInternalFrame("JIF", true, true, true, true); + dp.add(jif); + jif.setBounds(20, 20, 120, 100); + jif.setVisible(true); + fr.setSize(200, 200); + return fr; + } +} diff --git a/test/jdk/javax/swing/plaf/basic/BasicSplitPaneDivider/AddMouseListenerTest.java b/test/jdk/javax/swing/plaf/basic/BasicSplitPaneDivider/AddMouseListenerTest.java new file mode 100644 index 0000000000000..79ae9bd5ec8e3 --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicSplitPaneDivider/AddMouseListenerTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4165874 + * @summary Adds a MouseListener to the splitpane divider. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AddMouseListenerTest + */ + +import java.awt.Component; +import java.awt.event.MouseAdapter; + +import javax.swing.JFrame; +import javax.swing.JSplitPane; + +public class AddMouseListenerTest { + static final String INSTRUCTIONS = """ + Try dragging the split pane divider, if you can, click PASS, + else click FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("AddMouseListenerTest Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(AddMouseListenerTest::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("JSplitPane With ActionListener Test"); + JSplitPane sp = new JSplitPane(); + + sp.setContinuousLayout(true); + Component[] children = sp.getComponents(); + for (int counter = children.length - 1; counter >= 0; counter--) { + children[counter].addMouseListener(new MouseAdapter() {}); + } + f.getContentPane().add(sp); + f.setSize(400, 400); + return f; + } +} diff --git a/test/jdk/javax/swing/plaf/basic/BasicToolBarUI/bug4305622.java b/test/jdk/javax/swing/plaf/basic/BasicToolBarUI/bug4305622.java new file mode 100644 index 0000000000000..5fdae14e74747 --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicToolBarUI/bug4305622.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4305622 + * @summary MetalToolBarUI.installUI invokeLater causes flickering + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4305622 + */ + +import java.awt.BorderLayout; +import java.awt.Color; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JToolBar; +import javax.swing.UIManager; +import javax.swing.border.LineBorder; + + +public class bug4305622 { + private static JFrame fr; + static final String INSTRUCTIONS = """ + Press button "Create ToolBar" at frame "Create ToolBar Test". + If you see any flickering during creating of toolbar + then the test FAILS, otherwise the test PASSES. + """; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + PassFailJFrame.builder() + .title("bug4305622 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4305622::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + fr = new JFrame("Create ToolBar Test"); + JButton button = new JButton("Create ToolBar"); + button.addActionListener(ae -> addToolBar()); + fr.add(button, BorderLayout.SOUTH); + fr.setSize(400, 400); + return fr; + } + + static void addToolBar() { + fr.repaint(); + fr.revalidate(); + JToolBar toolbar = new JToolBar(); + + JButton btn = new JButton("Button 1"); + btn.setBorder(new LineBorder(Color.red, 30)); + toolbar.add(btn); + + btn = new JButton("Button 2"); + btn.setBorder(new LineBorder(Color.red, 30)); + toolbar.add(btn); + + toolbar.updateUI(); + fr.add(toolbar, BorderLayout.NORTH); + } +} diff --git a/test/jdk/javax/swing/plaf/basic/BasicToolBarUI/bug4331392.java b/test/jdk/javax/swing/plaf/basic/BasicToolBarUI/bug4331392.java new file mode 100644 index 0000000000000..eaca65bfa6d3c --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicToolBarUI/bug4331392.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4331392 + * @summary Tests if BasicToolBarUI has bogus logic that prevents vertical + * toolbars from docking + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4331392 + */ + +import java.awt.BorderLayout; +import java.awt.Container; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JToolBar; + +public class bug4331392 { + static final String INSTRUCTIONS = """ + Try to dock the toolbar across all the edges of frame. If you succeed, + then the test PASSES. Otherwise, it FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4331392 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4331392::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("JToolBar Docking Test"); + Container c = frame.getContentPane(); + + JToolBar tbar = new JToolBar(JToolBar.VERTICAL); + + tbar.add(new JButton("A")); + tbar.add(new JButton("B")); + tbar.add(new JButton("C")); + + JButton b = new JButton("Hello"); + c.add(b, BorderLayout.CENTER); + c.add(tbar, BorderLayout.EAST); + frame.setSize(300, 300); + return frame; + } +} From 566092256861d6c7142fe22cc709ecb70f9db937 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Thu, 17 Apr 2025 16:20:35 +0000 Subject: [PATCH 0643/1101] 8353070: Clean up and open source couple AWT Graphics related tests (Part 1) Reviewed-by: serb --- .../java/awt/Graphics/LineLocationTest.java | 106 ++++++++++++++ .../java/awt/Graphics/NativeWin32Clear.java | 136 ++++++++++++++++++ .../java/awt/Graphics/PolygonFillTest.java | 96 +++++++++++++ test/jdk/java/awt/Graphics/TallText.java | 69 +++++++++ 4 files changed, 407 insertions(+) create mode 100644 test/jdk/java/awt/Graphics/LineLocationTest.java create mode 100644 test/jdk/java/awt/Graphics/NativeWin32Clear.java create mode 100644 test/jdk/java/awt/Graphics/PolygonFillTest.java create mode 100644 test/jdk/java/awt/Graphics/TallText.java diff --git a/test/jdk/java/awt/Graphics/LineLocationTest.java b/test/jdk/java/awt/Graphics/LineLocationTest.java new file mode 100644 index 0000000000000..5c382ceac959c --- /dev/null +++ b/test/jdk/java/awt/Graphics/LineLocationTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4094059 + * @summary drawing to a subclass of canvas didn't draw to the correct location. + * @key headful + * @run main LineLocationTest + */ + +import java.awt.AWTException; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.lang.reflect.InvocationTargetException; + +public class LineLocationTest extends Frame { + private DrawScreen screen; + + public void initialize() { + setSize(400, 400); + setLocationRelativeTo(null); + setTitle("Line Location Test"); + Panel p = new Panel(); + screen = new DrawScreen(); + p.add(screen); + p.setLocation(50, 50); + p.setSize(300, 300); + add(p); + setBackground(Color.white); + setForeground(Color.blue); + setVisible(true); + } + + public void requestCoordinates(Rectangle r) { + Point location = screen.getLocationOnScreen(); + Dimension size = screen.getSize(); + r.setBounds(location.x, location.y, size.width, size.height); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + LineLocationTest me = new LineLocationTest(); + EventQueue.invokeAndWait(me::initialize); + try { + Robot robot = new Robot(); + robot.delay(1000); + Rectangle coords = new Rectangle(); + EventQueue.invokeAndWait(() -> { + me.requestCoordinates(coords); + }); + BufferedImage capture = robot.createScreenCapture(coords); + robot.delay(2000); + for (int y = 0; y < capture.getHeight(); y++) { + for (int x = 0; x < capture.getWidth(); x++) { + int blue = Color.blue.getRGB(); + if (capture.getRGB(x, y) == blue) { + throw new RuntimeException("Blue detected at " + x + ", " + y); + } + } + } + } finally { + EventQueue.invokeAndWait(me::dispose); + } + } +} + +class DrawScreen extends Canvas { + public Dimension getPreferredSize() { + return new Dimension(300, 300); + } + + public void paint(Graphics g) { + g.setColor(Color.blue); + g.drawLine(5, -3145583, 50, -3145583); + } +} diff --git a/test/jdk/java/awt/Graphics/NativeWin32Clear.java b/test/jdk/java/awt/Graphics/NativeWin32Clear.java new file mode 100644 index 0000000000000..6cef4fa810aa3 --- /dev/null +++ b/test/jdk/java/awt/Graphics/NativeWin32Clear.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4216180 + * @summary This test verifies that Graphics2D.setBackground and clearRect + * performs correctly regardless of antialiasing hint. + * @key headful + * @run main NativeWin32Clear + */ + +import java.awt.AWTException; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.lang.reflect.InvocationTargetException; + +public class NativeWin32Clear extends Frame { + + public void initialize() { + setLocationRelativeTo(null); + setSize(300, 200); + setBackground(Color.red); + setVisible(true); + } + + public void paint(Graphics g) { + Graphics2D g2 = (Graphics2D) g; + Dimension d = getSize(); + g2.setBackground(Color.green); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2.clearRect(0, 0, d.width / 2, d.height); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_OFF); + g2.clearRect(d.width / 2, 0, d.width / 2, d.height); + g2.setColor(Color.black); + } + + public void cleanup() { + setVisible(false); + dispose(); + } + + public void requestCoordinates(Rectangle r) { + Insets insets = getInsets(); + Point location = getLocationOnScreen(); + Dimension size = getSize(); + r.x = location.x + insets.left + 5; + r.y = location.y + insets.top + 5; + r.width = size.width - (insets.left + insets.right + 10); + r.height = size.height - (insets.top + insets.bottom + 10); + } + + /* + * Check color match within allowed deviation. + * Prints first non-matching pixel coordinates and actual and expected values. + * Returns true if image is filled with the provided color, false otherwise. + */ + private boolean checkColor(BufferedImage img, Color c, int delta) { + int cRed = c.getRed(); + int cGreen = c.getGreen(); + int cBlue = c.getBlue(); + for (int y = 0; y < img.getHeight(); y++) { + for (int x = 0; x < img.getWidth(); x++) { + int rgb = img.getRGB(x, y); + int red = (rgb & 0x00ff0000) >> 16; + int green = (rgb & 0x0000ff00) >> 8; + int blue = rgb & 0x000000ff; + if (cRed > (red + delta) || cRed < (red - delta) + || cGreen > (green + delta) || cGreen < (green - delta) + || cBlue > (blue + delta) || cBlue < (blue - delta)) { + System.err.println("Color at coordinates (" + x + ", " + y + ") does not match"); + System.err.println("Expected color: " + c.getRGB()); + System.err.println("Actual color: " + rgb); + System.err.println("Allowed deviation: " + delta); + return false; + } + } + } + return true; + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + NativeWin32Clear test = new NativeWin32Clear(); + try { + EventQueue.invokeAndWait(test::initialize); + Robot robot = new Robot(); + Rectangle coords = new Rectangle(); + EventQueue.invokeAndWait(() -> { + test.requestCoordinates(coords); + }); + robot.delay(2000); + robot.mouseMove(coords.x - 50, coords.y - 50); + robot.waitForIdle(); + BufferedImage capture = robot.createScreenCapture(coords); + robot.delay(2000); + if (!test.checkColor(capture, Color.green, 5)) { + throw new RuntimeException("Incorrect color encountered, check error log for details"); + } + } finally { + EventQueue.invokeAndWait(test::cleanup); + } + } +} diff --git a/test/jdk/java/awt/Graphics/PolygonFillTest.java b/test/jdk/java/awt/Graphics/PolygonFillTest.java new file mode 100644 index 0000000000000..72c216f9e4b56 --- /dev/null +++ b/test/jdk/java/awt/Graphics/PolygonFillTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4465509 4453725 4489667 + * @summary verify that fillPolygon completely fills area defined by drawPolygon + * @key headful + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PolygonFillTest +*/ + +import java.awt.Color; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Polygon; +import java.lang.reflect.InvocationTargetException; + +public class PolygonFillTest extends Frame { + Polygon poly; + static String INSTRUCTIONS = """ + There should be two hourglass shapes drawn inside the window + called "Polygon Fill Test". The outline should be blue + and the interior should be green and there should be no gaps + between the filled interior and the outline nor should the green + filler spill outside the blue outline. You may need + to use a screen magnifier to inspect the smaller shape + on the left to verify that there are no gaps. + + If both polygons painted correctly press "Pass" otherwise press "Fail". + """; + + public PolygonFillTest() { + poly = new Polygon(); + poly.addPoint(0, 0); + poly.addPoint(10, 10); + poly.addPoint(0, 10); + poly.addPoint(10, 0); + setSize(300, 300); + setTitle("Polygon Fill Test"); + } + + public void paint(Graphics g) { + int w = getWidth(); + int h = getHeight(); + Image img = createImage(20, 20); + Graphics g2 = img.getGraphics(); + drawPolys(g2, 20, 20, 5, 5); + g2.dispose(); + drawPolys(g, w, h, (w / 4) - 5, (h / 2) - 5); + g.drawImage(img, (3 * w / 4) - 40, (h / 2) - 40, 80, 80, null); + } + + public void drawPolys(Graphics g, int w, int h, int x, int y) { + g.setColor(Color.white); + g.fillRect(0, 0, w, h); + g.translate(x, y); + g.setColor(Color.green); + g.fillPolygon(poly); + g.setColor(Color.blue); + g.drawPolygon(poly); + g.translate(-x, -y); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Polygon Fill Instructions") + .instructions(INSTRUCTIONS) + .testUI(PolygonFillTest::new) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Graphics/TallText.java b/test/jdk/java/awt/Graphics/TallText.java new file mode 100644 index 0000000000000..b21b8a985d04b --- /dev/null +++ b/test/jdk/java/awt/Graphics/TallText.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4844952 + * @summary test large text draws properly to the screen + * @key headful + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TallText + */ + +import java.awt.Color; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.lang.reflect.InvocationTargetException; + +public class TallText extends Frame { + static String INSTRUCTIONS = """ + There should be a window called "Tall Text Test" that contains text "ABCDEFGHIJ". + Test should be properly displayed: no missing letters + and all letters fit within the frame without overlapping. + If all letters are properly displayed press "Pass", otherwise press "Fail". + """; + + public TallText() { + setSize(800, 200); + setTitle("Tall Text Test"); + } + + public void paint(Graphics g) { + Font font = new Font("dialog", Font.PLAIN, 99); + g.setFont(font); + g.setColor(Color.black); + g.drawString("ABCDEFGHIJ", 10, 150); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Tall Text Instructions") + .instructions(INSTRUCTIONS) + .testUI(TallText::new) + .build() + .awaitAndCheck(); + } +} From 04c32fc08a67eaf6d3f47a0f9ea3d620b7ec6a07 Mon Sep 17 00:00:00 2001 From: Johannes Graham Date: Thu, 17 Apr 2025 16:22:00 +0000 Subject: [PATCH 0644/1101] 8354522: Clones of DecimalFormat cause interferences when used concurrently Reviewed-by: jlu, naoto --- .../share/classes/java/text/DigitList.java | 8 +- .../text/Format/DecimalFormat/CloneTest.java | 167 ++++++++++++++++++ 2 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/text/Format/DecimalFormat/CloneTest.java diff --git a/src/java.base/share/classes/java/text/DigitList.java b/src/java.base/share/classes/java/text/DigitList.java index fde0e93214ad2..f269698d6dacb 100644 --- a/src/java.base/share/classes/java/text/DigitList.java +++ b/src/java.base/share/classes/java/text/DigitList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -725,7 +725,13 @@ public Object clone() { char[] newDigits = new char[digits.length]; System.arraycopy(digits, 0, newDigits, 0, digits.length); other.digits = newDigits; + + // data and tempBuilder do not need to be copied because they do + // not carry significant information. They will be recreated on demand. + // Setting them to null is needed to avoid sharing across clones. + other.data = null; other.tempBuilder = null; + return other; } catch (CloneNotSupportedException e) { throw new InternalError(e); diff --git a/test/jdk/java/text/Format/DecimalFormat/CloneTest.java b/test/jdk/java/text/Format/DecimalFormat/CloneTest.java new file mode 100644 index 0000000000000..fa46b09d6ac0f --- /dev/null +++ b/test/jdk/java/text/Format/DecimalFormat/CloneTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8354522 + * @summary Check for cloning interference + * @library /test/lib + * @run junit/othervm --add-opens=java.base/java.text=ALL-UNNAMED CloneTest + */ + +import jtreg.SkippedException; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Field; +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.jupiter.api.Assertions.*; + +public class CloneTest { + + // Note: this is a white-box test that may fail if the implementation is changed + @Test + public void testClone() { + DecimalFormat df = new DecimalFormat("#"); + new CloneTester(df).testClone(); + } + + // Note: this is a white-box test that may fail if the implementation is changed + @Test + public void testCloneAfterInit() { + DecimalFormat df = new DecimalFormat("#"); + + // This initial use of the formatter initialises its internal state, which could + // subsequently be shared across clones. This is key to reproducing this specific + // issue. + String _ = df.format(Math.PI); + new CloneTester(df).testClone(); + } + + private static class CloneTester { + private final Field digitListField; + private final Class digitListClass; + private final DecimalFormat original; + + public CloneTester(DecimalFormat original) { + this.original = original; + try { + digitListField = DecimalFormat.class.getDeclaredField("digitList"); + digitListField.setAccessible(true); + + DecimalFormat df = new DecimalFormat(); + Object digitList = digitListField.get(df); + + digitListClass = digitList.getClass(); + } catch (ReflectiveOperationException e) { + throw new SkippedException("reflective access in white-box test failed", e); + } + } + + public void testClone() { + try { + DecimalFormat dfClone = (DecimalFormat) original.clone(); + + Object digits = valFromDigitList(original, "digits"); + assertNotSame(digits, valFromDigitList(dfClone, "digits")); + + + Object data = valFromDigitList(original, "data"); + if (data != null) { + assertNotSame(data, valFromDigitList(dfClone, "data")); + } + + Object tempBuilder = valFromDigitList(original, "tempBuilder"); + if (tempBuilder != null) { + assertNotSame(data, valFromDigitList(dfClone, "data")); + } + + assertEquals(digitListField.get(original), digitListField.get(dfClone)); + } catch (ReflectiveOperationException e) { + throw new SkippedException("reflective access in white-box test failed", e); + } + } + + private Object valFromDigitList(DecimalFormat df, String fieldName) throws ReflectiveOperationException { + Object digitList = digitListField.get(df); + Field field = digitListClass.getDeclaredField(fieldName); + field.setAccessible(true); + + return field.get(digitList); + } + } + + // Tests that when DecimalFormat is cloned after use with + // a long double/BigDecimal, clones will be independent. This is not an + // exhaustive test. This tests for the issue of the same DigitList.data + // array being reused across clones of DecimalFormat. + + @Test + public void testCloneIndependence() { + AtomicInteger mismatchCount = new AtomicInteger(0); + DecimalFormat df = new DecimalFormat("#"); + CountDownLatch startSignal = new CountDownLatch(1); + + // This initial use of the formatter initialises its internal state, which could + // subsequently be shared across clones. This is key to reproducing this specific + // issue. + String _ = df.format(Math.PI); + + try (var ex = Executors.newThreadPerTaskExecutor(Thread.ofPlatform().factory())) { + for (int i = 0; i < 5; i++) { + final int finalI = i; + // Each thread gets its own clone of df + DecimalFormat threadDf = (DecimalFormat) df.clone(); + Runnable task = () -> { + try { + startSignal.await(); + for (int j = 0; j < 1_000; j++) { + if (mismatchCount.get() > 0) { + // Exit early if mismatch has already occurred + break; + } + + int value = finalI * j; + String dfString = threadDf.format(BigDecimal.valueOf(value)); + String str = String.valueOf(value); + if (!str.equals(dfString)) { + mismatchCount.getAndIncrement(); + System.err.println("mismatch: str = " + str + " dfString = " + dfString); + break; + } + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }; + ex.execute(task); + } + startSignal.countDown(); // let all tasks start working at the same time + } + assertEquals(0, mismatchCount.get()); + } +} From e163a76f2bacf06980026feb7e645e616ffe2ad4 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Thu, 17 Apr 2025 16:26:36 +0000 Subject: [PATCH 0645/1101] 8354106: Clean up and open source KeyEvent related tests (Part 2) Reviewed-by: abhiscxk, prr --- .../event/KeyEvent/KeyPressedModifiers.java | 108 ++++++++++++++++++ test/jdk/java/awt/event/KeyEvent/KeyTest.java | 104 +++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 test/jdk/java/awt/event/KeyEvent/KeyPressedModifiers.java create mode 100644 test/jdk/java/awt/event/KeyEvent/KeyTest.java diff --git a/test/jdk/java/awt/event/KeyEvent/KeyPressedModifiers.java b/test/jdk/java/awt/event/KeyEvent/KeyPressedModifiers.java new file mode 100644 index 0000000000000..08958bdbac21e --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/KeyPressedModifiers.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4174399 + * @summary Check that modifier values are set on a KeyPressed event + * when a modifier key is pressed. + * @key headful + * @run main KeyPressedModifiers + */ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.TextField; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.atomic.AtomicBoolean; + +public class KeyPressedModifiers extends Frame implements KeyListener { + static AtomicBoolean shiftDown = new AtomicBoolean(false); + static AtomicBoolean controlDown = new AtomicBoolean(false); + static AtomicBoolean altDown = new AtomicBoolean(false); + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + KeyPressedModifiers test = new KeyPressedModifiers(); + try { + EventQueue.invokeAndWait(test::initUI); + Robot robot = new Robot(); + robot.setAutoDelay(100); + robot.delay(500); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.keyPress(KeyEvent.VK_ALT); + robot.keyRelease(KeyEvent.VK_ALT); + robot.delay(500); + robot.waitForIdle(); + if (!shiftDown.get() || !controlDown.get() || !altDown.get()) { + String error = "Following key modifiers were not registered:" + + (shiftDown.get() ? "" : " SHIFT") + + (controlDown.get() ? "" : " CONTROL") + + (altDown.get() ? "" : " ALT"); + throw new RuntimeException(error); + } + } finally { + EventQueue.invokeAndWait(test::dispose); + } + } + + public void initUI() { + setLayout(new BorderLayout()); + TextField tf = new TextField(30); + tf.addKeyListener(this); + add(tf, BorderLayout.CENTER); + setSize(350, 100); + setVisible(true); + tf.requestFocus(); + } + + public void keyTyped(KeyEvent ignore) { + } + + public void keyReleased(KeyEvent ignore) { + } + + public void keyPressed(KeyEvent e) { + System.out.println(e); + switch (e.getKeyCode()) { + case KeyEvent.VK_SHIFT: + shiftDown.set(e.isShiftDown()); + break; + case KeyEvent.VK_CONTROL: + controlDown.set(e.isControlDown()); + break; + case KeyEvent.VK_ALT: + altDown.set(e.isAltDown()); + break; + } + } +} diff --git a/test/jdk/java/awt/event/KeyEvent/KeyTest.java b/test/jdk/java/awt/event/KeyEvent/KeyTest.java new file mode 100644 index 0000000000000..d11798b4473af --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/KeyTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4151419 4090870 4169733 + * @summary Ensures that KeyEvent has right results for the following + * keys -=\[];,./ + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual KeyTest + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.lang.reflect.InvocationTargetException; + +public class KeyTest extends Frame implements KeyListener { + + static String INSTRUCTIONS = """ + Click on the text field in window named "Check KeyChar values" + Type the following keys/characters in the TextField: + - = \\ [ ] ; , . / + Verify that the keyChar and keyCode is correct for each key pressed. + Remember that the keyCode for the KEY_TYPED event should be zero. + Also verify that the character you typed appears in the TextField. + + Key Name keyChar Keycode + ------------------------------------- + - Minus - 45 45 + = Equals = 61 61 + \\ Slash \\ 92 92 + [ Left Brace [ 91 91 + ] Right Brace ] 93 93 + ; Semicolon ; 59 59 + , Comma , 44 44 + . Period . 46 46 + / Front Slash / 47 47 + """; + public KeyTest() { + super("Check KeyChar values"); + setLayout(new BorderLayout()); + TextField tf = new TextField(30); + tf.addKeyListener(this); + add(tf, BorderLayout.CENTER); + pack(); + + } + + public void keyPressed(KeyEvent evt) { + printKey(evt); + } + + public void keyTyped(KeyEvent evt) { + printKey(evt); + } + + public void keyReleased(KeyEvent evt) { + printKey(evt); + } + + protected void printKey(KeyEvent evt) { + if (evt.isActionKey()) { + PassFailJFrame.log("params= " + evt.paramString() + " KeyChar: " + + (int) evt.getKeyChar() + " Action Key"); + } else { + PassFailJFrame.log("params= " + evt.paramString() + " KeyChar: " + + (int) evt.getKeyChar()); + } + } + + public static void main(String[] args) throws InterruptedException, InvocationTargetException { + PassFailJFrame.builder() + .title("KeyTest Instructions") + .instructions(INSTRUCTIONS) + .logArea(20) + .testUI(KeyTest::new) + .build() + .awaitAndCheck(); + } +} From 3e3dff6767f467b53c739c34b4350dd6840534a3 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 17 Apr 2025 16:31:24 +0000 Subject: [PATCH 0646/1101] 8354451: Open source some more Swing popup menu tests Reviewed-by: jdv, kizune --- .../javax/swing/JPopupMenu/bug4188832.java | 82 ++++++ .../javax/swing/JPopupMenu/bug4212464.java | 142 ++++++++++ .../javax/swing/JPopupMenu/bug4234793.java | 242 ++++++++++++++++++ 3 files changed, 466 insertions(+) create mode 100644 test/jdk/javax/swing/JPopupMenu/bug4188832.java create mode 100644 test/jdk/javax/swing/JPopupMenu/bug4212464.java create mode 100644 test/jdk/javax/swing/JPopupMenu/bug4234793.java diff --git a/test/jdk/javax/swing/JPopupMenu/bug4188832.java b/test/jdk/javax/swing/JPopupMenu/bug4188832.java new file mode 100644 index 0000000000000..9c958ebc1efb5 --- /dev/null +++ b/test/jdk/javax/swing/JPopupMenu/bug4188832.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 Test that medium weight submenus are not hidden by a heavyweight canvas. + * @bug 4188832 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4188832 + */ + +import java.awt.Color; +import java.awt.Panel; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; + +public class bug4188832 { + + static final String INSTRUCTIONS = """ + Select the File menu, then select the "Save As..." submenu. + If you can see the submenu items displayed, press PASS, else press FAIL + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4188832::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + // for Medium Weight menus + JPopupMenu.setDefaultLightWeightPopupEnabled(false); + JFrame frame = new JFrame("bug4188832"); + + // Create the menus + JMenuBar menuBar = new JMenuBar(); + JMenu fileMenu = new JMenu("File"); + menuBar.add(fileMenu); + fileMenu.add(new JMenuItem("New")); + fileMenu.add(new JMenuItem("Open")); + fileMenu.add(new JMenuItem("Save")); + JMenu sm = new JMenu("Save As..."); + // these guys don't show up + sm.add(new JMenuItem("This")); + sm.add(new JMenuItem("That")); + fileMenu.add(sm); + fileMenu.add(new JMenuItem("Exit")); + frame.setJMenuBar(menuBar); + + Panel field = new Panel(); // a heavyweight container + field.setBackground(Color.blue); + frame.add(field); + frame.setSize(400, 400); + return frame; + } +} diff --git a/test/jdk/javax/swing/JPopupMenu/bug4212464.java b/test/jdk/javax/swing/JPopupMenu/bug4212464.java new file mode 100644 index 0000000000000..c1c434f6b16f7 --- /dev/null +++ b/test/jdk/javax/swing/JPopupMenu/bug4212464.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4212464 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Verify popup menu borders are drawn correctly when switching L&Fs + * @run main/manual bug4212464 + */ + +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.JApplet; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class bug4212464 extends JFrame implements ActionListener { + + static String strMotif = "Motif"; + static String motifClassName = "com.sun.java.swing.plaf.motif.MotifLookAndFeel"; + + static String strMetal = "Metal"; + static String metalClassName = "javax.swing.plaf.metal.MetalLookAndFeel"; + + static bug4212464 frame; + static JPopupMenu popup; + + static final String INSTRUCTIONS = """ + This test is to see whether popup menu borders behave properly when switching + back and forth between Motif and Metal L&F. The initial L&F is Metal. + + Pressing the mouse button on the label in the center of the test window brings + up a popup menu. + + In order to test, use the labeled buttons to switch the look and feel. + Clicking a button will cause the menu to be hidden. This is OK. Just click the label again. + Switch back and forth and verify that the popup menu border changes consistently + and there is a title for the menu when using Motif L&F (Metal won't have a title). + + Make sure you switch back and forth several times. + If the change is consistent, press PASS otherwise press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4212464::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + try { + UIManager.setLookAndFeel(metalClassName); // initialize to Metal. + } catch (Exception e) { + throw new RuntimeException(e); + } + frame = new bug4212464("bug4212464"); + popup = new JPopupMenu("Test"); + popup.add("Item 1"); + popup.add("Item 2"); + popup.add("Item 3"); + popup.add("Item 4"); + + JPanel p = new JPanel(); + p.setLayout(new FlowLayout()); + JButton motif = (JButton)p.add(new JButton(strMotif)); + JButton metal = (JButton)p.add(new JButton(strMetal)); + motif.setActionCommand(motifClassName); + metal.setActionCommand(metalClassName); + motif.addActionListener(frame); + metal.addActionListener(frame); + frame.add(BorderLayout.NORTH, p); + + JLabel l = new JLabel("Click any mouse button on this big label"); + l.setFont(new Font(Font.DIALOG, Font.PLAIN, 20)); + l.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + popup.show(e.getComponent(), e.getX(), e.getY()); + } + }); + frame.add(BorderLayout.CENTER, l); + frame.setSize(500, 400); + return frame; + } + + public bug4212464(String title) { + super(title); + } + + public void actionPerformed(ActionEvent e) { + String str = e.getActionCommand(); + if (str.equals(metalClassName) || str.equals(motifClassName)) { + changeLNF(str); + } else { + System.out.println("ActionEvent: " + str); + } + } + + public void changeLNF(String str) { + System.out.println("Changing LNF to " + str); + try { + UIManager.setLookAndFeel(str); + SwingUtilities.updateComponentTreeUI(frame); + SwingUtilities.updateComponentTreeUI(popup); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/test/jdk/javax/swing/JPopupMenu/bug4234793.java b/test/jdk/javax/swing/JPopupMenu/bug4234793.java new file mode 100644 index 0000000000000..9ad91e5165f50 --- /dev/null +++ b/test/jdk/javax/swing/JPopupMenu/bug4234793.java @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4234793 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary PopupMenuListener popupMenuCanceled is never called + * @run main/manual bug4234793 + */ + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JSeparator; +import javax.swing.KeyStroke; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; + +/** + * For all 3 components (JPopupMenu, JComboBox, JPopup) when the popup is visible, + * the popupMenuCanceled should be invoked in these two circumstances: + * + * 1. The ESCAPE key is pressed while the popup is open. + * + * 2. The mouse is clicked on another component. + * + */ + +public class bug4234793 extends JFrame implements PopupMenuListener { + + static final String INSTRUCTIONS = """ + The test window will contain several kinds of menus. + + * A menu bar with two menus labeled "1 - First Menu" and "2 - Second Menu" + * A drop down combo box - ie a button which pops up a menu when clicked + * Clicking any where on the background of the window will display a popup menu + + That is 4 menus in total. + + For each case, verify that the menu can be cancelled (hidden) in two ways + 1) Click to display the menu, then to hide it, press the ESCAPE key. + 2) Click to display the menu, then to hide it, LEFT click on the window background. + Note : the popup menu must be displayed using RIGHT click, the others use LEFT click. + + Notice each time you perform a hide/cancel action an appropriate message should + appear in the log area + If this is true for all 8 combinations of menus + hide actions the test PASSES + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(bug4234793::createUI) + .logArea() + .build() + .awaitAndCheck(); + } + + private static String[] numData = { + "One", "Two", "Three", "Four", "Five", "Six", "Seven" + }; + + private static String[] dayData = { + "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" + }; + + private static char[] mnDayData = { + 'M', 'T', 'W', 'R', 'F', 'S', 'U' + }; + + bug4234793(String title) { + super(title); + } + + static volatile JPopupMenu popupMenu; + static volatile bug4234793 frame; + + static JFrame createUI() { + frame = new bug4234793("bug4234793"); + frame.setJMenuBar(createMenuBar()); + JPanel panel = createContentPane(); + frame.add(panel); + + // CTRL-down will show the popup. + panel.getInputMap().put(KeyStroke.getKeyStroke( + KeyEvent.VK_DOWN, InputEvent.CTRL_MASK), "OPEN_POPUP"); + panel.getActionMap().put("OPEN_POPUP", new PopupHandler()); + panel.addMouseListener(new PopupListener(popupMenu)); + panel.setPreferredSize(new Dimension(400, 300)); + frame.setSize(400, 300); + return frame; + } + + static class PopupListener extends MouseAdapter { + private JPopupMenu popup; + + public PopupListener(JPopupMenu popup) { + this.popup = popup; + } + + public void mousePressed(MouseEvent e) { + maybeShowPopup(e); + } + + public void mouseReleased(MouseEvent e) { + maybeShowPopup(e); + } + + public void mouseClicked(MouseEvent ex) { + } + + private void maybeShowPopup(MouseEvent e) { + if (e.isPopupTrigger()) { + popup.show(e.getComponent(), e.getX(), e.getY()); + } + } + } + + static class PopupHandler extends AbstractAction { + public void actionPerformed(ActionEvent e) { + if (!popupMenu.isVisible()) + popupMenu.show((Component)e.getSource(), 40, 40); + } + } + + static JPanel createContentPane() { + popupMenu = new JPopupMenu(); + JMenuItem item; + for (int i = 0; i < dayData.length; i++) { + item = popupMenu.add(new JMenuItem(dayData[i], mnDayData[i])); + } + popupMenu.addPopupMenuListener(frame); + + JComboBox combo = new JComboBox(numData); + combo.addPopupMenuListener(frame); + JPanel comboPanel = new JPanel(); + comboPanel.add(combo); + + JPanel panel = new JPanel(new BorderLayout()); + + panel.add(new JLabel("Right click on the panel to show the PopupMenu"), BorderLayout.NORTH); + panel.add(comboPanel, BorderLayout.CENTER); + + return panel; + } + + static JMenuBar createMenuBar() { + JMenuBar menubar = new JMenuBar(); + JMenuItem menuitem; + + JMenu menu = new JMenu("1 - First Menu"); + menu.setMnemonic('1'); + menu.getPopupMenu().addPopupMenuListener(frame); + + menubar.add(menu); + for (int i = 0; i < 10; i ++) { + menuitem = new JMenuItem("1 JMenuItem" + i); + menuitem.setMnemonic('0' + i); + menu.add(menuitem); + } + + // second menu + menu = new JMenu("2 - Second Menu"); + menu.getPopupMenu().addPopupMenuListener(frame); + menu.setMnemonic('2'); + + menubar.add(menu); + for (int i = 0; i < 5; i++) { + menuitem = new JMenuItem("2 JMenuItem" + i); + menuitem.setMnemonic('0' + i); + menu.add(menuitem); + } + + JMenu submenu = new JMenu("Sub Menu"); + submenu.setMnemonic('S'); + submenu.getPopupMenu().addPopupMenuListener(frame); + for (int i = 0; i < 5; i++) { + menuitem = new JMenuItem("S JMenuItem" + i); + menuitem.setMnemonic('0' + i); + submenu.add(menuitem); + } + menu.add(new JSeparator()); + menu.add(submenu); + + return menubar; + } + + // PopupMenuListener methods. + + public void popupMenuWillBecomeVisible(PopupMenuEvent e) { + Object source = e.getSource(); + PassFailJFrame.log("popupmenu visible: " + source.getClass().getName()); + } + + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { + Object source = e.getSource(); + PassFailJFrame.log("popupMenuWillBecomeInvisible: " + source.getClass().getName()); + } + + public void popupMenuCanceled(PopupMenuEvent e) { + Object source = e.getSource(); + PassFailJFrame.log("POPUPMENU CANCELED: " + source.getClass().getName()); + } +} From 31e293b0821b754f0fd0dd3a9d9143a0fd43a256 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 17 Apr 2025 16:32:46 +0000 Subject: [PATCH 0647/1101] 8354552: Open source a few Swing tests Reviewed-by: dnguyen, psadhukhan --- .../ScrollToReferenceTest.java | 91 ++++++++++++++++++ .../ScrollToReferenceTest/test.html | 93 +++++++++++++++++++ test/jdk/javax/swing/JLabel/bug4106007.java | 66 +++++++++++++ test/jdk/javax/swing/JLabel/bug4945795.java | 73 +++++++++++++++ 4 files changed, 323 insertions(+) create mode 100644 test/jdk/javax/swing/JEditorPane/ScrollToReferenceTest/ScrollToReferenceTest.java create mode 100644 test/jdk/javax/swing/JEditorPane/ScrollToReferenceTest/test.html create mode 100644 test/jdk/javax/swing/JLabel/bug4106007.java create mode 100644 test/jdk/javax/swing/JLabel/bug4945795.java diff --git a/test/jdk/javax/swing/JEditorPane/ScrollToReferenceTest/ScrollToReferenceTest.java b/test/jdk/javax/swing/JEditorPane/ScrollToReferenceTest/ScrollToReferenceTest.java new file mode 100644 index 0000000000000..5d96dd70dd174 --- /dev/null +++ b/test/jdk/javax/swing/JEditorPane/ScrollToReferenceTest/ScrollToReferenceTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4194428 + * @summary Checks that scrolling an href to visible scrolls it to the top of the page. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ScrollToReferenceTest + */ + +import java.awt.Container; +import java.awt.Dimension; +import java.io.IOException; +import java.net.URL; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; + +public class ScrollToReferenceTest { + + static final String INSTRUCTIONS = """ + Wait for the html document to finish loading, click on the anchor + with text 'CLICK ME'. If 'should be at top of editor pane' is + scrolled to the top of the visible region of the text, click PASS, + otherwise click FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(ScrollToReferenceTest::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("ScrollToReferenceTest"); + JEditorPane pane = new JEditorPane(); + + try { + pane.setPage(ScrollToReferenceTest.class.getResource("test.html")); + } catch (IOException ioe) { + PassFailJFrame.forceFail("Couldn't find html file"); + } + + + pane.addHyperlinkListener(new HyperlinkListener() { + public void hyperlinkUpdate(HyperlinkEvent e) { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED && + e.getURL() != null) { + try { + pane.setPage(e.getURL()); + } catch (IOException ioe) { + pane.setText("error finding url, click fail!"); + } + } + } + }); + pane.setEditable(false); + JScrollPane sp = new JScrollPane(pane); + sp.setPreferredSize(new Dimension(400, 400)); + frame.add(sp); + frame.setSize(400, 400); + return frame; + } +} diff --git a/test/jdk/javax/swing/JEditorPane/ScrollToReferenceTest/test.html b/test/jdk/javax/swing/JEditorPane/ScrollToReferenceTest/test.html new file mode 100644 index 0000000000000..d7e82e516db0b --- /dev/null +++ b/test/jdk/javax/swing/JEditorPane/ScrollToReferenceTest/test.html @@ -0,0 +1,93 @@ + + +

Click ME! +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

should be at top of editor pane +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

a +

TEST! +

a + + diff --git a/test/jdk/javax/swing/JLabel/bug4106007.java b/test/jdk/javax/swing/JLabel/bug4106007.java new file mode 100644 index 0000000000000..b78813809c134 --- /dev/null +++ b/test/jdk/javax/swing/JLabel/bug4106007.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4106007 + * @summary Multi-line JLabel is now supported for HTML labels. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4106007 + * */ + +import java.awt.BorderLayout; +import javax.swing.JFrame; +import javax.swing.JLabel; + +public class bug4106007 { + + static final String INSTRUCTIONS = """ + The test window should have a label spanning multiple lines. + If it is press PASS, else press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4106007::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("Bug4106007"); + frame.setLayout(new BorderLayout()); + String str = ""; + String longLine = + "I hope multi-line JLabel is now supported and you can see several lines instead of one long line. "; + str += longLine; + str += longLine; + str += ""; + JLabel lab = new JLabel(str); + frame.add(lab, BorderLayout.NORTH); + frame.setSize(400, 400); + return frame; + } +} diff --git a/test/jdk/javax/swing/JLabel/bug4945795.java b/test/jdk/javax/swing/JLabel/bug4945795.java new file mode 100644 index 0000000000000..56f6e0eb60f5b --- /dev/null +++ b/test/jdk/javax/swing/JLabel/bug4945795.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 4945795 + * @summary With mnemonic hiding turned on, Java does not display all mnemonics with ALT key + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4945795 + * */ + +import java.awt.BorderLayout; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.UIManager; + +public class bug4945795 { + + static final String INSTRUCTIONS = """ + This test is for the Swing Windows Look And Feel. + A test window will be displayed with the label 'Mnemonic Test' + Click the mouse in the test window to make sure it has keyboard focus. + Now press and hold the 'Alt' key. + An underline should be displayed below the initial 'M' character. + If it is press PASS, else press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4945795::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame mainFrame = new JFrame("Bug4945795"); + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception ex) { + throw new RuntimeException("Can not set system look and feel"); + } + mainFrame.setLayout(new BorderLayout()); + mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + JLabel label = new JLabel("Mnemonic test"); + label.setDisplayedMnemonic('M'); + mainFrame.add(label, BorderLayout.NORTH); + mainFrame.setSize(400, 300); + return mainFrame; + } +} From 4eae9b5ba61bfe262b43346a7499c98c1a54d2fe Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Thu, 17 Apr 2025 17:40:38 +0000 Subject: [PATCH 0648/1101] 8354541: Remove Shenandoah post barrier expand loop opts Reviewed-by: shade --- .../shenandoah/c2/shenandoahBarrierSetC2.cpp | 5 - .../shenandoah/c2/shenandoahBarrierSetC2.hpp | 4 +- .../gc/shenandoah/c2/shenandoahSupport.cpp | 236 ------------------ .../gc/shenandoah/c2/shenandoahSupport.hpp | 6 - src/hotspot/share/opto/compile.hpp | 1 - .../TestShenandoahBarrierExpansion.java | 2 +- 6 files changed, 3 insertions(+), 251 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index a7e854aaf8399..8df4413cc2f49 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -826,11 +826,6 @@ bool ShenandoahBarrierSetC2::optimize_loops(PhaseIdealLoop* phase, LoopOptsMode assert(UseShenandoahGC, "only for shenandoah"); ShenandoahBarrierC2Support::pin_and_expand(phase); return true; - } else if (mode == LoopOptsShenandoahPostExpand) { - assert(UseShenandoahGC, "only for shenandoah"); - visited.clear(); - ShenandoahBarrierC2Support::optimize_after_expansion(visited, nstack, worklist, phase); - return true; } return false; } diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp index 61f8bfb1140b3..5bf549203ea96 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp @@ -120,8 +120,8 @@ class ShenandoahBarrierSetC2 : public BarrierSetC2 { virtual Node* step_over_gc_barrier(Node* c) const; virtual bool expand_barriers(Compile* C, PhaseIterGVN& igvn) const; virtual bool optimize_loops(PhaseIdealLoop* phase, LoopOptsMode mode, VectorSet& visited, Node_Stack& nstack, Node_List& worklist) const; - virtual bool strip_mined_loops_expanded(LoopOptsMode mode) const { return mode == LoopOptsShenandoahExpand || mode == LoopOptsShenandoahPostExpand; } - virtual bool is_gc_specific_loop_opts_pass(LoopOptsMode mode) const { return mode == LoopOptsShenandoahExpand || mode == LoopOptsShenandoahPostExpand; } + virtual bool strip_mined_loops_expanded(LoopOptsMode mode) const { return mode == LoopOptsShenandoahExpand; } + virtual bool is_gc_specific_loop_opts_pass(LoopOptsMode mode) const { return mode == LoopOptsShenandoahExpand; } // Support for macro expanded GC barriers virtual void register_potential_barrier_node(Node* node) const; diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index 860bcb38038ff..4652dbce0e36d 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -51,12 +51,6 @@ bool ShenandoahBarrierC2Support::expand(Compile* C, PhaseIterGVN& igvn) { C->clear_major_progress(); PhaseIdealLoop::optimize(igvn, LoopOptsShenandoahExpand); if (C->failing()) return false; - - C->set_major_progress(); - if (!C->optimize_loops(igvn, LoopOptsShenandoahPostExpand)) { - return false; - } - C->clear_major_progress(); C->process_for_post_loop_opts_igvn(igvn); if (C->failing()) return false; @@ -1504,236 +1498,6 @@ Node* ShenandoahBarrierC2Support::get_load_addr(PhaseIdealLoop* phase, VectorSet } -void ShenandoahBarrierC2Support::move_gc_state_test_out_of_loop(IfNode* iff, PhaseIdealLoop* phase) { - IdealLoopTree *loop = phase->get_loop(iff); - Node* loop_head = loop->_head; - Node* entry_c = loop_head->in(LoopNode::EntryControl); - - Node* bol = iff->in(1); - Node* cmp = bol->in(1); - Node* andi = cmp->in(1); - Node* load = andi->in(1); - - assert(is_gc_state_load(load), "broken"); - if (!phase->is_dominator(load->in(0), entry_c)) { - Node* mem_ctrl = nullptr; - Node* mem = dom_mem(load->in(MemNode::Memory), loop_head, Compile::AliasIdxRaw, mem_ctrl, phase); - load = load->clone(); - load->set_req(MemNode::Memory, mem); - load->set_req(0, entry_c); - phase->register_new_node(load, entry_c); - andi = andi->clone(); - andi->set_req(1, load); - phase->register_new_node(andi, entry_c); - cmp = cmp->clone(); - cmp->set_req(1, andi); - phase->register_new_node(cmp, entry_c); - bol = bol->clone(); - bol->set_req(1, cmp); - phase->register_new_node(bol, entry_c); - - phase->igvn().replace_input_of(iff, 1, bol); - } -} - -bool ShenandoahBarrierC2Support::identical_backtoback_ifs(Node* n, PhaseIdealLoop* phase) { - if (!n->is_If() || n->is_CountedLoopEnd()) { - return false; - } - Node* region = n->in(0); - - if (!region->is_Region()) { - return false; - } - Node* dom = phase->idom(region); - if (!dom->is_If()) { - return false; - } - - if (!is_heap_stable_test(n) || !is_heap_stable_test(dom)) { - return false; - } - - IfNode* dom_if = dom->as_If(); - Node* proj_true = dom_if->proj_out(1); - Node* proj_false = dom_if->proj_out(0); - - for (uint i = 1; i < region->req(); i++) { - if (phase->is_dominator(proj_true, region->in(i))) { - continue; - } - if (phase->is_dominator(proj_false, region->in(i))) { - continue; - } - return false; - } - - return true; -} - -bool ShenandoahBarrierC2Support::merge_point_safe(Node* region) { - for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) { - Node* n = region->fast_out(i); - if (n->is_LoadStore()) { - // Splitting a LoadStore node through phi, causes it to lose its SCMemProj: the split if code doesn't have support - // for a LoadStore at the region the if is split through because that's not expected to happen (LoadStore nodes - // should be between barrier nodes). It does however happen with Shenandoah though because barriers can get - // expanded around a LoadStore node. - return false; - } - } - return true; -} - - -void ShenandoahBarrierC2Support::merge_back_to_back_tests(Node* n, PhaseIdealLoop* phase) { - assert(is_heap_stable_test(n), "no other tests"); - if (identical_backtoback_ifs(n, phase)) { - Node* n_ctrl = n->in(0); - if (phase->can_split_if(n_ctrl) && merge_point_safe(n_ctrl)) { - IfNode* dom_if = phase->idom(n_ctrl)->as_If(); - if (is_heap_stable_test(n)) { - Node* gc_state_load = n->in(1)->in(1)->in(1)->in(1); - assert(is_gc_state_load(gc_state_load), "broken"); - Node* dom_gc_state_load = dom_if->in(1)->in(1)->in(1)->in(1); - assert(is_gc_state_load(dom_gc_state_load), "broken"); - if (gc_state_load != dom_gc_state_load) { - phase->igvn().replace_node(gc_state_load, dom_gc_state_load); - } - } - PhiNode* bolphi = PhiNode::make_blank(n_ctrl, n->in(1)); - Node* proj_true = dom_if->proj_out(1); - Node* proj_false = dom_if->proj_out(0); - Node* con_true = phase->igvn().makecon(TypeInt::ONE); - Node* con_false = phase->igvn().makecon(TypeInt::ZERO); - - for (uint i = 1; i < n_ctrl->req(); i++) { - if (phase->is_dominator(proj_true, n_ctrl->in(i))) { - bolphi->init_req(i, con_true); - } else { - assert(phase->is_dominator(proj_false, n_ctrl->in(i)), "bad if"); - bolphi->init_req(i, con_false); - } - } - phase->register_new_node(bolphi, n_ctrl); - phase->igvn().replace_input_of(n, 1, bolphi); - phase->do_split_if(n); - } - } -} - -IfNode* ShenandoahBarrierC2Support::find_unswitching_candidate(const IdealLoopTree* loop, PhaseIdealLoop* phase) { - // Find first invariant test that doesn't exit the loop - LoopNode *head = loop->_head->as_Loop(); - IfNode* unswitch_iff = nullptr; - Node* n = head->in(LoopNode::LoopBackControl); - int loop_has_sfpts = -1; - while (n != head) { - Node* n_dom = phase->idom(n); - if (n->is_Region()) { - if (n_dom->is_If()) { - IfNode* iff = n_dom->as_If(); - if (iff->in(1)->is_Bool()) { - BoolNode* bol = iff->in(1)->as_Bool(); - if (bol->in(1)->is_Cmp()) { - // If condition is invariant and not a loop exit, - // then found reason to unswitch. - if (is_heap_stable_test(iff) && - (loop_has_sfpts == -1 || loop_has_sfpts == 0)) { - assert(!loop->is_loop_exit(iff), "both branches should be in the loop"); - if (loop_has_sfpts == -1) { - for(uint i = 0; i < loop->_body.size(); i++) { - Node *m = loop->_body[i]; - if (m->is_SafePoint() && !m->is_CallLeaf()) { - loop_has_sfpts = 1; - break; - } - } - if (loop_has_sfpts == -1) { - loop_has_sfpts = 0; - } - } - if (!loop_has_sfpts) { - unswitch_iff = iff; - } - } - } - } - } - } - n = n_dom; - } - return unswitch_iff; -} - - -void ShenandoahBarrierC2Support::optimize_after_expansion(VectorSet &visited, Node_Stack &stack, Node_List &old_new, PhaseIdealLoop* phase) { - Node_List heap_stable_tests; - stack.push(phase->C->start(), 0); - do { - Node* n = stack.node(); - uint i = stack.index(); - - if (i < n->outcnt()) { - Node* u = n->raw_out(i); - stack.set_index(i+1); - if (!visited.test_set(u->_idx)) { - stack.push(u, 0); - } - } else { - stack.pop(); - if (n->is_If() && is_heap_stable_test(n)) { - heap_stable_tests.push(n); - } - } - } while (stack.size() > 0); - - for (uint i = 0; i < heap_stable_tests.size(); i++) { - Node* n = heap_stable_tests.at(i); - assert(is_heap_stable_test(n), "only evacuation test"); - merge_back_to_back_tests(n, phase); - } - - if (!phase->C->major_progress()) { - VectorSet seen; - for (uint i = 0; i < heap_stable_tests.size(); i++) { - Node* n = heap_stable_tests.at(i); - IdealLoopTree* loop = phase->get_loop(n); - if (loop != phase->ltree_root() && - loop->_child == nullptr && - !loop->_irreducible) { - Node* head = loop->_head; - if (head->is_Loop() && - (!head->is_CountedLoop() || head->as_CountedLoop()->is_main_loop() || head->as_CountedLoop()->is_normal_loop()) && - !seen.test_set(head->_idx)) { - IfNode* iff = find_unswitching_candidate(loop, phase); - if (iff != nullptr) { - Node* bol = iff->in(1); - if (head->as_Loop()->is_strip_mined()) { - head->as_Loop()->verify_strip_mined(0); - } - move_gc_state_test_out_of_loop(iff, phase); - - AutoNodeBudget node_budget(phase); - - if (loop->policy_unswitching(phase)) { - if (head->as_Loop()->is_strip_mined()) { - OuterStripMinedLoopNode* outer = head->as_CountedLoop()->outer_loop(); - hide_strip_mined_loop(outer, head->as_CountedLoop(), phase); - } - phase->do_unswitching(loop, old_new); - } else { - // Not proceeding with unswitching. Move load back in - // the loop. - phase->igvn().replace_input_of(iff, 1, bol); - } - } - } - } - } - } -} - #ifdef ASSERT static bool has_never_branch(Node* root) { for (uint i = 1; i < root->req(); i++) { diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp index 164502e6358f9..93572cddc5b9a 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp @@ -63,12 +63,7 @@ class ShenandoahBarrierC2Support : public AllStatic { static void call_lrb_stub(Node*& ctrl, Node*& val, Node* load_addr, DecoratorSet decorators, PhaseIdealLoop* phase); static void test_in_cset(Node*& ctrl, Node*& not_cset_ctrl, Node* val, Node* raw_mem, PhaseIdealLoop* phase); - static void move_gc_state_test_out_of_loop(IfNode* iff, PhaseIdealLoop* phase); - static void merge_back_to_back_tests(Node* n, PhaseIdealLoop* phase); - static bool merge_point_safe(Node* region); - static bool identical_backtoback_ifs(Node *n, PhaseIdealLoop* phase); static void fix_ctrl(Node* barrier, Node* region, const MemoryGraphFixer& fixer, Unique_Node_List& uses, Unique_Node_List& uses_to_ignore, uint last, PhaseIdealLoop* phase); - static IfNode* find_unswitching_candidate(const IdealLoopTree *loop, PhaseIdealLoop* phase); static Node* get_load_addr(PhaseIdealLoop* phase, VectorSet& visited, Node* lrb); public: @@ -80,7 +75,6 @@ class ShenandoahBarrierC2Support : public AllStatic { static bool expand(Compile* C, PhaseIterGVN& igvn); static void pin_and_expand(PhaseIdealLoop* phase); - static void optimize_after_expansion(VectorSet& visited, Node_Stack& nstack, Node_List& old_new, PhaseIdealLoop* phase); #ifdef ASSERT static void verify(RootNode* root); diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 6f505e502b54d..33b9187e26267 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -106,7 +106,6 @@ enum LoopOptsMode { LoopOptsNone, LoopOptsMaxUnroll, LoopOptsShenandoahExpand, - LoopOptsShenandoahPostExpand, LoopOptsSkipSplitIf, LoopOptsVerify }; diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestShenandoahBarrierExpansion.java b/test/hotspot/jtreg/compiler/gcbarriers/TestShenandoahBarrierExpansion.java index 84a34695092dd..6a1431c43df80 100644 --- a/test/hotspot/jtreg/compiler/gcbarriers/TestShenandoahBarrierExpansion.java +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestShenandoahBarrierExpansion.java @@ -71,7 +71,7 @@ private static int testLoadTwoObjectFieldsWithNullCheck() { @Test @IR(failOn = IRNode.IF, phase = CompilePhase.AFTER_PARSING) - @IR(counts = { IRNode.IF, "3" }, phase = CompilePhase.BARRIER_EXPANSION) + @IR(counts = { IRNode.IF, "4" }, phase = CompilePhase.BARRIER_EXPANSION) private static void testLoadTwoFieldObjectAndEscape() { final A field2 = staticField2; final A field3 = staticField3; From 7b0618859a7764b0d4c8b893a19dfb64f4351c07 Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Thu, 17 Apr 2025 18:31:10 +0000 Subject: [PATCH 0649/1101] 8354464: Additional cleanup setting up native.encoding Reviewed-by: naoto, alanb --- src/java.base/share/native/libjava/System.c | 11 ++----- .../unix/native/libjava/java_props_md.c | 4 --- .../windows/native/libjava/java_props_md.c | 33 +++++-------------- 3 files changed, 12 insertions(+), 36 deletions(-) diff --git a/src/java.base/share/native/libjava/System.c b/src/java.base/share/native/libjava/System.c index 530828b17420e..b1feaf3dff7a2 100644 --- a/src/java.base/share/native/libjava/System.c +++ b/src/java.base/share/native/libjava/System.c @@ -23,6 +23,7 @@ * questions. */ +#include #include #include "jni.h" @@ -147,15 +148,9 @@ Java_jdk_internal_util_SystemProps_00024Raw_platformProperties(JNIEnv *env, jcla PUTPROP(propArray, _line_separator_NDX, sprops->line_separator); /* basic encoding properties, always non-NULL */ -#ifdef MACOSX - /* - * Since sun_jnu_encoding is now hard-coded to UTF-8 on Mac, we don't - * want to use it to overwrite native.encoding - */ + assert(sprops->encoding != NULL); + assert(sprops->sun_jnu_encoding != NULL); PUTPROP(propArray, _native_encoding_NDX, sprops->encoding); -#else - PUTPROP(propArray, _native_encoding_NDX, sprops->sun_jnu_encoding); -#endif PUTPROP(propArray, _sun_jnu_encoding_NDX, sprops->sun_jnu_encoding); /* encodings for standard streams, may be NULL */ diff --git a/src/java.base/unix/native/libjava/java_props_md.c b/src/java.base/unix/native/libjava/java_props_md.c index 5adfeb0f894ca..6db307088b019 100644 --- a/src/java.base/unix/native/libjava/java_props_md.c +++ b/src/java.base/unix/native/libjava/java_props_md.c @@ -27,7 +27,6 @@ #include #include #endif -#include #include #include #ifndef ARCHPROPNAME @@ -465,9 +464,6 @@ GetJavaProperties(JNIEnv *env) sprops.sun_jnu_encoding = sprops.encoding; #endif - assert(sprops.encoding != NULL); - assert(sprops.sun_jnu_encoding != NULL); - if (isatty(STDOUT_FILENO) == 1) { sprops.stdout_encoding = sprops.encoding; } diff --git a/src/java.base/windows/native/libjava/java_props_md.c b/src/java.base/windows/native/libjava/java_props_md.c index 8fb1ee838417c..275dd3795c500 100644 --- a/src/java.base/windows/native/libjava/java_props_md.c +++ b/src/java.base/windows/native/libjava/java_props_md.c @@ -26,7 +26,6 @@ #include "jni.h" #include "jni_util.h" -#include #include #include #include @@ -47,7 +46,7 @@ typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); static BOOL SetupI18nProps(LCID lcid, char** language, char** script, char** country, - char** variant, char** encoding); + char** variant); #define PROPSIZE 9 // eight-letter + null terminator #define SNAMESIZE 86 // max number of chars for LOCALE_SNAME is 85 @@ -167,7 +166,7 @@ getEncodingFromLangID(LANGID langID) DllExport const char * getJavaIDFromLangID(LANGID langID) { - char * elems[5]; // lang, script, ctry, variant, encoding + char * elems[4]; // lang, script, ctry, variant char * ret; int index; @@ -176,12 +175,12 @@ getJavaIDFromLangID(LANGID langID) return NULL; } - for (index = 0; index < 5; index++) { + for (index = 0; index < 4; index++) { elems[index] = NULL; } if (SetupI18nProps(MAKELCID(langID, SORT_DEFAULT), - &(elems[0]), &(elems[1]), &(elems[2]), &(elems[3]), &(elems[4]))) { + &(elems[0]), &(elems[1]), &(elems[2]), &(elems[3]))) { // there always is the "language" tag strcpy(ret, elems[0]); @@ -198,7 +197,7 @@ getJavaIDFromLangID(LANGID langID) ret = NULL; } - for (index = 0; index < 5; index++) { + for (index = 0; index < 4; index++) { if (elems[index] != NULL) { free(elems[index]); } @@ -263,7 +262,7 @@ cpu_isalist(void) static BOOL SetupI18nProps(LCID lcid, char** language, char** script, char** country, - char** variant, char** encoding) { + char** variant) { /* script */ char tmp[SNAMESIZE]; *script = malloc(PROPSIZE); @@ -320,11 +319,6 @@ SetupI18nProps(LCID lcid, char** language, char** script, char** country, strcpy(*variant, "NY"); } - /* encoding */ - *encoding = getEncodingInternal(lcid); - if (*encoding == NULL) { - return FALSE; - } return TRUE; } @@ -640,7 +634,6 @@ GetJavaProperties(JNIEnv* env) LCID userDefaultUILCID = MAKELCID(userDefaultUILang, SORTIDFROMLCID(userDefaultLCID)); { - char * display_encoding; HANDLE hStdOutErr; // Windows UI Language selection list only cares "language" @@ -659,23 +652,18 @@ GetJavaProperties(JNIEnv* env) &sprops.format_language, &sprops.format_script, &sprops.format_country, - &sprops.format_variant, - &sprops.encoding); + &sprops.format_variant); SetupI18nProps(userDefaultUILCID, &sprops.display_language, &sprops.display_script, &sprops.display_country, - &sprops.display_variant, - &display_encoding); - - if (sprops.encoding == NULL) { - sprops.encoding = "UTF-8"; - } + &sprops.display_variant); sprops.sun_jnu_encoding = getEncodingInternal(0); if (sprops.sun_jnu_encoding == NULL) { sprops.sun_jnu_encoding = "UTF-8"; } + sprops.encoding = sprops.sun_jnu_encoding; if (LANGIDFROMLCID(userDefaultLCID) == 0x0c04 && majorVersion == 6) { // MS claims "Vista has built-in support for HKSCS-2004. @@ -689,9 +677,6 @@ GetJavaProperties(JNIEnv* env) sprops.sun_jnu_encoding = "MS950_HKSCS"; } - assert(sprops.encoding != NULL); - assert(sprops.sun_jnu_encoding != NULL); - hStdOutErr = GetStdHandle(STD_OUTPUT_HANDLE); if (hStdOutErr != INVALID_HANDLE_VALUE && GetFileType(hStdOutErr) == FILE_TYPE_CHAR) { From 1b4b317aacbdfc499c28b00aeaf7120790a6c11a Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Thu, 17 Apr 2025 19:19:26 +0000 Subject: [PATCH 0650/1101] 8354789: Unnecessary null check in sun.awt.windows.WToolkit.getFontPeer Reviewed-by: aivanov, tr --- .../classes/sun/awt/windows/WToolkit.java | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java b/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java index 120f67dad19f0..e151a69a0f110 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -593,22 +593,20 @@ public int getScreenResolution() { @Override public FontPeer getFontPeer(String name, int style) { - FontPeer retval = null; String lcName = name.toLowerCase(); if (null != cacheFontPeer) { - retval = cacheFontPeer.get(lcName + style); - if (null != retval) { - return retval; + FontPeer cachedVal = cacheFontPeer.get(lcName + style); + if (null != cachedVal) { + return cachedVal; } } - retval = new WFontPeer(name, style); - if (retval != null) { - if (null == cacheFontPeer) { - cacheFontPeer = new Hashtable<>(5, 0.9f); - } - if (null != cacheFontPeer) { - cacheFontPeer.put(lcName + style, retval); - } + + FontPeer retval = new WFontPeer(name, style); + if (null == cacheFontPeer) { + cacheFontPeer = new Hashtable<>(5, 0.9f); + } + if (null != cacheFontPeer) { + cacheFontPeer.put(lcName + style, retval); } return retval; } From ad7c475fb1e23f583a33d58f0bd73ea0fb56740c Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Thu, 17 Apr 2025 19:53:45 +0000 Subject: [PATCH 0651/1101] 8353655: Clean up and open source KeyEvent related tests (Part 1) Reviewed-by: abhiscxk --- .../awt/event/KeyEvent/FrenchKeyboard.java | 71 ++++++++++ .../awt/event/KeyEvent/HomeEndKeyTest.java | 126 ++++++++++++++++++ .../java/awt/event/KeyEvent/NumpadTest.java | 119 +++++++++++++++++ 3 files changed, 316 insertions(+) create mode 100644 test/jdk/java/awt/event/KeyEvent/FrenchKeyboard.java create mode 100644 test/jdk/java/awt/event/KeyEvent/HomeEndKeyTest.java create mode 100644 test/jdk/java/awt/event/KeyEvent/NumpadTest.java diff --git a/test/jdk/java/awt/event/KeyEvent/FrenchKeyboard.java b/test/jdk/java/awt/event/KeyEvent/FrenchKeyboard.java new file mode 100644 index 0000000000000..c4765c9e17ed3 --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/FrenchKeyboard.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4308606 + * @summary Tests whether the keys on the numeric keyboard work + * correctly under French input locale. + * @key i18n + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrenchKeyboard + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.TextField; +import java.lang.reflect.InvocationTargetException; + +public class FrenchKeyboard extends Frame { + static String INSTRUCTIONS = """ + This test is intended for computers with French input method. If French + input method can not be enabled or your keyboard does not have a numeric + keypad press "Pass" to skip the test. + Make sure that French input method is active and the NumLock is on. + Click on the text field in the window called "Check your keys" + and type once of each of the following keys on the numeric keypad: + /*-+1234567890 + If all the expected characters are displayed exactly once press "Pass". + If any characters do not display or display multiple times press "Fail". + """; + + public FrenchKeyboard() { + super("Check your keys"); + setLayout(new BorderLayout()); + TextField tf = new TextField(30); + add(tf, BorderLayout.CENTER); + pack(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("FrenchKeyboard Instructions") + .instructions(INSTRUCTIONS) + .testUI(FrenchKeyboard::new) + .build() + .awaitAndCheck(); + } +} + diff --git a/test/jdk/java/awt/event/KeyEvent/HomeEndKeyTest.java b/test/jdk/java/awt/event/KeyEvent/HomeEndKeyTest.java new file mode 100644 index 0000000000000..2c0155a0b60a8 --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/HomeEndKeyTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * bug 4268912 4115514 + * summary Ensures that KeyEvent has right results for the following + * non-numpad keys: Home/Eng/PageUp/PageDn + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual HomeEndKeyTest + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.lang.reflect.InvocationTargetException; + + +public class HomeEndKeyTest extends Frame implements KeyListener { + static String INSTRUCTIONS = """ + Before starting this test make sure that system shortcuts and + keybindings for the keys in the list below are disabled. + For example pressing "Print Screen" key should not launch + screen capturing software. + Click on the text field in the window named "Check keyCode values" + and one by one start typing the keys in the list below. + (If you do not have some of the keys on your keyboard skip it + and move to the next line). + After clicking each key look at the log area - the printed name + and key code should correspond to the ones for the key you typed. + Note that on some systems the graphical symbol for the key + can be printed instead of the symbolic name. + If you do not encounter unexpected key codes for the keys you typed, + press "Pass". Otherwise press "Fail". + + Key Keycode + ------------------------- + PrintScreen 154 + ScrollLock 145 + Pause 19 + + Insert 155 + Del 127 + Home 36 + End 35 + PageUp 33 + PageDown 34 + + Left Arrow 37 + Up Arrow 38 + Right Arrow 39 + Down Arrow 40 + """; + + public HomeEndKeyTest() { + super("Check KeyCode values"); + setLayout(new BorderLayout()); + TextField tf = new TextField(30); + tf.addKeyListener(this); + add(tf, BorderLayout.CENTER); + pack(); + } + + public void keyPressed(KeyEvent evt) { + printKey(evt); + } + + public void keyTyped(KeyEvent ignore) { + } + + public void keyReleased(KeyEvent evt) { + printKey(evt); + } + + protected void printKey(KeyEvent evt) { + String str; + switch (evt.getID()) { + case KeyEvent.KEY_PRESSED: + str = "KEY_PRESSED"; + break; + case KeyEvent.KEY_RELEASED: + str = "KEY_RELEASED"; + break; + default: + str = "unknown type"; + } + + str = str + ":name=" + KeyEvent.getKeyText(evt.getKeyCode()) + + " keyCode=" + evt.getKeyCode(); + PassFailJFrame.log(str); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("HomeEndKeyTest Instructions") + .instructions(INSTRUCTIONS) + .logArea(20) + .testUI(HomeEndKeyTest::new) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/event/KeyEvent/NumpadTest.java b/test/jdk/java/awt/event/KeyEvent/NumpadTest.java new file mode 100644 index 0000000000000..00c98ad4150ed --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/NumpadTest.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4083691 + * @summary Ensures that KeyEvent has right results for the following + * keys \*-+ + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual NumpadTest + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.lang.reflect.InvocationTargetException; + + +public class NumpadTest extends Frame implements KeyListener { + static String INSTRUCTIONS = """ + This test requires a keyboard with a numeric keypad (numpad). + If your keyboard does not have a numpad press "Pass" to skip testing. + Make sure NumLock is on. + Click on the text field in the window named "Check KeyChar values". + Then, type the following keys/characters in the TextField. + using the numpad keys: + /*-+ + + Verify that the keyChar and keyCode is correct for each key pressed. + Remember that the keyCode for the KEY_TYPED event should be zero. + Also verify that the character you typed appears in the TextField. + + Key Name keyChar Keycode + ------------------------------------- + / Divide / 47 111 + * Multiply * 42 106 + - Subtract - 45 109 + + Add + 43 107 + + Now repeat with the NumLock off. + + If all keycodes are valid and expected characters appear + in the text field press "Pass". Otherwise press "Fail". + """; + + public NumpadTest() { + super("Check KeyChar values"); + setLayout(new BorderLayout()); + TextField tf = new TextField(30); + tf.addKeyListener(this); + add(tf, BorderLayout.CENTER); + pack(); + } + public void keyPressed(KeyEvent evt) { + printKey(evt); + } + + public void keyTyped(KeyEvent evt) { + printKey(evt); + } + + public void keyReleased(KeyEvent evt) { + printKey(evt); + } + + protected void printKey(KeyEvent evt) { + switch (evt.getID()) { + case KeyEvent.KEY_TYPED: + break; + case KeyEvent.KEY_PRESSED: + break; + case KeyEvent.KEY_RELEASED: + break; + default: + return; + } + + if (evt.isActionKey()) { + PassFailJFrame.log("params= " + evt.paramString() + " KeyChar: " + + (int) evt.getKeyChar() + " Action Key"); + } else { + PassFailJFrame.log("params= " + evt.paramString() + " KeyChar: " + + (int) evt.getKeyChar()); + } + } + + public static void main(String[] args) throws InterruptedException, InvocationTargetException { + PassFailJFrame.builder() + .title("NumpadTest Instructions") + .instructions(INSTRUCTIONS) + .logArea(20) + .testUI(NumpadTest::new) + .build() + .awaitAndCheck(); + } +} From 38f138bc22ae705e8e09f75fe6bac4bb470dc29b Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 17 Apr 2025 23:37:45 +0000 Subject: [PATCH 0652/1101] 8354985: Add unit tests for Executor class from jpackage test lib Reviewed-by: almatvee --- .../jdk/jpackage/test/ExecutorTest.java | 370 ++++++++++++++++++ .../helpers/jdk/jpackage/test/Executor.java | 30 +- 2 files changed, 387 insertions(+), 13 deletions(-) create mode 100644 test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ExecutorTest.java diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ExecutorTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ExecutorTest.java new file mode 100644 index 0000000000000..8175f49a2b213 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ExecutorTest.java @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toSet; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.UncheckedIOException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; +import java.util.spi.ToolProvider; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +public class ExecutorTest extends JUnitAdapter { + + private record Command(List stdout, List stderr) { + Command { + stdout.forEach(Objects::requireNonNull); + stderr.forEach(Objects::requireNonNull); + } + + List asExecutable() { + final List commandline = new ArrayList<>(); + if (TKit.isWindows()) { + commandline.addAll(List.of("cmd", "/C")); + } else { + commandline.addAll(List.of("sh", "-c")); + } + commandline.add(Stream.concat(createEchoCommands(stdout), + createEchoCommands(stderr).map(v -> v + ">&2")).collect(joining(" && "))); + return commandline; + } + + private static Stream createEchoCommands(List lines) { + return lines.stream().map(line -> { + if (TKit.isWindows()) { + return "(echo " + line + ")"; + } else { + return "echo " + line; + } + }); + } + + ToolProvider asToolProvider() { + return new ToolProvider() { + + @Override + public int run(PrintWriter out, PrintWriter err, String... args) { + stdout.forEach(out::println); + stderr.forEach(err::println); + return 0; + } + + @Override + public String name() { + return "test"; + } + }; + } + } + + private enum OutputData { + EMPTY(List.of()), + ONE_LINE(List.of("Jupiter")), + MANY(List.of("Uranus", "Saturn", "Earth")); + + OutputData(List data) { + data.forEach(Objects::requireNonNull); + this.data = data; + } + + final List data; + } + + private record CommandSpec(OutputData stdout, OutputData stderr) { + CommandSpec { + Objects.requireNonNull(stdout); + Objects.requireNonNull(stderr); + } + + Command command() { + return new Command(stdout.data.stream().map(line -> { + return "stdout." + line; + }).toList(), stderr.data.stream().map(line -> { + return "stderr." + line; + }).toList()); + } + } + + public enum OutputControl { + DUMP(Executor::dumpOutput), + SAVE_ALL(Executor::saveOutput), + SAVE_FIRST_LINE(Executor::saveFirstLineOfOutput), + DISCARD_STDOUT(NOP), + DISCARD_STDERR(NOP), + ; + + OutputControl(Consumer configureExector) { + this.configureExector = Objects.requireNonNull(configureExector); + } + + Executor applyTo(Executor exec) { + configureExector.accept(exec); + return exec; + } + + static List> variants() { + final List> variants = new ArrayList<>(); + for (final var withDump : BOOLEAN_VALUES) { + variants.addAll(Stream.of( + Set.of(), + Set.of(SAVE_ALL), + Set.of(SAVE_FIRST_LINE), + Set.of(DISCARD_STDOUT), + Set.of(DISCARD_STDERR), + Set.of(SAVE_ALL, DISCARD_STDOUT), + Set.of(SAVE_FIRST_LINE, DISCARD_STDOUT), + Set.of(SAVE_ALL, DISCARD_STDERR), + Set.of(SAVE_FIRST_LINE, DISCARD_STDERR), + Set.of(SAVE_ALL, DISCARD_STDOUT, DISCARD_STDERR), + Set.of(SAVE_FIRST_LINE, DISCARD_STDOUT, DISCARD_STDERR) + ).map(v -> { + if (withDump) { + return Stream.concat(Stream.of(DUMP), v.stream()).collect(toSet()); + } else { + return v; + } + }).toList()); + } + return variants.stream().map(options -> { + return options.stream().filter(o -> { + return o.configureExector != NOP; + }).collect(toSet()); + }).distinct().toList(); + } + + private final Consumer configureExector; + + static final Set SAVE = Set.of(SAVE_ALL, SAVE_FIRST_LINE); + } + + public record OutputTestSpec(boolean toolProvider, Set outputControl, CommandSpec commandSpec) { + public OutputTestSpec { + outputControl.forEach(Objects::requireNonNull); + if (outputControl.containsAll(OutputControl.SAVE)) { + throw new IllegalArgumentException(); + } + Objects.requireNonNull(commandSpec); + } + + @Override + public String toString() { + final List tokens = new ArrayList<>(); + + if (toolProvider) { + tokens.add("tool-provider"); + } + + tokens.add("output=" + format(outputControl)); + tokens.add("command=" + commandSpec); + + return String.join(",", tokens.toArray(String[]::new)); + } + + void test() { + final var command = commandSpec.command(); + final var commandWithDiscardedStreams = discardStreams(command); + + final Executor.Result[] result = new Executor.Result[1]; + final var outputCapture = OutputCapture.captureOutput(() -> { + result[0] = createExecutor(command).executeWithoutExitCodeCheck(); + }); + + assertEquals(0, result[0].getExitCode()); + + assertEquals(expectedCapturedSystemOut(commandWithDiscardedStreams), outputCapture.outLines()); + assertEquals(expectedCapturedSystemErr(commandWithDiscardedStreams), outputCapture.errLines()); + + if (!saveOutput()) { + assertNull(result[0].getOutput()); + } else { + assertNotNull(result[0].getOutput()); + final var allExpectedOutput = expectedCommandOutput(command); + assertEquals(allExpectedOutput.isEmpty(), result[0].getOutput().isEmpty()); + if (!allExpectedOutput.isEmpty()) { + if (outputControl.contains(OutputControl.SAVE_ALL)) { + assertEquals(allExpectedOutput, result[0].getOutput()); + } else if (outputControl.contains(OutputControl.SAVE_FIRST_LINE)) { + assertEquals(1, result[0].getOutput().size()); + assertEquals(allExpectedOutput.getFirst(), result[0].getFirstLineOfOutput()); + } else { + throw new UnsupportedOperationException(); + } + } + } + } + + private boolean dumpOutput() { + return outputControl.contains(OutputControl.DUMP); + } + + private boolean saveOutput() { + return !Collections.disjoint(outputControl, OutputControl.SAVE); + } + + private boolean discardStdout() { + return outputControl.contains(OutputControl.DISCARD_STDOUT); + } + + private boolean discardStderr() { + return outputControl.contains(OutputControl.DISCARD_STDERR); + } + + private static String format(Set outputControl) { + return outputControl.stream().map(OutputControl::name).sorted().collect(joining("+")); + } + + private List expectedCapturedSystemOut(Command command) { + if (!dumpOutput() || (!toolProvider && !saveOutput())) { + return List.of(); + } else if(saveOutput()) { + return Stream.concat(command.stdout().stream(), command.stderr().stream()).toList(); + } else { + return command.stdout(); + } + } + + private List expectedCapturedSystemErr(Command command) { + if (!dumpOutput() || (!toolProvider && !saveOutput())) { + return List.of(); + } else if(saveOutput()) { + return List.of(); + } else { + return command.stderr(); + } + } + + private Command discardStreams(Command command) { + return new Command(discardStdout() ? List.of() : command.stdout(), discardStderr() ? List.of() : command.stderr()); + } + + private record OutputCapture(byte[] out, byte[] err, Charset outCharset, Charset errCharset) { + OutputCapture { + Objects.requireNonNull(out); + Objects.requireNonNull(err); + Objects.requireNonNull(outCharset); + Objects.requireNonNull(errCharset); + } + + List outLines() { + return toLines(out, outCharset); + } + + List errLines() { + return toLines(err, errCharset); + } + + private static List toLines(byte[] buf, Charset charset) { + try (var reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buf), charset))) { + return reader.lines().filter(line -> { + return !line.contains("TRACE"); + }).toList(); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + static OutputCapture captureOutput(Runnable runnable) { + final var captureOut = new ByteArrayOutputStream(); + final var captureErr = new ByteArrayOutputStream(); + + final var out = System.out; + final var err = System.err; + try { + final var outCharset = System.out.charset(); + final var errCharset = System.err.charset(); + System.setOut(new PrintStream(captureOut, true, outCharset)); + System.setErr(new PrintStream(captureErr, true, errCharset)); + runnable.run(); + return new OutputCapture(captureOut.toByteArray(), captureErr.toByteArray(), outCharset, errCharset); + } finally { + try { + System.setOut(out); + } finally { + System.setErr(err); + } + } + } + } + + private List expectedCommandOutput(Command command) { + command = discardStreams(command); + return Stream.of(command.stdout(), command.stderr()).flatMap(List::stream).toList(); + } + + private Executor createExecutor(Command command) { + final Executor exec; + if (toolProvider) { + exec = Executor.of(command.asToolProvider()); + } else { + exec = Executor.of(command.asExecutable()); + } + + outputControl.forEach(control -> control.applyTo(exec)); + + return exec; + } + } + + @ParameterizedTest + @MethodSource + public void testSavedOutput(OutputTestSpec spec) { + spec.test(); + } + + public static List testSavedOutput() { + List testCases = new ArrayList<>(); + for (final var toolProvider : BOOLEAN_VALUES) { + for (final var outputControl : OutputControl.variants()) { + for (final var stdoutContent : List.of(OutputData.values())) { + for (final var stderrContent : List.of(OutputData.values())) { + final var commandSpec = new CommandSpec(stdoutContent, stderrContent); + testCases.add(new OutputTestSpec(toolProvider, outputControl, commandSpec)); + } + } + } + } + return testCases; + } + + private static final List BOOLEAN_VALUES = List.of(Boolean.TRUE, Boolean.FALSE); + private static final Consumer NOP = exec -> {}; +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index 66cd422203b2a..053674960c49c 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -29,9 +29,9 @@ import java.io.OutputStream; import java.io.PrintStream; import java.io.StringReader; +import java.io.Writer; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -50,8 +50,16 @@ public final class Executor extends CommandArguments { public static Executor of(String... cmdline) { - return new Executor().setExecutable(cmdline[0]).addArguments( - Arrays.copyOfRange(cmdline, 1, cmdline.length)); + return of(List.of(cmdline)); + } + + public static Executor of(List cmdline) { + cmdline.forEach(Objects::requireNonNull); + return new Executor().setExecutable(cmdline.getFirst()).addArguments(cmdline.subList(1, cmdline.size())); + } + + public static Executor of(ToolProvider toolProvider, String... args) { + return new Executor().setToolProvider(toolProvider).addArguments(List.of(args)); } public Executor() { @@ -414,8 +422,8 @@ private Result runExecutable() throws IOException, InterruptedException { || saveOutputType.contains(SaveOutputType.FULL)) { outputLines = outReader.lines().collect(Collectors.toList()); } else { - outputLines = Arrays.asList( - outReader.lines().findFirst().orElse(null)); + outputLines = Optional.ofNullable(outReader.readLine()).map(List::of).orElseGet(List::of); + outReader.transferTo(Writer.nullWriter()); } } finally { if (saveOutputType.contains(SaveOutputType.DUMP) && outputLines != null) { @@ -475,15 +483,11 @@ public void write(int b) { final var exitCode = runToolProvider(ps, ps); ps.flush(); final List output; + final var bufAsString = buf.toString(); try (BufferedReader bufReader = new BufferedReader(new StringReader( - buf.toString()))) { + bufAsString))) { if (saveOutputType.contains(SaveOutputType.FIRST_LINE)) { - String firstLine = bufReader.lines().findFirst().orElse(null); - if (firstLine != null) { - output = List.of(firstLine); - } else { - output = null; - } + output = bufReader.lines().findFirst().map(List::of).orElseGet(List::of); } else if (saveOutputType.contains(SaveOutputType.FULL)) { output = bufReader.lines().collect(Collectors.toUnmodifiableList()); } else { @@ -495,7 +499,7 @@ public void write(int b) { if (saveOutputType.contains(SaveOutputType.FULL)) { lines = output.stream(); } else { - lines = bufReader.lines(); + lines = new BufferedReader(new StringReader(bufAsString)).lines(); } lines.forEach(System.out::println); } From 0995b9409d910d816276673b5c06fdf7826bfac7 Mon Sep 17 00:00:00 2001 From: Anjian-Wen Date: Fri, 18 Apr 2025 02:20:39 +0000 Subject: [PATCH 0653/1101] 8354815: RISC-V: Change type of bitwise rotation shift to iRegIorL2I Reviewed-by: fyang, fjiang --- src/hotspot/cpu/riscv/riscv.ad | 14 ++++++-------- src/hotspot/cpu/riscv/riscv_b.ad | 20 +++++++++++++++----- src/hotspot/cpu/riscv/riscv_v.ad | 4 ++++ 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index aca2f4dd488ae..1eb1464e7d938 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -6445,7 +6445,6 @@ instruct addI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immIAdd src2) %{ format %{ "addiw $dst, $src1, $src2\t#@addI_reg_imm" %} ins_encode %{ - int32_t con = (int32_t)$src2$$constant; __ addiw(as_Register($dst$$reg), as_Register($src1$$reg), $src2$$constant); @@ -6507,7 +6506,6 @@ instruct addP_reg_imm(iRegPNoSp dst, iRegP src1, immLAdd src2) %{ format %{ "addi $dst, $src1, $src2\t# ptr, #@addP_reg_imm" %} ins_encode %{ - // src2 is imm, so actually call the addi __ addi(as_Register($dst$$reg), as_Register($src1$$reg), $src2$$constant); @@ -6829,7 +6827,7 @@ instruct UmodL(iRegLNoSp dst, iRegL src1, iRegL src2) %{ // Integer Shifts // Shift Left Register -// In RV64I, only the low 5 bits of src2 are considered for the shift amount +// Only the low 5 bits of src2 are considered for the shift amount, all other bits are ignored. instruct lShiftI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (LShiftI src1 src2)); ins_cost(ALU_COST); @@ -6862,7 +6860,7 @@ instruct lShiftI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immI src2) %{ %} // Shift Right Logical Register -// In RV64I, only the low 5 bits of src2 are considered for the shift amount +// Only the low 5 bits of src2 are considered for the shift amount, all other bits are ignored. instruct urShiftI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (URShiftI src1 src2)); ins_cost(ALU_COST); @@ -6895,7 +6893,7 @@ instruct urShiftI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immI src2) %{ %} // Shift Right Arithmetic Register -// In RV64I, only the low 5 bits of src2 are considered for the shift amount +// Only the low 5 bits of src2 are considered for the shift amount, all other bits are ignored. instruct rShiftI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (RShiftI src1 src2)); ins_cost(ALU_COST); @@ -6930,7 +6928,7 @@ instruct rShiftI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immI src2) %{ // Long Shifts // Shift Left Register -// In RV64I, only the low 6 bits of src2 are considered for the shift amount +// Only the low 6 bits of src2 are considered for the shift amount, all other bits are ignored. instruct lShiftL_reg_reg(iRegLNoSp dst, iRegL src1, iRegIorL2I src2) %{ match(Set dst (LShiftL src1 src2)); @@ -6965,7 +6963,7 @@ instruct lShiftL_reg_imm(iRegLNoSp dst, iRegL src1, immI src2) %{ %} // Shift Right Logical Register -// In RV64I, only the low 6 bits of src2 are considered for the shift amount +// Only the low 6 bits of src2 are considered for the shift amount, all other bits are ignored. instruct urShiftL_reg_reg(iRegLNoSp dst, iRegL src1, iRegIorL2I src2) %{ match(Set dst (URShiftL src1 src2)); @@ -7018,7 +7016,7 @@ instruct urShiftP_reg_imm(iRegLNoSp dst, iRegP src1, immI src2) %{ %} // Shift Right Arithmetic Register -// In RV64I, only the low 6 bits of src2 are considered for the shift amount +// Only the low 6 bits of src2 are considered for the shift amount, all other bits are ignored. instruct rShiftL_reg_reg(iRegLNoSp dst, iRegL src1, iRegIorL2I src2) %{ match(Set dst (RShiftL src1 src2)); diff --git a/src/hotspot/cpu/riscv/riscv_b.ad b/src/hotspot/cpu/riscv/riscv_b.ad index ed9fca13a1b06..beac10ec03d04 100644 --- a/src/hotspot/cpu/riscv/riscv_b.ad +++ b/src/hotspot/cpu/riscv/riscv_b.ad @@ -25,7 +25,8 @@ // RISCV Bit-Manipulation Extension Architecture Description File -instruct rorI_imm_b(iRegINoSp dst, iRegI src, immI shift) %{ +// Rotate Right Word Immediate +instruct rorI_imm_b(iRegINoSp dst, iRegIorL2I src, immI shift) %{ predicate(UseZbb); match(Set dst (RotateRight src shift)); @@ -39,6 +40,7 @@ instruct rorI_imm_b(iRegINoSp dst, iRegI src, immI shift) %{ ins_pipe(ialu_reg_shift); %} +// Rotate Right Immediate instruct rorL_imm_b(iRegLNoSp dst, iRegL src, immI shift) %{ predicate(UseZbb); match(Set dst (RotateRight src shift)); @@ -53,7 +55,9 @@ instruct rorL_imm_b(iRegLNoSp dst, iRegL src, immI shift) %{ ins_pipe(ialu_reg_shift); %} -instruct rorI_reg_b(iRegINoSp dst, iRegI src, iRegI shift) %{ +// Rotate Right Word Register +// Only the low 5 bits of shift value are used, all other bits are ignored. +instruct rorI_reg_b(iRegINoSp dst, iRegIorL2I src, iRegIorL2I shift) %{ predicate(UseZbb); match(Set dst (RotateRight src shift)); @@ -65,7 +69,9 @@ instruct rorI_reg_b(iRegINoSp dst, iRegI src, iRegI shift) %{ ins_pipe(ialu_reg_reg); %} -instruct rorL_reg_b(iRegLNoSp dst, iRegL src, iRegI shift) %{ +// Rotate Right Register +// Only the low 6 bits of shift value are used, all other bits are ignored. +instruct rorL_reg_b(iRegLNoSp dst, iRegL src, iRegIorL2I shift) %{ predicate(UseZbb); match(Set dst (RotateRight src shift)); @@ -77,7 +83,9 @@ instruct rorL_reg_b(iRegLNoSp dst, iRegL src, iRegI shift) %{ ins_pipe(ialu_reg_reg); %} -instruct rolI_reg_b(iRegINoSp dst, iRegI src, iRegI shift) %{ +// Rotate Left Word Register +// Only the low 5 bits of shift value are used, all other bits are ignored. +instruct rolI_reg_b(iRegINoSp dst, iRegIorL2I src, iRegIorL2I shift) %{ predicate(UseZbb); match(Set dst (RotateLeft src shift)); @@ -89,7 +97,9 @@ instruct rolI_reg_b(iRegINoSp dst, iRegI src, iRegI shift) %{ ins_pipe(ialu_reg_reg); %} -instruct rolL_reg_b(iRegLNoSp dst, iRegL src, iRegI shift) %{ +// Rotate Left Register +// Only the low 6 bits of shift value are used, all other bits are ignored. +instruct rolL_reg_b(iRegLNoSp dst, iRegL src, iRegIorL2I shift) %{ predicate(UseZbb); match(Set dst (RotateLeft src shift)); diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 9b135215b3d0f..7c1ca4f8960ab 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -3499,6 +3499,7 @@ instruct vrotate_right(vReg dst, vReg src, vReg shift) %{ ins_pipe(pipe_slow); %} +// Only the low log2(SEW) bits of shift value are used, all other bits are ignored. instruct vrotate_right_reg(vReg dst, vReg src, iRegIorL2I shift) %{ match(Set dst (RotateRightV src (Replicate shift))); format %{ "vrotate_right_reg $dst, $src, $shift\t" %} @@ -3541,6 +3542,7 @@ instruct vrotate_right_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} +// Only the low log2(SEW) bits of shift value are used, all other bits are ignored. instruct vrotate_right_reg_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0) %{ match(Set dst_src (RotateRightV (Binary dst_src (Replicate shift)) v0)); format %{ "vrotate_right_reg_masked $dst_src, $dst_src, $shift, v0.t\t" %} @@ -3584,6 +3586,7 @@ instruct vrotate_left(vReg dst, vReg src, vReg shift) %{ ins_pipe(pipe_slow); %} +// Only the low log2(SEW) bits of shift value are used, all other bits are ignored. instruct vrotate_left_reg(vReg dst, vReg src, iRegIorL2I shift) %{ match(Set dst (RotateLeftV src (Replicate shift))); format %{ "vrotate_left_reg $dst, $src, $shift\t" %} @@ -3627,6 +3630,7 @@ instruct vrotate_left_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} +// Only the low log2(SEW) bits of shift value are used, all other bits are ignored. instruct vrotate_left_reg_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0) %{ match(Set dst_src (RotateLeftV (Binary dst_src (Replicate shift)) v0)); format %{ "vrotate_left_reg_masked $dst_src, $dst_src, $shift, v0.t\t" %} From 0feecb7c6a982e5c65df0242711ecdb0691cef87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=A0ipka?= Date: Fri, 18 Apr 2025 10:44:29 +0000 Subject: [PATCH 0654/1101] 8351851: Update PmemTest to run on AMD64 Reviewed-by: adinn --- test/jdk/java/nio/MappedByteBuffer/PmemTest.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/test/jdk/java/nio/MappedByteBuffer/PmemTest.java b/test/jdk/java/nio/MappedByteBuffer/PmemTest.java index 2771295c8a030..0c931b3606f01 100644 --- a/test/jdk/java/nio/MappedByteBuffer/PmemTest.java +++ b/test/jdk/java/nio/MappedByteBuffer/PmemTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,25 +77,24 @@ * make test TEST=jdk/java/nio/MappedByteBuffer/PmemTest.java */ -/* @test +/* @test id=default_architecture_test_case * @summary Testing NVRAM mapped byte buffer support * @run main/manual PmemTest * @requires (os.family == "linux") - * @requires (os.arch == "x86_64") + * @requires ((os.arch == "x86_64")|(os.arch == "amd64")) */ -/* @test +/* @test id=other_architectures_test_case * @summary Testing NVRAM mapped byte buffer support * @run main/manual PmemTest * @requires (os.family == "linux") - * @requires ((os.arch == "amd64")|(os.arch == "aarch64")|(os.arch == "ppc64le")) + * @requires ((os.arch == "aarch64")|(os.arch == "ppc64le")) * @ignore The test described here is currently disabled on systems that are not * x64-based and lack an external NVRAM memory device. In order to re-enable the * test, you will need to mount the NVRAM device, which will typically appear as * /dev/pmem0, to the directory /mnt/pmem. Once that is done, you can follow the * instructions above to create a test directory and remove the ignore tag. */ - import java.io.File; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; @@ -173,4 +172,4 @@ public static void dumpBufferPoolBeans() "\n}"); } } -} +} \ No newline at end of file From eda7394551b470e9dc547be93711bcceac45f303 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Fri, 18 Apr 2025 12:05:01 +0000 Subject: [PATCH 0655/1101] 8354900: javax/swing/AbstractButton/bug4133768.java failing on macosx-aarch64 Reviewed-by: abhiscxk --- .../swing/AbstractButton/bug4133768.java | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/test/jdk/javax/swing/AbstractButton/bug4133768.java b/test/jdk/javax/swing/AbstractButton/bug4133768.java index ad5f56c014984..4ccec98c6ec3a 100644 --- a/test/jdk/javax/swing/AbstractButton/bug4133768.java +++ b/test/jdk/javax/swing/AbstractButton/bug4133768.java @@ -34,8 +34,11 @@ import java.awt.GridLayout; import java.awt.Point; import java.awt.Robot; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; import java.awt.image.BufferedImage; -import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import javax.swing.AbstractButton; import javax.swing.Icon; import javax.swing.ImageIcon; @@ -47,20 +50,28 @@ import javax.swing.SwingUtilities; public class bug4133768 { - private static Icon RED, GREEN; + private static Icon RED; + private static Icon GREEN; private static JFrame f; private static AbstractButton[] buttons; private static volatile Point buttonLocation; private static volatile int buttonWidth; private static volatile int buttonHeight; private static Robot robot; + private static int ROLLOVER_Y_OFFSET = 4; + private static CountDownLatch frameGainedFocusLatch = + new CountDownLatch(1); public static void main(String[] args) throws Exception { try { createTestImages(); createUI(); + f.requestFocus(); + if (!frameGainedFocusLatch.await(5, TimeUnit.SECONDS)) { + throw new RuntimeException("Waited too long, but can't gain" + + " focus for frame"); + } robot = new Robot(); - robot.delay(1000); for (AbstractButton b : buttons) { testEnabledButton(b); } @@ -78,9 +89,9 @@ public static void main(String[] args) throws Exception { } } - private static void createTestImages() throws IOException { - int imageWidth = 32; - int imageHeight = 32; + private static void createTestImages() { + int imageWidth = 100; + int imageHeight = 100; BufferedImage redImg = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB); Graphics2D g = redImg.createGraphics(); @@ -114,6 +125,12 @@ private static void createUI() throws Exception { b.setRolloverSelectedIcon(GREEN); buttonPanel.add(b); } + f.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + frameGainedFocusLatch.countDown(); + } + }); f.setLayout(new GridLayout(2, 1)); f.add(buttonPanel); f.pack(); @@ -123,7 +140,8 @@ private static void createUI() throws Exception { }); } - private static void testEnabledButton(AbstractButton button) throws Exception { + private static void testEnabledButton(AbstractButton button) + throws Exception { robot.waitForIdle(); SwingUtilities.invokeAndWait(() -> { buttonLocation = button.getLocationOnScreen(); @@ -131,7 +149,7 @@ private static void testEnabledButton(AbstractButton button) throws Exception { buttonHeight = button.getHeight(); }); robot.mouseMove(buttonLocation.x + buttonWidth / 2, - buttonLocation.y + buttonHeight / 2 ); + buttonLocation.y + ROLLOVER_Y_OFFSET); robot.delay(1000); Color buttonColor = robot.getPixelColor(buttonLocation.x + buttonWidth / 2, buttonLocation.y + buttonHeight / 2); @@ -141,16 +159,15 @@ private static void testEnabledButton(AbstractButton button) throws Exception { } } - private static void testDisabledButton(AbstractButton button) throws Exception { + private static void testDisabledButton(AbstractButton button) + throws Exception { robot.waitForIdle(); SwingUtilities.invokeAndWait(() -> { buttonLocation = button.getLocationOnScreen(); buttonWidth = button.getWidth(); buttonHeight = button.getHeight(); }); - robot.mouseMove(buttonLocation.x + buttonWidth / 2, - buttonLocation.y + buttonHeight / 2 ); - robot.delay(1000); + robot.delay(200); Color buttonColor = robot.getPixelColor(buttonLocation.x + buttonWidth / 2, buttonLocation.y + buttonHeight / 2); if (buttonColor.equals(Color.GREEN) || From 22e8a97a1ce4e1c781fbc6f1e271c477fe95f069 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 18 Apr 2025 12:12:52 +0000 Subject: [PATCH 0656/1101] 8354988: Separate stderr and stdout in Executor class from jpackage test lib Reviewed-by: almatvee --- .../jdk/jpackage/test/ExecutorTest.java | 29 +- .../jdk/jpackage/test/PackageTestTest.java | 2 +- .../helpers/jdk/jpackage/test/Executor.java | 668 ++++++++++++++---- .../jdk/jpackage/test/JPackageCommand.java | 17 + .../jdk/jpackage/test/WindowsHelper.java | 13 +- test/jdk/tools/jpackage/share/BasicTest.java | 7 +- .../jpackage/windows/Win8301247Test.java | 36 +- 7 files changed, 601 insertions(+), 171 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ExecutorTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ExecutorTest.java index 8175f49a2b213..c5d8aed845c58 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ExecutorTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ExecutorTest.java @@ -128,8 +128,8 @@ public enum OutputControl { DUMP(Executor::dumpOutput), SAVE_ALL(Executor::saveOutput), SAVE_FIRST_LINE(Executor::saveFirstLineOfOutput), - DISCARD_STDOUT(NOP), - DISCARD_STDERR(NOP), + DISCARD_STDOUT(Executor::discardStdout), + DISCARD_STDERR(Executor::discardStderr), ; OutputControl(Consumer configureExector) { @@ -213,6 +213,9 @@ void test() { assertEquals(expectedCapturedSystemOut(commandWithDiscardedStreams), outputCapture.outLines()); assertEquals(expectedCapturedSystemErr(commandWithDiscardedStreams), outputCapture.errLines()); + assertEquals(expectedResultStdout(commandWithDiscardedStreams), result[0].stdout().getOutput()); + assertEquals(expectedResultStderr(commandWithDiscardedStreams), result[0].stderr().getOutput()); + if (!saveOutput()) { assertNull(result[0].getOutput()); } else { @@ -272,6 +275,28 @@ private List expectedCapturedSystemErr(Command command) { } } + private List expectedResultStdout(Command command) { + return expectedResultStream(command.stdout()); + } + + private List expectedResultStderr(Command command) { + if (outputControl.contains(OutputControl.SAVE_FIRST_LINE) && !command.stdout().isEmpty()) { + return List.of(); + } + return expectedResultStream(command.stderr()); + } + + private List expectedResultStream(List commandOutput) { + Objects.requireNonNull(commandOutput); + if (outputControl.contains(OutputControl.SAVE_ALL)) { + return commandOutput; + } else if (outputControl.contains(OutputControl.SAVE_FIRST_LINE)) { + return commandOutput.stream().findFirst().map(List::of).orElseGet(List::of); + } else { + return null; + } + } + private Command discardStreams(Command command) { return new Command(discardStdout() ? List.of() : command.stdout(), discardStderr() ? List.of() : command.stderr()); } diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java index 3e14022a70e2e..da94db30925da 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java @@ -370,7 +370,7 @@ public Executor.Result execute(int expectedExitCode) { } catch (IOException ex) { throw new UncheckedIOException(ex); } - return new Executor.Result(actualJPackageExitCode, null, + return new Executor.Result(actualJPackageExitCode, this::getPrintableCommandLine).assertExitCodeIs(expectedExitCode); } }; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index 053674960c49c..91625603a2b33 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -22,9 +22,12 @@ */ package jdk.jpackage.test; +import static java.util.stream.Collectors.joining; + import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; @@ -32,7 +35,6 @@ import java.io.Writer; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -63,7 +65,7 @@ public static Executor of(ToolProvider toolProvider, String... args) { } public Executor() { - saveOutputType = new HashSet<>(Set.of(SaveOutputType.NONE)); + outputStreamsControl = new OutputStreamsControl(); winEnglishOutput = false; } @@ -131,54 +133,48 @@ public Executor setWindowsTmpDir(String tmp) { } /** - * Configures this instance to save full output that command will produce. - * This function is mutual exclusive with - * saveFirstLineOfOutput() function. + * Configures this instance to save all stdout and stderr streams from the to be + * executed command. + *

+ * This function is mutually exclusive with {@link #saveFirstLineOfOutput()}. * * @return this */ public Executor saveOutput() { - saveOutputType.remove(SaveOutputType.FIRST_LINE); - saveOutputType.add(SaveOutputType.FULL); - return this; + return saveOutput(true); } /** - * Configures how to save output that command will produce. If - * v is true, the function call is equivalent to - * saveOutput() call. If v is false, - * the function will result in not preserving command output. + * Configures if all stdout and stderr streams from the to be executed command + * should be saved. + *

+ * If v is true, the function call is equivalent to + * {@link #saveOutput()} call. If v is false, command + * output will not be saved. + * + * @parameter v if both stdout and stderr streams should be saved * * @return this */ public Executor saveOutput(boolean v) { - if (v) { - saveOutput(); - } else { - saveOutputType.remove(SaveOutputType.FIRST_LINE); - saveOutputType.remove(SaveOutputType.FULL); - } - return this; + return setOutputControl(v, OutputControlOption.SAVE_ALL); } /** - * Configures this instance to save only the first line out output that - * command will produce. This function is mutual exclusive with - * saveOutput() function. + * Configures this instance to save the first line of a stream merged from + * stdout and stderr streams from the to be executed command. + *

+ * This function is mutually exclusive with {@link #saveOutput()}. * * @return this */ public Executor saveFirstLineOfOutput() { - saveOutputType.add(SaveOutputType.FIRST_LINE); - saveOutputType.remove(SaveOutputType.FULL); - return this; + return setOutputControl(true, OutputControlOption.SAVE_FIRST_LINE); } /** - * Configures this instance to dump all output that command will produce to - * System.out and System.err. Can be used together with saveOutput() and - * saveFirstLineOfOutput() to save command output and also copy it in the - * default output streams. + * Configures this instance to dump both stdout and stderr streams from the to + * be executed command into {@link System.out}. * * @return this */ @@ -187,26 +183,60 @@ public Executor dumpOutput() { } public Executor dumpOutput(boolean v) { - if (v) { - saveOutputType.add(SaveOutputType.DUMP); - } else { - saveOutputType.remove(SaveOutputType.DUMP); - } + return setOutputControl(v, OutputControlOption.DUMP); + } + + public Executor discardStdout(boolean v) { + outputStreamsControl.stdout().discard(v); return this; } - public record Result(int exitCode, List output, Supplier cmdline) { + public Executor discardStdout() { + return discardStdout(true); + } + public Executor discardStderr(boolean v) { + outputStreamsControl.stderr().discard(v); + return this; + } + + public Executor discardStderr() { + return discardStderr(true); + } + + public interface Output { + public List getOutput(); + + public default String getFirstLineOfOutput() { + return findFirstLineOfOutput().orElseThrow(); + } + + public default Optional findFirstLineOfOutput() { + return getOutput().stream().findFirst(); + } + } + + public record Result(int exitCode, CommandOutput output, Supplier cmdline) implements Output { public Result { + Objects.requireNonNull(output); Objects.requireNonNull(cmdline); } - public String getFirstLineOfOutput() { - return output.get(0); + public Result(int exitCode, Supplier cmdline) { + this(exitCode, CommandOutput.EMPTY, cmdline); } + @Override public List getOutput() { - return output; + return output.lines().orElse(null); + } + + public Output stdout() { + return createView(output.stdoutLines()); + } + + public Output stderr() { + return createView(output.stderrLines()); } public Result assertExitCodeIs(int expectedExitCode) { @@ -223,6 +253,15 @@ public Result assertExitCodeIsZero() { public int getExitCode() { return exitCode; } + + private static Output createView(Optional> lines) { + return new Output() { + @Override + public List getOutput() { + return lines.orElse(null); + } + }; + } } public Result executeWithoutExitCodeCheck() { @@ -278,27 +317,42 @@ Result getValue() { private static final long serialVersionUID = 1L; } - /* - * Repeates command "max" times and waits for "wait" seconds between each - * execution until command returns expected error code. + /** + * Executes the configured command {@code max} at most times and waits for + * {@code wait} seconds between each execution until the command exits with + * {@code expectedCode} exit code. + * + * @param expectedExitCode the expected exit code of the command + * @param max the maximum times to execute the command + * @param wait number of seconds to wait between executions of the + * command */ - public Result executeAndRepeatUntilExitCode(int expectedCode, int max, int wait) { + public Result executeAndRepeatUntilExitCode(int expectedExitCode, int max, int wait) { try { return tryRunMultipleTimes(() -> { Result result = executeWithoutExitCodeCheck(); - if (result.getExitCode() != expectedCode) { + if (result.getExitCode() != expectedExitCode) { throw new BadResultException(result); } return result; - }, max, wait).assertExitCodeIs(expectedCode); + }, max, wait).assertExitCodeIs(expectedExitCode); } catch (BadResultException ex) { - return ex.getValue().assertExitCodeIs(expectedCode); + return ex.getValue().assertExitCodeIs(expectedExitCode); } } - /* - * Repeates a "task" "max" times and waits for "wait" seconds between each - * execution until the "task" returns without throwing an exception. + /** + * Calls {@code task.get()} at most {@code max} times and waits for {@code wait} + * seconds between each call until {@code task.get()} invocation returns without + * throwing {@link RuntimeException} exception. + *

+ * Returns the object returned by the first {@code task.get()} invocation that + * didn't throw an exception or rethrows the last exception if all of + * {@code max} attempts ended in exception being thrown. + * + * @param task the object of which to call {@link Supplier#get()} function + * @param max the maximum times to execute the command + * @param wait number of seconds to wait between executions of the */ public static T tryRunMultipleTimes(Supplier task, int max, int wait) { RuntimeException lastException = null; @@ -334,9 +388,10 @@ public List executeWithoutExitCodeCheckAndGetOutput() { return saveOutput().executeWithoutExitCodeCheck().getOutput(); } - private boolean withSavedOutput() { - return saveOutputType.contains(SaveOutputType.FULL) || saveOutputType.contains( - SaveOutputType.FIRST_LINE); + private Executor setOutputControl(boolean set, OutputControlOption v) { + outputStreamsControl.stdout().set(set, v); + outputStreamsControl.stderr().set(set, v); + return this; } private Path executablePath() { @@ -349,8 +404,8 @@ private Path executablePath() { // If relative path to executable is used it seems to be broken when // ProcessBuilder changes the directory. On Windows it changes the // directory first and on Linux it looks up for executable before - // changing the directory. So to stay of safe side, use absolute path - // to executable. + // changing the directory. Use absolute path to executable to play + // it safely on all platforms. return executable.toAbsolutePath(); } @@ -371,18 +426,14 @@ private Result runExecutable() throws IOException, InterruptedException { if (winTmpDir != null) { builder.environment().put("TMP", winTmpDir); } + + outputStreamsControl.applyTo(builder); + StringBuilder sb = new StringBuilder(getPrintableCommandLine()); - if (withSavedOutput()) { - builder.redirectErrorStream(true); - sb.append("; save output"); - } else if (saveOutputType.contains(SaveOutputType.DUMP)) { - builder.inheritIO(); - sb.append("; inherit I/O"); - } else { - builder.redirectError(ProcessBuilder.Redirect.DISCARD); - builder.redirectOutput(ProcessBuilder.Redirect.DISCARD); - sb.append("; discard I/O"); - } + outputStreamsControl.describe().ifPresent(desc -> { + sb.append("; ").append(desc); + }); + if (directory != null) { builder.directory(directory.toFile()); sb.append(String.format("; in directory [%s]", directory)); @@ -414,100 +465,112 @@ private Result runExecutable() throws IOException, InterruptedException { trace("Execute " + sb.toString() + "..."); Process process = builder.start(); - List outputLines = null; - if (withSavedOutput()) { - try (BufferedReader outReader = new BufferedReader( - new InputStreamReader(process.getInputStream()))) { - if (saveOutputType.contains(SaveOutputType.DUMP) - || saveOutputType.contains(SaveOutputType.FULL)) { - outputLines = outReader.lines().collect(Collectors.toList()); - } else { - outputLines = Optional.ofNullable(outReader.readLine()).map(List::of).orElseGet(List::of); - outReader.transferTo(Writer.nullWriter()); - } - } finally { - if (saveOutputType.contains(SaveOutputType.DUMP) && outputLines != null) { - outputLines.stream().forEach(System.out::println); - if (saveOutputType.contains(SaveOutputType.FIRST_LINE)) { - // Pick the first line of saved output if there is one - for (String line: outputLines) { - outputLines = List.of(line); - break; - } - } - } - } - } + final var output = combine( + processProcessStream(outputStreamsControl.stdout(), process.getInputStream()), + processProcessStream(outputStreamsControl.stderr(), process.getErrorStream())); final int exitCode = process.waitFor(); trace("Done. Exit code: " + exitCode); - final List output; - if (outputLines != null) { - output = Collections.unmodifiableList(outputLines); - } else { - output = null; - } return createResult(exitCode, output); } private int runToolProvider(PrintStream out, PrintStream err) { - trace("Execute " + getPrintableCommandLine() + "..."); + final var sb = new StringBuilder(getPrintableCommandLine()); + outputStreamsControl.describe().ifPresent(desc -> { + sb.append("; ").append(desc); + }); + trace("Execute " + sb + "..."); final int exitCode = toolProvider.run(out, err, args.toArray( String[]::new)); trace("Done. Exit code: " + exitCode); return exitCode; } - private Result createResult(int exitCode, List output) { - return new Result(exitCode, output, this::getPrintableCommandLine); + private Result runToolProvider() throws IOException { + final var toolProviderStreamConfig = ToolProviderStreamConfig.create(outputStreamsControl); + + final var exitCode = runToolProvider(toolProviderStreamConfig); + + final var output = combine( + read(outputStreamsControl.stdout(), toolProviderStreamConfig.out()), + read(outputStreamsControl.stderr(), toolProviderStreamConfig.err())); + return createResult(exitCode, output); } - private Result runToolProvider() throws IOException { - if (!withSavedOutput()) { - if (saveOutputType.contains(SaveOutputType.DUMP)) { - return createResult(runToolProvider(System.out, System.err), null); - } + private int runToolProvider(ToolProviderStreamConfig cfg) throws IOException { + try { + return runToolProvider(cfg.out().ps(), cfg.err().ps()); + } finally { + cfg.out().ps().flush(); + cfg.err().ps().flush(); + } + } - PrintStream nullPrintStream = new PrintStream(new OutputStream() { - @Override - public void write(int b) { - // Nop - } - }); - return createResult(runToolProvider(nullPrintStream, nullPrintStream), null); - } - - try (ByteArrayOutputStream buf = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(buf)) { - final var exitCode = runToolProvider(ps, ps); - ps.flush(); - final List output; - final var bufAsString = buf.toString(); - try (BufferedReader bufReader = new BufferedReader(new StringReader( - bufAsString))) { - if (saveOutputType.contains(SaveOutputType.FIRST_LINE)) { - output = bufReader.lines().findFirst().map(List::of).orElseGet(List::of); - } else if (saveOutputType.contains(SaveOutputType.FULL)) { - output = bufReader.lines().collect(Collectors.toUnmodifiableList()); - } else { - output = null; + private static Optional> processProcessStream(OutputControl outputControl, InputStream in) throws IOException { + List outputLines = null; + try (final var bufReader = new BufferedReader(new InputStreamReader(in))) { + if (outputControl.dump() || outputControl.saveAll()) { + outputLines = bufReader.lines().toList(); + } else if (outputControl.saveFirstLine()) { + outputLines = Optional.ofNullable(bufReader.readLine()).map(List::of).orElseGet(List::of); + // Read all input, or the started process may exit with an error (cmd.exe does so). + bufReader.transferTo(Writer.nullWriter()); + } else { + // This should be empty input stream, fetch it anyway. + bufReader.transferTo(Writer.nullWriter()); + } + } finally { + if (outputControl.dump() && outputLines != null) { + outputLines.forEach(System.out::println); + if (outputControl.saveFirstLine()) { + outputLines = outputLines.stream().findFirst().map(List::of).orElseGet(List::of); } + } + if (!outputControl.save()) { + outputLines = null; + } + } + return Optional.ofNullable(outputLines); + } + + private static Optional> read(OutputControl outputControl, CachingPrintStream cps) throws IOException { + final var bufferAsString = cps.bufferContents(); + try (final var bufReader = new BufferedReader(new StringReader(bufferAsString.orElse("")))) { + if (outputControl.saveFirstLine()) { + return Optional.of(bufReader.lines().findFirst().map(List::of).orElseGet(List::of)); + } else if (outputControl.saveAll()) { + return Optional.of(bufReader.lines().toList()); + } else if (bufferAsString.isPresent()) { + return Optional.of(List.of()); + } else { + return Optional.empty(); + } + } + } - if (saveOutputType.contains(SaveOutputType.DUMP)) { - Stream lines; - if (saveOutputType.contains(SaveOutputType.FULL)) { - lines = output.stream(); - } else { - lines = new BufferedReader(new StringReader(bufAsString)).lines(); - } - lines.forEach(System.out::println); - } + private CommandOutput combine(Optional> out, Optional> err) { + if (out.isEmpty() && err.isEmpty()) { + return new CommandOutput(); + } else if (out.isEmpty()) { + return new CommandOutput(err, -1); + } else if (err.isEmpty()) { + return new CommandOutput(out, Integer.MAX_VALUE); + } else { + final var combined = Stream.of(out, err).map(Optional::orElseThrow).flatMap(List::stream); + if (outputStreamsControl.stdout().saveFirstLine() && outputStreamsControl.stderr().saveFirstLine()) { + return new CommandOutput(Optional.of(combined.findFirst().map(List::of).orElseGet(List::of)), + Integer.min(1, out.orElseThrow().size())); + } else { + return new CommandOutput(Optional.of(combined.toList()), out.orElseThrow().size()); } - return createResult(exitCode, output); } } + private Result createResult(int exitCode, CommandOutput output) { + return new Result(exitCode, output, this::getPrintableCommandLine); + } + public String getPrintableCommandLine() { final String exec; String format = "[%s](%d)"; @@ -539,16 +602,343 @@ private static void trace(String msg) { TKit.trace(String.format("exec: %s", msg)); } + private static PrintStream nullPrintStream() { + return new PrintStream(OutputStream.nullOutputStream()); + } + + private record OutputStreamsControl(OutputControl stdout, OutputControl stderr) { + OutputStreamsControl { + Objects.requireNonNull(stdout); + Objects.requireNonNull(stderr); + } + + OutputStreamsControl() { + this(new OutputControl(), new OutputControl()); + } + + void applyTo(ProcessBuilder pb) { + pb.redirectOutput(stdout.asProcessBuilderRedirect()); + pb.redirectError(stderr.asProcessBuilderRedirect()); + } + + Optional describe() { + final List tokens = new ArrayList<>(); + if (stdout.save() || stderr.save()) { + streamsLabel("save ", true).ifPresent(tokens::add); + } + if (stdout.dump() || stderr.dump()) { + streamsLabel("inherit ", true).ifPresent(tokens::add); + } + streamsLabel("discard ", false).ifPresent(tokens::add); + if (tokens.isEmpty()) { + return Optional.empty(); + } else { + return Optional.of(String.join("; ", tokens)); + } + } + + Optional streamsLabel(String prefix, boolean negate) { + Objects.requireNonNull(prefix); + final var str = Stream.of(stdoutLabel(negate), stderrLabel(negate)) + .filter(Optional::isPresent) + .map(Optional::orElseThrow) + .collect(joining("+")); + if (str.isEmpty()) { + return Optional.empty(); + } else { + return Optional.of(prefix + str); + } + } + + private Optional stdoutLabel(boolean negate) { + if ((stdout.discard() && !negate) || (!stdout.discard() && negate)) { + return Optional.of("out"); + } else { + return Optional.empty(); + } + } + + private Optional stderrLabel(boolean negate) { + if ((stderr.discard() && !negate) || (!stderr.discard() && negate)) { + return Optional.of("err"); + } else { + return Optional.empty(); + } + } + } + + private record CachingPrintStream(PrintStream ps, Optional buf) { + CachingPrintStream { + Objects.requireNonNull(ps); + Objects.requireNonNull(buf); + } + + Optional bufferContents() { + return buf.map(ByteArrayOutputStream::toString); + } + + static Builder build() { + return new Builder(); + } + + static final class Builder { + + Builder save(boolean v) { + save = v; + return this; + } + + Builder discard(boolean v) { + discard = v; + return this; + } + + Builder dumpStream(PrintStream v) { + dumpStream = v; + return this; + } + + CachingPrintStream create() { + final Optional buf; + if (save && !discard) { + buf = Optional.of(new ByteArrayOutputStream()); + } else { + buf = Optional.empty(); + } + + final PrintStream ps; + if (buf.isPresent() && dumpStream != null) { + ps = new PrintStream(new TeeOutputStream(List.of(buf.orElseThrow(), dumpStream)), true, dumpStream.charset()); + } else if (!discard) { + ps = buf.map(PrintStream::new).or(() -> Optional.ofNullable(dumpStream)).orElseGet(Executor::nullPrintStream); + } else { + ps = nullPrintStream(); + } + + return new CachingPrintStream(ps, buf); + } + + private boolean save; + private boolean discard; + private PrintStream dumpStream; + } + } + + private record ToolProviderStreamConfig(CachingPrintStream out, CachingPrintStream err) { + ToolProviderStreamConfig { + Objects.requireNonNull(out); + Objects.requireNonNull(err); + } + + static ToolProviderStreamConfig create(OutputStreamsControl cfg) { + final var errCfgBuilder = cfg.stderr().buildCachingPrintStream(System.err); + if (cfg.stderr().dump() && cfg.stderr().save()) { + errCfgBuilder.dumpStream(System.out); + } + return new ToolProviderStreamConfig( + cfg.stdout().buildCachingPrintStream(System.out).create(), errCfgBuilder.create()); + } + } + + private static final class OutputControl { + + boolean save() { + return save.isPresent(); + } + + boolean saveAll() { + return save.orElse(null) == OutputControlOption.SAVE_ALL; + } + + boolean saveFirstLine() { + return save.orElse(null) == OutputControlOption.SAVE_FIRST_LINE; + } + + boolean discard() { + return discard || (!dump && save.isEmpty()); + } + + boolean dump() { + return !discard && dump; + } + + OutputControl dump(boolean v) { + this.dump = v; + return this; + } + + OutputControl discard(boolean v) { + this.discard = v; + return this; + } + + OutputControl saveAll(boolean v) { + if (v) { + save = Optional.of(OutputControlOption.SAVE_ALL); + } else { + save = Optional.empty(); + } + return this; + } + + OutputControl saveFirstLine(boolean v) { + if (v) { + save = Optional.of(OutputControlOption.SAVE_FIRST_LINE); + } else { + save = Optional.empty(); + } + return this; + } + + OutputControl set(boolean set, OutputControlOption v) { + switch (v) { + case DUMP -> dump(set); + case SAVE_ALL -> saveAll(set); + case SAVE_FIRST_LINE -> saveFirstLine(set); + } + return this; + } + + ProcessBuilder.Redirect asProcessBuilderRedirect() { + if (discard()) { + return ProcessBuilder.Redirect.DISCARD; + } else if (dump && !save()) { + return ProcessBuilder.Redirect.INHERIT; + } else { + return ProcessBuilder.Redirect.PIPE; + } + } + + CachingPrintStream.Builder buildCachingPrintStream(PrintStream dumpStream) { + Objects.requireNonNull(dumpStream); + final var builder = CachingPrintStream.build().save(save()).discard(discard()); + if (dump()) { + builder.dumpStream(dumpStream); + } + return builder; + } + + private boolean dump; + private boolean discard; + private Optional save = Optional.empty(); + } + + private static final class TeeOutputStream extends OutputStream { + + public TeeOutputStream(Iterable streams) { + streams.forEach(Objects::requireNonNull); + this.streams = streams; + } + + @Override + public void write(int b) throws IOException { + for (final var out : streams) { + out.write(b); + } + } + + @Override + public void write(byte[] b) throws IOException { + for (final var out : streams) { + out.write(b); + } + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + for (final var out : streams) { + out.write(b, off, len); + } + } + + @Override + public void flush() throws IOException { + forEach(OutputStream::flush); + } + + @Override + public void close() throws IOException { + forEach(OutputStream::close); + } + + private void forEach(OutputStreamConsumer c) throws IOException { + IOException firstEx = null; + for (final var out : streams) { + try { + c.accept(out); + } catch (IOException e) { + if (firstEx == null) { + firstEx = e; + } + } + } + if (firstEx != null) { + throw firstEx; + } + } + + @FunctionalInterface + private static interface OutputStreamConsumer { + void accept(OutputStream out) throws IOException; + } + + private final Iterable streams; + } + + private static final class CommandOutput { + CommandOutput(Optional> lines, int stdoutLineCount) { + this.lines = Objects.requireNonNull(lines); + this.stdoutLineCount = stdoutLineCount; + } + + CommandOutput() { + this(Optional.empty(), 0); + } + + Optional> lines() { + return lines; + } + + Optional> stdoutLines() { + if (lines.isEmpty() || stdoutLineCount < 0) { + return Optional.empty(); + } + + final var theLines = lines.orElseThrow(); + if (stdoutLineCount == theLines.size()) { + return lines; + } else { + return Optional.of(theLines.subList(0, Integer.min(stdoutLineCount, theLines.size()))); + } + } + + Optional> stderrLines() { + if (lines.isEmpty() || stdoutLineCount > lines.orElseThrow().size()) { + return Optional.empty(); + } else if (stdoutLineCount == 0) { + return lines; + } else { + final var theLines = lines.orElseThrow(); + return Optional.of(theLines.subList(stdoutLineCount, theLines.size())); + } + } + + private final Optional> lines; + private final int stdoutLineCount; + + static final CommandOutput EMPTY = new CommandOutput(); + } + private ToolProvider toolProvider; private Path executable; - private Set saveOutputType; + private OutputStreamsControl outputStreamsControl; private Path directory; private Set removeEnvVars = new HashSet<>(); private Map setEnvVars = new HashMap<>(); private boolean winEnglishOutput; private String winTmpDir = null; - private static enum SaveOutputType { - NONE, FULL, FIRST_LINE, DUMP - }; + private static enum OutputControlOption { + SAVE_ALL, SAVE_FIRST_LINE, DUMP + } } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index b4d2d1872eb9f..cb9e3a687c7b3 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -67,6 +67,8 @@ public JPackageCommand(JPackageCommand cmd) { args.addAll(cmd.args); withToolProvider = cmd.withToolProvider; saveConsoleOutput = cmd.saveConsoleOutput; + discardStdout = cmd.discardStdout; + discardStderr = cmd.discardStderr; suppressOutput = cmd.suppressOutput; ignoreDefaultRuntime = cmd.ignoreDefaultRuntime; ignoreDefaultVerbose = cmd.ignoreDefaultVerbose; @@ -679,6 +681,18 @@ public JPackageCommand saveConsoleOutput(boolean v) { return this; } + public JPackageCommand discardStdout(boolean v) { + verifyMutable(); + discardStdout = v; + return this; + } + + public JPackageCommand discardStderr(boolean v) { + verifyMutable(); + discardStderr = v; + return this; + } + public JPackageCommand dumpOutput(boolean v) { verifyMutable(); suppressOutput = !v; @@ -770,6 +784,7 @@ public JPackageCommand executeVerifyActions() { private Executor createExecutor() { Executor exec = new Executor() .saveOutput(saveConsoleOutput).dumpOutput(!suppressOutput) + .discardStdout(discardStdout).discardStderr(discardStderr) .setDirectory(executeInDirectory) .addArguments(args); @@ -1272,6 +1287,8 @@ public void run() { private Boolean withToolProvider; private boolean saveConsoleOutput; + private boolean discardStdout; + private boolean discardStderr; private boolean suppressOutput; private boolean ignoreDefaultRuntime; private boolean ignoreDefaultVerbose; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java index bc67f6e417de5..1c6ac9a7669fe 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java @@ -323,18 +323,19 @@ public static void killAppLauncherProcess(JPackageCommand cmd, private static long[] findAppLauncherPIDs(JPackageCommand cmd, String launcherName) { // Get the list of PIDs and PPIDs of app launcher processes. Run setWinRunWithEnglishOutput(true) for JDK-8344275. // wmic process where (name = "foo.exe") get ProcessID,ParentProcessID - List output = Executor.of("wmic", "process", "where", "(name", + final var result = Executor.of("wmic", "process", "where", "(name", "=", "\"" + cmd.appLauncherPath(launcherName).getFileName().toString() + "\"", ")", "get", "ProcessID,ParentProcessID").dumpOutput(true).saveOutput(). - setWinRunWithEnglishOutput(true).executeAndGetOutput(); - if ("No Instance(s) Available.".equals(output.getFirst().trim())) { + setWinRunWithEnglishOutput(true).execute(); + if ("No Instance(s) Available.".equals(result.stderr().findFirstLineOfOutput().map(String::trim).orElse(""))) { return new long[0]; } - String[] headers = Stream.of(output.getFirst().split("\\s+", 2)).map( + final var stdout = result.stdout(); + String[] headers = Stream.of(stdout.getFirstLineOfOutput().split("\\s+", 2)).map( String::trim).map(String::toLowerCase).toArray(String[]::new); - Pattern pattern; + final Pattern pattern; if (headers[0].equals("parentprocessid") && headers[1].equals( "processid")) { pattern = Pattern.compile("^(?\\d+)\\s+(?\\d+)\\s+$"); @@ -346,7 +347,7 @@ private static long[] findAppLauncherPIDs(JPackageCommand cmd, String launcherNa "Unrecognizable output of \'wmic process\' command"); } - List processes = output.stream().skip(1).map(line -> { + List processes = stdout.getOutput().stream().skip(1).map(line -> { Matcher m = pattern.matcher(line); long[] pids = null; if (m.matches()) { diff --git a/test/jdk/tools/jpackage/share/BasicTest.java b/test/jdk/tools/jpackage/share/BasicTest.java index 68c1b2c76cb0d..bfcfe7587d494 100644 --- a/test/jdk/tools/jpackage/share/BasicTest.java +++ b/test/jdk/tools/jpackage/share/BasicTest.java @@ -237,20 +237,21 @@ public void testErrorsAlwaysPrinted(boolean verbose) { final var cmd = JPackageCommand.helloAppImage() .ignoreDefaultVerbose(true) .useToolProvider(false) + .discardStdout(true) .removeArgumentWithValue("--main-class"); if (verbose) { cmd.addArgument("--verbose"); } - final var textVerifier = Stream.of( + cmd.validateOutput(Stream.of( List.of("error.no-main-class-with-main-jar", "hello.jar"), List.of("error.no-main-class-with-main-jar.advice", "hello.jar") ).map(args -> { return JPackageStringBundle.MAIN.cannedFormattedString(args.getFirst(), args.subList(1, args.size()).toArray()); - }).map(CannedFormattedString::getValue).map(TKit::assertTextStream).reduce(TKit.TextStreamVerifier::andThen).orElseThrow(); + }).toArray(CannedFormattedString[]::new)); - textVerifier.apply(cmd.saveConsoleOutput(true).execute(1).getOutput().stream().filter(Predicate.not(JPackageCommand::withTimestamp))); + cmd.execute(1); } @Test diff --git a/test/jdk/tools/jpackage/windows/Win8301247Test.java b/test/jdk/tools/jpackage/windows/Win8301247Test.java index b0c11147a1748..2f98141dcb468 100644 --- a/test/jdk/tools/jpackage/windows/Win8301247Test.java +++ b/test/jdk/tools/jpackage/windows/Win8301247Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,14 +21,12 @@ * questions. */ -import java.io.IOException; +import static jdk.jpackage.test.WindowsHelper.killAppLauncherProcess; + import java.time.Duration; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.HelloApp; -import static jdk.jpackage.test.WindowsHelper.killAppLauncherProcess; +import jdk.jpackage.test.JPackageCommand; /** * Test that terminating of the parent app launcher process automatically @@ -48,7 +46,7 @@ public class Win8301247Test { @Test - public void test() throws IOException, InterruptedException { + public void test() throws InterruptedException { var cmd = JPackageCommand.helloAppImage().ignoreFakeRuntime(); // Launch the app in a way it doesn't exit to let us trap app laucnher @@ -56,22 +54,20 @@ public void test() throws IOException, InterruptedException { cmd.addArguments("--java-options", "-Djpackage.test.noexit=true"); cmd.executeAndAssertImageCreated(); - try ( // Launch the app in a separate thread - ExecutorService exec = Executors.newSingleThreadExecutor()) { - exec.execute(() -> { - HelloApp.executeLauncher(cmd); - }); + // Launch the app in a separate thread + new Thread(() -> { + HelloApp.executeLauncher(cmd); + }).start(); - // Wait a bit to let the app start - Thread.sleep(Duration.ofSeconds(10)); + // Wait a bit to let the app start + Thread.sleep(Duration.ofSeconds(10)); - // Find the main app launcher process and kill it - killAppLauncherProcess(cmd, null, 2); + // Find the main app launcher process and kill it + killAppLauncherProcess(cmd, null, 2); - // Wait a bit and check if child app launcher process is still running (it must NOT) - Thread.sleep(Duration.ofSeconds(5)); + // Wait a bit and check if child app launcher process is still running (it must NOT) + Thread.sleep(Duration.ofSeconds(5)); - killAppLauncherProcess(cmd, null, 0); - } + killAppLauncherProcess(cmd, null, 0); } } From bb08a70bd8deadc9c7522d1ce2ec779d5a6bd986 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 18 Apr 2025 17:01:42 +0000 Subject: [PATCH 0657/1101] 8355002: Clean up some mentions of "applet" in tests Reviewed-by: serb --- .../ChoiceLocationTest.java | 2 +- .../Dialog/CloseDialog/CloseDialogTest.java | 2 +- .../awt/Focus/ChoiceFocus/ChoiceFocus.java | 1 - .../FirstItemRemoveTest.java | 2 +- .../FocusEmptyListTest.java | 2 +- .../GetMousePositionWithOverlay.java | 2 +- .../GetMousePositionWithPopup.java | 4 +- .../PageSetupDlgBlockingTest.java | 1 - .../jdk/java/awt/TextArea/TextScrollTest.java | 2 +- .../DragUnicodeBetweenJVMTest.java | 1 - .../MissedHtmlAndRtfBug.java | 1 - .../DnDFileGroupDescriptor.java | 2 +- .../FileListBetweenJVMsTest.java | 1 - .../URIListBetweenJVMsTest.java | 1 - .../URIListToFileListBetweenJVMsTest.java | 1 - .../MenuDragMouseEventAbsoluteCoordsTest.java | 2 +- .../InfiniteRecursion_2.java | 12 +- .../InfiniteRecursion_3.java | 8 +- .../event/helpers/lwcomponents/LWButton.java | 12 +- .../EmbeddedFrameTest1.java | 4 +- test/jdk/java/awt/im/8041990/bug8041990.java | 2 +- .../java/awt/print/Dialog/DialogOrient.java | 3 - .../awt/print/PrinterJob/PrintDialog.java | 3 - .../print/PrinterJob/PrintDialogCancel.java | 3 - .../java/awt/print/PrinterJob/ThinLines.java | 3 - .../java/awt/regtesthelpers/AbstractTest.java | 2 - test/jdk/java/awt/regtesthelpers/Util.java | 2 - .../process/ProcessCommunicator.java | 2 +- .../sound/sampled/Clip/ClipFlushCrash.java | 2 +- .../sound/sampled/LinuxBlock/PlaySine.java | 2 +- .../javax/swing/JPopupMenu/bug4212464.java | 1 - .../swing/JTextArea/4697612/bug4697612.java | 2 +- .../swing/JTextArea/4697612/bug4697612.txt | 221 ------------------ .../parser/Parser/6990651/bug6990651.java | 2 +- .../SwingMark/src/AbstractSwingTest.java | 9 - .../client/SwingMark/src/JMTest_01.java | 8 - .../client/SwingMark/src/JMTest_02.java | 8 - .../client/SwingMark/src/JMTest_03.java | 8 - .../client/SwingMark/src/JMTest_04.java | 8 - .../client/SwingMark/src/JMTest_05.java | 8 - .../client/SwingMark/src/MenuTest.java | 8 - .../client/SwingMark/src/TypingTest.java | 4 - 42 files changed, 28 insertions(+), 346 deletions(-) delete mode 100644 test/jdk/javax/swing/JTextArea/4697612/bug4697612.txt diff --git a/test/jdk/java/awt/Choice/ChoiceLocationTest/ChoiceLocationTest.java b/test/jdk/java/awt/Choice/ChoiceLocationTest/ChoiceLocationTest.java index 78c83185cbed9..5bff03d5b34d4 100644 --- a/test/jdk/java/awt/Choice/ChoiceLocationTest/ChoiceLocationTest.java +++ b/test/jdk/java/awt/Choice/ChoiceLocationTest/ChoiceLocationTest.java @@ -25,7 +25,7 @@ * @test * @key headful * @bug 7159566 - * @summary The choice positioned in the top of applet when clicking the choice. + * @summary The choice positioned in the top of window when clicking the choice. * @author Petr Pchelko * @library ../../regtesthelpers * @build Util diff --git a/test/jdk/java/awt/Dialog/CloseDialog/CloseDialogTest.java b/test/jdk/java/awt/Dialog/CloseDialog/CloseDialogTest.java index 4db2d52e4ea78..93bf59d27573b 100644 --- a/test/jdk/java/awt/Dialog/CloseDialog/CloseDialogTest.java +++ b/test/jdk/java/awt/Dialog/CloseDialog/CloseDialogTest.java @@ -32,7 +32,7 @@ * @test * @key headful * @bug 8043705 - * @summary Can't exit color chooser dialog when running as an applet + * @summary Can't exit color chooser dialog when running in non-default AppContext * @modules java.desktop/sun.awt * @run main CloseDialogTest */ diff --git a/test/jdk/java/awt/Focus/ChoiceFocus/ChoiceFocus.java b/test/jdk/java/awt/Focus/ChoiceFocus/ChoiceFocus.java index 904992f96b287..2456379f0f914 100644 --- a/test/jdk/java/awt/Focus/ChoiceFocus/ChoiceFocus.java +++ b/test/jdk/java/awt/Focus/ChoiceFocus/ChoiceFocus.java @@ -32,7 +32,6 @@ @run main ChoiceFocus */ -import java.applet.*; import java.awt.*; import java.awt.event.*; import test.java.awt.regtesthelpers.Util; diff --git a/test/jdk/java/awt/List/FirstItemRemoveTest/FirstItemRemoveTest.java b/test/jdk/java/awt/List/FirstItemRemoveTest/FirstItemRemoveTest.java index 1efcee3e675ac..69bd1dd6c835f 100644 --- a/test/jdk/java/awt/List/FirstItemRemoveTest/FirstItemRemoveTest.java +++ b/test/jdk/java/awt/List/FirstItemRemoveTest/FirstItemRemoveTest.java @@ -127,4 +127,4 @@ private void test(){ } -}// class AutomaticAppletTest +} diff --git a/test/jdk/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.java b/test/jdk/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.java index 67926b5fe19ba..1b1d4e4b5c4d3 100644 --- a/test/jdk/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.java +++ b/test/jdk/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.java @@ -99,4 +99,4 @@ public void start() { }// start() -}// class AutomaticAppletTest +} diff --git a/test/jdk/java/awt/Mouse/GetMousePositionTest/GetMousePositionWithOverlay.java b/test/jdk/java/awt/Mouse/GetMousePositionTest/GetMousePositionWithOverlay.java index b380af149f6a7..fb3ea40a53188 100644 --- a/test/jdk/java/awt/Mouse/GetMousePositionTest/GetMousePositionWithOverlay.java +++ b/test/jdk/java/awt/Mouse/GetMousePositionTest/GetMousePositionWithOverlay.java @@ -31,7 +31,7 @@ * @test * @key headful * @bug 8012026 8196435 - * @summary Component.getMousePosition() does not work in an applet on MacOS + * @summary Component.getMousePosition() does not work in some cases on MacOS * @run main GetMousePositionWithOverlay */ diff --git a/test/jdk/java/awt/Mouse/GetMousePositionTest/GetMousePositionWithPopup.java b/test/jdk/java/awt/Mouse/GetMousePositionTest/GetMousePositionWithPopup.java index 5bfadc6fbe7cd..663942b7630df 100644 --- a/test/jdk/java/awt/Mouse/GetMousePositionTest/GetMousePositionWithPopup.java +++ b/test/jdk/java/awt/Mouse/GetMousePositionTest/GetMousePositionWithPopup.java @@ -33,7 +33,7 @@ * @test * @key headful * @bug 8012026 8027154 - * @summary Component.getMousePosition() does not work in an applet on MacOS + * @summary Component.getMousePosition() does not work in some cases on MacOS * * @requires (os.family == "windows") * @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1 GetMousePositionWithPopup @@ -48,7 +48,7 @@ * @test * @key headful * @bug 8012026 8027154 - * @summary Component.getMousePosition() does not work in an applet on MacOS + * @summary Component.getMousePosition() does not work in some cases on MacOS * * @requires (os.family == "mac" | os.family == "linux") * @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=1 GetMousePositionWithPopup diff --git a/test/jdk/java/awt/PrintJob/PageSetupDlgBlockingTest/PageSetupDlgBlockingTest.java b/test/jdk/java/awt/PrintJob/PageSetupDlgBlockingTest/PageSetupDlgBlockingTest.java index 9fbf48f3eb467..bc392ab9efe79 100644 --- a/test/jdk/java/awt/PrintJob/PageSetupDlgBlockingTest/PageSetupDlgBlockingTest.java +++ b/test/jdk/java/awt/PrintJob/PageSetupDlgBlockingTest/PageSetupDlgBlockingTest.java @@ -34,7 +34,6 @@ import java.awt.print.*; import java.awt.event.*; import javax.swing.*; -import java.applet.*; public class PageSetupDlgBlockingTest extends Panel { public static Frame frame = new TestFrame("Test Frame"); diff --git a/test/jdk/java/awt/TextArea/TextScrollTest.java b/test/jdk/java/awt/TextArea/TextScrollTest.java index 4a92391e7af58..fbd5c022580a9 100644 --- a/test/jdk/java/awt/TextArea/TextScrollTest.java +++ b/test/jdk/java/awt/TextArea/TextScrollTest.java @@ -38,7 +38,7 @@ public class TextScrollTest extends Frame { private static final String INSTRUCTIONS = """ 1. A TextArea whose content starts with the text ", - 'Scroll till the' will appear on the applet ", + 'Scroll till the' will appear on the window ", 2. Use the Horizontal thumb button of the TextArea to view the entire", content of the TextArea", 3. While scrolling, if the text 'Scroll till the' appears repeatedly, Click Fail ", diff --git a/test/jdk/java/awt/datatransfer/DragUnicodeBetweenJVMTest/DragUnicodeBetweenJVMTest.java b/test/jdk/java/awt/datatransfer/DragUnicodeBetweenJVMTest/DragUnicodeBetweenJVMTest.java index 18159dce64f69..aa785f54733ed 100644 --- a/test/jdk/java/awt/datatransfer/DragUnicodeBetweenJVMTest/DragUnicodeBetweenJVMTest.java +++ b/test/jdk/java/awt/datatransfer/DragUnicodeBetweenJVMTest/DragUnicodeBetweenJVMTest.java @@ -101,7 +101,6 @@ private static void verifyTestResults(ProcessResults processResults) { processResults.printProcessStandartOutput(System.out); } - //We cannot make an instance of the applet without the default constructor public DragUnicodeBetweenJVMTest () { super(); } diff --git a/test/jdk/java/awt/datatransfer/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.java b/test/jdk/java/awt/datatransfer/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.java index 0254a3f0d41ab..3502cd4f9c527 100644 --- a/test/jdk/java/awt/datatransfer/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.java +++ b/test/jdk/java/awt/datatransfer/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.java @@ -123,7 +123,6 @@ private static void verifyTestResults(ProcessResults processResults) { processResults.printProcessStandartOutput(System.out); } - //We cannot make an instance of the applet without the default constructor public MissedHtmlAndRtfBug() { super(); } diff --git a/test/jdk/java/awt/dnd/DnDFileGroupDescriptor/DnDFileGroupDescriptor.java b/test/jdk/java/awt/dnd/DnDFileGroupDescriptor/DnDFileGroupDescriptor.java index 51129f2640829..b106deac73cc3 100644 --- a/test/jdk/java/awt/dnd/DnDFileGroupDescriptor/DnDFileGroupDescriptor.java +++ b/test/jdk/java/awt/dnd/DnDFileGroupDescriptor/DnDFileGroupDescriptor.java @@ -42,7 +42,7 @@ public class DnDFileGroupDescriptor { When the test starts, a RED panel appears. 1. Start MS Outlook program. Find and open the mail form with attachments. - 2. Select attachments from the mail and drag into a red field of applet. + 2. Select attachments from the mail and drag into a red field of the window. When the mouse enters the field during the process of drag, the application should change the cursor form to OLE-copy and field color to yellow. diff --git a/test/jdk/java/awt/dnd/FileListBetweenJVMsTest/FileListBetweenJVMsTest.java b/test/jdk/java/awt/dnd/FileListBetweenJVMsTest/FileListBetweenJVMsTest.java index 6fc7b9e049d51..102ff50104083 100644 --- a/test/jdk/java/awt/dnd/FileListBetweenJVMsTest/FileListBetweenJVMsTest.java +++ b/test/jdk/java/awt/dnd/FileListBetweenJVMsTest/FileListBetweenJVMsTest.java @@ -80,7 +80,6 @@ private static void verifyTestResults(ProcessResults processResults) { processResults.printProcessStandartOutput(System.out); } - //We cannot make an instance of the applet without the default constructor public FileListBetweenJVMsTest () { super(); } diff --git a/test/jdk/java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.java b/test/jdk/java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.java index e847752ee6a9a..6de649f846f0c 100644 --- a/test/jdk/java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.java +++ b/test/jdk/java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.java @@ -89,7 +89,6 @@ private static void verifyTestResults(ProcessResults processResults) { processResults.printProcessStandartOutput(System.out); } - //We cannot make an instance of the applet without the default constructor public URIListBetweenJVMsTest () { super(); } diff --git a/test/jdk/java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.java b/test/jdk/java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.java index f2e34493b8b60..d9b6bd5e87ca5 100644 --- a/test/jdk/java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.java +++ b/test/jdk/java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.java @@ -77,7 +77,6 @@ private static void verifyTestResults(ProcessResults processResults) { processResults.printProcessStandartOutput(System.out); } - //We cannot make an instance of the applet without the default constructor public URIListToFileListBetweenJVMsTest() { super(); } diff --git a/test/jdk/java/awt/event/MouseEvent/MenuDragMouseEventAbsoluteCoordsTest/MenuDragMouseEventAbsoluteCoordsTest.java b/test/jdk/java/awt/event/MouseEvent/MenuDragMouseEventAbsoluteCoordsTest/MenuDragMouseEventAbsoluteCoordsTest.java index e0cfbaba1bb95..41dc4709fc20b 100644 --- a/test/jdk/java/awt/event/MouseEvent/MenuDragMouseEventAbsoluteCoordsTest/MenuDragMouseEventAbsoluteCoordsTest.java +++ b/test/jdk/java/awt/event/MouseEvent/MenuDragMouseEventAbsoluteCoordsTest/MenuDragMouseEventAbsoluteCoordsTest.java @@ -150,4 +150,4 @@ public void checkEventAbsolutePosition(MouseEvent evt, String message){ } System.out.println(message); } -}// class AutomaticAppletTest +} diff --git a/test/jdk/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_2.java b/test/jdk/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_2.java index 7db513eeac856..6022ed32094bc 100644 --- a/test/jdk/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_2.java +++ b/test/jdk/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_2.java @@ -27,21 +27,17 @@ @bug 6480024 @library ../../../regtesthelpers @build Util Sysout AbstractTest - @summary stack overflow on mouse wheel rotation within JApplet + @summary stack overflow on mouse wheel rotation within a Window @run main InfiniteRecursion_2 */ /** * InfiniteRecursion_2.java * - * summary: put a JButton into JPanel and then put JPanel into Applet. - * Add MouseWheelListener to Applet. + * summary: put a JButton into JPanel and then put JPanel into the Window. + * Add MouseWheelListener to the Window * Add MouseListener to JPanel. * Rotating a wheel over the JButton would result in stack overflow. - - * summary: put a JButton into JApplet. - * Add MouseWheelListener to JApplet. - * Rotating a wheel over the JButton would result in stack overflow. */ import java.awt.*; @@ -79,7 +75,7 @@ public void start () this.addMouseWheelListener(new MouseWheelListener() { public void mouseWheelMoved(MouseWheelEvent e) { - System.out.println("Wheel moved on APPLET : "+e); + System.out.println("Wheel moved on Window : "+e); actualEvents++; } }); diff --git a/test/jdk/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_3.java b/test/jdk/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_3.java index 911e7c10864a3..e1f2991a2fb9f 100644 --- a/test/jdk/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_3.java +++ b/test/jdk/java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_3.java @@ -27,15 +27,15 @@ @bug 6480024 @library ../../../regtesthelpers @build Util Sysout AbstractTest - @summary stack overflow on mouse wheel rotation within JApplet + @summary stack overflow on mouse wheel rotation within a Window @run main InfiniteRecursion_3 */ /** * InfiniteRecursion_3.java * - * summary: put a JButton into Applet. - * Add MouseWheelListener to Applet. + * summary: put a JButton into the Window. + * Add MouseWheelListener to the Window. * Rotating a wheel over the JButton would result in stack overflow. */ @@ -72,7 +72,7 @@ public void start () this.addMouseWheelListener(new MouseWheelListener() { public void mouseWheelMoved(MouseWheelEvent e) { - System.out.println("Wheel moved on APPLET : "+e); + System.out.println("Wheel moved on Window : "+e); actualEvents++; } }); diff --git a/test/jdk/java/awt/event/helpers/lwcomponents/LWButton.java b/test/jdk/java/awt/event/helpers/lwcomponents/LWButton.java index 866844e1ce70d..e45d3d5f430c9 100644 --- a/test/jdk/java/awt/event/helpers/lwcomponents/LWButton.java +++ b/test/jdk/java/awt/event/helpers/lwcomponents/LWButton.java @@ -116,16 +116,8 @@ public void run() { repaint(); } } - try { - unClicker uc = new unClicker(); - new Thread(uc).start(); - } catch (Exception e) { - // In case we're in an applet and the security has not been - // turned off (in which case we can't start a new thread) - // we can catch that and set the flag back to how it should be. - isInClick = false; - repaint(); - } + unClicker uc = new unClicker(); + new Thread(uc).start(); } /** diff --git a/test/jdk/java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java b/test/jdk/java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java index fd2acaad396e9..7942402af4fd8 100644 --- a/test/jdk/java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java +++ b/test/jdk/java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java @@ -25,7 +25,7 @@ @test @key headful @bug 6359129 - @summary REGRESSION: Popup menus dont respond to selections when extend outside Applet + @summary REGRESSION: Popup menus dont respond to selections when extend outside EmbeddedFrame @author oleg.sukhodolsky area=awt.grab @modules java.desktop/java.awt.peer java.desktop/sun.awt @@ -38,7 +38,7 @@ /** * EmbeddedFrameTest1.java * - * summary: REGRESSION: Popup menus dont respond to selections when extend outside Applet + * summary: REGRESSION: Popup menus dont respond to selections when extend outside EmbeddedFrame */ import java.awt.BorderLayout; diff --git a/test/jdk/java/awt/im/8041990/bug8041990.java b/test/jdk/java/awt/im/8041990/bug8041990.java index 303fde5a459f2..d4bf847592df1 100644 --- a/test/jdk/java/awt/im/8041990/bug8041990.java +++ b/test/jdk/java/awt/im/8041990/bug8041990.java @@ -26,7 +26,7 @@ * @test * @key headful * @bug 8041990 - * @summary Language specific keys does not work in applets when opened outside the browser + * @summary Language specific keys does not work in non-default AppContexts of top-level windows * @author Petr Pchelko * @modules java.desktop/sun.awt */ diff --git a/test/jdk/java/awt/print/Dialog/DialogOrient.java b/test/jdk/java/awt/print/Dialog/DialogOrient.java index 6650ced64f46e..b89f3950e997e 100644 --- a/test/jdk/java/awt/print/Dialog/DialogOrient.java +++ b/test/jdk/java/awt/print/Dialog/DialogOrient.java @@ -34,9 +34,6 @@ import java.awt.geom.*; import java.awt.print.*; -// This test is a "main" test as applets would need Runtime permission -// "queuePrintJob". - public class DialogOrient implements Printable { private static void init() throws Exception { diff --git a/test/jdk/java/awt/print/PrinterJob/PrintDialog.java b/test/jdk/java/awt/print/PrinterJob/PrintDialog.java index fa9569e1aa74e..395312aaa45cd 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintDialog.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintDialog.java @@ -42,9 +42,6 @@ import java.awt.event.*; import java.awt.print.*; -// This test is a "main" test as applets would need Runtime permission -// "queuePrintJob". - public class PrintDialog { diff --git a/test/jdk/java/awt/print/PrinterJob/PrintDialogCancel.java b/test/jdk/java/awt/print/PrinterJob/PrintDialogCancel.java index b2d3d3a223075..9a1884a5f54c5 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintDialogCancel.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintDialogCancel.java @@ -43,9 +43,6 @@ import java.awt.event.*; import java.awt.print.*; -// This test is a "main" test as applets would need Runtime permission -// "queuePrintJob". - public class PrintDialogCancel { diff --git a/test/jdk/java/awt/print/PrinterJob/ThinLines.java b/test/jdk/java/awt/print/PrinterJob/ThinLines.java index f8e4e60b31969..95cbfed8796c5 100644 --- a/test/jdk/java/awt/print/PrinterJob/ThinLines.java +++ b/test/jdk/java/awt/print/PrinterJob/ThinLines.java @@ -42,9 +42,6 @@ import java.awt.event.*; import java.awt.print.*; -// This test is a "main" test as applets would need Runtime permission -// "queuePrintJob". - public class ThinLines implements Printable { private static final int INCH = 72; diff --git a/test/jdk/java/awt/regtesthelpers/AbstractTest.java b/test/jdk/java/awt/regtesthelpers/AbstractTest.java index f5c34cc6fbd16..fbf66e45e3be6 100644 --- a/test/jdk/java/awt/regtesthelpers/AbstractTest.java +++ b/test/jdk/java/awt/regtesthelpers/AbstractTest.java @@ -30,8 +30,6 @@ @build AbstractTest @run main YourTest - * Note that if you are about to create a test based on - * Applet-template, then put those lines into html-file, not in java-file. *

And put an * import test.java.awt.regtesthelpers.AbstractTest; * into the java source. diff --git a/test/jdk/java/awt/regtesthelpers/Util.java b/test/jdk/java/awt/regtesthelpers/Util.java index 6d570e903b678..45d9c89ee4652 100644 --- a/test/jdk/java/awt/regtesthelpers/Util.java +++ b/test/jdk/java/awt/regtesthelpers/Util.java @@ -31,8 +31,6 @@ @build Util @run main YourTest - * Note that if you are about to create a test based on - * Applet-template, then put those lines into html-file, not in java-file. *

And put an * import test.java.awt.regtesthelpers.Util; * into the java source of test. diff --git a/test/jdk/java/awt/regtesthelpers/process/ProcessCommunicator.java b/test/jdk/java/awt/regtesthelpers/process/ProcessCommunicator.java index d6806947af265..3b173009d2379 100644 --- a/test/jdk/java/awt/regtesthelpers/process/ProcessCommunicator.java +++ b/test/jdk/java/awt/regtesthelpers/process/ProcessCommunicator.java @@ -31,7 +31,7 @@ * behavior such as DnD data transfer, Clipboard data transfer, focus * transfer etc., you could use the next scenario: * - * 1. Write an implementation for the parent JVM, using applet test. + * 1. Write an implementation for the parent JVM * 2. Write an implementation for the child JVM or native application, using * main() function. * 3. Execute child process using ProcessCommunicator.executeChildProcess() diff --git a/test/jdk/javax/sound/sampled/Clip/ClipFlushCrash.java b/test/jdk/javax/sound/sampled/Clip/ClipFlushCrash.java index a72509fdf53df..2baeb499eac94 100644 --- a/test/jdk/javax/sound/sampled/Clip/ClipFlushCrash.java +++ b/test/jdk/javax/sound/sampled/Clip/ClipFlushCrash.java @@ -35,7 +35,7 @@ * @test * @key sound * @bug 4946945 - * @summary Crash in javasound while running TicTacToe demo applet tiger b26 + * @summary Crash in javasound while running TicTacToe demo tiger b26 */ public class ClipFlushCrash { static int frameCount = 441000; // lets say 10 seconds diff --git a/test/jdk/javax/sound/sampled/LinuxBlock/PlaySine.java b/test/jdk/javax/sound/sampled/LinuxBlock/PlaySine.java index ab567dacb2365..ceead0dae620f 100644 --- a/test/jdk/javax/sound/sampled/LinuxBlock/PlaySine.java +++ b/test/jdk/javax/sound/sampled/LinuxBlock/PlaySine.java @@ -36,7 +36,7 @@ * @test * @key sound * @bug 4834461 - * @summary Applet hang when you load it during sound card is in use + * @summary App hang when you load it during sound card is in use * @run main/manual PlaySine */ public class PlaySine { diff --git a/test/jdk/javax/swing/JPopupMenu/bug4212464.java b/test/jdk/javax/swing/JPopupMenu/bug4212464.java index c1c434f6b16f7..cbfecc989cc87 100644 --- a/test/jdk/javax/swing/JPopupMenu/bug4212464.java +++ b/test/jdk/javax/swing/JPopupMenu/bug4212464.java @@ -36,7 +36,6 @@ import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; diff --git a/test/jdk/javax/swing/JTextArea/4697612/bug4697612.java b/test/jdk/javax/swing/JTextArea/4697612/bug4697612.java index ed7f3dba73fd7..ee01c38ed672d 100644 --- a/test/jdk/javax/swing/JTextArea/4697612/bug4697612.java +++ b/test/jdk/javax/swing/JTextArea/4697612/bug4697612.java @@ -224,7 +224,7 @@ private static void createAndShowGUI() { text = new JTextArea(); try { InputStream is = - bug4697612.class.getResourceAsStream("bug4697612.txt"); + bug4697612.class.getResourceAsStream("bug4697612.java"); text.read(new InputStreamReader(is), null); } catch (IOException e) { throw new Error(e); diff --git a/test/jdk/javax/swing/JTextArea/4697612/bug4697612.txt b/test/jdk/javax/swing/JTextArea/4697612/bug4697612.txt deleted file mode 100644 index f7273541285f5..0000000000000 --- a/test/jdk/javax/swing/JTextArea/4697612/bug4697612.txt +++ /dev/null @@ -1,221 +0,0 @@ - README - - Java(TM) 2 SDK, Standard Edition - Version 1.4.2 Beta - - For a more extensive HTML version of this file, see README.html. - -Contents - - * Introduction - * Release Notes - * Bug Reports and Feedback - * Java 2 SDK Documentation - * Redistribution - * Web Pages - - -Introduction - - Thank you for downloading this release of the Java(TM) 2 SDK, - Standard Edition. The Java 2 SDK is a development environment for - building applications, applets, and components that can be - deployed on the Java platform. - - The Java 2 SDK software includes tools useful for developing and - testing programs written in the Java programming language and - running on the Java platform. These tools are designed to be used - from the command line. Except for appletviewer, these tools do not - provide a graphical user interface. - - -Release Notes - - See the Release Notes on the Java Software web site for additional - information pertaining to this release. - - http://java.sun.com/j2se/1.4.2/relnotes.html - - The on-line release notes will be updated as needed, so you should - check it occasionally for the latest information. - - -Bug Reports and Feedback - - The Bug Parade Web Page on the Java Developer Connection(SM) web - site lets you search for and examine existing bug reports, submit - your own bug reports, and tell us which bug fixes matter most to you. - - http://java.sun.com/jdc/bugParade/ - - To directly submit a bug or request a feature, fill out this form: - - http://java.sun.com/cgi-bin/bugreport.cgi - - You can also send comments directly to Java Software engineering - team email addresses. - - http://java.sun.com/mail/ - - -Java 2 SDK Documentation - - The on-line Java 2 SDK Documentation contains API specifications, - feature descriptions, developer guides, tool reference pages, demos, - and links to related information. It is located at - - http://java.sun.com/j2se/1.4.2/docs/ - - The Java 2 SDK documentation is also available in a download bundle - which you can install locally on your machine. See the - Java 2 SDK download page: - - http://java.sun.com/j2se/1.4.2/download.html - - -Redistribution - - The term "vendors" used here refers to licensees, developers, - and independent software vendors (ISVs) who license and - distribute the Java 2 Runtime Environment with their programs. - Vendors must follow the terms of the Java 2 SDK, Standard - Edition, Binary Code License agreement. - Required vs. Optional Files - - The files that make up the Java 2 SDK, Standard Edition, are - divided into two categories: required and optional. Optional - files may be excluded from redistributions of the Java 2 SDK - at the vendor's discretion. The following section contains a - list of the files and directories that may optionally be - omitted from redistributions of the Java 2 SDK. All files not - in these lists of optional files must be included in - redistributions of the Java 2 SDK. - - Optional Files and Directories - - The following files may be optionally excluded from - redistributions: - - jre/lib/charsets.jar - Character conversion classes - jre/lib/ext/ - sunjce_provider.jar - the SunJCE provider for Java - Cryptography APIs - localedata.jar - contains many of the resources - needed for non US English locales - ldapsec.jar - contains security features supported - by the LDAP service provider - dnsns.jar - for the InetAddress wrapper of JNDI DNS - provider - bin/rmid and jre/bin/rmid - Java RMI Activation System Daemon - bin/rmiregistry and jre/bin/rmiregistry - Java Remote Object Registry - bin/tnameserv and jre/bin/tnameserv - Java IDL Name Server - bin/keytool and jre/bin/keytool - Key and Certificate Management Tool - bin/kinit and jre/bin/kinit - Used to obtain and cache Kerberos ticket-granting tickets - bin/klist and jre/bin/klist - Kerberos display entries in credentials cache and keytab - bin/ktab and jre/bin/ktab - Kerberos key table manager - bin/policytool and jre/bin/policytool - Policy File Creation and Management Tool - bin/orbd and jre/bin/orbd - Object Request Broker Daemon - bin/servertool and jre/bin/servertool - Java IDL Server Tool - src.zip - Archive of source files - - In addition, the Java Web Start product may be excluded from - redistributions. The Java Web Start product is contained in a - file named javaws-1_2-solaris-sparc-i.zip, - javaws-1_2-solaris-i586-i.zip, - javaws-1_2-linux-i586-i.zip, or - javaws-1_2-windows-i586-i.exe, depending on the platform. - - - Unlimited Strength Java Cryptography Extension - - Due to import control restrictions for some countries, the - Java Cryptography Extension (JCE) policy files shipped with - the Java 2 SDK, Standard Edition and the Java 2 Runtime - Environment allow strong but limited cryptography to be - used. These files are located at - - /lib/security/local_policy.jar - /lib/security/US_export_policy.jar - - where is the jre directory of the Java 2 - SDK or the top-level directory of the Java 2 Runtime - Environment. - - An unlimited strength version of these files indicating - no restrictions on cryptographic strengths is available - on the Java 2 SDK web site for those living in eligible - countries. Those living in eligible countries may download - the unlimited strength version and replace the strong - cryptography jar files with the unlimited strength files. - - - Endorsed Standards Override Mechanism - - An endorsed standard is a Java API defined through a standards - process other than the Java Community Process(SM) (JCP(SM)). - Because endorsed standards are defined outside the JCP, it is - anticipated that such standards will be revised between - releases of the Java 2 Platform. In order to take advantage of - new revisions to endorsed standards, developers and software - vendors may use the Endorsed Standards Override Mechanism to - provide newer versions of an endorsed standard than those - included in the Java 2 Platform as released by Sun Microsystems. - - For more information on the Endorsed Standards Override - Mechanism, including the list of platform packages that it may - be used to override, see - - http://java.sun.com/j2se/1.4.2/docs/guide/standards/ - - Classes in the packages listed on that web page may be replaced - only by classes implementing a more recent version of the API - as defined by the appropriate standards body. - - In addition to the packages listed in the document at the above - URL, which are part of the Java 2 Platform, Standard Edition - (J2SE(TM)) specification, redistributors of Sun's J2SE - Reference Implementation are allowed to override classes whose - sole purpose is to implement the functionality provided by - public APIs defined in these Endorsed Standards packages. - Redistributors may also override classes in the org.w3c.dom.* - packages, or other classes whose sole purpose is to implement - these APIs. - - -Sun Java Web Pages - - For additional information, refer to these Sun Microsystems pages - on the World Wide Web: - - http://java.sun.com/ - The Java Software web site, with the latest information on - Java technology, product information, news, and features. - http://java.sun.com/docs - Java Platform Documentation provides access to white papers, - the Java Tutorial and other documents. - http://java.sun.com/jdc - The Java Developer Connection(SM) web site. (Free registration - required.) Additional technical information, news, and - features; user forums; support information, and much more. - http://java.sun.com/products/ - Java Technology Products & API - - ------------------------------------------------------------------------- -The Java 2 SDK, Standard Edition, is a product of Sun Microsystems(TM), -Inc. This product includes code licensed from RSA Security. - -Copyright 2003 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -California 95054, U.S.A. All rights reserved. diff --git a/test/jdk/javax/swing/text/html/parser/Parser/6990651/bug6990651.java b/test/jdk/javax/swing/text/html/parser/Parser/6990651/bug6990651.java index b939f3e148fd8..9dada22ba6072 100644 --- a/test/jdk/javax/swing/text/html/parser/Parser/6990651/bug6990651.java +++ b/test/jdk/javax/swing/text/html/parser/Parser/6990651/bug6990651.java @@ -23,7 +23,7 @@ /* @test @bug 6990651 - @summary Regression: NPE when refreshing applet since 6u22-b01 + @summary Regression: NPE when refreshing embedded window since 6u22-b01 @author Pavel Porvatov @modules java.desktop/sun.awt */ diff --git a/test/jdk/performance/client/SwingMark/src/AbstractSwingTest.java b/test/jdk/performance/client/SwingMark/src/AbstractSwingTest.java index 52394054f2987..8a62d196857d3 100644 --- a/test/jdk/performance/client/SwingMark/src/AbstractSwingTest.java +++ b/test/jdk/performance/client/SwingMark/src/AbstractSwingTest.java @@ -86,15 +86,6 @@ public abstract class AbstractSwingTest { */ public abstract void runTest(); - /** - * This method is used to determine if a test can be run from within - * an applet. If your test will cause security exceptions when run as - * an applet then you should return false from this method. - */ - public boolean canRunInApplet() { - return true; - } - public int getPaintCount() { return paintCount; } diff --git a/test/jdk/performance/client/SwingMark/src/JMTest_01.java b/test/jdk/performance/client/SwingMark/src/JMTest_01.java index 83127e3bc2173..fcc5fe309ba94 100644 --- a/test/jdk/performance/client/SwingMark/src/JMTest_01.java +++ b/test/jdk/performance/client/SwingMark/src/JMTest_01.java @@ -66,14 +66,6 @@ public class JMTest_01 extends AbstractSwingTest { int DOWN = 40; int UP = 38; - /** - * This test cannot run as an applet because it - * posts events to the event queue - */ - public boolean canRunInApplet() { - return false; - } - public JComponent getTestComponent() { JPanel panel = new JPanel(); diff --git a/test/jdk/performance/client/SwingMark/src/JMTest_02.java b/test/jdk/performance/client/SwingMark/src/JMTest_02.java index b77844162abbd..680ada9f1df93 100644 --- a/test/jdk/performance/client/SwingMark/src/JMTest_02.java +++ b/test/jdk/performance/client/SwingMark/src/JMTest_02.java @@ -67,14 +67,6 @@ public class JMTest_02 extends AbstractSwingTest { int repeat = 15; - /** - * This test cannot run as an applet because it - * posts events to the event queue - */ - public boolean canRunInApplet() { - return false; - } - public JComponent getTestComponent() { JPanel panel = new JPanel(); diff --git a/test/jdk/performance/client/SwingMark/src/JMTest_03.java b/test/jdk/performance/client/SwingMark/src/JMTest_03.java index eed96da1e93e5..38f5dff43bc81 100644 --- a/test/jdk/performance/client/SwingMark/src/JMTest_03.java +++ b/test/jdk/performance/client/SwingMark/src/JMTest_03.java @@ -65,14 +65,6 @@ public class JMTest_03 extends AbstractSwingTest { int DOWN = 40; int UP = 38; - /** - * This test cannot run as an applet because it - * posts events to the event queue - */ - public boolean canRunInApplet() { - return false; - } - public JComponent getTestComponent() { JPanel panel = new JPanel(); diff --git a/test/jdk/performance/client/SwingMark/src/JMTest_04.java b/test/jdk/performance/client/SwingMark/src/JMTest_04.java index 4c4c7f65d32b5..cbb32e5b91681 100644 --- a/test/jdk/performance/client/SwingMark/src/JMTest_04.java +++ b/test/jdk/performance/client/SwingMark/src/JMTest_04.java @@ -70,14 +70,6 @@ public class JMTest_04 extends AbstractSwingTest { String MENU_ITEM_STRING = "JMenuItem"; String SUB_MENU_STRING = "SubMenu"; - /** - * This test cannot run as an applet because it - * posts events to the event queue - */ - public boolean canRunInApplet() { - return false; - } - public JComponent getTestComponent() { loadBundle(); JPanel panel = new JPanel(); diff --git a/test/jdk/performance/client/SwingMark/src/JMTest_05.java b/test/jdk/performance/client/SwingMark/src/JMTest_05.java index bd4eea45f9b3f..dc2a0bd1489d4 100644 --- a/test/jdk/performance/client/SwingMark/src/JMTest_05.java +++ b/test/jdk/performance/client/SwingMark/src/JMTest_05.java @@ -65,14 +65,6 @@ public class JMTest_05 extends AbstractSwingTest { int DOWN = 40; int UP = 38; - /** - * This test cannot run as an applet because it - * posts events to the event queue - */ - public boolean canRunInApplet() { - return false; - } - public JComponent getTestComponent() { JPanel panel = new JPanel(); diff --git a/test/jdk/performance/client/SwingMark/src/MenuTest.java b/test/jdk/performance/client/SwingMark/src/MenuTest.java index 9d9d8751d3e8f..91ce63e76677b 100644 --- a/test/jdk/performance/client/SwingMark/src/MenuTest.java +++ b/test/jdk/performance/client/SwingMark/src/MenuTest.java @@ -69,14 +69,6 @@ public class MenuTest extends AbstractSwingTest { int repeat = 50; - /** - * This test cannot run as an applet because it - * posts events to the event queue - */ - public boolean canRunInApplet() { - return false; - } - public JComponent getTestComponent() { listener = new MyListener(); diff --git a/test/jdk/performance/client/SwingMark/src/TypingTest.java b/test/jdk/performance/client/SwingMark/src/TypingTest.java index 0019f7bd2c4bf..440b8b09e87ad 100644 --- a/test/jdk/performance/client/SwingMark/src/TypingTest.java +++ b/test/jdk/performance/client/SwingMark/src/TypingTest.java @@ -52,10 +52,6 @@ public JComponent getTestComponent() { return panel; } - public boolean canRunInApplet() { - return false; - } - public String getTestName() { return "Typing"; } From a551cc929426590bfbbcaa4bd8bee5e4e8cfe16d Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Fri, 18 Apr 2025 17:07:16 +0000 Subject: [PATCH 0658/1101] 8353293: Open source several swing tests batch4 Reviewed-by: serb --- .../DrawEtchedRectTest.java | 77 ++++++++++++++++ .../basic/BasicHTML/4228104/bug4228104.java | 75 +++++++++++++++ .../plaf/basic/BasicHTML/4228104/duke.gif | Bin 0 -> 1929 bytes .../plaf/basic/BasicSliderUI/bug4220108.java | 75 +++++++++++++++ .../BasicSplitPaneUI/NegativeSizeTest.java | 87 ++++++++++++++++++ .../PreferredSizeLayoutTest.java | 71 ++++++++++++++ 6 files changed, 385 insertions(+) create mode 100644 test/jdk/javax/swing/plaf/basic/BasicGraphicsUtils/DrawEtchedRectTest.java create mode 100644 test/jdk/javax/swing/plaf/basic/BasicHTML/4228104/bug4228104.java create mode 100644 test/jdk/javax/swing/plaf/basic/BasicHTML/4228104/duke.gif create mode 100644 test/jdk/javax/swing/plaf/basic/BasicSliderUI/bug4220108.java create mode 100644 test/jdk/javax/swing/plaf/basic/BasicSplitPaneUI/NegativeSizeTest.java create mode 100644 test/jdk/javax/swing/plaf/basic/BasicSplitPaneUI/PreferredSizeLayoutTest.java diff --git a/test/jdk/javax/swing/plaf/basic/BasicGraphicsUtils/DrawEtchedRectTest.java b/test/jdk/javax/swing/plaf/basic/BasicGraphicsUtils/DrawEtchedRectTest.java new file mode 100644 index 0000000000000..0c5c501596ce0 --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicGraphicsUtils/DrawEtchedRectTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4198822 + * @summary Tests that the bottom line drawn by + * BasicGraphicsUtils.drawEtchedRect extends to the end. + * @run main DrawEtchedRectTest + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.File; + +import javax.imageio.ImageIO; +import javax.swing.plaf.basic.BasicGraphicsUtils; + +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; + +public class DrawEtchedRectTest { + private static final int WIDTH = 200; + private static final int HEIGHT = 200; + private static final int RANGE = 10; + + public static void main(String[] args) throws Exception { + // Draw etched rectangle to a BufferedImage + BufferedImage image = new BufferedImage(WIDTH, HEIGHT, TYPE_INT_ARGB); + Graphics2D g2d = image.createGraphics(); + Component sq = new Component() { + public void paint(Graphics g) { + g.setColor(Color.WHITE); + g.fillRect(0, 0, WIDTH, HEIGHT); + BasicGraphicsUtils.drawEtchedRect(g, 0, 0, WIDTH, HEIGHT, + Color.black, Color.black, + Color.black, Color.black); + } + }; + sq.paint(g2d); + g2d.dispose(); + + // Check if connected at bottom-right corner + int c1; + int c2; + for (int i = 1; i < RANGE; i++) { + c1 = image.getRGB(WIDTH - i, HEIGHT - 1); + c2 = image.getRGB(WIDTH - 1, HEIGHT - i); + if (c1 == Color.WHITE.getRGB() || c2 == Color.WHITE.getRGB()) { + ImageIO.write(image, "png", new File("failImage.png")); + throw new RuntimeException("Bottom line is not connected!"); + } + } + } +} diff --git a/test/jdk/javax/swing/plaf/basic/BasicHTML/4228104/bug4228104.java b/test/jdk/javax/swing/plaf/basic/BasicHTML/4228104/bug4228104.java new file mode 100644 index 0000000000000..451590c66abad --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicHTML/4228104/bug4228104.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4228104 + * @summary Tests work of BODY BACKGROUND tag in HTML renderer + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4228104 + */ + +import java.awt.BorderLayout; + +import javax.swing.JFrame; +import javax.swing.JLabel; + +public class bug4228104 { + static final String INSTRUCTIONS = """ + There should be an image displaying dukes under the rows of digits. + If you can see it, the test PASSES. Otherwise, the test FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4228104 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4228104::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("Background HTML Text Test"); + String dir = System.getProperty("test.src", + System.getProperty("user.dir")); + String htmlText1 = + "\n" + + "
111111111111111111" + + "
111111111111111111" + + "
111111111111111111" + + "
111111111111111111" + + "
111111111111111111" + + "
111111111111111111" + + "
111111111111111111" + + "
111111111111111111" + + "
111111111111111111"; + JLabel button1 = new JLabel(htmlText1); + f.add(button1, BorderLayout.NORTH); + f.setSize(200, 200); + return f; + } +} diff --git a/test/jdk/javax/swing/plaf/basic/BasicHTML/4228104/duke.gif b/test/jdk/javax/swing/plaf/basic/BasicHTML/4228104/duke.gif new file mode 100644 index 0000000000000000000000000000000000000000..ed32e0ff79b05c07b82863ce6fb07fa9898adaa2 GIT binary patch literal 1929 zcmWlYe^AtB8pi`HvM4_?{J2I$8$dLc1#@!R2zwgXMWdj^k;9xr+bDW&4{JlE8WpDj z7F-cwwK{H<)?L&#SJz$!;hJ{%BY2FYf)Wp^xl?aq!5Xcdi$c#hV~>m9_n-Hl=Xsy+ z=li^?*Q~;pZ+R1N1J40KRkeWM7ew3~jLM24A{CM-A}~TzqzYpq&od0GC=z71!w_=b z-==B0rt2t*nA}((5YSLs6a*Z@X__WqiSjTW6oLo{5km&|K1mGAimYjhs#wwZtvV8SV~7LCFpgub+-TTAk%UQb0dE_cj+pc?!+0o?qG$?% zVFD)%!w7Z;g)ndE8Uk6Aky=+kLaUQ{UW`XS?Nn*s@SQ{VmFgGdkV{&&98EcEQ5hjc@H$`e)fX zj@&GdchxpMUo|-A^M4iBP3(#Ib53Ap?5{nGT7SBA_V!o!TTzL5R~FUWe)4X?@iTd8 z1;TcF^rQLj?4p0uy?@ikb2eUSXdHVa_jIn=@W%a<6~57D>am6&Z!{lzc=@ZbuGB8` zpU38H8d~@82Da!+qdYG5ls&Cx?~|oPMnbqTHMw%I*KlV~?fc{rSwe29?Om}fsknG# z@n5IwY=4Mx>>0WJLG>=yJX^WbHA30iQ$H!X)3<4K zBe1|sf3NKKTS;)mg{$k(2eDJG^u5=&x{@M!V>EWgzRA((>}?o{WQBehp1mIHU!BGG zYz5_6B(+KIVdCVoum2ItM&gXZd+SB^vQTN=a zeYbbah=i-xCho2{4Pazv_i%2mH`EkM{r8XYDLbdY@(a7Ud}$%!$QrTN_DqwNXA9~g zTGKxKyfto7NDp;5A3O5zgb(hyxjN@OAG!(zy^*Ug4!yjF=Y*8aHA@ovB1({&a4;sR zTf1CVC{>Pgy`m$lG;P1$pC_6F7u%iP+qz0q4{lXT`i9g-ThiYgO^GXC`f?JNo*|@p zr{b%U-tSKw99q0|YJa9{Va?`H{IaNICo>p5lGEY*+IDR4bfIUwq~CTRuC_mGWA%~W zea{@eKJ(Iq^7MvdsPsR%&vt$@4i&s?bPptz#y#!FcRZEaMS0WFTyXMCUEfsNxnJ_9 zPwpt`Er4O>``2G{7=4r1GCSTO8#0xw+{<^L4X(K8y1wKj72KLrYD}Y7SJuY7y==wf z;UkI5?(v?h+4r;vR{P*U`ul~=D@U7K5$eV8c!%rX-38vE>azU80UrhFXCv#d`(ylZS4+i2a^vI91MTIxCx%9gd2&N&D9RC&xcpx8#f=GZv%9;F z#?CEVT%UV$nk;L%RJA+d=f8ZB@U*Xz-TZbG?HKKT(VJZMBH!)$#qRuwbFc%Aljqha zoNBs8od~V$_^vux0ZSk!iP!hI($t35SxY8`FV{pxCjpU}Ova2VIg1&>V)CvvMb_ cardLayout.show(mainPanel, "split")); + f.add(button, BorderLayout.SOUTH); + f.setSize(400, 300); + return f; + } +} diff --git a/test/jdk/javax/swing/plaf/basic/BasicSplitPaneUI/PreferredSizeLayoutTest.java b/test/jdk/javax/swing/plaf/basic/BasicSplitPaneUI/PreferredSizeLayoutTest.java new file mode 100644 index 0000000000000..76d0e45b8eb57 --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicSplitPaneUI/PreferredSizeLayoutTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4208549 + * @summary Makes sure preferred size returned by layout managers used by + * JSplitPane is correct. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PreferredSizeLayoutTest + */ + +import java.awt.Container; +import java.awt.FlowLayout; + +import javax.swing.JFrame; +import javax.swing.JSplitPane; + +public class PreferredSizeLayoutTest { + static final String INSTRUCTIONS = """ + If the buttons in the JSplitpanes do not have '...' in them, + click PASS, otherwise click FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("PreferredSizeLayoutTest Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(PreferredSizeLayoutTest::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("Preferred Size Layout Test"); + Container parent = f.getContentPane(); + JSplitPane sp = new JSplitPane(); + + parent.setLayout(new FlowLayout()); + + sp.setOrientation(JSplitPane.HORIZONTAL_SPLIT); + parent.add(sp); + sp = new JSplitPane(); + sp.setOrientation(JSplitPane.VERTICAL_SPLIT); + parent.add(sp); + f.setSize(400, 300); + return f; + } +} From 924638c471b0bf4a00a890ce6a3fd7e118cdd578 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Fri, 18 Apr 2025 17:08:46 +0000 Subject: [PATCH 0659/1101] 8353661: Open source several swing tests batch5 Reviewed-by: jdv --- test/jdk/javax/swing/JSlider/bug4186062.java | 99 +++++++++++++ test/jdk/javax/swing/JSlider/bug4275631.java | 132 ++++++++++++++++++ test/jdk/javax/swing/JSlider/bug4382876.java | 110 +++++++++++++++ .../javax/swing/plaf/windows/bug4991587.java | 95 +++++++++++++ 4 files changed, 436 insertions(+) create mode 100644 test/jdk/javax/swing/JSlider/bug4186062.java create mode 100644 test/jdk/javax/swing/JSlider/bug4275631.java create mode 100644 test/jdk/javax/swing/JSlider/bug4382876.java create mode 100644 test/jdk/javax/swing/plaf/windows/bug4991587.java diff --git a/test/jdk/javax/swing/JSlider/bug4186062.java b/test/jdk/javax/swing/JSlider/bug4186062.java new file mode 100644 index 0000000000000..1db2f1bba6c29 --- /dev/null +++ b/test/jdk/javax/swing/JSlider/bug4186062.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4382876 + * @summary Tests if JSlider fires ChangeEvents when thumb is clicked and not moved + * @key headful + * @run main bug4186062 + */ + +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.SwingUtilities; +import javax.swing.event.ChangeListener; + +public class bug4186062 { + private static JFrame f; + private static JSlider slider; + private static volatile Point loc; + private static volatile int labelNum; + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("JSlider Click Value Test"); + f.setSize(400, 200); + f.setLocationRelativeTo(null); + f.setVisible(true); + JPanel panel = new JPanel(); + slider = new JSlider(); + final JLabel label = new JLabel("0"); + labelNum = 0; + + ChangeListener listener = e -> { + labelNum++; + label.setText("" + labelNum); + }; + slider.addChangeListener(listener); + + panel.add(slider); + panel.add(label); + f.add(panel); + }); + + Robot r = new Robot(); + r.setAutoDelay(100); + r.waitForIdle(); + r.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + loc = slider.getLocationOnScreen(); + loc.setLocation(loc.x + (slider.getWidth() / 2), + loc.y + (slider.getHeight() / 2)); + }); + + r.mouseMove(loc.x, loc.y); + r.mousePress(InputEvent.BUTTON1_DOWN_MASK); + r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + if (labelNum > 0) { + throw new RuntimeException(labelNum + " ChangeEvents fired. " + + "Test failed"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } +} diff --git a/test/jdk/javax/swing/JSlider/bug4275631.java b/test/jdk/javax/swing/JSlider/bug4275631.java new file mode 100644 index 0000000000000..4d0aa55572131 --- /dev/null +++ b/test/jdk/javax/swing/JSlider/bug4275631.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4275631 + * @summary Tests if vertical JSlider is properly aligned in large container + * @key headful + * @run main bug4275631 + */ + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Point; +import java.awt.Robot; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.SwingUtilities; + +public class bug4275631 { + private static final int OFFSET = 1; + private static JFrame f; + private static JSlider slider1; + private static JSlider slider2; + private static volatile Point loc1; + private static volatile Point loc2; + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("JSlider Alignment Test"); + f.setSize(400, 200); + f.setLocationRelativeTo(null); + + // Create two sliders, verify the alignment on the slider to be + // used in the border layout + slider1 = new JSlider(JSlider.VERTICAL, 0, 99, 50); + slider1.setInverted(true); + slider1.setMajorTickSpacing(10); + slider1.setMinorTickSpacing(1); + slider1.setPaintTicks(true); + slider1.setPaintLabels(true); + slider2 = new JSlider(JSlider.VERTICAL, 0, 99, 50); + slider2.setInverted(true); + slider2.setMajorTickSpacing(10); + slider2.setMinorTickSpacing(1); + slider2.setPaintTicks(true); + slider2.setPaintLabels(true); + + // Try to center the natural way, using a border layout in the "Center" + JPanel borderPanel = new JPanel(); + borderPanel.setLayout(new BorderLayout()); + borderPanel.setBorder(BorderFactory.createTitledBorder("BorderLayout")); + borderPanel.add(slider1, BorderLayout.CENTER); + borderPanel.setPreferredSize(new Dimension(200, 200)); + + // Try to center using GridBagLayout, with glue on left + // and right to squeeze slider into place + JPanel gridBagPanel = new JPanel(new GridBagLayout()); + gridBagPanel.setBorder(BorderFactory.createTitledBorder("GridBagLayout")); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 1; + c.fill = GridBagConstraints.VERTICAL; + c.weighty = 1.0; + gridBagPanel.add(slider2, c); + c.gridx = 0; + c.fill = GridBagConstraints.BOTH; + c.weighty = 0.0; + gridBagPanel.add(Box.createHorizontalGlue(), c); + c.gridx = 2; + c.fill = GridBagConstraints.BOTH; + gridBagPanel.add(Box.createHorizontalGlue(), c); + gridBagPanel.setPreferredSize(new Dimension(200, 200)); + + f.add(borderPanel, BorderLayout.WEST); + f.add(gridBagPanel, BorderLayout.EAST); + f.setVisible(true); + }); + + Robot r = new Robot(); + r.setAutoDelay(100); + r.waitForIdle(); + r.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + loc1 = slider1.getLocationOnScreen(); + loc1.setLocation(loc1.x + (slider1.getWidth() / 2), + loc1.y + (slider1.getHeight() / 2)); + + loc2 = slider2.getLocationOnScreen(); + loc2.setLocation(loc2.x + (slider2.getWidth() / 2), + loc2.y + (slider2.getHeight() / 2)); + }); + + if (loc1.y > loc2.y + OFFSET || loc1.y < loc2.y - OFFSET) { + throw new RuntimeException("JSlider position is not aligned!"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } +} diff --git a/test/jdk/javax/swing/JSlider/bug4382876.java b/test/jdk/javax/swing/JSlider/bug4382876.java new file mode 100644 index 0000000000000..b9ec64aab216c --- /dev/null +++ b/test/jdk/javax/swing/JSlider/bug4382876.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4382876 + * @summary Tests how PgUp and PgDn keys work with JSlider + * @key headful + * @run main bug4382876 + */ + +import java.awt.BorderLayout; +import java.awt.ComponentOrientation; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Robot; +import java.awt.event.KeyEvent; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.JFrame; +import javax.swing.JSlider; +import javax.swing.SwingUtilities; + +public class bug4382876 { + private static Robot r; + private static JFrame f; + private static JSlider slider; + private static boolean upFail; + private static boolean downFail; + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("JSlider PageUp/Down Test"); + f.setSize(300, 200); + f.setLocationRelativeTo(null); + f.setVisible(true); + slider = new JSlider(-1000, -900, -1000); + slider.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + slider.putClientProperty("JSlider.isFilled", Boolean.TRUE); + f.add(slider, BorderLayout.CENTER); + }); + + r = new Robot(); + r.setAutoDelay(100); + r.waitForIdle(); + r.delay(1000); + + r.keyPress(KeyEvent.VK_PAGE_UP); + SwingUtilities.invokeAndWait(() -> { + if (slider.getValue() < -1000) { + System.out.println("PAGE_UP VAL: " + slider.getValue()); + upFail = true; + } + }); + if (upFail) { + writeFailImage(); + throw new RuntimeException("Slider value did NOT change with PAGE_UP"); + } + r.keyPress(KeyEvent.VK_PAGE_DOWN); + SwingUtilities.invokeAndWait(() -> { + if (slider.getValue() > -1000) { + System.out.println("PAGE_DOWN VAL: " + slider.getValue()); + downFail = true; + } + }); + if (downFail) { + writeFailImage(); + throw new RuntimeException("Slider value did NOT change with PAGE_DOWN"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private static void writeFailImage() throws IOException { + GraphicsConfiguration ge = GraphicsEnvironment + .getLocalGraphicsEnvironment().getDefaultScreenDevice() + .getDefaultConfiguration(); + BufferedImage failImage = r.createScreenCapture(ge.getBounds()); + ImageIO.write(failImage, "png", new File("failImage.png")); + } +} diff --git a/test/jdk/javax/swing/plaf/windows/bug4991587.java b/test/jdk/javax/swing/plaf/windows/bug4991587.java new file mode 100644 index 0000000000000..e4e4fde2b8620 --- /dev/null +++ b/test/jdk/javax/swing/plaf/windows/bug4991587.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4991587 + * @requires (os.family == "windows") + * @summary Tests that disabled JButton text is positioned properly in Windows L&F + * @modules java.desktop/com.sun.java.swing.plaf.windows + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4991587 + */ + +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.AbstractButton; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.UIManager; + +import com.sun.java.swing.plaf.windows.WindowsButtonUI; + +public class bug4991587 { + static final String INSTRUCTIONS = """ + There are two buttons: enabled (left) and disabled (right). + Ensure that the disabled button text is painted entirely + inside the blue bounding rectangle, just like the enabled + button (use it as an example of how this should look like). + """; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + PassFailJFrame.builder() + .title("bug4991587 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4991587::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("Disabled JButton Text Test"); + f.setLayout(new FlowLayout()); + f.setSize(400, 100); + + JButton button1 = new JButton("\u0114 Enabled JButton"); + button1.setUI(new MyButtonUI()); + f.add(button1); + + JButton button2 = new JButton("\u0114 Disabled JButton"); + button2.setEnabled(false); + button2.setUI(new MyButtonUI()); + f.add(button2); + + return f; + } + + static class MyButtonUI extends WindowsButtonUI { + protected void paintText(Graphics g, AbstractButton b, + Rectangle textRect, String text) { + g.setColor(Color.blue); + g.drawRect(textRect.x, + textRect.y, + textRect.width + 1, // add 1 for the shadow, otherwise it + // will be painted over the textRect + textRect.height); + super.paintText(g, b, textRect, text); + } + } +} From f8f1be3de56986c06f368334b7c64ef50f0117cf Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 18 Apr 2025 18:50:08 +0000 Subject: [PATCH 0660/1101] 8353552: Opensource Several Font related tests - Batch 3 8355048: ProblemList TestGlyphVectorLayout.java on all platforms Reviewed-by: serb, aivanov --- test/jdk/ProblemList.txt | 1 + .../jdk/java/awt/font/BoldItalicFontTest.java | 73 +++++++ .../GlyphVector/TestGlyphVectorLayout.java | 121 +++++++++++ .../GlyphVector/TestSetGlyphPositions.java | 96 +++++++++ .../jdk/java/awt/font/Rotate/RotateTest1.java | 97 +++++++++ .../java/awt/font/TestGraphicPlacement.java | 199 ++++++++++++++++++ 6 files changed, 587 insertions(+) create mode 100644 test/jdk/java/awt/font/BoldItalicFontTest.java create mode 100644 test/jdk/java/awt/font/GlyphVector/TestGlyphVectorLayout.java create mode 100644 test/jdk/java/awt/font/GlyphVector/TestSetGlyphPositions.java create mode 100644 test/jdk/java/awt/font/Rotate/RotateTest1.java create mode 100644 test/jdk/java/awt/font/TestGraphicPlacement.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 4a00130d3aa40..b0a97929c6deb 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -796,6 +796,7 @@ java/awt/Modal/InvisibleParentTest/InvisibleParentTest.java 8172245 linux-all java/awt/Frame/FrameStateTest/FrameStateTest.java 8203920 macosx-all,linux-all java/awt/print/PrinterJob/ScaledText/ScaledText.java 8231226 macosx-all java/awt/print/PrinterJob/PrintTextTest.java 8148334 macosx-all +java/awt/font/GlyphVector/TestGlyphVectorLayout.java 8354987 generic-all java/awt/font/TextLayout/TestJustification.java 8250791 macosx-all java/awt/TrayIcon/DragEventSource/DragEventSource.java 8252242 macosx-all java/awt/FileDialog/DefaultFocusOwner/DefaultFocusOwner.java 7187728 macosx-all,linux-all diff --git a/test/jdk/java/awt/font/BoldItalicFontTest.java b/test/jdk/java/awt/font/BoldItalicFontTest.java new file mode 100644 index 0000000000000..7fdefcfe2b52f --- /dev/null +++ b/test/jdk/java/awt/font/BoldItalicFontTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Font; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; + +/* + * @test + * @bug 4935871 + * @summary Check that correct type faces are used regardless of bold/italic styles + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual/othervm -Duser.language=ja -Duser.country=JP BoldItalicFontTest + */ + +public class BoldItalicFontTest { + + public static void main(String[] args) throws Exception { + final String INSTRUCTIONS = """ + This test is reproduced with a non-English user locale only. + All the letters "X" in the first line should be in serif font. + All the letters "X" in the second line should be in sans-serif font. + + If so, press Pass, else press Fail."""; + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(BoldItalicFontTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + String[] faces = { Font.SERIF, Font.SANS_SERIF }; + int[] styles = { 0, Font.BOLD, Font.ITALIC, Font.BOLD | Font.ITALIC }; + + Frame f = new Frame("BoldItalicFontTest Test UI"); + f.setLayout(new GridLayout(faces.length, styles.length)); + for (int fn = 0; fn < faces.length; fn++) { + for (int sn = 0; sn < styles.length; sn++) { + Label l = new Label("X"); + Font f1 = new Font(faces[fn], styles[sn], 36); + l.setFont(f1); + f.add(l); + } + } + f.setSize(300, 300); + return f; + } +} diff --git a/test/jdk/java/awt/font/GlyphVector/TestGlyphVectorLayout.java b/test/jdk/java/awt/font/GlyphVector/TestGlyphVectorLayout.java new file mode 100644 index 0000000000000..b183b65264216 --- /dev/null +++ b/test/jdk/java/awt/font/GlyphVector/TestGlyphVectorLayout.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.font.GlyphVector; +import java.awt.font.FontRenderContext; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; + +import javax.swing.JPanel; + +/* + * @test + * @bug 4615017 + * @summary Display two GlyphVectors, and ensure they are of the same length. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestGlyphVectorLayout + */ + +public class TestGlyphVectorLayout extends JPanel { + private final Font font; + private final FontRenderContext frc; + private final String text; + + private GlyphVector aftergv; + private Rectangle pbounds; + private Rectangle2D vbounds; + + public static void main(String[] args) throws Exception { + final String INSTRUCTIONS = """ + Two lines of text should appear, the top one with boxes + (red and blue) around it. + The two lines should be of the same length, and the boxes around the + top line should 'fit' the text with no empty space between the end + of the text and the box. + + Pass the test if this is true."""; + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(TestGlyphVectorLayout::new) + .build() + .awaitAndCheck(); + } + + private TestGlyphVectorLayout() { + setBackground(Color.WHITE); + font = new Font(Font.DIALOG, Font.PLAIN, 24); + frc = new FontRenderContext(null, false, false); + text = "this is a test of glyph vector"; + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(550, 150); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + Graphics2D g2d = (Graphics2D) g; + + float x = 50; + float y = 50; + AffineTransform oldtx = g2d.getTransform(); + g2d.translate(x, y); + g2d.scale(1.5, 1.5); + + g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_OFF); + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + + g2d.setColor(Color.BLACK); + + GlyphVector gv = font.createGlyphVector(frc, text); // new each time + g2d.drawGlyphVector(gv, 0, 0); + + if (vbounds == null) { + vbounds = gv.getVisualBounds(); + pbounds = gv.getPixelBounds(g2d.getFontRenderContext(), 0, 0); + aftergv = gv; + } + g2d.drawGlyphVector(aftergv, 0, 30); + + g2d.setColor(Color.BLUE); + g2d.draw(vbounds); + + g2d.setTransform(oldtx); + g2d.setColor(Color.RED); + g2d.draw(pbounds); + } +} diff --git a/test/jdk/java/awt/font/GlyphVector/TestSetGlyphPositions.java b/test/jdk/java/awt/font/GlyphVector/TestSetGlyphPositions.java new file mode 100644 index 0000000000000..f56d821439508 --- /dev/null +++ b/test/jdk/java/awt/font/GlyphVector/TestSetGlyphPositions.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.font.GlyphVector; +import java.awt.font.FontRenderContext; +import java.awt.geom.Point2D; + +import javax.swing.JPanel; + +/* + * @test + * @bug 4180379 + * @summary set the positions of glyphs in the GlyphVector to other than + * their default x, y positions, and verify that the rendered glyphs are + * in the new positions, not the default positions. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestSetGlyphPositions + */ + +public class TestSetGlyphPositions extends JPanel { + GlyphVector gv = null; + + public static void main(String[] args) throws Exception { + final String INSTRUCTIONS = """ + 'TopLeft text and >' should appear towards the top left of the frame, + and '< and BottomRight text' should appear towards the bottom right. + + There should be some space between the '>' and '<' symbols, both vertically + and horizontally. + + Pass the test if this is true."""; + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(TestSetGlyphPositions::new) + .build() + .awaitAndCheck(); + } + + public TestSetGlyphPositions() { + setBackground(Color.WHITE); + setSize(550, 150); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(550, 150); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + Graphics2D g2d = (Graphics2D) g; + + if (gv == null) { + Font font = new Font(Font.DIALOG, Font.PLAIN, 36); + FontRenderContext frc = g2d.getFontRenderContext(); + String str = "TopLeft> Date: Fri, 18 Apr 2025 19:38:09 +0000 Subject: [PATCH 0661/1101] 8355051: Problemlist java/awt/Graphics2D/CopyAreaOOB.java on macosx-aarch64 Reviewed-by: prr, aivanov --- test/jdk/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index b0a97929c6deb..075ce0e9c10b8 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -473,6 +473,7 @@ java/awt/MenuBar/TestNoScreenMenuBar.java 8265987 macosx-all java/awt/Graphics2D/DrawString/DrawRotatedStringUsingRotatedFont.java 8266283 generic-all java/awt/Graphics2D/DrawString/RotTransText.java 8316878 linux-all +java/awt/Graphics2D/CopyAreaOOB.java 8343106 macosx-aarch64 java/awt/KeyboardFocusmanager/TypeAhead/ButtonActionKeyTest/ButtonActionKeyTest.java 8257529 windows-x64 java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeForModalDialogTest/ConsumeForModalDialogTest.java 8302787 windows-all java/awt/KeyboardFocusmanager/TypeAhead/MenuItemActivatedTest/MenuItemActivatedTest.java 8302787 windows-all From bf63f9ffa5e107ecb01e67dbef785a7bf4c89f16 Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Fri, 18 Apr 2025 20:58:21 +0000 Subject: [PATCH 0662/1101] 8353319: Open source Swing tests - Set 3 Reviewed-by: abhiscxk, dnguyen --- test/jdk/javax/swing/JFrame/bug4419914.java | 128 +++++++++++++++--- .../jdk/javax/swing/JRootPane/bug4614623.java | 84 ++++++++++++ .../javax/swing/JTabbedPane/bug4613811.java | 82 +++++++++++ test/jdk/javax/swing/JWindow/bug4251781.java | 76 +++++++++++ 4 files changed, 349 insertions(+), 21 deletions(-) create mode 100644 test/jdk/javax/swing/JRootPane/bug4614623.java create mode 100644 test/jdk/javax/swing/JTabbedPane/bug4613811.java create mode 100644 test/jdk/javax/swing/JWindow/bug4251781.java diff --git a/test/jdk/javax/swing/JFrame/bug4419914.java b/test/jdk/javax/swing/JFrame/bug4419914.java index 4574b1ac3d6ff..f87dcc8c46889 100644 --- a/test/jdk/javax/swing/JFrame/bug4419914.java +++ b/test/jdk/javax/swing/JFrame/bug4419914.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,55 +28,141 @@ * @library /java/awt/regtesthelpers * @build PassFailJFrame * @run main/manual bug4419914 -*/ + */ import java.awt.BorderLayout; import java.awt.ComponentOrientation; +import java.awt.Frame; +import java.awt.Window; +import java.util.List; +import java.util.Locale; import javax.swing.JButton; +import javax.swing.JDialog; import javax.swing.JFrame; -import java.util.Locale; +import javax.swing.JLabel; +import javax.swing.JWindow; public class bug4419914 { + private static JFrame frame; private static final String INSTRUCTIONS = """ - 1. You will see a frame with five buttons. - 2. Confirm that each button is placed as follows: - NORTH - END CENTER START - SOUTH - 3. Press the "NORTH" button and confirm the button is focused. - 4. Press TAB repeatedly and confirm that the TAB focus moves from right to left. - (NORTH - START - CENTER - END - SOUTH - NORTH - START - CENTER - ...) + This test verifies tab movement on RTL component orientation + in JWindow, JFrame and JDialog. + + When test starts 3 test windows are displayed - JFrame, JWindow and JDialog. + Follow the instructions below and if any condition does not hold + press FAIL. + + 1. Confirm that each button in the child window is placed as follows: + + For JFrame: + NORTH + END CENTER START + SOUTH + + For JWindow: + END CENTER START + QUIT + + For JDialog: + END CENTER START + + 3. Press on the "START" button in case of JWindow & JDialog and "NORTH" + in case of JFrame, confirm that the respective button is focused. + + 4. Press TAB repeatedly and confirm that the TAB focus moves + from right to left. + + For JFrame: + (NORTH - START - CENTER - END - SOUTH - NORTH - START - CENTER - ...) - If there's anything different from the above items, click Fail else click Pass."""; + For JWindow: + (START - CENTER - END - QUIT - START - CENTER - END - QUIT - ...) + + For JDialog: + (START - CENTER - END - START - CENTER - END - ...) + + If all of the above conditions are true press PASS else FAIL. + """; public static void main(String[] args) throws Exception { PassFailJFrame.builder() - .title("Tab movement Instructions") .instructions(INSTRUCTIONS) - .rows((int) INSTRUCTIONS.lines().count() + 2) - .columns(48) - .testUI(bug4419914::createTestUI) + .columns(45) + .testTimeOut(10) + .testUI(bug4419914::createAndShowUI) + .positionTestUI(WindowLayouts::rightOneColumn) .build() .awaitAndCheck(); } - private static JFrame createTestUI() { - JFrame frame = new JFrame("bug4419914"); + private static List createAndShowUI() { + return List.of(createJFrame(), createJWindow(), createJDialog()); + } + + private static JFrame createJFrame() { + frame = new JFrame("bug4419914 JFrame"); frame.setFocusCycleRoot(true); + // Tab movement set to RTL frame.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); frame.setLocale(Locale.ENGLISH); frame.enableInputMethods(false); + // Component placement within content pane set to RTL frame.getContentPane().setComponentOrientation( - ComponentOrientation.RIGHT_TO_LEFT); + ComponentOrientation.RIGHT_TO_LEFT); frame.getContentPane().setLocale(Locale.ENGLISH); - frame.getContentPane().setLayout(new BorderLayout()); + frame.setLayout(new BorderLayout()); frame.add(new JButton("SOUTH"), BorderLayout.SOUTH); frame.add(new JButton("CENTER"), BorderLayout.CENTER); frame.add(new JButton("END"), BorderLayout.LINE_END); frame.add(new JButton("START"), BorderLayout.LINE_START); frame.add(new JButton("NORTH"), BorderLayout.NORTH); - frame.setSize(300, 150); + frame.setSize(300, 160); return frame; } + + private static JWindow createJWindow() { + JWindow window = new JWindow(frame); + window.setFocusableWindowState(true); + // Tab movement set to RTL + window.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); + window.setLocale(new Locale("en")); + window.enableInputMethods(false); + + // Component placement within content pane set to RTL + window.getContentPane().setComponentOrientation( + ComponentOrientation.RIGHT_TO_LEFT); + window.getContentPane().setLocale(new Locale("en")); + window.setLayout(new BorderLayout()); + window.add(new JLabel("bug4419914 JWindow"), BorderLayout.NORTH); + window.add(new JButton("START"), BorderLayout.LINE_START); + window.add(new JButton("CENTER"), BorderLayout.CENTER); + window.add(new JButton("END"), BorderLayout.LINE_END); + + JButton quitButton = new JButton("QUIT"); + quitButton.addActionListener(e1 -> window.dispose()); + window.add(quitButton, BorderLayout.SOUTH); + window.setSize(300, 153); + window.requestFocus(); + return window; + } + + private static JDialog createJDialog() { + JDialog dialog = new JDialog((Frame) null, "bug4419914 JDialog"); + // Tab movement set to RTL + dialog.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); + dialog.setLocale(new Locale("en")); + dialog.enableInputMethods(false); + + // Component placement within content pane set to RTL + dialog.getContentPane().setComponentOrientation( + ComponentOrientation.RIGHT_TO_LEFT); + dialog.getContentPane().setLocale(new Locale("en")); + dialog.setLayout(new BorderLayout()); + dialog.add(new JButton("CENTER"), BorderLayout.CENTER); + dialog.add(new JButton("END"), BorderLayout.LINE_END); + dialog.add(new JButton("START"), BorderLayout.LINE_START); + dialog.setSize(300, 160); + return dialog; + } } diff --git a/test/jdk/javax/swing/JRootPane/bug4614623.java b/test/jdk/javax/swing/JRootPane/bug4614623.java new file mode 100644 index 0000000000000..9a714d3cdfdee --- /dev/null +++ b/test/jdk/javax/swing/JRootPane/bug4614623.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4614623 + * @requires (os.family == "windows") + * @summary Tests that w2k mnemonic underlining works when there's no + focus owner + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4614623 + */ + +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.UIManager; + +public class bug4614623 { + private static final String INSTRUCTIONS = """ + This test verifies if the short-cut character + (menu mnemonic) is underlined when the ALT key is held down. + + Check if the following is true. + 1) Press Alt key. The letter 'F' (menu mnemonic) of + the "File" menu should now be underlined. + 2) Release the Alt key, the selection background (light grey) + should appear around the "File" menu. Compare "About" menu + with "File" menu to see the light grey selection background. + + If the above is true, press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(62) + .rows(12) + .testUI(bug4614623::createAndShowUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createAndShowUI() { + JFrame frame = new JFrame("bug4614623 - File menu test"); + JMenuBar menuBar = new JMenuBar(); + + JMenu fileMenu = new JMenu("File"); + fileMenu.setMnemonic('F'); + menuBar.add(fileMenu); + + JMenu about = new JMenu("About"); + menuBar.add(about); + menuBar.setSize(300, 100); + + frame.setJMenuBar(menuBar); + menuBar.requestFocus(); + frame.setSize(300, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTabbedPane/bug4613811.java b/test/jdk/javax/swing/JTabbedPane/bug4613811.java new file mode 100644 index 0000000000000..ecad64e95f8d1 --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/bug4613811.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4613811 + * @summary Scrollable Buttons of JTabbedPane don't + * get enabled or disabled on selecting tab + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4613811 + */ + +import java.awt.BorderLayout; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JTabbedPane; + +public class bug4613811 { + private static final String INSTRUCTIONS = """ + Select different tabs and check that the scrollable + buttons are correctly enabled and disabled. + + When the very first tab (Tab 1) is fully visible + On macOS: + the left arrow button should NOT be visible. + + On other platforms: + the left arrow button should be disabled. + + If the last tab (Tab 5) is fully visible + On macOS: + the right arrow button should NOT be visible. + + On other platforms: + the right arrow button should be disabled. + + If the above is true press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(30) + .testUI(bug4613811::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createAndShowUI() { + JFrame frame = new JFrame("bug4613811 - JTabbedPane Test"); + final JTabbedPane tabPane = new JTabbedPane(JTabbedPane.TOP, + JTabbedPane.SCROLL_TAB_LAYOUT); + for (int i = 1; i <= 5; i++) { + tabPane.addTab("TabbedPane: Tab " + i, null, new JLabel("Tab " + i)); + } + frame.add(tabPane, BorderLayout.CENTER); + frame.setResizable(false); + frame.setSize(400, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JWindow/bug4251781.java b/test/jdk/javax/swing/JWindow/bug4251781.java new file mode 100644 index 0000000000000..0152db71f2497 --- /dev/null +++ b/test/jdk/javax/swing/JWindow/bug4251781.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4251781 + * @summary Tests that JWindow repaint is optimized (background is not + cleared). + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4251781 + */ + +import java.awt.Color; +import java.awt.Container; +import javax.swing.JButton; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.JWindow; + +public class bug4251781 { + private static final String INSTRUCTIONS = """ + Press the button at the bottom-right corner of the gray + window with the mouse. + If the window DOES NOT flicker when you press and/or release + the mouse button press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4251781::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static JWindow createAndShowUI() { + JWindow w = new JWindow(); + final Container pane = w.getContentPane(); + pane.setLayout(null); + pane.setBackground(Color.GRAY.darker()); + + final JPopupMenu popup = new JPopupMenu(); + popup.add(new JMenuItem("item 1")); + popup.add(new JMenuItem("exit")); + + JButton b = new JButton("menu"); + b.setBounds(350, 250, 50, 50); + b.addActionListener(ev -> popup.show(pane, 0, 0)); + pane.add(b); + + w.setSize(400, 300); + return w; + } +} From 38f9b3a9738de7896d840fc114a76ced3b77c269 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Fri, 18 Apr 2025 21:11:41 +0000 Subject: [PATCH 0663/1101] 8353748: Open source several swing tests batch6 Reviewed-by: kizune --- .../javax/swing/JTree/NodeChangedTest.java | 72 +++++++++++ test/jdk/javax/swing/JTree/bug4118860.java | 97 ++++++++++++++ test/jdk/javax/swing/JTree/bug4169215.java | 65 ++++++++++ test/jdk/javax/swing/JTree/bug4196987.java | 70 ++++++++++ test/jdk/javax/swing/JTree/bug4270654.java | 76 +++++++++++ test/jdk/javax/swing/JTree/bug4618767.java | 121 ++++++++++++++++++ 6 files changed, 501 insertions(+) create mode 100644 test/jdk/javax/swing/JTree/NodeChangedTest.java create mode 100644 test/jdk/javax/swing/JTree/bug4118860.java create mode 100644 test/jdk/javax/swing/JTree/bug4169215.java create mode 100644 test/jdk/javax/swing/JTree/bug4196987.java create mode 100644 test/jdk/javax/swing/JTree/bug4270654.java create mode 100644 test/jdk/javax/swing/JTree/bug4618767.java diff --git a/test/jdk/javax/swing/JTree/NodeChangedTest.java b/test/jdk/javax/swing/JTree/NodeChangedTest.java new file mode 100644 index 0000000000000..5461136c57be7 --- /dev/null +++ b/test/jdk/javax/swing/JTree/NodeChangedTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4199472 + * @summary Tests that node changed for the root of the tree update the + * structure. + * @run main NodeChangedTest + */ + +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; + +public class NodeChangedTest { + public static void main(String[] args) { + // Create 3 nodes + final DefaultMutableTreeNode root = new DefaultMutableTreeNode("root", + true); + final DefaultMutableTreeNode child = new DefaultMutableTreeNode("child", + true); + final DefaultMutableTreeNode leaf = new DefaultMutableTreeNode("leaf", + false); + root.add(child); + child.add(leaf); + + final JTree tree = new JTree(root); + + // Change the root node + root.setUserObject("New root"); + ((DefaultTreeModel) tree.getModel()).nodeChanged(root); + + // Check + if (!root.getUserObject().toString().equals("New root")) { + throw new RuntimeException("Failed changing root node for default model."); + } + + // Change to large model + tree.setLargeModel(true); + tree.setRowHeight(20); + root.setUserObject("root"); + tree.setModel(new DefaultTreeModel(root)); + root.setUserObject("New root"); + ((DefaultTreeModel) tree.getModel()).nodeChanged(root); + + // Check again + if (!root.getUserObject().toString().equals("New root")) { + throw new RuntimeException("Failed changing root node for large model."); + } + } +} diff --git a/test/jdk/javax/swing/JTree/bug4118860.java b/test/jdk/javax/swing/JTree/bug4118860.java new file mode 100644 index 0000000000000..eb266eb9324ab --- /dev/null +++ b/test/jdk/javax/swing/JTree/bug4118860.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4118860 + * @summary setToggleClickCount/getToggleClickCount have been added. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4118860 + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.GridLayout; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTree; + +public class bug4118860 { + static final String INSTRUCTIONS = """ + Push the "Single Click" button and try expanding/contracting + branch nodes of the tree with one left mouse button click + on the label part of the node (not the icon or handles). + + Then push the "Double Click" button and try doing the same using + left mouse button double click. Single click shouldn't cause + expanding/contracting. A double click should now be required + to expand/contract nodes. + + If it works then the test PASSES, else the test FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4118860 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4118860::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("ToggleClickCount Test"); + JTree tr = new JTree(); + JPanel p = new JPanel(); + p.setBackground(Color.red); + p.setLayout(new GridLayout(1, 1)); + tr.setOpaque(false); + p.add(tr); + f.add(p, BorderLayout.CENTER); + JPanel bp = new JPanel(); + JButton bt1 = new JButton("Single Click"); + bt1.addActionListener(e -> { + tr.setToggleClickCount(1); + if (tr.getToggleClickCount() != 1) { + throw new RuntimeException("ToggleClickCount doesn't set..."); + } + }); + JButton bt2 = new JButton("Double Click"); + bt2.addActionListener(e -> { + tr.setToggleClickCount(2); + if (tr.getToggleClickCount() != 2) { + throw new RuntimeException("ToggleClickCount doesn't set..."); + } + }); + bp.setLayout(new GridLayout(1, 2)); + bp.add(bt1); + bp.add(bt2); + f.add(bp, BorderLayout.SOUTH); + f.setSize(300, 200); + return f; + } +} diff --git a/test/jdk/javax/swing/JTree/bug4169215.java b/test/jdk/javax/swing/JTree/bug4169215.java new file mode 100644 index 0000000000000..0b8780b3939d7 --- /dev/null +++ b/test/jdk/javax/swing/JTree/bug4169215.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4169215 + * @summary Accessibility hierarchy JTree node test. + * @run main bug4169215 + */ + +import javax.accessibility.AccessibleContext; +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; + +public class bug4169215 { + public static void main(String[] args) { + // create the tree + DefaultMutableTreeNode root = new DefaultMutableTreeNode("top"); + DefaultMutableTreeNode nodeA = new DefaultMutableTreeNode("A"); + DefaultMutableTreeNode nodeB = new DefaultMutableTreeNode("B"); + root.add(nodeA); + root.add(nodeB); + JTree tree = new JTree(root); + + // find the AccessibleContext of the tree + AccessibleContext actree = tree.getAccessibleContext(); + + // find the AccessibleContext of top node of the tree + AccessibleContext act = actree.getAccessibleChild(0).getAccessibleContext(); + + // find the AccessibleContext of the first child of the table -> + // the AccessibleContext of nodeA + AccessibleContext accA = act.getAccessibleChild(0).getAccessibleContext(); + + // find the AccessibleContext of the next sibling of nodeA, by getting + // child+1 of the parent (the table) + AccessibleContext accB = act.getAccessibleChild( + accA.getAccessibleIndexInParent()+1).getAccessibleContext(); + + // look to see who the sibling is. + if (accB.getAccessibleName().compareTo("B") != 0) { + throw new RuntimeException("Parent node is a sibling instead!"); + } + } +} diff --git a/test/jdk/javax/swing/JTree/bug4196987.java b/test/jdk/javax/swing/JTree/bug4196987.java new file mode 100644 index 0000000000000..1387b669b0560 --- /dev/null +++ b/test/jdk/javax/swing/JTree/bug4196987.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4196987 + * @summary Test Metal L&F JTree expander icons transparency. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4196987 + */ + +import java.awt.Color; +import java.awt.GridLayout; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTree; +import javax.swing.UIManager; + +public class bug4196987 { + static final String INSTRUCTIONS = """ + If the background of tree icons are red, the test PASSES. + Otherwise the test FAILS. + """; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + PassFailJFrame.builder() + .title("bug4196987 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4196987::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("JTree Icon Transparency Test"); + JPanel p = new JPanel(); + p.setBackground(Color.red); + p.setLayout(new GridLayout(1, 1)); + JTree t = new JTree(); + t.setOpaque(false); + p.add(t); + f.add(p); + f.setSize(200, 200); + return f; + } +} diff --git a/test/jdk/javax/swing/JTree/bug4270654.java b/test/jdk/javax/swing/JTree/bug4270654.java new file mode 100644 index 0000000000000..413626d788158 --- /dev/null +++ b/test/jdk/javax/swing/JTree/bug4270654.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4270654 + * @summary Tests that selection change in JTree does not cause unnecessary + scrolling. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4270654 + */ + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; + +public class bug4270654 { + static final String INSTRUCTIONS = """ + Select the "dan" node and scroll to the right a little using the + scrollbar. Then press down arrow key. If the tree unscrolls back + to the left, the test FAILS. Otherwise, the test PASSES. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4270654 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4270654::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("JTree Scroll Back Test"); + DefaultMutableTreeNode root = new DefaultMutableTreeNode("root"); + String[] lev1 = {"foo", "bar", "dan"}; + String[][] lev2 = { + {}, + {"small", "a nice big node for testing"}, + {"xyz", "pqd", "a really really big node for testing"}}; + for (int i = 0; i < lev1.length; i++) { + DefaultMutableTreeNode child = new DefaultMutableTreeNode(lev1[i]); + root.add(child); + for (int j = 0; j < lev2[i].length; j++) + child.add(new DefaultMutableTreeNode(lev2[i][j])); + } + final JTree tree = new JTree(root); + tree.expandRow(3); + f.add(new JScrollPane(tree)); + f.setSize(200, 200); + return f; + } +} diff --git a/test/jdk/javax/swing/JTree/bug4618767.java b/test/jdk/javax/swing/JTree/bug4618767.java new file mode 100644 index 0000000000000..d8aa52c3952f2 --- /dev/null +++ b/test/jdk/javax/swing/JTree/bug4618767.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4618767 + * @summary First letter navigation in JTree interferes with mnemonics + * @key headful + * @run main bug4618767 + */ + +import java.awt.Robot; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuListener; + +public class bug4618767 { + private static JFrame f; + private static final JTree tree = new + JTree(new String[] {"one", "two", "three", "four"}); + private static boolean menuSelected; + private static CountDownLatch listGainedFocusLatch = new CountDownLatch(1); + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("bug4618767 Test"); + JMenu menu = new JMenu("File"); + menu.setMnemonic('F'); + JMenuItem menuItem = new JMenuItem("item"); + menu.add(menuItem); + JMenuBar menuBar = new JMenuBar(); + menuBar.add(menu); + f.setJMenuBar(menuBar); + + menu.addMenuListener(new MenuListener() { + public void menuCanceled(MenuEvent e) {} + public void menuDeselected(MenuEvent e) {} + public void menuSelected(MenuEvent e) { + menuSelected = true; + } + }); + + tree.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + listGainedFocusLatch.countDown(); + } + }); + f.add(tree); + f.pack(); + f.setLocationRelativeTo(null); + f.setAlwaysOnTop(true); + f.setVisible(true); + }); + runTest(); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private static void runTest() throws Exception { + if (!listGainedFocusLatch.await(3, TimeUnit.SECONDS)) { + throw new RuntimeException("Waited too long, but can't gain" + + " focus for list"); + } + Robot robot = new Robot(); + robot.setAutoDelay(200); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_O); + robot.keyRelease(KeyEvent.VK_O); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_ALT); + + SwingUtilities.invokeAndWait(() -> { + if (menuSelected && !tree.getSelectionPath() + .getLastPathComponent().toString().equals("one")) { + throw new RuntimeException("Mnemonics interferes with JTree" + + " item selection using KeyEvent"); + } + }); + } +} From 76dec47f00230214e9ba58714be5a3ad26f8308d Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Fri, 18 Apr 2025 21:35:17 +0000 Subject: [PATCH 0664/1101] 8354340: Open source Swing Tests - Set 6 Reviewed-by: azvegint, achung --- .../JViewport/ScrollRectToVisibleTest3.java | 165 ++++++++++++++++++ .../javax/swing/JViewport/SetViewRepaint.java | 114 ++++++++++++ 2 files changed, 279 insertions(+) create mode 100644 test/jdk/javax/swing/JViewport/ScrollRectToVisibleTest3.java create mode 100644 test/jdk/javax/swing/JViewport/SetViewRepaint.java diff --git a/test/jdk/javax/swing/JViewport/ScrollRectToVisibleTest3.java b/test/jdk/javax/swing/JViewport/ScrollRectToVisibleTest3.java new file mode 100644 index 0000000000000..bf96ab2fc46c2 --- /dev/null +++ b/test/jdk/javax/swing/JViewport/ScrollRectToVisibleTest3.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 + * @key headful + * @bug 4217252 + * @summary Verify that scrolling beyond the visible region and scrolling + * a component smaller than the viewport is not allowed. + * @library /javax/swing/regtesthelpers + * @build Util + * @run main/othervm -Dsun.java2d.uiScale=1 ScrollRectToVisibleTest3 + */ + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.AbstractTableModel; + +public class ScrollRectToVisibleTest3 { + private static JFrame frame; + private static JTable table; + private static JButton scrollButton; + private static volatile int clickCount = 0; + private static final String[] EXPECTED_TEXT = {"99 x 0", "98 x 0", + "97 x 0", "96 x 0"}; + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + robot.setAutoWaitForIdle(true); + + SwingUtilities.invokeAndWait(ScrollRectToVisibleTest3::createTestUI); + robot.waitForIdle(); + robot.delay(1000); + + Rectangle frameBounds = Util.invokeOnEDT(() -> getComponentBounds(frame)); + robot.delay(100); + Point scrollBtnLoc = Util.getCenterPoint(scrollButton); + + robot.mouseMove(scrollBtnLoc.x, scrollBtnLoc.y); + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); + robot.delay(50); + + int rowHeight = Util.invokeOnEDT(() -> table.getRowHeight()); + for (int i = 1; i <= 4; i++) { + robot.mouseMove(frameBounds.x + 50, + frameBounds.y + frameBounds.height - (rowHeight * i + 2)); + robot.delay(300); + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); + // 500 ms delay added so that current mouseClicked event + // is processed successfully before proceeding to the next + robot.delay(500); + } + if (clickCount != 4) { + throw new RuntimeException("Test Failed! Expected 4 mouse clicks" + + " but got " + clickCount); + } + } + + private static void createTestUI() { + frame = new JFrame("ScrollRectToVisibleTest3"); + table = new JTable(new TestModel()); + table.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + JTable testTable = (JTable) e.getComponent(); + int row = testTable.getSelectedRow(); + int column = testTable.getSelectedColumn(); + String cellContent = testTable.getValueAt(row, column).toString(); + if (!EXPECTED_TEXT[clickCount].equals(cellContent)) { + throw new RuntimeException(("Test failed! Table Cell Content" + + " at (row %d , col %d)\n Expected: %s vs Actual: %s") + .formatted(row, column, + EXPECTED_TEXT[clickCount], cellContent)); + } + clickCount++; + } + }); + + scrollButton = new JButton("Scroll"); + scrollButton.addActionListener(ae -> { + Rectangle bounds = table.getBounds(); + bounds.y = bounds.height + table.getRowHeight(); + bounds.height = table.getRowHeight(); + System.out.println("scrolling: " + bounds); + table.scrollRectToVisible(bounds); + System.out.println("bounds: " + table.getVisibleRect()); + }); + + frame.add(scrollButton, BorderLayout.NORTH); + frame.add(new JScrollPane(table), BorderLayout.CENTER); + frame.setSize(400, 300); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + + private static class TestModel extends AbstractTableModel { + @Override + public String getColumnName(int column) { + return Integer.toString(column); + } + + @Override + public int getRowCount() { + return 100; + } + + @Override + public int getColumnCount() { + return 5; + } + + @Override + public Object getValueAt(int row, int col) { + return row + " x " + col; + } + + @Override + public boolean isCellEditable(int row, int column) { return false; } + + @Override + public void setValueAt(Object value, int row, int col) { + } + } + + private static Rectangle getComponentBounds(Component c) { + Point locationOnScreen = c.getLocationOnScreen(); + Dimension size = c.getSize(); + return new Rectangle(locationOnScreen, size); + } +} diff --git a/test/jdk/javax/swing/JViewport/SetViewRepaint.java b/test/jdk/javax/swing/JViewport/SetViewRepaint.java new file mode 100644 index 0000000000000..379a3e4e33b63 --- /dev/null +++ b/test/jdk/javax/swing/JViewport/SetViewRepaint.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4128110 + * @summary Verify that JViewport.setViewportView() and JScrollPane.setViewport() + * force a re-layout and a repaint. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetViewRepaint + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.GridLayout; +import java.awt.event.ActionListener; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JViewport; + +public class SetViewRepaint { + private static final String INSTRUCTIONS = """ + Verify the following two cases: + + 1) Press "JViewport.setViewportView()" button and verify that + the blue label is replaced by a scrolling list. + + 2) Press "JScrollPane.setViewport()" button and verify that + the red label is replaced by a scrolling list as well. + + In either case the display should update automatically after + pressing the button. + + If the above is true, press PASS else press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(30) + .testUI(SetViewRepaint::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("SetViewRepaint"); + JPanel p1 = new JPanel(new BorderLayout()); + JPanel p2 = new JPanel(new BorderLayout()); + + JLabel label1 = new ColorLabel(Color.BLUE, "Blue Label"); + final JList list1 = new JList(new String[]{"one", "two", "three", "four"}); + final JScrollPane sp1 = new JScrollPane(label1); + ActionListener doSetViewportView = e -> sp1.setViewportView(list1); + JButton b1 = new JButton("JViewport.setViewportView()"); + b1.addActionListener(doSetViewportView); + p1.add(sp1, BorderLayout.CENTER); + p1.add(b1, BorderLayout.SOUTH); + + JLabel label2 = new ColorLabel(Color.RED, "Red Label"); + final JList list2 = new JList(new String[]{"five", "six", "seven", "eight"}); + final JScrollPane sp2 = new JScrollPane(label2); + ActionListener doSetViewport = e -> { + JViewport vp = new JViewport(); + vp.setView(list2); + sp2.setViewport(vp); + }; + JButton b2 = new JButton("JScrollPane.setViewport()"); + b2.addActionListener(doSetViewport); + p2.add(sp2, BorderLayout.CENTER); + p2.add(b2, BorderLayout.SOUTH); + frame.setLayout(new GridLayout(1, 2)); + frame.add(p1); + frame.add(p2); + frame.setResizable(false); + frame.setSize(500, 120); + return frame; + } + + private static class ColorLabel extends JLabel { + ColorLabel(Color color, String text) { + super(text); + setForeground(Color.WHITE); + setBackground(color); + setOpaque(true); + setHorizontalAlignment(CENTER); + } + } +} From bd73127d7495244f93f941530db32b4559d45689 Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Fri, 18 Apr 2025 23:29:53 +0000 Subject: [PATCH 0665/1101] 8354532: Open source JFileChooser Tests - Set 7 Reviewed-by: prr --- .../javax/swing/JFileChooser/bug4357012.java | 99 +++++++++++++++ .../javax/swing/JFileChooser/bug4926884.java | 114 ++++++++++++++++++ .../javax/swing/JFileChooser/bug5045464.java | 68 +++++++++++ .../javax/swing/JFileChooser/bug6515169.java | 106 ++++++++++++++++ 4 files changed, 387 insertions(+) create mode 100644 test/jdk/javax/swing/JFileChooser/bug4357012.java create mode 100644 test/jdk/javax/swing/JFileChooser/bug4926884.java create mode 100644 test/jdk/javax/swing/JFileChooser/bug5045464.java create mode 100644 test/jdk/javax/swing/JFileChooser/bug6515169.java diff --git a/test/jdk/javax/swing/JFileChooser/bug4357012.java b/test/jdk/javax/swing/JFileChooser/bug4357012.java new file mode 100644 index 0000000000000..2dfdcd336d5fd --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/bug4357012.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4357012 + * @requires (os.family == "windows") + * @summary JFileChooser.showSaveDialog inconsistent with Windows Save Dialog + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4357012 + */ + +import java.io.File; +import java.io.IOException; +import javax.swing.JComponent; +import javax.swing.JFileChooser; +import javax.swing.UIManager; + +public class bug4357012 { + private static File workDir = null; + private static File dir = null; + private static File file = null; + private static final String INSTRUCTIONS = """ + + Test is for Windows LAF only +

In JFileChooser's files list : +

    +
  1. Select directory. Verify that the directory name doesn't + appear in "file name" field.
  2. +
  3. Select file. Verify that the file name appears in + "file name" field.
  4. +
  5. Select directory again. Verify that the previous file name + remains in file name field.
  6. +
+

+ + """; + + public static void main(String[] argv) throws Exception { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + createTestDir(); + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .rows(10) + .columns(40) + .testUI(bug4357012::createTestUI) + .build() + .awaitAndCheck(); + } finally { + if (workDir != null) { + System.out.println("Deleting '" + file + "': " + file.delete()); + System.out.println("Deleting '" + dir + "': " + dir.delete()); + System.out.println("Deleting '" + workDir + "': " + workDir.delete()); + } + } + } + + private static void createTestDir() throws IOException { + String tempDir = "."; + String fs = System.getProperty("file.separator"); + + workDir = new File(tempDir + fs + "bug4357012"); + System.out.println("Creating '" + workDir + "': " + workDir.mkdir()); + + dir = new File(workDir + fs + "Directory"); + System.out.println("Creating '" + dir + "': " + dir.mkdir()); + + file = new File(workDir + fs + "File.txt"); + System.out.println("Creating '" + file + "': " + file.createNewFile()); + } + + private static JComponent createTestUI() { + JFileChooser fc = new JFileChooser(workDir); + fc.setDialogType(JFileChooser.SAVE_DIALOG); + return fc; + } +} diff --git a/test/jdk/javax/swing/JFileChooser/bug4926884.java b/test/jdk/javax/swing/JFileChooser/bug4926884.java new file mode 100644 index 0000000000000..29d6c4e913450 --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/bug4926884.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4926884 + * @requires (os.family == "windows") + * @summary Win L&F: JFileChooser problems with "My Documents" folder + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4926884 + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import javax.swing.JFileChooser; +import javax.swing.UIManager; + +public class bug4926884 { + private static final String INSTRUCTIONS = """ + Validate next statements step by step: + + 1. In the file list there are several dirs and files (like "ski", + "Snowboard" etc.) + 2. Select "Details" view mode. + 3. Make file list in focus (e.g. by pressing mouse button) + 4. Press key "w" several times with delay LESS than 1 second. + Selection should be changed across files started with letter "w" + (without case sensitive). + 5. Press key "w" several times with delay MORE than 1 second. + Selection should be changed across files started with letter "w" + (without case sensitive). + 6. Type "winnt" (with delay less than 1 second between letters) - + directory "winnt" should be selected. + 7. Change conditions: + - Move column "Name" to the second position + - Change sort mode by clicking column "Size" + 8. Repeat items 4-6 + + If above is true press PASS else FAIL + """; + + private static final String[] DIRS = {"www", "winnt", "ski"}; + private static final String[] FILES = {"Window", "weel", "mice", + "Wall", "Snowboard", "wood"}; + private static final File testDir = new File("."); + + public static void main(String[] argv) throws Exception { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + try { + createTestDir(); + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(() -> new JFileChooser(testDir)) + .build() + .awaitAndCheck(); + } finally { + deleteTempDir(); + } + } + + private static void createTestDir() throws IOException { + testDir.mkdir(); + + for (String dir : DIRS) { + new File(testDir, dir).mkdir(); + } + + for (int i = 0; i < FILES.length; i++) { + + try (OutputStream outputStream = new FileOutputStream( + new File(testDir, FILES[i]))) { + for (int j = 0; j < i * 1024; j++) { + outputStream.write('#'); + } + } + } + } + + private static void deleteTempDir() { + File[] files = testDir.listFiles(); + + for (File file : files) { + if (file != null) { + file.delete(); + } + } + + testDir.delete(); + } +} diff --git a/test/jdk/javax/swing/JFileChooser/bug5045464.java b/test/jdk/javax/swing/JFileChooser/bug5045464.java new file mode 100644 index 0000000000000..0fbeedcec6bd4 --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/bug5045464.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5045464 + * @requires (os.family == "linux") + * @summary Regression: GTK L&F, JFileChooser shows "null/" in folder list + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug5045464 + */ + +import javax.swing.JComponent; +import javax.swing.JFileChooser; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class bug5045464 { + private static final String INSTRUCTIONS = """ + When the filechooser appears check the directory list (the left list). + If it starts with two items: "./" (current directory) + and "../" (parent directory) press PASS. + If something else is here (e.g. "null/" instead of "./") + press FAIL. + """; + + public static void main(String[] argv) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug5045464::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JComponent createTestUI() { + JFileChooser fc = new JFileChooser(); + fc.setControlButtonsAreShown(false); + try { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); + } catch (Exception ex) { + throw new RuntimeException("Test Failed!", ex); + } + SwingUtilities.updateComponentTreeUI(fc); + return fc; + } +} diff --git a/test/jdk/javax/swing/JFileChooser/bug6515169.java b/test/jdk/javax/swing/JFileChooser/bug6515169.java new file mode 100644 index 0000000000000..98cd813eefb26 --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/bug6515169.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6515169 + * @requires (os.family == "windows") + * @summary wrong grid header in JFileChooser + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug6515169 + */ + +import javax.swing.ButtonGroup; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class bug6515169 { + private static JFrame frame; + private static final String INSTRUCTIONS = """ + This test is to verify JFileChooser on Windows and Metal LAF. + Use the "Change LaF" menu to switch between the 2 LaF + and verify the following. + + a. Change view mode to "Details" + b. Check that 4 columns appear: Name, Size, Type and Date Modified + c. Change current directory by pressing any available subdirectory + or by pressing button "Up One Level". + d. Check that still four columns exist. + + Change LaF and repeat the steps a-d. + If all conditions are true press PASS, else FAIL. + """; + + public static void main(String[] argv) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug6515169::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + frame = new JFrame("bug6515169"); + JMenuBar bar = new JMenuBar(); + JMenu lafMenu = new JMenu("Change LaF"); + ButtonGroup lafGroup = new ButtonGroup(); + JCheckBoxMenuItem lafItem1 = new JCheckBoxMenuItem("Window LaF"); + lafItem1.addActionListener(e -> + setLaF(UIManager.getSystemLookAndFeelClassName())); + lafGroup.add(lafItem1); + lafMenu.add(lafItem1); + + JCheckBoxMenuItem lafItem2 = new JCheckBoxMenuItem("Metal LaF"); + lafItem2.addActionListener(e -> + setLaF(UIManager.getCrossPlatformLookAndFeelClassName())); + lafGroup.add(lafItem2); + lafMenu.add(lafItem2); + + bar.add(lafMenu); + frame.setJMenuBar(bar); + + String dir = "."; + JFileChooser fc = new JFileChooser(dir); + fc.setControlButtonsAreShown(false); + frame.add(fc); + frame.pack(); + + return frame; + } + + private static void setLaF(String laf) { + try { + UIManager.setLookAndFeel(laf); + SwingUtilities.updateComponentTreeUI(frame); + } catch (Exception e) { + throw new RuntimeException("Test Failed!", e); + } + } +} From 4f58af0a8dd5eced77259bed180f6af36501f502 Mon Sep 17 00:00:00 2001 From: Alexey Bakhtin Date: Sat, 19 Apr 2025 00:30:37 +0000 Subject: [PATCH 0666/1101] 8259540: MissingResourceException for key cvc-complex-type.2.4.d.1 Reviewed-by: joehw --- .../apache/xerces/internal/impl/msg/XMLSchemaMessages.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties index f6402e8f65e49..4f15b428c8b5b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties @@ -56,6 +56,7 @@ cvc-complex-type.2.4.b = cvc-complex-type.2.4.b: The content of element ''{0}'' is not complete. One of ''{1}'' is expected. cvc-complex-type.2.4.c = cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element ''{0}''. cvc-complex-type.2.4.d = cvc-complex-type.2.4.d: Invalid content was found starting with element ''{0}''. No child element is expected at this point. + cvc-complex-type.2.4.d.1 = cvc-complex-type.2.4.d: Invalid content was found starting with element ''{0}''. No child element ''{1}'' is expected at this point. cvc-complex-type.2.4.e = cvc-complex-type.2.4.e: ''{0}'' can occur a maximum of ''{2}'' times in the current sequence. This limit was exceeded. At this point one of ''{1}'' is expected. cvc-complex-type.2.4.f = cvc-complex-type.2.4.f: ''{0}'' can occur a maximum of ''{1}'' times in the current sequence. This limit was exceeded. No child element is expected at this point. cvc-complex-type.2.4.g = cvc-complex-type.2.4.g: Invalid content was found starting with element ''{0}''. ''{1}'' is expected to occur a minimum of ''{2}'' times in the current sequence. One more instance is required to satisfy this constraint. From c7c77eb6aa25cbf84ba4b7519e16c092c222e504 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Sat, 19 Apr 2025 07:48:54 +0000 Subject: [PATCH 0667/1101] 8354077: Get rid of offscreenSharingEnabled windows flag Reviewed-by: prr --- .../sun/java2d/windows/WindowsFlags.java | 32 ++----------------- .../libawt/java2d/windows/WindowsFlags.cpp | 9 +----- .../libawt/java2d/windows/WindowsFlags.h | 4 +-- 3 files changed, 4 insertions(+), 41 deletions(-) diff --git a/src/java.desktop/windows/classes/sun/java2d/windows/WindowsFlags.java b/src/java.desktop/windows/classes/sun/java2d/windows/WindowsFlags.java index 5bf2ba3227fd3..7333eeda3dd92 100644 --- a/src/java.desktop/windows/classes/sun/java2d/windows/WindowsFlags.java +++ b/src/java.desktop/windows/classes/sun/java2d/windows/WindowsFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,16 +55,6 @@ public class WindowsFlags { * This flag can force us to use d3d * anyway in these situations. Or, this flag can force us to * not use d3d in a situation where we would use it otherwise. - * offscreenSharingEnabled: usage: "-Dsun.java2d.offscreenSharing=true" - * Turns on the ability to share a hardware-accelerated - * offscreen surface through the JAWT interface. See - * src/windows/native/sun/windows/awt_DrawingSurface.* for - * more information. This capability is disabled by default - * pending more testing and time to work out the right - * solution; we do not want to expose more public JAWT api - * without being very sure that we will be willing to support - * that API in the future regardless of other native - * rendering pipeline changes. * magPresent: usage: "-Djavax.accessibility.screen_magnifier_present" * This flag is set either on the command line or in the * properties file. It tells Swing whether the user is @@ -101,7 +91,6 @@ public class WindowsFlags { private static boolean d3dOnScreenEnabled; private static boolean oglEnabled; private static boolean oglVerbose; - private static boolean offscreenSharingEnabled; private static boolean magPresent; private static boolean setHighDPIAware; // TODO: other flags, including nopixfmt @@ -206,8 +195,6 @@ private static void initJavaFlags() { if (d3dSet) { d3dVerbose = isBooleanPropTrueVerbose("sun.java2d.d3d"); } - offscreenSharingEnabled = - getBooleanProp("sun.java2d.offscreenSharing", false); String dpiOverride = System.getProperty("sun.java2d.dpiaware"); if (dpiOverride != null) { setHighDPIAware = dpiOverride.equalsIgnoreCase("true"); @@ -217,16 +204,6 @@ private static void initJavaFlags() { setHighDPIAware = sunLauncherProperty.equalsIgnoreCase("SUN_STANDARD"); } - /* - // Output info based on some non-default flags: - if (offscreenSharingEnabled) { - System.out.println( - "Warning: offscreenSharing has been enabled. " + - "The use of this capability will change in future " + - "releases and applications that depend on it " + - "may not work correctly"); - } - */ /* System.out.println("WindowsFlags (Java):"); System.out.println(" ddEnabled: " + ddEnabled + "\n" + @@ -235,8 +212,7 @@ private static void initJavaFlags() { " d3dSet: " + d3dSet + "\n" + " oglEnabled: " + oglEnabled + "\n" + " oglVerbose: " + oglVerbose + "\n" + - " gdiBlitEnabled: " + gdiBlitEnabled + "\n" + - " offscreenSharingEnabled: " + offscreenSharingEnabled); + " gdiBlitEnabled: " + gdiBlitEnabled); */ } @@ -260,10 +236,6 @@ public static boolean isGdiBlitEnabled() { return gdiBlitEnabled; } - public static boolean isOffscreenSharingEnabled() { - return offscreenSharingEnabled; - } - public static boolean isMagPresent() { return magPresent; } diff --git a/src/java.desktop/windows/native/libawt/java2d/windows/WindowsFlags.cpp b/src/java.desktop/windows/native/libawt/java2d/windows/WindowsFlags.cpp index 528e95e326ade..9ed0f38bd1086 100644 --- a/src/java.desktop/windows/native/libawt/java2d/windows/WindowsFlags.cpp +++ b/src/java.desktop/windows/native/libawt/java2d/windows/WindowsFlags.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ BOOL useD3D = TRUE; // d3d enabled flag // initially is TRUE to allow D3D preloading BOOL forceD3DUsage; // force d3d on or off -jboolean g_offscreenSharing; // JAWT accelerated surface sharing BOOL setHighDPIAware; // Whether to set the high-DPI awareness flag extern WCHAR *j2dAccelKey; // Name of java2d root key @@ -89,10 +88,6 @@ void GetFlagValues(JNIEnv *env, jclass wFlagsClass) } useD3D = d3dEnabled; forceD3DUsage = d3dSet; - g_offscreenSharing = GetStaticBoolean(env, wFlagsClass, - "offscreenSharingEnabled"); - JNU_CHECK_EXCEPTION(env); - setHighDPIAware = (IS_WINVISTA && GetStaticBoolean(env, wFlagsClass, "setHighDPIAware")); JNU_CHECK_EXCEPTION(env); @@ -102,8 +97,6 @@ void GetFlagValues(JNIEnv *env, jclass wFlagsClass) (useD3D ? "true" : "false")); J2dTraceLn1(J2D_TRACE_INFO, " d3dSet = %s", (forceD3DUsage ? "true" : "false")); - J2dTraceLn1(J2D_TRACE_INFO, " offscreenSharing = %s", - (g_offscreenSharing ? "true" : "false")); J2dTraceLn1(J2D_TRACE_INFO, " setHighDPIAware = %s", (setHighDPIAware ? "true" : "false")); } diff --git a/src/java.desktop/windows/native/libawt/java2d/windows/WindowsFlags.h b/src/java.desktop/windows/native/libawt/java2d/windows/WindowsFlags.h index 85ba1657000c3..d5e34fdaa6979 100644 --- a/src/java.desktop/windows/native/libawt/java2d/windows/WindowsFlags.h +++ b/src/java.desktop/windows/native/libawt/java2d/windows/WindowsFlags.h @@ -1,6 +1,5 @@ - /* - * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +28,6 @@ extern BOOL useD3D; // d3d enabled flag extern BOOL forceD3DUsage; // force d3d on or off -extern jboolean g_offscreenSharing; // JAWT accelerated surface sharing extern BOOL setHighDPIAware; // whether to set High DPI Aware flag on Vista void SetD3DEnabledFlag(JNIEnv *env, BOOL d3dEnabled, BOOL d3dSet); From 128f2d1cadae3cf91e4c590e6dabe2086737b7dd Mon Sep 17 00:00:00 2001 From: Liming Liu Date: Sat, 19 Apr 2025 10:02:13 +0000 Subject: [PATCH 0668/1101] 8354572: Turn off AlwaysMergeDMB for Ampere CPU by default Reviewed-by: shade --- src/hotspot/cpu/aarch64/vm_version_aarch64.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index c555e393ca57c..b2d3455348791 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -161,6 +161,9 @@ void VM_Version::initialize() { (_model == CPU_MODEL_AMPERE_1A || _model == CPU_MODEL_AMPERE_1B)) { FLAG_SET_DEFAULT(CodeEntryAlignment, 32); } + if (FLAG_IS_DEFAULT(AlwaysMergeDMB)) { + FLAG_SET_DEFAULT(AlwaysMergeDMB, false); + } } // ThunderX From 4dd64b49716144cc697fb461ff88860e2cbcaaea Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Mon, 21 Apr 2025 11:41:45 +0000 Subject: [PATCH 0669/1101] 8354477: C2 SuperWord: make use of memory edges more explicit Reviewed-by: kvn, roland --- .../share/opto/superwordVTransformBuilder.cpp | 89 +++++++++---------- .../share/opto/superwordVTransformBuilder.hpp | 14 +-- src/hotspot/share/opto/vectorization.cpp | 4 + src/hotspot/share/opto/vectorization.hpp | 5 ++ src/hotspot/share/opto/vtransform.hpp | 5 +- 5 files changed, 62 insertions(+), 55 deletions(-) diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp index d356fcd510970..83496f9d0be0a 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.cpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -34,9 +34,9 @@ void SuperWordVTransformBuilder::build() { // Connect all vtnodes with their inputs. Possibly create vtnodes for input // nodes that are outside the loop. - VectorSet vtn_dependencies; // Shared, but cleared for every vtnode. - build_inputs_for_vector_vtnodes(vtn_dependencies); - build_inputs_for_scalar_vtnodes(vtn_dependencies); + VectorSet vtn_memory_dependencies; // Shared, but cleared for every vtnode. + build_inputs_for_vector_vtnodes(vtn_memory_dependencies); + build_inputs_for_scalar_vtnodes(vtn_memory_dependencies); } void SuperWordVTransformBuilder::build_vector_vtnodes_for_packed_nodes() { @@ -58,75 +58,77 @@ void SuperWordVTransformBuilder::build_scalar_vtnodes_for_non_packed_nodes() { } } -void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_dependencies) { +void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_memory_dependencies) { for (int i = 0; i < _packset.length(); i++) { Node_List* pack = _packset.at(i); Node* p0 = pack->at(0); VTransformVectorNode* vtn = get_vtnode(p0)->isa_Vector(); assert(vtn != nullptr, "all packs must have vector vtnodes"); - vtn_dependencies.clear(); // Add every dependency only once per vtn. + vtn_memory_dependencies.clear(); // Add every memory dependency only once per vtn. if (p0->is_Load()) { - set_req_with_scalar(p0, vtn, vtn_dependencies, MemNode::Address); + set_req_with_scalar(p0, vtn, MemNode::Address); + for (uint k = 0; k < pack->size(); k++) { + add_memory_dependencies_of_node_to_vtnode(pack->at(k), vtn, vtn_memory_dependencies); + } } else if (p0->is_Store()) { - set_req_with_scalar(p0, vtn, vtn_dependencies, MemNode::Address); - set_req_with_vector(pack, vtn, vtn_dependencies, MemNode::ValueIn); + set_req_with_scalar(p0, vtn, MemNode::Address); + set_req_with_vector(pack, vtn, MemNode::ValueIn); + for (uint k = 0; k < pack->size(); k++) { + add_memory_dependencies_of_node_to_vtnode(pack->at(k), vtn, vtn_memory_dependencies); + } } else if (vtn->isa_ReductionVector() != nullptr) { - set_req_with_scalar(p0, vtn, vtn_dependencies, 1); // scalar init - set_req_with_vector(pack, vtn, vtn_dependencies, 2); // vector + set_req_with_scalar(p0, vtn, 1); // scalar init + set_req_with_vector(pack, vtn, 2); // vector } else { assert(vtn->isa_ElementWiseVector() != nullptr, "all other vtnodes are handled above"); if (VectorNode::is_scalar_rotate(p0) && p0->in(2)->is_Con() && Matcher::supports_vector_constant_rotates(p0->in(2)->get_int())) { - set_req_with_vector(pack, vtn, vtn_dependencies, 1); - set_req_with_scalar(p0, vtn, vtn_dependencies, 2); // constant rotation + set_req_with_vector(pack, vtn, 1); + set_req_with_scalar(p0, vtn, 2); // constant rotation } else if (VectorNode::is_roundopD(p0)) { - set_req_with_vector(pack, vtn, vtn_dependencies, 1); - set_req_with_scalar(p0, vtn, vtn_dependencies, 2); // constant rounding mode + set_req_with_vector(pack, vtn, 1); + set_req_with_scalar(p0, vtn, 2); // constant rounding mode } else if (p0->is_CMove()) { // Cmp + Bool + CMove -> VectorMaskCmp + VectorBlend. - set_all_req_with_vectors(pack, vtn, vtn_dependencies); + set_all_req_with_vectors(pack, vtn); VTransformBoolVectorNode* vtn_mask_cmp = vtn->in(1)->isa_BoolVector(); if (vtn_mask_cmp->test()._is_negated) { vtn->swap_req(2, 3); // swap if test was negated. } } else { - set_all_req_with_vectors(pack, vtn, vtn_dependencies); + set_all_req_with_vectors(pack, vtn); } } - - for (uint k = 0; k < pack->size(); k++) { - add_dependencies_of_node_to_vtnode(pack->at(k), vtn, vtn_dependencies); - } } } -void SuperWordVTransformBuilder::build_inputs_for_scalar_vtnodes(VectorSet& vtn_dependencies) { +void SuperWordVTransformBuilder::build_inputs_for_scalar_vtnodes(VectorSet& vtn_memory_dependencies) { for (int i = 0; i < _vloop_analyzer.body().body().length(); i++) { Node* n = _vloop_analyzer.body().body().at(i); VTransformScalarNode* vtn = get_vtnode(n)->isa_Scalar(); if (vtn == nullptr) { continue; } - vtn_dependencies.clear(); // Add every dependency only once per vtn. + vtn_memory_dependencies.clear(); // Add every dependency only once per vtn. if (n->is_Load()) { - set_req_with_scalar(n, vtn, vtn_dependencies, MemNode::Address); + set_req_with_scalar(n, vtn, MemNode::Address); + add_memory_dependencies_of_node_to_vtnode(n, vtn, vtn_memory_dependencies); } else if (n->is_Store()) { - set_req_with_scalar(n, vtn, vtn_dependencies, MemNode::Address); - set_req_with_scalar(n, vtn, vtn_dependencies, MemNode::ValueIn); + set_req_with_scalar(n, vtn, MemNode::Address); + set_req_with_scalar(n, vtn, MemNode::ValueIn); + add_memory_dependencies_of_node_to_vtnode(n, vtn, vtn_memory_dependencies); } else if (n->is_CountedLoop()) { continue; // Is "root", has no dependency. } else if (n->is_Phi()) { // CountedLoop Phi's: ignore backedge (and entry value). assert(n->in(0) == _vloop.cl(), "only Phi's from the CountedLoop allowed"); - set_req_with_scalar(n, vtn, vtn_dependencies, 0); + set_req_with_scalar(n, vtn, 0); continue; } else { - set_all_req_with_scalars(n, vtn, vtn_dependencies); + set_all_req_with_scalars(n, vtn); } - - add_dependencies_of_node_to_vtnode(n, vtn, vtn_dependencies); } } @@ -175,10 +177,9 @@ VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(co return vtn; } -void SuperWordVTransformBuilder::set_req_with_scalar(Node* n, VTransformNode* vtn, VectorSet& vtn_dependencies, const int index) { +void SuperWordVTransformBuilder::set_req_with_scalar(Node* n, VTransformNode* vtn, const int index) { VTransformNode* req = get_vtnode_or_wrap_as_input_scalar(n->in(index)); vtn->set_req(index, req); - vtn_dependencies.set(req->_idx); } // Either get the existing vtnode vector input (when input is a pack), or else make a @@ -273,46 +274,42 @@ VTransformNode* SuperWordVTransformBuilder::get_vtnode_or_wrap_as_input_scalar(N return vtn; } -void SuperWordVTransformBuilder::set_req_with_vector(const Node_List* pack, VTransformNode* vtn, VectorSet& vtn_dependencies, int j) { +void SuperWordVTransformBuilder::set_req_with_vector(const Node_List* pack, VTransformNode* vtn, int j) { VTransformNode* req = get_or_make_vtnode_vector_input_at_index(pack, j); vtn->set_req(j, req); - vtn_dependencies.set(req->_idx); } -void SuperWordVTransformBuilder::set_all_req_with_scalars(Node* n, VTransformNode* vtn, VectorSet& vtn_dependencies) { +void SuperWordVTransformBuilder::set_all_req_with_scalars(Node* n, VTransformNode* vtn) { assert(vtn->req() == n->req(), "scalars must have same number of reqs"); for (uint j = 0; j < n->req(); j++) { Node* def = n->in(j); if (def == nullptr) { continue; } - set_req_with_scalar(n, vtn, vtn_dependencies, j); + set_req_with_scalar(n, vtn, j); } } -void SuperWordVTransformBuilder::set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn, VectorSet& vtn_dependencies) { +void SuperWordVTransformBuilder::set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn) { Node* p0 = pack->at(0); assert(vtn->req() <= p0->req(), "must have at at most as many reqs"); // Vectors have no ctrl, so ignore it. for (uint j = 1; j < vtn->req(); j++) { Node* def = p0->in(j); if (def == nullptr) { continue; } - set_req_with_vector(pack, vtn, vtn_dependencies, j); + set_req_with_vector(pack, vtn, j); } } -void SuperWordVTransformBuilder::add_dependencies_of_node_to_vtnode(Node*n, VTransformNode* vtn, VectorSet& vtn_dependencies) { +void SuperWordVTransformBuilder::add_memory_dependencies_of_node_to_vtnode(Node*n, VTransformNode* vtn, VectorSet& vtn_memory_dependencies) { for (VLoopDependencyGraph::PredsIterator preds(_vloop_analyzer.dependency_graph(), n); !preds.done(); preds.next()) { Node* pred = preds.current(); if (!_vloop.in_bb(pred)) { continue; } + if (!preds.is_current_memory_edge()) { continue; } - // Only add memory dependencies to memory nodes. All others are taken care of with the req. - if (n->is_Mem() && !pred->is_Mem()) { continue; } - + // Only track every memory edge once. VTransformNode* dependency = get_vtnode(pred); + if (vtn_memory_dependencies.test_set(dependency->_idx)) { continue; } - // Reduction self-cycle? - if (vtn == dependency && _vloop_analyzer.reductions().is_marked_reduction(n)) { continue; } - - if (vtn_dependencies.test_set(dependency->_idx)) { continue; } - vtn->add_dependency(dependency); // Add every dependency only once per vtn. + assert(n->is_Mem() && pred->is_Mem(), "only memory edges"); + vtn->add_memory_dependency(dependency); // Add every dependency only once per vtn. } } diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.hpp b/src/hotspot/share/opto/superwordVTransformBuilder.hpp index 847f870bef616..bff900377f66d 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.hpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.hpp @@ -54,8 +54,8 @@ class SuperWordVTransformBuilder : public StackObj { void build(); void build_vector_vtnodes_for_packed_nodes(); void build_scalar_vtnodes_for_non_packed_nodes(); - void build_inputs_for_vector_vtnodes(VectorSet& vtn_dependencies); - void build_inputs_for_scalar_vtnodes(VectorSet& vtn_dependencies); + void build_inputs_for_vector_vtnodes(VectorSet& vtn_memory_dependencies); + void build_inputs_for_scalar_vtnodes(VectorSet& vtn_memory_dependencies); // Helper methods for building VTransform. VTransformNode* get_vtnode_or_null(Node* n) const { @@ -77,11 +77,11 @@ class SuperWordVTransformBuilder : public StackObj { VTransformVectorNode* make_vector_vtnode_for_pack(const Node_List* pack) const; VTransformNode* get_or_make_vtnode_vector_input_at_index(const Node_List* pack, const int index); VTransformNode* get_vtnode_or_wrap_as_input_scalar(Node* n); - void set_req_with_scalar(Node* n, VTransformNode* vtn, VectorSet& vtn_dependencies, const int index); - void set_req_with_vector(const Node_List* pack, VTransformNode* vtn, VectorSet& vtn_dependencies, const int index); - void set_all_req_with_scalars(Node* n, VTransformNode* vtn, VectorSet& vtn_dependencies); - void set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn, VectorSet& vtn_dependencies); - void add_dependencies_of_node_to_vtnode(Node* n, VTransformNode* vtn, VectorSet& vtn_dependencies); + void set_req_with_scalar(Node* n, VTransformNode* vtn, const int index); + void set_req_with_vector(const Node_List* pack, VTransformNode* vtn, const int index); + void set_all_req_with_scalars(Node* n, VTransformNode* vtn); + void set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn); + void add_memory_dependencies_of_node_to_vtnode(Node* n, VTransformNode* vtn, VectorSet& vtn_memory_dependencies); }; #endif // SHARE_OPTO_SUPERWORD_VTRANSFORM_BUILDER_HPP diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index e607a1065dd03..d2cb62c92c9cd 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -399,6 +399,7 @@ VLoopDependencyGraph::PredsIterator::PredsIterator(const VLoopDependencyGraph& d _node(node), _dependency_node(dependency_graph.dependency_node(node)), _current(nullptr), + _is_current_memory_edge(false), _next_pred(0), _end_pred(node->req()), _next_memory_pred(0), @@ -418,11 +419,14 @@ VLoopDependencyGraph::PredsIterator::PredsIterator(const VLoopDependencyGraph& d void VLoopDependencyGraph::PredsIterator::next() { if (_next_pred < _end_pred) { _current = _node->in(_next_pred++); + _is_current_memory_edge = false; } else if (_next_memory_pred < _end_memory_pred) { int pred_bb_idx = _dependency_node->memory_pred_edge(_next_memory_pred++); _current = _dependency_graph._body.body().at(pred_bb_idx); + _is_current_memory_edge = true; } else { _current = nullptr; // done + _is_current_memory_edge = false; } } diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index d4b785153127c..9d0887a993f87 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -648,6 +648,7 @@ class VLoopDependencyGraph : public StackObj { const DependencyNode* _dependency_node; Node* _current; + bool _is_current_memory_edge; // Iterate in node->in(i) int _next_pred; @@ -665,6 +666,10 @@ class VLoopDependencyGraph : public StackObj { assert(!done(), "not done yet"); return _current; } + bool is_current_memory_edge() const { + assert(!done(), "not done yet"); + return _is_current_memory_edge; + } }; }; diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 588da3cd56ee0..555f565360d2e 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -264,7 +264,8 @@ class VTransformNode : public ArenaObj { const VTransformNodeIDX _idx; private: - // _in is split into required inputs (_req), and additional dependencies. + // _in is split into required inputs (_req, i.e. all data dependencies), + // and memory dependencies. const uint _req; GrowableArray _in; GrowableArray _out; @@ -294,7 +295,7 @@ class VTransformNode : public ArenaObj { _in.at_put(j, tmp); } - void add_dependency(VTransformNode* n) { + void add_memory_dependency(VTransformNode* n) { assert(n != nullptr, "no need to add nullptr"); _in.push(n); n->add_out(this); From cd2d49f7119459f07844ce8201ca2320850cd51f Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Mon, 21 Apr 2025 17:37:58 +0000 Subject: [PATCH 0670/1101] 8354472: Clean up and open source KeyEvent related tests (Part 3) Reviewed-by: honkar --- .../awt/event/KeyEvent/CharUndefinedTest.java | 95 +++++++++++++ .../awt/event/KeyEvent/ExtendedKeysTest.java | 66 +++++++++ .../event/KeyEvent/KeyDownCaptureTest.java | 111 +++++++++++++++ .../event/KeyEvent/KeyEventToLightweight.java | 125 ++++++++++++++++ .../java/awt/event/KeyEvent/KeyModifiers.java | 134 ++++++++++++++++++ 5 files changed, 531 insertions(+) create mode 100644 test/jdk/java/awt/event/KeyEvent/CharUndefinedTest.java create mode 100644 test/jdk/java/awt/event/KeyEvent/ExtendedKeysTest.java create mode 100644 test/jdk/java/awt/event/KeyEvent/KeyDownCaptureTest.java create mode 100644 test/jdk/java/awt/event/KeyEvent/KeyEventToLightweight.java create mode 100644 test/jdk/java/awt/event/KeyEvent/KeyModifiers.java diff --git a/test/jdk/java/awt/event/KeyEvent/CharUndefinedTest.java b/test/jdk/java/awt/event/KeyEvent/CharUndefinedTest.java new file mode 100644 index 0000000000000..bc58bdab14a0e --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/CharUndefinedTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4115484 4164672 4167893 + * @summary Ensures that KeyEvent has right keyChar for modifier and action keys. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CharUndefinedTest + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.lang.reflect.InvocationTargetException; + +public class CharUndefinedTest extends Frame implements KeyListener { + + static String INSTRUCTIONS = """ + Click on the text field inside the window named "Check KeyChar values". + Of any of the keys mentioned in this list that exist on your keyboard + press each of the listed keys once and also press them in two-key combinations such as + Control-Shift or Alt-Control. + The list of keys is: "Control, Shift, Meta, Alt, Command, Option". + After that press all function keys from F1 to F12 once, + Insert, Home, End, PageUp, PageDown and four arrow keys. + Check the log area below. If there are no messages starting with word "ERROR" + press "Pass" otherwise press "Fail". + """; + + public CharUndefinedTest() { + super("Check KeyChar values"); + setLayout(new BorderLayout()); + TextField tf = new TextField(30); + tf.addKeyListener(this); + add(tf, BorderLayout.CENTER); + pack(); + tf.requestFocus(); + } + + public void keyPressed(KeyEvent e) { + if (e.getKeyChar() != KeyEvent.CHAR_UNDEFINED) { + PassFailJFrame.log("ERROR: KeyPressed: keyChar = " + e.getKeyChar() + + " keyCode = " + e.getKeyCode() + " " + e.getKeyText(e.getKeyCode())); + } + } + + public void keyTyped(KeyEvent e) { + if (e.getKeyChar() != KeyEvent.CHAR_UNDEFINED) { + PassFailJFrame.log("ERROR: KeyTyped: keyChar = " + e.getKeyChar() + + " keyCode = " + e.getKeyCode() + " " + e.getKeyText(e.getKeyCode())); + } + } + + public void keyReleased(KeyEvent e) { + if (e.getKeyChar() != KeyEvent.CHAR_UNDEFINED) { + PassFailJFrame.log("ERROR: KeyReleased: keyChar = " + e.getKeyChar() + + " keyCode = " + e.getKeyCode() + " " + e.getKeyText(e.getKeyCode())); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(45) + .logArea(10) + .testUI(CharUndefinedTest::new) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/event/KeyEvent/ExtendedKeysTest.java b/test/jdk/java/awt/event/KeyEvent/ExtendedKeysTest.java new file mode 100644 index 0000000000000..1423b2a007e9f --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/ExtendedKeysTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4218892 4191924 4199284 + * @summary Unable to enter some chars via european keyboard layout(s) + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ExtendedKeysTest + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.TextArea; +import java.lang.reflect.InvocationTargetException; + +public class ExtendedKeysTest extends Frame { + static String INSTRUCTIONS = """ + This test requires Swiss German input. If the Swiss German input + can not be installed or configured press "Pass" to skip testing. + Click on the text area inside the window named "Check input". + Switch to Swiss German input and press key with "\\" on it + (usually this key is above or to the left of the main "Enter" key). + If you see a dollar sign press "Pass". + If you see any other character or question mark press "Fail". + """; + + public ExtendedKeysTest() { + super("Check input"); + setLayout(new BorderLayout()); + add(new TextArea(20, 20), "Center"); + pack(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(45) + .logArea(10) + .testUI(ExtendedKeysTest::new) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/event/KeyEvent/KeyDownCaptureTest.java b/test/jdk/java/awt/event/KeyEvent/KeyDownCaptureTest.java new file mode 100644 index 0000000000000..bf2ab7ae95839 --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/KeyDownCaptureTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4093998 + * @summary keyDown not called on subclasses of Component + * @key headful + * @run main KeyDownCaptureTest + */ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.atomic.AtomicBoolean; + +public class KeyDownCaptureTest extends Frame implements KeyListener { + static AtomicBoolean passed = new AtomicBoolean(false); + + public KeyDownCaptureTest() { + super("Key Down Capture Test"); + } + + public void initUI() { + setLayout (new BorderLayout()); + setSize(200, 200); + setLocationRelativeTo(null); + Canvas canvas = new Canvas(); + canvas.setBackground(Color.RED); + canvas.addKeyListener(this); + add(canvas, BorderLayout.CENTER); + setVisible(true); + } + + public void middle(Point p) { + Point loc = getLocationOnScreen(); + Dimension size = getSize(); + p.setLocation(loc.x + (size.width / 2), loc.y + (size.height / 2)); + } + + @Override + public void keyTyped(KeyEvent ignore) {} + + @Override + public void keyPressed(KeyEvent e) { + passed.set(true); + } + + @Override + public void keyReleased(KeyEvent ignore) {} + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + KeyDownCaptureTest test = new KeyDownCaptureTest(); + try { + EventQueue.invokeAndWait((test::initUI)); + Robot robot = new Robot(); + robot.setAutoDelay(50); + robot.delay(500); + robot.waitForIdle(); + Point target = new Point(); + EventQueue.invokeAndWait(() -> { + test.middle(target); + }); + robot.mouseMove(target.x, target.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyPress(KeyEvent.VK_SPACE); + robot.keyRelease(KeyEvent.VK_SPACE); + robot.delay(100); + robot.waitForIdle(); + if (!passed.get()) { + throw new RuntimeException("KeyPressed has not arrived to canvas"); + } + } finally { + if (test != null) { + EventQueue.invokeAndWait(test::dispose); + } + } + } +} diff --git a/test/jdk/java/awt/event/KeyEvent/KeyEventToLightweight.java b/test/jdk/java/awt/event/KeyEvent/KeyEventToLightweight.java new file mode 100644 index 0000000000000..de832bf2e6d4d --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/KeyEventToLightweight.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4397557 + * @summary Check that focused lightweight component gets key events + * even if mouse is outside of it or on top of heavyweight component + * @key headful + * @run main KeyEventToLightweight + */ + +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.swing.JButton; + +public class KeyEventToLightweight extends Frame { + JButton lwbutton = new JButton("Select Me"); + Button hwbutton = new Button("Heavyweight"); + + AtomicBoolean aTyped = new AtomicBoolean(false); + AtomicBoolean bTyped = new AtomicBoolean(false); + AtomicBoolean cTyped = new AtomicBoolean(false); + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + KeyEventToLightweight test = new KeyEventToLightweight(); + try { + EventQueue.invokeAndWait(test::initUI); + test.performTest(); + } finally { + EventQueue.invokeAndWait(test::dispose); + } + } + + public void initUI() { + this.setLayout(new FlowLayout()); + add(lwbutton); + add(hwbutton); + setSize(200, 200); + setLocationRelativeTo(null); + lwbutton.addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_A) { + aTyped.set(true); + } else if (e.getKeyCode() == KeyEvent.VK_B) { + bTyped.set(true); + } else if (e.getKeyCode() == KeyEvent.VK_C) { + cTyped.set(true); + } + } + }); + setVisible(true); + } + + public void middleOf(Component c, Point p) { + Point loc = c.getLocationOnScreen(); + Dimension size = c.getSize(); + p.setLocation(loc.x + (size.width / 2), loc.y + (size.height / 2)); + } + + public void performTest() throws AWTException, InterruptedException, + InvocationTargetException { + Robot robot = new Robot(); + robot.setAutoDelay(50); + robot.delay(500); + robot.waitForIdle(); + Point target = new Point(); + EventQueue.invokeAndWait(() -> middleOf(lwbutton, target)); + robot.mouseMove(target.x, target.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(500); + robot.keyPress(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_A); + robot.waitForIdle(); + robot.mouseMove(target.x - 200, target.y); + robot.keyPress(KeyEvent.VK_B); + robot.keyRelease(KeyEvent.VK_B); + robot.waitForIdle(); + robot.delay(500); + EventQueue.invokeAndWait(() -> middleOf(hwbutton, target)); + robot.mouseMove(target.x, target.y); + robot.keyPress(KeyEvent.VK_C); + robot.keyRelease(KeyEvent.VK_C); + if (!aTyped.get() || !bTyped.get() || !cTyped.get()) { + throw new RuntimeException("Key event was not delivered, case 1: " + + aTyped.get() + ", case 2: " + bTyped.get() + ", case 3: " + + cTyped.get()); + } + } +} diff --git a/test/jdk/java/awt/event/KeyEvent/KeyModifiers.java b/test/jdk/java/awt/event/KeyEvent/KeyModifiers.java new file mode 100644 index 0000000000000..13cc35581dbe5 --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/KeyModifiers.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4193779 4174399 + * @summary Ensures that KeyEvents have the right modifiers set + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jdk.test.lib.Platform + * @run main/manual KeyModifiers + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.lang.reflect.InvocationTargetException; + +import jdk.test.lib.Platform; + + +public class KeyModifiers extends Frame implements KeyListener { + public KeyModifiers() { + super("Check KeyChar values"); + setLayout(new BorderLayout()); + TextField tf = new TextField(30); + tf.addKeyListener(this); + add(tf, BorderLayout.CENTER); + pack(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + + String keys; + if (Platform.isWindows()) { + keys = "\"Shift-n\", \"Alt-n\"\n"; + } else if (Platform.isOSX()) { + keys = "\"Shift-n\", \"Alt-n\", \"Command-n\"\n"; + } else { + keys = "\"Shift-n\", \"Alt-n\", \"Meta-n\"\n"; + } + + String INSTRUCTIONS1 = """ + Click on the text field in the window named "Check KeyChar values" + and type the following key combinations: + """; + String INSTRUCTIONS2 = """ + After each combination check that the KeyPressed and KeyTyped modifiers + are correctly displayed. If modifiers are correct press "Pass", + otherwise press "Fail". + """; + PassFailJFrame.builder() + .title("KeyModifiers Test Instructions") + .instructions(INSTRUCTIONS1 + keys + INSTRUCTIONS2) + .columns(45) + .logArea(10) + .testUI(KeyModifiers::new) + .build() + .awaitAndCheck(); + } + + public void keyPressed(KeyEvent evt) { + int kc = evt.getKeyCode(); + + if (kc == KeyEvent.VK_CONTROL) { + return; + } + + if ((kc == KeyEvent.VK_SHIFT) || (kc == KeyEvent.VK_META) || + (kc == KeyEvent.VK_ALT) || (kc == KeyEvent.VK_ALT_GRAPH)) { + PassFailJFrame.log("Key pressed= " + KeyEvent.getKeyText(kc) + + " modifiers = " + InputEvent.getModifiersExText(evt.getModifiersEx())); + } else { + PassFailJFrame.log("Key pressed = " + evt.getKeyChar() + + " modifiers = " + InputEvent.getModifiersExText(evt.getModifiersEx())); + } + } + + public void keyTyped(KeyEvent evt) { + int kc = evt.getKeyCode(); + + if (kc == KeyEvent.VK_CONTROL) { + return; + } + + if ((kc == KeyEvent.VK_SHIFT) || (kc == KeyEvent.VK_META) || + (kc == KeyEvent.VK_ALT) || (kc == KeyEvent.VK_ALT_GRAPH)) { + PassFailJFrame.log("Key typed = " + KeyEvent.getKeyText(kc) + + " modifiers = " + InputEvent.getModifiersExText(evt.getModifiersEx())); + } else { + PassFailJFrame.log("Key typed = " + evt.getKeyChar() + + " modifiers = " + InputEvent.getModifiersExText(evt.getModifiersEx())); + } + } + + public void keyReleased(KeyEvent evt) { + int kc = evt.getKeyCode(); + + if (kc == KeyEvent.VK_CONTROL) + return; + + if ((kc == KeyEvent.VK_SHIFT) || (kc == KeyEvent.VK_META) || + (kc == KeyEvent.VK_ALT) || (kc == KeyEvent.VK_ALT_GRAPH)) { + PassFailJFrame.log("Key = released " + KeyEvent.getKeyText(kc) + + " modifiers = " + InputEvent.getModifiersExText(evt.getModifiersEx())); + } else { + PassFailJFrame.log("Key released = " + evt.getKeyChar() + + " modifiers = " + InputEvent.getModifiersExText(evt.getModifiersEx())); + } + } +} From ecb54a05c6774e1a93d76b1181bda734129b6ace Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Mon, 21 Apr 2025 17:43:09 +0000 Subject: [PATCH 0671/1101] 8354523: runtime/Monitor/SyncOnValueBasedClassTest.java triggers SIGSEGV Co-authored-by: Martin Doerr Co-authored-by: Fei Yang Co-authored-by: Amit Kumar Reviewed-by: coleenp, aboldtch --- .../cpu/aarch64/c1_MacroAssembler_aarch64.cpp | 15 ++++++++------- .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 2 +- .../cpu/aarch64/interp_masm_aarch64.cpp | 15 ++++++++------- .../cpu/aarch64/macroAssembler_aarch64.cpp | 9 ++++++++- src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp | 15 ++++++++------- src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp | 15 ++++++++------- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 18 +++++++++++++----- .../cpu/riscv/c1_MacroAssembler_riscv.cpp | 15 ++++++++------- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 2 +- src/hotspot/cpu/riscv/interp_masm_riscv.cpp | 15 ++++++++------- src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 9 ++++++++- .../cpu/s390/c1_MacroAssembler_s390.cpp | 13 +++++++------ src/hotspot/cpu/s390/interp_masm_s390.cpp | 12 ++++++------ src/hotspot/cpu/s390/macroAssembler_s390.cpp | 10 ++++++++-- src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp | 13 +++++++------ src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 2 +- src/hotspot/cpu/x86/interp_masm_x86.cpp | 12 ++++++------ src/hotspot/cpu/x86/macroAssembler_x86.cpp | 8 +++++++- 18 files changed, 121 insertions(+), 79 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp index 6b1a5a7f1e0c4..afa2ddb47b454 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp @@ -72,16 +72,17 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr null_check_offset = offset(); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(hdr, obj); - ldrb(hdr, Address(hdr, Klass::misc_flags_offset())); - tst(hdr, KlassFlags::_misc_is_value_based_class); - br(Assembler::NE, slow_case); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(disp_hdr, obj, hdr, temp, rscratch2, slow_case); } else if (LockingMode == LM_LEGACY) { + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(hdr, obj); + ldrb(hdr, Address(hdr, Klass::misc_flags_offset())); + tst(hdr, KlassFlags::_misc_is_value_based_class); + br(Assembler::NE, slow_case); + } + Label done; // Load object header ldr(hdr, Address(obj, hdr_offset)); diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index 605a05a44a731..56a91310dcded 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -360,7 +360,7 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist Label slow_path; if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. str(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); } diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp index d5ba85da989dc..dd1d7d1d2e1b4 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp @@ -693,17 +693,18 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) // Load object pointer into obj_reg %c_rarg3 ldr(obj_reg, Address(lock_reg, obj_offset)); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, obj_reg); - ldrb(tmp, Address(tmp, Klass::misc_flags_offset())); - tst(tmp, KlassFlags::_misc_is_value_based_class); - br(Assembler::NE, slow_case); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(lock_reg, obj_reg, tmp, tmp2, tmp3, slow_case); b(done); } else if (LockingMode == LM_LEGACY) { + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp, obj_reg); + ldrb(tmp, Address(tmp, Klass::misc_flags_offset())); + tst(tmp, KlassFlags::_misc_is_value_based_class); + br(Assembler::NE, slow_case); + } + // Load (object->mark() | 1) into swap_reg ldr(rscratch1, Address(obj_reg, oopDesc::mark_offset_in_bytes())); orr(swap_reg, rscratch1, 1); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 1e226c70420de..9a4b8e243a978 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -7034,10 +7034,17 @@ void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Registe ldr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. str(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes())))); } + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(t1, obj); + ldrb(t1, Address(t1, Klass::misc_flags_offset())); + tst(t1, KlassFlags::_misc_is_value_based_class); + br(Assembler::NE, slow); + } + // Check if the lock-stack is full. ldrw(top, Address(rthread, JavaThread::lock_stack_top_offset())); cmpw(top, (unsigned)LockStack::end_offset()); diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index ac9c5984de050..77d3653aefdb8 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -83,16 +83,17 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox // Save object being locked into the BasicObjectLock... std(Roop, in_bytes(BasicObjectLock::obj_offset()), Rbox); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(Rscratch, Roop); - lbz(Rscratch, in_bytes(Klass::misc_flags_offset()), Rscratch); - testbitdi(CR0, R0, Rscratch, exact_log2(KlassFlags::_misc_is_value_based_class)); - bne(CR0, slow_int); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(Rbox, Roop, Rmark, Rscratch, slow_int); } else if (LockingMode == LM_LEGACY) { + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(Rscratch, Roop); + lbz(Rscratch, in_bytes(Klass::misc_flags_offset()), Rscratch); + testbitdi(CR0, R0, Rscratch, exact_log2(KlassFlags::_misc_is_value_based_class)); + bne(CR0, slow_int); + } + // ... and mark it unlocked. ori(Rmark, Rmark, markWord::unlocked_value); diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index 7a75dfd3de18b..b51a0739d63ed 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -958,17 +958,18 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // markWord displaced_header = obj->mark().set_unlocked(); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, object); - lbz(tmp, in_bytes(Klass::misc_flags_offset()), tmp); - testbitdi(CR0, R0, tmp, exact_log2(KlassFlags::_misc_is_value_based_class)); - bne(CR0, slow_case); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(monitor, object, header, tmp, slow_case); b(done); } else if (LockingMode == LM_LEGACY) { + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp, object); + lbz(tmp, in_bytes(Klass::misc_flags_offset()), tmp); + testbitdi(CR0, R0, tmp, exact_log2(KlassFlags::_misc_is_value_based_class)); + bne(CR0, slow_case); + } + // Load markWord from object into header. ld(header, oopDesc::mark_offset_in_bytes(), object); diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index f82395b14fb35..ca0a1344d143c 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -3000,7 +3000,7 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister fla Label slow_path; if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. li(tmp1, 0); std(tmp1, in_bytes(BasicObjectLock::lock_offset()) + BasicLock::object_monitor_cache_offset_in_bytes(), box); } @@ -4999,19 +4999,27 @@ void MacroAssembler::atomically_flip_locked_state(bool is_unlock, Register obj, // - t1, t2: temporary register void MacroAssembler::lightweight_lock(Register box, Register obj, Register t1, Register t2, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); - assert_different_registers(box, obj, t1, t2); + assert_different_registers(box, obj, t1, t2, R0); Label push; - const Register top = t1; - const Register mark = t2; const Register t = R0; if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. li(t, 0); std(t, in_bytes(BasicObjectLock::lock_offset()) + BasicLock::object_monitor_cache_offset_in_bytes(), box); } + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(t1, obj); + lbz(t1, in_bytes(Klass::misc_flags_offset()), t1); + testbitdi(CR0, R0, t1, exact_log2(KlassFlags::_misc_is_value_based_class)); + bne(CR0, slow); + } + + const Register top = t1; + const Register mark = t2; + // Check if the lock-stack is full. lwz(top, in_bytes(JavaThread::lock_stack_top_offset()), R16_thread); cmplwi(CR0, top, LockStack::end_offset()); diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp index 76089e8dd4536..29bf3e5f2ed65 100644 --- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp @@ -61,16 +61,17 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr null_check_offset = offset(); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(hdr, obj); - lbu(hdr, Address(hdr, Klass::misc_flags_offset())); - test_bit(temp, hdr, exact_log2(KlassFlags::_misc_is_value_based_class)); - bnez(temp, slow_case, true /* is_far */); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(disp_hdr, obj, hdr, temp, t1, slow_case); } else if (LockingMode == LM_LEGACY) { + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(hdr, obj); + lbu(hdr, Address(hdr, Klass::misc_flags_offset())); + test_bit(temp, hdr, exact_log2(KlassFlags::_misc_is_value_based_class)); + bnez(temp, slow_case, /* is_far */ true); + } + Label done; // Load object header ld(hdr, Address(obj, hdr_offset)); diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 99cbcedb8ff55..39a49f8f1eb85 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -289,7 +289,7 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Label slow_path; if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. sd(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); } diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp index f1f9414d98a11..8be5408cb2b88 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp @@ -736,17 +736,18 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) // Load object pointer into obj_reg c_rarg3 ld(obj_reg, Address(lock_reg, obj_offset)); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, obj_reg); - lbu(tmp, Address(tmp, Klass::misc_flags_offset())); - test_bit(tmp, tmp, exact_log2(KlassFlags::_misc_is_value_based_class)); - bnez(tmp, slow_case); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(lock_reg, obj_reg, tmp, tmp2, tmp3, slow_case); j(done); } else if (LockingMode == LM_LEGACY) { + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp, obj_reg); + lbu(tmp, Address(tmp, Klass::misc_flags_offset())); + test_bit(tmp, tmp, exact_log2(KlassFlags::_misc_is_value_based_class)); + bnez(tmp, slow_case); + } + // Load (object->mark() | 1) into swap_reg ld(t0, Address(obj_reg, oopDesc::mark_offset_in_bytes())); ori(swap_reg, t0, 1); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index b5c311c341db4..c6393be071401 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -6362,10 +6362,17 @@ void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Registe ld(mark, Address(obj, oopDesc::mark_offset_in_bytes())); if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. sd(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes())))); } + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp1, obj); + lbu(tmp1, Address(tmp1, Klass::misc_flags_offset())); + test_bit(tmp1, tmp1, exact_log2(KlassFlags::_misc_is_value_based_class)); + bnez(tmp1, slow, /* is_far */ true); + } + // Check if the lock-stack is full. lwu(top, Address(xthread, JavaThread::lock_stack_top_offset())); mv(t, (unsigned)LockStack::end_offset()); diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp index 5691a2055b3a2..0e873250dca3b 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp @@ -69,17 +69,18 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox // Save object being locked into the BasicObjectLock... z_stg(Roop, Address(Rbox, BasicObjectLock::obj_offset())); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, Roop); - z_tm(Address(tmp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); - branch_optimized(Assembler::bcondAllOne, slow_case); - } - assert(LockingMode != LM_MONITOR, "LM_MONITOR is already handled, by emit_lock()"); if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(Rbox, Roop, Rmark, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp, Roop); + z_tm(Address(tmp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); + branch_optimized(Assembler::bcondAllOne, slow_case); + } + NearLabel done; // Load object header. diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index 48f4c7293a291..4ba99eb9e8830 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -1002,16 +1002,16 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // markWord header = obj->mark().set_unlocked(); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, object); - z_tm(Address(tmp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); - z_btrue(slow_case); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(monitor, object, header, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp, object); + z_tm(Address(tmp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); + z_btrue(slow_case); + } + // Load markWord from object into header. z_lg(header, hdr_offset, object); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index 88aedd1b5c00f..0129e6049783c 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -6363,11 +6363,17 @@ void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Registe z_lg(mark, Address(obj, mark_offset)); if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. const Address om_cache_addr = Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))); z_mvghi(om_cache_addr, 0); } + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(temp1, obj); + z_tm(Address(temp1, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); + z_brne(slow); + } + // First we need to check if the lock-stack has room for pushing the object reference. z_lgf(top, Address(Z_thread, ls_top_offset)); @@ -6501,7 +6507,7 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Registe NearLabel slow_path; if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. z_mvghi(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0); } diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index b8873758b6167..684347e35fa40 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -55,16 +55,17 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr null_check_offset = offset(); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(hdr, obj, rscratch1); - testb(Address(hdr, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); - jcc(Assembler::notZero, slow_case); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(disp_hdr, obj, hdr, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { Label done; + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(hdr, obj, rscratch1); + testb(Address(hdr, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); + jcc(Assembler::notZero, slow_case); + } + // Load object header movptr(hdr, Address(obj, hdr_offset)); // and mark it as unlocked diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index a7967d83a4e7f..574bc081fceab 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -476,7 +476,7 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist Label slow_path; if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0); } diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index bd029f2e4ac41..d982495d883df 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -1023,15 +1023,15 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) { // Load object pointer into obj_reg movptr(obj_reg, Address(lock_reg, obj_offset)); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp_reg, obj_reg, rklass_decode_tmp); - testb(Address(tmp_reg, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); - jcc(Assembler::notZero, slow_case); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(lock_reg, obj_reg, swap_reg, tmp_reg, slow_case); } else if (LockingMode == LM_LEGACY) { + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp_reg, obj_reg, rklass_decode_tmp); + testb(Address(tmp_reg, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); + jcc(Assembler::notZero, slow_case); + } + // Load immediate 1 into swap_reg %rax movl(swap_reg, 1); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 25de76a7e4008..4d3bd12ed6697 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -9584,10 +9584,16 @@ void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Registe movptr(reg_rax, Address(obj, oopDesc::mark_offset_in_bytes())); if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. movptr(Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))), 0); } + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp, obj, rscratch1); + testb(Address(tmp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); + jcc(Assembler::notZero, slow); + } + // Load top. movl(top, Address(thread, JavaThread::lock_stack_top_offset())); From 684d3b336e9cb31707d35e75f9b785e04e1fdbee Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Mon, 21 Apr 2025 18:25:59 +0000 Subject: [PATCH 0672/1101] 8354774: DocumentBuilderFactory getAttribute throws NPE Reviewed-by: naoto, lancea --- .../xsltc/trax/TransformerFactoryImpl.java | 15 +- .../xerces/internal/impl/PropertyManager.java | 34 +--- .../jaxp/DocumentBuilderFactoryImpl.java | 26 +-- .../internal/jaxp/DocumentBuilderImpl.java | 15 +- .../xerces/internal/jaxp/SAXParserImpl.java | 34 +--- .../jaxp/validation/XMLSchemaFactory.java | 22 +-- .../XMLSchemaValidatorComponentManager.java | 22 +-- .../classes/jdk/xml/internal/JdkXmlUtils.java | 43 ++++- .../jdk/xml/internal/XMLSecurityManager.java | 2 +- .../jaxp/libs/jaxp/library/JUnitTestUtil.java | 13 ++ .../jaxp/unittest/common/PropertiesTest.java | 162 ++++++++++++++++++ 11 files changed, 268 insertions(+), 120 deletions(-) create mode 100644 test/jaxp/javax/xml/jaxp/unittest/common/PropertiesTest.java diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java index 747ec8473fe38..ee730d3900a3c 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java @@ -371,17 +371,10 @@ else if (name.equals(ENABLE_INLINING)) { return _cdataChunkSize; } - /** Check to see if the property is managed by the security manager **/ - String propertyValue = (_xmlSecurityManager != null) ? - _xmlSecurityManager.getLimitAsString(name) : null; - if (propertyValue != null) { - return propertyValue; - } else { - propertyValue = (_xmlSecurityPropertyMgr != null) ? - _xmlSecurityPropertyMgr.getValue(name) : null; - if (propertyValue != null) { - return propertyValue; - } + //check if the property is managed by security manager + String value; + if ((value = JdkXmlUtils.getProperty(_xmlSecurityManager, _xmlSecurityPropertyMgr, name)) != null) { + return value; } // Throw an exception for all other attributes diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/PropertyManager.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/PropertyManager.java index 2167c22e00125..8d83f0396178c 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/PropertyManager.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/PropertyManager.java @@ -27,13 +27,10 @@ import com.sun.xml.internal.stream.StaxEntityResolverWrapper; import java.util.HashMap; import javax.xml.XMLConstants; -import javax.xml.catalog.CatalogFeatures; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLResolver; -import jdk.xml.internal.FeaturePropertyBase; import jdk.xml.internal.JdkConstants; -import jdk.xml.internal.JdkProperty; import jdk.xml.internal.JdkXmlUtils; import jdk.xml.internal.XMLSecurityManager; import jdk.xml.internal.XMLSecurityPropertyManager; @@ -188,20 +185,13 @@ public Object getProperty(String property) { if (XMLInputFactory.SUPPORT_DTD.equals(property)) { return fSecurityManager.is(XMLSecurityManager.Limit.STAX_SUPPORT_DTD); } - /** - * Check to see if the property is managed by the security manager * - */ - String propertyValue = (fSecurityManager != null) - ? fSecurityManager.getLimitAsString(property) : null; - /** - * Check to see if the property is managed by the security property - * manager - */ - if (propertyValue == null) { - propertyValue = (fSecurityPropertyMgr != null) - ? fSecurityPropertyMgr.getValue(property) : null; + + //check if the property is managed by security manager + String value; + if ((value = JdkXmlUtils.getProperty(fSecurityManager, fSecurityPropertyMgr, property)) != null) { + return value; } - return propertyValue != null ? propertyValue : supportedProps.get(property); + return supportedProps.get(property); } /** @@ -250,15 +240,9 @@ public void setProperty(String property, Object value) { return; } - //check if the property is managed by security manager - if (fSecurityManager == null - || !fSecurityManager.setLimit(property, JdkProperty.State.APIPROPERTY, value)) { - //check if the property is managed by security property manager - if (fSecurityPropertyMgr == null - || !fSecurityPropertyMgr.setValue(property, FeaturePropertyBase.State.APIPROPERTY, value)) { - //fall back to the existing property manager - supportedProps.put(property, value); - } + if (!JdkXmlUtils.setProperty(fSecurityManager, fSecurityPropertyMgr, property, value)) { + //fall back to the existing property manager + supportedProps.put(property, value); } if (equivalentProperty != null) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderFactoryImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderFactoryImpl.java index 6909f2b51ffb5..2939058e7d4e7 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderFactoryImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderFactoryImpl.java @@ -29,7 +29,7 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.validation.Schema; -import jdk.xml.internal.JdkProperty; +import jdk.xml.internal.JdkXmlUtils; import jdk.xml.internal.XMLSecurityManager; import jdk.xml.internal.XMLSecurityPropertyManager; import org.xml.sax.SAXException; @@ -114,20 +114,13 @@ public void setAttribute(String name, Object value) attributes = new HashMap<>(); } - //check if the property is managed by security manager - String pName; - if ((pName = fSecurityManager.find(name)) != null) { - // as the qName is deprecated, let the manager decide whether the - // value shall be changed - fSecurityManager.setLimit(name, JdkProperty.State.APIPROPERTY, value); - attributes.put(pName, fSecurityManager.getLimitAsString(pName)); + if (JdkXmlUtils.setProperty(fSecurityManager, fSecurityPropertyMgr, name, value)) { + // necessary as DocumentBuilder recreate property manager + // remove this line once that's changed + attributes.put(name, value); // no need to create a DocumentBuilderImpl return; - } else if ((pName = fSecurityPropertyMgr.find(name)) != null) { - attributes.put(pName, value); - return; } - attributes.put(name, value); // Test the attribute name by possibly throwing an exception @@ -146,13 +139,10 @@ public void setAttribute(String name, Object value) public Object getAttribute(String name) throws IllegalArgumentException { - //check if the property is managed by security manager - String pName; - if ((pName = fSecurityManager.find(name)) != null) { - return fSecurityManager.getLimitAsString(pName); - } else if ((pName = fSecurityPropertyMgr.find(name)) != null) { - return attributes.get(pName); + String value; + if ((value = JdkXmlUtils.getProperty(fSecurityManager, fSecurityPropertyMgr, name)) != null) { + return value; } // See if it's in the attributes Map diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderImpl.java index a8af265c3251c..43b986b99392e 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderImpl.java @@ -43,7 +43,7 @@ import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration; import jdk.xml.internal.FeaturePropertyBase.State; import jdk.xml.internal.JdkConstants; -import jdk.xml.internal.JdkProperty; +import jdk.xml.internal.JdkXmlUtils; import jdk.xml.internal.XMLSecurityManager; import jdk.xml.internal.XMLSecurityPropertyManager; import jdk.xml.internal.XMLSecurityPropertyManager.Property; @@ -297,17 +297,10 @@ private void setDocumentBuilderFactoryAttributes( Map dbfAttrs) } } } else { - //check if the property is managed by security manager - if (fSecurityManager == null || - !fSecurityManager.setLimit(name, JdkProperty.State.APIPROPERTY, val)) { - //check if the property is managed by security property manager - if (fSecurityPropertyMgr == null || - !fSecurityPropertyMgr.setValue(name, State.APIPROPERTY, val)) { - //fall back to the existing property manager - domParser.setProperty(name, val); - } + if (!JdkXmlUtils.setProperty(fSecurityManager, fSecurityPropertyMgr, name, val)) { + //fall back to the existing property manager + domParser.setProperty(name, val); } - } } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/SAXParserImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/SAXParserImpl.java index 053718c657d74..fe435aabbcc2b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/SAXParserImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/SAXParserImpl.java @@ -43,7 +43,7 @@ import javax.xml.validation.Schema; import jdk.xml.internal.FeaturePropertyBase; import jdk.xml.internal.JdkConstants; -import jdk.xml.internal.JdkProperty; +import jdk.xml.internal.JdkXmlUtils; import jdk.xml.internal.XMLSecurityManager; import jdk.xml.internal.XMLSecurityPropertyManager; import org.xml.sax.EntityResolver; @@ -569,20 +569,13 @@ else if (JAXP_SCHEMA_SOURCE.equals(name)) { super.setProperty(name, value); } - //check if the property is managed by security manager - if (fSecurityManager == null || - !fSecurityManager.setLimit(name, JdkProperty.State.APIPROPERTY, value)) { - //check if the property is managed by security property manager - if (fSecurityPropertyMgr == null || - !fSecurityPropertyMgr.setValue(name, FeaturePropertyBase.State.APIPROPERTY, value)) { - //fall back to the existing property manager - if (!fInitProperties.containsKey(name)) { - fInitProperties.put(name, super.getProperty(name)); - } - super.setProperty(name, value); + if (!JdkXmlUtils.setProperty(fSecurityManager, fSecurityPropertyMgr, name, value)) { + //fall back to the existing property manager + if (!fInitProperties.containsKey(name)) { + fInitProperties.put(name, super.getProperty(name)); } + super.setProperty(name, value); } - } public synchronized Object getProperty(String name) @@ -596,19 +589,10 @@ public synchronized Object getProperty(String name) return fSAXParser.schemaLanguage; } - /** Check to see if the property is managed by the security manager **/ - String propertyValue = (fSecurityManager != null) ? - fSecurityManager.getLimitAsString(name) : null; - if (propertyValue != null) { - return propertyValue; - } else { - propertyValue = (fSecurityPropertyMgr != null) ? - fSecurityPropertyMgr.getValue(name) : null; - if (propertyValue != null) { - return propertyValue; - } + String value; + if ((value = JdkXmlUtils.getProperty(fSecurityManager, fSecurityPropertyMgr, name)) != null) { + return value; } - return super.getProperty(name); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaFactory.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaFactory.java index 753fdea25cd29..82960821f4d9f 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaFactory.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaFactory.java @@ -40,7 +40,6 @@ import java.io.InputStream; import java.io.Reader; import javax.xml.XMLConstants; -import javax.xml.catalog.CatalogFeatures.Feature; import javax.xml.stream.XMLEventReader; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; @@ -404,10 +403,11 @@ else if (name.equals(XMLGRAMMAR_POOL)) { } try { /** Check to see if the property is managed by the security manager **/ - String propertyValue = (fSecurityManager != null) ? - fSecurityManager.getLimitAsString(name) : null; - return propertyValue != null ? propertyValue : - fXMLSchemaLoader.getProperty(name); + String value; + if ((value = JdkXmlUtils.getProperty(fSecurityManager, fSecurityPropertyMgr, name)) != null) { + return value; + } + return fXMLSchemaLoader.getProperty(name); } catch (XMLConfigurationException e) { String identifier = e.getIdentifier(); @@ -513,15 +513,9 @@ else if (name.equals(XMLGRAMMAR_POOL)) { "property-not-supported", new Object [] {name})); } try { - //check if the property is managed by security manager - if (fSecurityManager == null || - !fSecurityManager.setLimit(name, JdkProperty.State.APIPROPERTY, object)) { - //check if the property is managed by security property manager - if (fSecurityPropertyMgr == null || - !fSecurityPropertyMgr.setValue(name, FeaturePropertyBase.State.APIPROPERTY, object)) { - //fall back to the existing property manager - fXMLSchemaLoader.setProperty(name, object); - } + if (!JdkXmlUtils.setProperty(fSecurityManager, fSecurityPropertyMgr, name, object)) { + //fall back to the existing property manager + fXMLSchemaLoader.setProperty(name, object); } } catch (XMLConfigurationException e) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaValidatorComponentManager.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaValidatorComponentManager.java index bb4296349eb9f..419bfe4b25037 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaValidatorComponentManager.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/validation/XMLSchemaValidatorComponentManager.java @@ -48,7 +48,7 @@ import javax.xml.catalog.CatalogFeatures; import jdk.xml.internal.FeaturePropertyBase; import jdk.xml.internal.JdkConstants; -import jdk.xml.internal.JdkProperty; +import jdk.xml.internal.JdkXmlUtils; import jdk.xml.internal.XMLSecurityManager; import jdk.xml.internal.XMLSecurityPropertyManager; import org.w3c.dom.ls.LSResourceResolver; @@ -353,7 +353,7 @@ else if (SCHEMA_ELEMENT_DEFAULT.equals(featureId)) { * Set the state of a feature. * * @param featureId The unique identifier (URI) of the feature. - * @param state The requested state of the feature (true or false). + * @param value The value of the feature (true or false). * * @exception XMLConfigurationException If the requested feature is not known. */ @@ -361,7 +361,7 @@ public void setFeature(String featureId, boolean value) throws XMLConfigurationE if (PARSER_SETTINGS.equals(featureId)) { throw new XMLConfigurationException(Status.NOT_SUPPORTED, featureId); } - else if (value == false && (VALIDATION.equals(featureId) || SCHEMA_VALIDATION.equals(featureId))) { + else if (!value && (VALIDATION.equals(featureId) || SCHEMA_VALIDATION.equals(featureId))) { throw new XMLConfigurationException(Status.NOT_SUPPORTED, featureId); } else if (USE_GRAMMAR_POOL_ONLY.equals(featureId) && value != fUseGrammarPoolOnly) { @@ -452,18 +452,12 @@ else if (LOCALE.equals(propertyId)) { fComponents.put(propertyId, value); return; } - //check if the property is managed by security manager - if (fInitSecurityManager == null || - !fInitSecurityManager.setLimit(propertyId, JdkProperty.State.APIPROPERTY, value)) { - //check if the property is managed by security property manager - if (fSecurityPropertyMgr == null || - !fSecurityPropertyMgr.setValue(propertyId, FeaturePropertyBase.State.APIPROPERTY, value)) { - //fall back to the existing property manager - if (!fInitProperties.containsKey(propertyId)) { - fInitProperties.put(propertyId, super.getProperty(propertyId)); - } - super.setProperty(propertyId, value); + if (!JdkXmlUtils.setProperty(fInitSecurityManager, fSecurityPropertyMgr, propertyId, value)) { + //fall back to the existing property manager + if (!fInitProperties.containsKey(propertyId)) { + fInitProperties.put(propertyId, super.getProperty(propertyId)); } + super.setProperty(propertyId, value); } } diff --git a/src/java.xml/share/classes/jdk/xml/internal/JdkXmlUtils.java b/src/java.xml/share/classes/jdk/xml/internal/JdkXmlUtils.java index 1654c1b6cd55a..93b63a746f15e 100644 --- a/src/java.xml/share/classes/jdk/xml/internal/JdkXmlUtils.java +++ b/src/java.xml/share/classes/jdk/xml/internal/JdkXmlUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,6 +98,47 @@ private static class DefaultSAXFactory { private static final SAXParserFactory instance = getSAXFactory(false); } + /** + * Sets the property if it's managed by either XMLSecurityManager or XMLSecurityPropertyManager. + * @param xsm the XMLSecurityManager + * @param xspm the XMLSecurityPropertyManager + * @param property the property + * @param value the value + * @return true if the property is managed by either XMLSecurityManager or + * XMLSecurityPropertyManager, false otherwise + */ + public static boolean setProperty(XMLSecurityManager xsm, XMLSecurityPropertyManager xspm, + String property, Object value) { + if (xsm != null && xsm.find(property) != null) { + return xsm.setLimit(property, JdkProperty.State.APIPROPERTY, value); + + } else if (xspm != null && xspm.find(property) != null) { + return xspm.setValue(property, FeaturePropertyBase.State.APIPROPERTY, value); + } + return false; + } + + /** + * Returns the value of the property if it's managed by either XMLSecurityManager + * or XMLSecurityPropertyManager. + * @param xsm the XMLSecurityManager + * @param xspm the XMLSecurityPropertyManager + * @param property the property + * @return the value of the property if it's managed by either XMLSecurityManager + * or XMLSecurityPropertyManager, null otherwise + */ + public static String getProperty(XMLSecurityManager xsm, XMLSecurityPropertyManager xspm, + String property) { + String value = null; + if (xsm != null && (value = xsm.getLimitAsString(property)) != null) { + return value; + } + if (xspm != null) { + value = xspm.getValue(property); + } + return value; + } + /** * Returns the value. * diff --git a/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java b/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java index 394bf28e02adf..90c222de40e02 100644 --- a/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java +++ b/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java @@ -361,7 +361,7 @@ public String find(String propertyName) { for (Limit limit : Limit.values()) { if (limit.is(propertyName)) { // current spec: new property name == systemProperty - return limit.systemProperty(); + return (limit.systemProperty != null) ? limit.systemProperty : limit.apiProperty; } } //ENTITYCOUNT's new name is qName diff --git a/test/jaxp/javax/xml/jaxp/libs/jaxp/library/JUnitTestUtil.java b/test/jaxp/javax/xml/jaxp/libs/jaxp/library/JUnitTestUtil.java index a31963f21dec8..f4eb3188242b3 100644 --- a/test/jaxp/javax/xml/jaxp/libs/jaxp/library/JUnitTestUtil.java +++ b/test/jaxp/javax/xml/jaxp/libs/jaxp/library/JUnitTestUtil.java @@ -32,6 +32,19 @@ public class JUnitTestUtil { public static final String CLS_DIR = System.getProperty("test.classes"); public static final String SRC_DIR = System.getProperty("test.src"); + // as in the Processors table in java.xml module summary + public enum Processor { + DOM, + SAX, + XMLREADER, + StAX, + VALIDATION, + TRANSFORM, + XSLTC, + DOMLS, + XPATH + }; + /** * Returns the System identifier (URI) of the source. * @param path the path to the source diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/PropertiesTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/PropertiesTest.java new file mode 100644 index 0000000000000..1550c53794a74 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/common/PropertiesTest.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package common; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.stream.XMLInputFactory; +import javax.xml.transform.TransformerFactory; +import javax.xml.validation.SchemaFactory; +import java.util.EnumSet; +import java.util.Set; +import java.util.stream.Stream; +import jaxp.library.JUnitTestUtil.Processor; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.xml.sax.XMLReader; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/* + * @test + * @bug 8354774 + * @summary Verifies JAXP API Properties as specified in the java.xml module. + * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest /test/lib + * @run junit/othervm common.PropertiesTest + */ +public class PropertiesTest { + private static final String ACCESS_EXTERNAL_DTD = XMLConstants.ACCESS_EXTERNAL_DTD; + private static final String ACCESS_EXTERNAL_SCHEMA = XMLConstants.ACCESS_EXTERNAL_SCHEMA; + private static final String ACCESS_EXTERNAL_STYLESHEET = XMLConstants.ACCESS_EXTERNAL_STYLESHEET; + private static final String SP_ACCESS_EXTERNAL_DTD = "javax.xml.accessExternalDTD"; + private static final String SP_ACCESS_EXTERNAL_SCHEMA = "javax.xml.accessExternalSchema"; + private static final String SP_ACCESS_EXTERNAL_STYLESHEET = "javax.xml.accessExternalStylesheet"; + private static final String DEFAULT_VALUE = "all"; + /** + * Returns test data for testAccessExternalProperties + * @return test data for testAccessExternalProperties + */ + private static Stream testData() { + // Supported processors for Access External Properties + Set supportedProcessors1 = EnumSet.of(Processor.DOM, Processor.SAX, Processor.XMLREADER, + Processor.StAX, Processor.VALIDATION); + Set supportedProcessors2 = EnumSet.of(Processor.TRANSFORM); + + return Stream.of( + Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_DTD, null, SP_ACCESS_EXTERNAL_DTD, null, DEFAULT_VALUE), + Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_DTD, "http", SP_ACCESS_EXTERNAL_DTD, null, "http"), + Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_DTD, null, SP_ACCESS_EXTERNAL_DTD, "https", "https"), + Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_DTD, "http", SP_ACCESS_EXTERNAL_DTD, "https", "http"), + Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_SCHEMA, null, SP_ACCESS_EXTERNAL_SCHEMA, null, DEFAULT_VALUE), + Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_SCHEMA, "http", SP_ACCESS_EXTERNAL_SCHEMA, null, "http"), + Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_SCHEMA, null, SP_ACCESS_EXTERNAL_SCHEMA, "https", "https"), + Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_SCHEMA, "http", SP_ACCESS_EXTERNAL_SCHEMA, "https", "http"), + Arguments.of(supportedProcessors2, ACCESS_EXTERNAL_STYLESHEET, null, SP_ACCESS_EXTERNAL_STYLESHEET, null, DEFAULT_VALUE), + Arguments.of(supportedProcessors2, ACCESS_EXTERNAL_STYLESHEET, "http", SP_ACCESS_EXTERNAL_STYLESHEET, null, "http"), + Arguments.of(supportedProcessors2, ACCESS_EXTERNAL_STYLESHEET, null, SP_ACCESS_EXTERNAL_STYLESHEET, "https", "https"), + Arguments.of(supportedProcessors2, ACCESS_EXTERNAL_STYLESHEET, "http", SP_ACCESS_EXTERNAL_STYLESHEET, "https", "http") + ); + } + + /** + * Verifies that the Access External Properties are supported throughout the + * JAXP APIs. + * @param supportedProcessors the supported processors for the property + * @param apiProperty the API property + * @param apiValue the value of the API property + * @param sysProperty the System property corresponding to the API property + * @param sysValue the value of the System property + * @param expected the expected result + * @throws Exception if the test fails due to test configuration issues other + * than the expected result + */ + @ParameterizedTest + @MethodSource("testData") + public void testAccessExternalProperties(Set supportedProcessors, + String apiProperty, String apiValue, String sysProperty, String sysValue, + String expected) throws Exception { + for (Processor p : supportedProcessors) { + testProperties(p, apiProperty, apiValue, sysProperty, sysValue, + expected); + } + } + + /** + * Verifies that properties can be set via the JAXP APIs and their corresponding + * System Properties. + * @param processor the processor type + * @param apiProperty the API property + * @param apiValue the value to be set via the API property + * @param sysProperty the System Property + * @param sysValue the value to be set via the System property + * @param expected the expected result + * @throws Exception if the test fails, which can only happen if the property + * is set incorrectly. + */ + void testProperties(Processor processor, String apiProperty, String apiValue, + String sysProperty, String sysValue, String expected) + throws Exception { + Object ret1 = null; + if (sysValue != null) { + System.setProperty(sysProperty, sysValue); + } + switch (processor) { + case DOM: + DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); + if (apiValue != null) dbf.setAttribute(apiProperty, apiValue); + ret1 = dbf.getAttribute(apiProperty); + break; + case SAX: + SAXParser sp = SAXParserFactory.newDefaultInstance().newSAXParser(); + if (apiValue != null) sp.setProperty(apiProperty, apiValue); + ret1 = sp.getProperty(apiProperty); + break; + case XMLREADER: + XMLReader reader = SAXParserFactory.newDefaultInstance().newSAXParser().getXMLReader(); + if (apiValue != null) reader.setProperty(apiProperty, apiValue); + ret1 = reader.getProperty(apiProperty); + break; + case StAX: + XMLInputFactory xif = XMLInputFactory.newDefaultFactory(); + if (apiValue != null) xif.setProperty(apiProperty, apiValue); + ret1 = xif.getProperty(apiProperty); + break; + case VALIDATION: + SchemaFactory sf = SchemaFactory.newDefaultInstance(); + if (apiValue != null) sf.setProperty(apiProperty, apiValue); + ret1 = sf.getProperty(apiProperty); + break; + case TRANSFORM: + TransformerFactory tf = TransformerFactory.newDefaultInstance(); + if (apiValue != null) tf.setAttribute(apiProperty, apiValue); + ret1 = tf.getAttribute(apiProperty); + break; + } + + if (sysValue != null) System.clearProperty(sysProperty); + // property value is as expected + assertEquals(expected, ret1); + } +} From a7128d86eac2c40dbfa79811234ab6226fb4d080 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Mon, 21 Apr 2025 20:19:45 +0000 Subject: [PATCH 0673/1101] 8354653: Clean up and open source KeyEvent related tests (Part 4) Reviewed-by: serb --- .../java/awt/event/KeyEvent/AltGrTest.java | 90 +++++++++++++ test/jdk/java/awt/event/KeyEvent/CRTest.java | 124 ++++++++++++++++++ .../java/awt/event/KeyEvent/NumpadTest2.java | 108 +++++++++++++++ .../event/KeyEvent/TestDoubleKeyEvent.java | 87 ++++++++++++ 4 files changed, 409 insertions(+) create mode 100644 test/jdk/java/awt/event/KeyEvent/AltGrTest.java create mode 100644 test/jdk/java/awt/event/KeyEvent/CRTest.java create mode 100644 test/jdk/java/awt/event/KeyEvent/NumpadTest2.java create mode 100644 test/jdk/java/awt/event/KeyEvent/TestDoubleKeyEvent.java diff --git a/test/jdk/java/awt/event/KeyEvent/AltGrTest.java b/test/jdk/java/awt/event/KeyEvent/AltGrTest.java new file mode 100644 index 0000000000000..9f771ea7e1960 --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/AltGrTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4122687 4209844 + * @summary Characters typed with AltGr have Alt bit set on + * KEY_TYPED events + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AltGrTest + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.lang.reflect.InvocationTargetException; + +public class AltGrTest extends Frame implements KeyListener { + static String INSTRUCTIONS = """ + Switch to German (Germany) keyboard layout and type + few characters using key. + Note: on windows keyboards without an AltGr key, + you should use Ctrl-Alt to synthesize AltGr. + For example, on German keyboards, `@' is AltGr-Q + `{' is AltGr-7 and '[' is AltGr-8 + If you see the corresponding symbols appear in the text field + and there are no entries in log area starting with word "FAIL:" + press "Pass", otherwise press "Fail". + """; + + public AltGrTest() { + setLayout(new BorderLayout()); + TextField entry = new TextField(); + entry.addKeyListener(this); + add(entry, BorderLayout.CENTER); + pack(); + } + + public void keyTyped(KeyEvent e) { + PassFailJFrame.log("----"); + PassFailJFrame.log("Got " + e); + + if (e.isControlDown() || e.isAltDown()) { + PassFailJFrame.log("FAIL: character typed has following modifiers bits set:"); + PassFailJFrame.log((e.isControlDown() ? " Control" : "") + + (e.isAltDown() ? " Alt" : "")); + } + + if (!(e.isAltGraphDown())) { + PassFailJFrame.log("FAIL: AltGraph modifier is missing"); + } + } + + public void keyPressed(KeyEvent ignore) {} + public void keyReleased(KeyEvent ignore) {} + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .logArea(10) + .testUI(AltGrTest::new) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/event/KeyEvent/CRTest.java b/test/jdk/java/awt/event/KeyEvent/CRTest.java new file mode 100644 index 0000000000000..0cc17fd568eb3 --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/CRTest.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4257434 + * @summary Ensures that the right results are produced by the + * carriage return keys. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CRTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.atomic.AtomicBoolean; + +public class CRTest extends Frame implements KeyListener, ActionListener { + StringBuilder error = new StringBuilder(); + AtomicBoolean actionCompleted = new AtomicBoolean(false); + static String INSTRUCTIONS = """ + This test requires keyboard with the numeric keypad (numpad). + If your keyboard does not have numpad press "Pass" to skip testing. + Click on the text field in window named "Check KeyChar values". + Press Enter on keypad. Then press Return key on a standard keyboard. + Then click on "Done" button. Test will pass or fail automatically. + """; + + public CRTest() { + super("Check KeyChar values"); + setLayout(new BorderLayout()); + TextField tf = new TextField(30); + + tf.addKeyListener(this); + tf.addActionListener(this); + + add(tf, BorderLayout.CENTER); + + Button done = new Button("Done"); + done.addActionListener((event) -> { + checkAndComplete(); + }); + add(done, BorderLayout.SOUTH); + pack(); + } + + public void checkAndComplete() { + if (!actionCompleted.get()) { + error.append("\nNo action received!"); + } + + if (!error.isEmpty()) { + PassFailJFrame.forceFail(error.toString()); + } else { + PassFailJFrame.forcePass(); + } + } + + public void keyPressed(KeyEvent evt) { + if ((evt.getKeyChar() != '\n') || (evt.getKeyCode() != KeyEvent.VK_ENTER)) { + error.append("\nKeyPressed: Unexpected code " + evt.getKeyCode()); + } else { + PassFailJFrame.log("KeyPressed Test PASSED"); + } + } + + public void keyTyped(KeyEvent evt) { + if ((evt.getKeyChar() != '\n') || (evt.getKeyCode() != KeyEvent.VK_UNDEFINED)) { + error.append("\nKeyTyped: Unexpected code " + evt.getKeyCode()); + } else { + PassFailJFrame.log("KeyTyped Test PASSED"); + } + } + + public void keyReleased(KeyEvent evt) { + if ((evt.getKeyChar() != '\n') || (evt.getKeyCode() != KeyEvent.VK_ENTER)) { + error.append("\nKeyReleased: Unexpected code " + evt.getKeyCode()); + } else { + PassFailJFrame.log("KeyReleased Test PASSED"); + } + } + + public void actionPerformed(ActionEvent evt) { + PassFailJFrame.log("ActionPerformed Test PASSED"); + actionCompleted.set(true); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .logArea(10) + .testUI(CRTest::new) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/event/KeyEvent/NumpadTest2.java b/test/jdk/java/awt/event/KeyEvent/NumpadTest2.java new file mode 100644 index 0000000000000..1ee4735431896 --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/NumpadTest2.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4279566 + * @summary Tests that numpad keys produce the correct key codes and + * key chars when both the NumLock and CapsLock are on. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual NumpadTest2 +*/ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.lang.reflect.InvocationTargetException; + +public class NumpadTest2 extends Frame implements KeyListener { + static String INSTRUCTIONS = """ + Make sure that the NumLock and CapsLock are both ON. + Click on the text field inside the window named "Check KeyChar values" + Then, type the NumPad 7 key (not the regular 7 key). + Verify that the keyChar and keyCode is correct for each key pressed. + Remember that the keyCode for the KEY_TYPED event should be zero. + If 7 appears in the text field and the key code printed is correct + press "Pass", otherwise press "Fail". + + Key Name keyChar Keycode + ------------------------------------------------- + Numpad-7 Numpad-7 55 103 + """; + + public NumpadTest2() { + super("Check KeyChar values"); + setLayout(new BorderLayout()); + TextField tf = new TextField(30); + tf.addKeyListener(this); + add(tf, BorderLayout.CENTER); + pack(); + } + + public void keyPressed(KeyEvent evt) { + printKey(evt); + } + + public void keyTyped(KeyEvent evt) { + printKey(evt); + } + + public void keyReleased(KeyEvent evt) { + printKey(evt); + } + + protected void printKey(KeyEvent evt) { + switch (evt.getID()) { + case KeyEvent.KEY_TYPED: + break; + case KeyEvent.KEY_PRESSED: + break; + case KeyEvent.KEY_RELEASED: + break; + default: + System.out.println("Other Event "); + return; + } + + if (evt.isActionKey()) { + PassFailJFrame.log("params= " + evt.paramString() + " KeyChar: " + + (int) evt.getKeyChar() + " Action Key"); + } else { + PassFailJFrame.log("params= " + evt.paramString() + " KeyChar: " + + (int) evt.getKeyChar()); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .logArea(10) + .testUI(NumpadTest2::new) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/event/KeyEvent/TestDoubleKeyEvent.java b/test/jdk/java/awt/event/KeyEvent/TestDoubleKeyEvent.java new file mode 100644 index 0000000000000..24e0bd553c893 --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/TestDoubleKeyEvent.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4495473 + * @summary Tests that when you press key on canvas-type heavyweight only one key event arrives + * @key headful + * @run main TestDoubleKeyEvent + */ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Robot; +import java.awt.event.KeyEvent; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JFrame; +import javax.swing.JWindow; +import javax.swing.JTextField; + +public class TestDoubleKeyEvent extends JFrame { + JWindow w; + JTextField tf; + + public void initUI() { + setLayout(new BorderLayout()); + setTitle("Double Key Event Test"); + setLocationRelativeTo(null); + setVisible(true); + w = new JWindow(this); + w.setLayout(new FlowLayout()); + tf = new JTextField(20); + w.add(tf); + w.pack(); + w.setLocationRelativeTo(null); + w.setVisible(true); + tf.requestFocus(); + } + + public void testAndClean() { + String str = tf.getText(); + w.dispose(); + dispose(); + if (str.length() != str.chars().distinct().count()) { + throw new RuntimeException("Duplicate characters found!"); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + TestDoubleKeyEvent test = new TestDoubleKeyEvent(); + EventQueue.invokeAndWait(test::initUI); + Robot robot = new Robot(); + robot.setAutoDelay(50); + robot.waitForIdle(); + robot.delay(1000); + for (int i = 0; i < 15; i++) { + robot.keyPress(KeyEvent.VK_A + i); + robot.keyRelease(KeyEvent.VK_A + i); + robot.waitForIdle(); + } + robot.delay(1000); + EventQueue.invokeAndWait(test::testAndClean); + } +} From 8270cd0ad2e0df72f063f36853328a935595f71f Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Mon, 21 Apr 2025 20:23:15 +0000 Subject: [PATCH 0674/1101] 8353470: Clean up and open source couple AWT Graphics related tests (Part 2) Reviewed-by: serb --- test/jdk/ProblemList.txt | 1 + .../Graphics/GDIResourceExhaustionTest.java | 121 ++++++++++ .../awt/Graphics/RepeatedRepaintTest.java | 137 +++++++++++ .../java/awt/Graphics/SmallPrimitives.java | 224 ++++++++++++++++++ test/jdk/java/awt/Graphics/TextAfterXor.java | 123 ++++++++++ 5 files changed, 606 insertions(+) create mode 100644 test/jdk/java/awt/Graphics/GDIResourceExhaustionTest.java create mode 100644 test/jdk/java/awt/Graphics/RepeatedRepaintTest.java create mode 100644 test/jdk/java/awt/Graphics/SmallPrimitives.java create mode 100644 test/jdk/java/awt/Graphics/TextAfterXor.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 075ce0e9c10b8..e1e0a695ebca5 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -143,6 +143,7 @@ java/awt/Focus/TestDisabledAutoTransfer.java 8159871 macosx-all,windows-all java/awt/Focus/TestDisabledAutoTransferSwing.java 6962362 windows-all java/awt/Focus/ActivateOnProperAppContextTest.java 8136516 macosx-all java/awt/Focus/FocusPolicyTest.java 7160904 linux-all +java/awt/Graphics/SmallPrimitives.java 8047070 macosx-all,linux-all java/awt/EventQueue/6980209/bug6980209.java 8198615 macosx-all java/awt/EventQueue/PushPopDeadlock/PushPopDeadlock.java 8024034 generic-all java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java 7080150 macosx-all diff --git a/test/jdk/java/awt/Graphics/GDIResourceExhaustionTest.java b/test/jdk/java/awt/Graphics/GDIResourceExhaustionTest.java new file mode 100644 index 0000000000000..b8ba155da60ea --- /dev/null +++ b/test/jdk/java/awt/Graphics/GDIResourceExhaustionTest.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import javax.imageio.ImageIO; +import java.awt.AWTException; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Label; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +/* + * @test + * @bug 4191297 + * @summary Tests that unreferenced GDI resources are correctly + * destroyed when no longer needed. + * @key headful + * @run main GDIResourceExhaustionTest + */ + +public class GDIResourceExhaustionTest extends Frame { + public void initUI() { + setSize(200, 200); + setUndecorated(true); + setLocationRelativeTo(null); + Panel labelPanel = new Panel(); + Label label = new Label("Red label"); + label.setBackground(Color.red); + labelPanel.add(label); + labelPanel.setLocation(20, 50); + add(labelPanel); + setVisible(true); + } + + public void paint(Graphics graphics) { + super.paint(graphics); + for (int rgb = 0; rgb <= 0xfff; rgb++) { + graphics.setColor(new Color(rgb)); + graphics.fillRect(0, 0, 5, 5); + } + } + + public void requestCoordinates(Rectangle r) { + Insets insets = getInsets(); + Point location = getLocationOnScreen(); + Dimension size = getSize(); + r.x = location.x + insets.left; + r.y = location.y + insets.top; + r.width = size.width - (insets.left + insets.right); + r.height = size.height - (insets.top + insets.bottom); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException, IOException { + GDIResourceExhaustionTest test = new GDIResourceExhaustionTest(); + try { + EventQueue.invokeAndWait(test::initUI); + Robot robot = new Robot(); + robot.delay(2000); + Rectangle coords = new Rectangle(); + EventQueue.invokeAndWait(() -> { + test.requestCoordinates(coords); + }); + robot.mouseMove(coords.x - 50, coords.y - 50); + robot.waitForIdle(); + robot.delay(5000); + BufferedImage capture = robot.createScreenCapture(coords); + robot.delay(500); + boolean redFound = false; + int redRGB = Color.red.getRGB(); + for (int y = 0; y < capture.getHeight(); y++) { + for (int x = 0; x < capture.getWidth(); x++) { + if (capture.getRGB(x, y) == redRGB) { + redFound = true; + break; + } + if (redFound) { + break; + } + } + } + if (!redFound) { + File errorImage = new File("screenshot.png"); + ImageIO.write(capture, "png", errorImage); + throw new RuntimeException("Red label is not detected, possibly GDI resources exhausted"); + } + } finally { + EventQueue.invokeAndWait(test::dispose); + } + } +} diff --git a/test/jdk/java/awt/Graphics/RepeatedRepaintTest.java b/test/jdk/java/awt/Graphics/RepeatedRepaintTest.java new file mode 100644 index 0000000000000..140cb48630dbf --- /dev/null +++ b/test/jdk/java/awt/Graphics/RepeatedRepaintTest.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.lang.reflect.InvocationTargetException; + +/* + * @test + * @bug 4081126 4129709 + * @summary Test for proper repainting on multiprocessor systems. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual RepeatedRepaintTest + */ +public class RepeatedRepaintTest extends Frame { + private Font font = null; + private Image background; + + static String INSTRUCTIONS = """ + The frame next to this window called "AWT Draw Test" has + some elements drawn on it. Move this window partially outside of the + screen bounds and then drag it back. Repeat it couple of times. + Drag the instructions window over the frame partially obscuring it. + If after number of attempts the frame content stops repainting + press "Fail", otherwise press "Pass". + """; + + public RepeatedRepaintTest() { + setTitle("AWT Draw Test"); + setSize(300, 300); + background = new BufferedImage(300, 300, BufferedImage.TYPE_INT_ARGB); + Graphics g = background.getGraphics(); + g.setColor(Color.black); + g.fillRect(0, 0, 300, 300); + g.dispose(); + } + + public void paint(Graphics g) { + Dimension dim = this.getSize(); + super.paint(g); + g.drawImage(background, 0, 0, dim.width, dim.height, null); + g.setColor(Color.white); + if (font == null) { + font = new Font("SansSerif", Font.PLAIN, 24); + } + g.setFont(font); + FontMetrics metrics = g.getFontMetrics(); + String message = "Draw Test"; + g.drawString(message, (dim.width / 2) - (metrics.stringWidth(message) / 2), + (dim.height / 2) + (metrics.getHeight() / 2)); + + int counter = 50; + for (int i = 0; i < 50; i++) { + counter += 4; + g.drawOval(counter, 50, i, i); + } + + counter = 20; + for (int i = 0; i < 100; i++) { + counter += 4; + g.drawOval(counter, 150, i, i); + } + g.setColor(Color.black); + g.drawLine(0, dim.height - 25, dim.width, dim.height - 25); + g.setColor(Color.gray); + g.drawLine(0, dim.height - 24, dim.width, dim.height - 24); + g.setColor(Color.lightGray); + g.drawLine(0, dim.height - 23, dim.width, dim.height - 23); + g.fillRect(0, dim.height - 22, dim.width, dim.height); + + + g.setXORMode(Color.blue); + g.fillRect(0, 0, 25, dim.height - 26); + g.setColor(Color.red); + g.fillRect(0, 0, 25, dim.height - 26); + g.setColor(Color.green); + g.fillRect(0, 0, 25, dim.height - 26); + g.setPaintMode(); + + Image img = createImage(50, 50); + Graphics imgGraphics = img.getGraphics(); + imgGraphics.setColor(Color.magenta); + imgGraphics.fillRect(0, 0, 50, 50); + imgGraphics.setColor(Color.yellow); + imgGraphics.drawString("offscreen", 0, 20); + imgGraphics.drawString("image", 0, 30); + + g.drawImage(img, dim.width - 100, dim.height - 100, Color.blue, null); + + g.setXORMode(Color.white); + drawAt(g, 100, 100, 50, 50); + drawAt(g, 105, 105, 50, 50); + drawAt(g, 110, 110, 50, 50); + } + + public void drawAt(Graphics g, int x, int y, int width, int height) { + g.setColor(Color.magenta); + g.fillRect(x, y, width, height); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Repeated Repaint Test Instructions") + .instructions(INSTRUCTIONS) + .testUI(RepeatedRepaintTest::new) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Graphics/SmallPrimitives.java b/test/jdk/java/awt/Graphics/SmallPrimitives.java new file mode 100644 index 0000000000000..7eb267cf0b944 --- /dev/null +++ b/test/jdk/java/awt/Graphics/SmallPrimitives.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Polygon; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; +import java.lang.reflect.InvocationTargetException; + +/* + * @test + * @bug 4411814 4298688 4205762 4524760 4067534 + * @summary Check that Graphics rendering primitives function + * correctly when fed small and degenerate shapes + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SmallPrimitives + */ + + +public class SmallPrimitives extends Panel { + + static String INSTRUCTIONS = """ + In the borderless frame next to this window there should be a + set of tiny narrow blue polygons painted next to the green rectangles. + If rectangle is vertical the corresponding polygon is painted to the right of it, + if rectangle is horizontal the polygon is painted below it. + The length of the polygon should be roughly the same as the length of the + green rectangle next to it. If size is significantly different or any of the + polygons is not painted press "Fail" otherwise press "Pass". + Note: one may consider using screen magnifier to compare sizes. + """; + + public void paint(Graphics g) { + Dimension d = getSize(); + Polygon p; + GeneralPath gp; + + g.setColor(Color.white); + g.fillRect(0, 0, d.width, d.height); + + // Reposition for horizontal tests (below) + g.translate(0, 20); + + // Reference shapes + g.setColor(Color.green); + g.fillRect(10, 7, 11, 1); + g.fillRect(10, 17, 11, 2); + g.fillRect(10, 27, 11, 1); + g.fillRect(10, 37, 11, 1); + g.fillRect(10, 47, 11, 2); + g.fillRect(10, 57, 11, 2); + g.fillRect(10, 67, 11, 1); + g.fillRect(10, 77, 11, 2); + g.fillRect(10, 87, 11, 1); + g.fillRect(10, 97, 11, 1); + g.fillRect(10, 107, 11, 1); + g.fillRect(10, 117, 6, 1); g.fillRect(20, 117, 6, 1); + + // Potentially problematic test shapes + g.setColor(Color.blue); + g.drawRect(10, 10, 10, 0); + g.drawRect(10, 20, 10, 1); + g.drawRoundRect(10, 30, 10, 0, 0, 0); + g.drawRoundRect(10, 40, 10, 0, 4, 4); + g.drawRoundRect(10, 50, 10, 1, 0, 0); + g.drawRoundRect(10, 60, 10, 1, 4, 4); + g.drawOval(10, 70, 10, 0); + g.drawOval(10, 80, 10, 1); + p = new Polygon(); + p.addPoint(10, 90); + p.addPoint(20, 90); + g.drawPolyline(p.xpoints, p.ypoints, p.npoints); + p = new Polygon(); + p.addPoint(10, 100); + p.addPoint(20, 100); + g.drawPolygon(p.xpoints, p.ypoints, p.npoints); + ((Graphics2D) g).draw(new Line2D.Double(10, 110, 20, 110)); + gp = new GeneralPath(); + gp.moveTo(10, 120); + gp.lineTo(15, 120); + gp.moveTo(20, 120); + gp.lineTo(25, 120); + ((Graphics2D) g).draw(gp); + + // Polygon limit tests + p = new Polygon(); + trypoly(g, p); + p.addPoint(10, 120); + trypoly(g, p); + + // Reposition for vertical tests (below) + g.translate(20, -20); + + // Reference shapes + g.setColor(Color.green); + g.fillRect(7, 10, 1, 11); + g.fillRect(17, 10, 2, 11); + g.fillRect(27, 10, 1, 11); + g.fillRect(37, 10, 1, 11); + g.fillRect(47, 10, 2, 11); + g.fillRect(57, 10, 2, 11); + g.fillRect(67, 10, 1, 11); + g.fillRect(77, 10, 2, 11); + g.fillRect(87, 10, 1, 11); + g.fillRect(97, 10, 1, 11); + g.fillRect(107, 10, 1, 11); + g.fillRect(117, 10, 1, 6); g.fillRect(117, 20, 1, 6); + + // Potentially problematic test shapes + g.setColor(Color.blue); + g.drawRect(10, 10, 0, 10); + g.drawRect(20, 10, 1, 10); + g.drawRoundRect(30, 10, 0, 10, 0, 0); + g.drawRoundRect(40, 10, 0, 10, 4, 4); + g.drawRoundRect(50, 10, 1, 10, 0, 0); + g.drawRoundRect(60, 10, 1, 10, 4, 4); + g.drawOval(70, 10, 0, 10); + g.drawOval(80, 10, 1, 10); + p = new Polygon(); + p.addPoint(90, 10); + p.addPoint(90, 20); + g.drawPolyline(p.xpoints, p.ypoints, p.npoints); + p = new Polygon(); + p.addPoint(100, 10); + p.addPoint(100, 20); + g.drawPolygon(p.xpoints, p.ypoints, p.npoints); + ((Graphics2D) g).draw(new Line2D.Double(110, 10, 110, 20)); + gp = new GeneralPath(); + gp.moveTo(120, 10); + gp.lineTo(120, 15); + gp.moveTo(120, 20); + gp.lineTo(120, 25); + ((Graphics2D) g).draw(gp); + + // Polygon limit tests + p = new Polygon(); + trypoly(g, p); + p.addPoint(110, 10); + trypoly(g, p); + + // Reposition for oval tests + g.translate(0, 20); + + for (int i = 0, xy = 8; i < 11; i++) { + g.setColor(Color.green); + g.fillRect(xy, 5, i, 1); + g.fillRect(5, xy, 1, i); + g.setColor(Color.blue); + g.fillOval(xy, 8, i, 1); + g.fillOval(8, xy, 1, i); + xy += i + 2; + } + + g.translate(10, 10); + for (int i = 0, xy = 9; i < 6; i++) { + g.setColor(Color.green); + g.fillRect(xy, 5, i, 2); + g.fillRect(5, xy, 2, i); + g.setColor(Color.blue); + g.fillOval(xy, 8, i, 2); + g.fillOval(8, xy, 2, i); + xy += i + 2; + } + } + + public static void trypoly(Graphics g, Polygon p) { + g.drawPolygon(p); + g.drawPolygon(p.xpoints, p.ypoints, p.npoints); + g.drawPolyline(p.xpoints, p.ypoints, p.npoints); + g.fillPolygon(p); + g.fillPolygon(p.xpoints, p.ypoints, p.npoints); + } + + public Dimension getPreferredSize() { + return new Dimension(150, 150); + } + + public static Frame createFrame() { + Frame f = new Frame(); + SmallPrimitives sp = new SmallPrimitives(); + sp.setLocation(0, 0); + f.add(sp); + f.setUndecorated(true); + f.pack(); + return f; + } + + public static void main(String argv[]) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Small Primitives Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(SmallPrimitives::createFrame) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Graphics/TextAfterXor.java b/test/jdk/java/awt/Graphics/TextAfterXor.java new file mode 100644 index 0000000000000..c9dc56d8b808e --- /dev/null +++ b/test/jdk/java/awt/Graphics/TextAfterXor.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.RenderingHints; +import java.awt.image.VolatileImage; +import java.lang.reflect.InvocationTargetException; + +/* + * @test + * @bug 4505650 + * @summary Check that you can render solid text after doing XOR mode + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TextAfterXor + */ + +public class TextAfterXor extends Panel { + public static final int TESTW = 300; + public static final int TESTH = 100; + static String INSTRUCTIONS = """ + In the window called "Text After XOR Test" there should be two + composite components, at the bottom of each component the green text + "Test passes if this is green!" should be visible. + + On the top component this text should be green on all platforms. + On the bottom component it is possible that on non-Windows + platforms text can be of other color or not visible at all. + That does not constitute a problem. + + So if platform is Windows and green text appears twice or on any + other platform green text appears at least once press "Pass", + otherwise press "Fail". + """; + + VolatileImage vimg; + + public void paint(Graphics g) { + render(g); + g.drawString("(Drawing to screen)", 10, 60); + if (vimg == null) { + vimg = createVolatileImage(TESTW, TESTH); + } + do { + vimg.validate(null); + Graphics g2 = vimg.getGraphics(); + render(g2); + String not = vimg.getCapabilities().isAccelerated() ? "" : "not "; + g2.drawString("Image was " + not + "accelerated", 10, 55); + g2.drawString("(only matters on Windows)", 10, 65); + g2.dispose(); + g.drawImage(vimg, 0, TESTH, null); + } while (vimg.contentsLost()); + } + + public void render(Graphics g) { + g.setColor(Color.black); + g.fillRect(0, 0, TESTW, TESTH); + g.setColor(Color.white); + g.fillRect(5, 5, TESTW-10, TESTH-10); + + g.setColor(Color.black); + g.drawString("Test only passes if green string appears", 10, 20); + + g.setColor(Color.white); + g.setXORMode(Color.blue); + g.drawRect(30, 30, 10, 10); + g.setPaintMode(); + g.setColor(Color.green); + + ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.drawString("Test passes if this is green!", 10, 80); + + g.setColor(Color.black); + } + + public Dimension getPreferredSize() { + return new Dimension(TESTW, TESTH*2); + } + + public static Frame createFrame() { + Frame f = new Frame("Text After XOR Test"); + f.add(new TextAfterXor()); + f.pack(); + return f; + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Text After XOR Instructions") + .instructions(INSTRUCTIONS) + .testUI(TextAfterXor::createFrame) + .build() + .awaitAndCheck(); + } +} From 1526dd81d9b5bf4abaac1546c370cf7a056d01dc Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Mon, 21 Apr 2025 20:24:20 +0000 Subject: [PATCH 0675/1101] 8354344: Test behavior after cut-over for future ISO 4217 currency Reviewed-by: naoto --- .../java/util/Currency/ValidateISO4217.java | 135 +++++++++++++++++- .../java/util/Currency/currency.properties | 2 + 2 files changed, 132 insertions(+), 5 deletions(-) diff --git a/test/jdk/java/util/Currency/ValidateISO4217.java b/test/jdk/java/util/Currency/ValidateISO4217.java index cd6e4f41a9f06..607faefcfa439 100644 --- a/test/jdk/java/util/Currency/ValidateISO4217.java +++ b/test/jdk/java/util/Currency/ValidateISO4217.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,18 +26,44 @@ * @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203 7195759 * 8039317 8074350 8074351 8145952 8187946 8193552 8202026 8204269 * 8208746 8209775 8264792 8274658 8283277 8296239 8321480 8334653 + * 8354344 * @summary Validate ISO 4217 data for Currency class. * @modules java.base/java.util:open * jdk.localedata - * @run junit ValidateISO4217 + * @library /test/lib + * @run junit/othervm -DMOCKED.TIME=setup ValidateISO4217 + * @run main/othervm --patch-module java.base=${test.class.path} + * -DMOCKED.TIME=check -Djava.util.currency.data=${test.src}/currency.properties ValidateISO4217 + * @run junit/othervm --patch-module java.base=${test.class.path} + * -DMOCKED.TIME=true ValidateISO4217 + */ + +/* The run invocation order is important. The first invocation will generate + * class files for Currency that mock System.currentTimeMillis() as Long.MAX_VALUE, + * which is required by the subsequent invocations. The second invocation ensures that + * the module patch and mocked time are functioning correctly; it does not run any tests. + * The third invocation using the modded class files via a module patch allow us + * to test any cut-over dates after the transition. + * Valid MOCKED.TIME values are "setup", "check", and "true". */ import java.io.BufferedReader; import java.io.File; +import java.io.FileOutputStream; import java.io.FileReader; +import java.io.IOException; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.CodeTransform; +import java.lang.classfile.MethodTransform; +import java.lang.classfile.instruction.InvokeInstruction; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Paths; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Currency; import java.util.HashSet; import java.util.List; @@ -45,6 +71,7 @@ import java.util.Set; import java.util.StringTokenizer; import java.util.TimeZone; +import java.util.stream.Stream; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -113,10 +140,102 @@ public class ValidateISO4217 { {"XK", "EUR", "978", "2"}, // Kosovo }; private static SimpleDateFormat format = null; + private static final String MODULE_PATCH_LOCATION = + System.getProperty("test.classes") + "/java/util/"; + private static final String MOCKED_TIME = System.getProperty("MOCKED.TIME"); + + // Classes that should mock System.currentTimeMillis() + private static final String[] CLASSES = + Stream.concat( + Stream.of("Currency.class"), + Arrays.stream(Currency.class.getDeclaredClasses()) + .map(c -> "Currency$" + c.getSimpleName() + ".class") + ).toArray(String[]::new); + + // "check" invocation only runs the main method (and not any tests) to determine if the + // future time checking is correct + public static void main(String[] args) { + if (MOCKED_TIME.equals("check")) { + // Check that the module patch class files exist + checkModulePatchExists(); + // Check time is mocked + // Override for PK=PKR in test/currency.properties is PKZ - simple + // Override for PW=USD in test/currency.properties is MWP - special + assertEquals("PKZ", Currency.getInstance(Locale.of("", "PK")).getCurrencyCode(), + "Mocked time / module patch not working"); + assertEquals("MWP", Currency.getInstance(Locale.of("", "PW")).getCurrencyCode(), + "Mocked time / module patch not working"); + // Properly working. Do nothing and move to third invocation + } else { + throw new RuntimeException( + "Incorrect usage of ValidateISO4217. Main method invoked without proper system property value"); + } + } + + @BeforeAll + static void setUp() throws Exception { + checkUsage(); + setUpPatchedClasses(); + setUpTestingData(); + } + + // Enforce correct usage of ValidateISO4217 + static void checkUsage() { + if (MOCKED_TIME == null + || (!MOCKED_TIME.equals("setup") && !MOCKED_TIME.equals("true"))) { + throw new RuntimeException( + "Incorrect usage of ValidateISO4217. Missing \"MOCKED.TIME\" system property"); + } + if (MOCKED_TIME.equals("true")) { + checkModulePatchExists(); + } + } + + static void checkModulePatchExists() { + // Check that the module patch class files exist + for (String className : CLASSES) { + var file = new File(MODULE_PATCH_LOCATION + className); + assertTrue(file.isFile(), "Module patch class files missing"); + } + } + + // Patch the relevant classes required for module patch + static void setUpPatchedClasses() throws IOException { + if (MOCKED_TIME.equals("setup")) { + new File(MODULE_PATCH_LOCATION).mkdirs(); + for (String s : CLASSES) { + patchClass(s); + } + } + } + + // Mock calls of System.currentTimeMillis() within Currency to Long.MAX_VALUE. + // This effectively ensures that we are always past any cut-over dates. + private static void patchClass(String name) throws IOException { + CodeTransform codeTransform = (codeBuilder, e) -> { + switch (e) { + case InvokeInstruction i when + i.owner().asInternalName().equals("java/lang/System") + && i.name().equalsString("currentTimeMillis") -> + codeBuilder.loadConstant(Long.MAX_VALUE); // mock + default -> codeBuilder.accept(e); + } + }; + MethodTransform methodTransform = MethodTransform.transformingCode(codeTransform); + ClassTransform classTransform = ClassTransform.transformingMethods(methodTransform); + ClassFile cf = ClassFile.of(); + byte[] newBytes = cf.transformClass(cf.parse( + Files.readAllBytes(Paths.get(URI.create("jrt:/java.base/java/util/" + name)))), classTransform); + + String patchedClass = MODULE_PATCH_LOCATION + name; + var file = new File(patchedClass); + try (FileOutputStream fos = new FileOutputStream(file)) { + fos.write(newBytes); + } + } // Sets up the following test data: // ISO4217Codes, additionalCodes, testCurrencies, codes - @BeforeAll static void setUpTestingData() throws Exception { // These functions laterally setup 'testCurrencies' and 'codes' // at the same time @@ -169,8 +288,8 @@ private static void processColumns(StringTokenizer tokens, String country) throw if (format == null) { createDateFormat(); } - // If the cut-over already passed, use the new curency for ISO4217Codes - if (format.parse(tokens.nextToken()).getTime() < System.currentTimeMillis()) { + // If the cut-over already passed, use the new currency for ISO4217Codes + if (format.parse(tokens.nextToken()).getTime() < currentTimeMillis()) { currency = tokens.nextToken(); numeric = tokens.nextToken(); minorUnit = tokens.nextToken(); @@ -320,4 +439,10 @@ private static String getSetDiffs(Set jreCurrencies, Set tes bldr.append("\n"); return bldr.toString(); } + + // Either the current system time, or a mocked value equal to Long.MAX_VALUE + static long currentTimeMillis() { + var mocked = MOCKED_TIME.equals("true"); + return mocked ? Long.MAX_VALUE : System.currentTimeMillis(); + } } diff --git a/test/jdk/java/util/Currency/currency.properties b/test/jdk/java/util/Currency/currency.properties index ff5259e5933cb..0420d9cb5019c 100644 --- a/test/jdk/java/util/Currency/currency.properties +++ b/test/jdk/java/util/Currency/currency.properties @@ -13,6 +13,8 @@ MD=MDD,555,7 ME=MEE,555,8 MF=MFF,555,9 NO=EUR ,978 ,2, 2099-01-01T00:00:00 +PK=PKZ,999,0,3000-01-01T00:00:00 +PW=MWP,999,0,5000-01-01T00:00:00 SB=EUR,111,2, 2099-01-01T00:00:00 US=euR,978,2,2001-01-01T00:00:00 ZZ\t=\tZZZ\t,\t999\t,\t3 From f7155183d7f7c6fcea2090f906de69e02973a6d9 Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Mon, 21 Apr 2025 22:35:17 +0000 Subject: [PATCH 0676/1101] 8353011: Open source Swing JButton tests - Set 1 Reviewed-by: serb --- test/jdk/javax/swing/JButton/bug4151763.java | 94 +++++++++++++++ test/jdk/javax/swing/JButton/bug4415505.java | 77 +++++++++++++ test/jdk/javax/swing/JButton/bug4978274.java | 108 ++++++++++++++++++ .../javax/swing/JRadioButton/bug4673850.java | 104 +++++++++++++++++ test/jdk/javax/swing/JTable/bug4188504.java | 71 ++++++++++++ 5 files changed, 454 insertions(+) create mode 100644 test/jdk/javax/swing/JButton/bug4151763.java create mode 100644 test/jdk/javax/swing/JButton/bug4415505.java create mode 100644 test/jdk/javax/swing/JButton/bug4978274.java create mode 100644 test/jdk/javax/swing/JRadioButton/bug4673850.java create mode 100644 test/jdk/javax/swing/JTable/bug4188504.java diff --git a/test/jdk/javax/swing/JButton/bug4151763.java b/test/jdk/javax/swing/JButton/bug4151763.java new file mode 100644 index 0000000000000..d04b623ec4eb1 --- /dev/null +++ b/test/jdk/javax/swing/JButton/bug4151763.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4151763 + * @summary Tests that button icon is not drawn upon button border + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @run main/manual bug4151763 + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.UIManager; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; +import javax.swing.border.LineBorder; +import jtreg.SkippedException; + +public class bug4151763 { + private static final int IMAGE_SIZE = 150; + private static final String INSTRUCTIONS = """ + Verify that image icon is NOT painted outside + the black rectangle. + + If above is true press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4151763::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createAndShowUI() { + try { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); + } catch (Exception e) { + throw new SkippedException("Unsupported LaF", e); + } + + JFrame frame = new JFrame("bug4151763"); + final JButton b = new JButton(createImageIcon()); + b.setBorder(new CompoundBorder( + new EmptyBorder(20, 20, 20, 20), + new LineBorder(Color.BLACK))); + b.setPreferredSize(new Dimension(100, 100)); + + frame.setLayout(new FlowLayout()); + frame.add(b); + frame.setSize(400, 300); + return frame; + } + + private static ImageIcon createImageIcon() { + BufferedImage redImg = new BufferedImage(IMAGE_SIZE, IMAGE_SIZE, + BufferedImage.TYPE_INT_RGB); + Graphics2D g = redImg.createGraphics(); + g.setColor(Color.RED); + g.fillRect(0, 0, IMAGE_SIZE, IMAGE_SIZE); + g.dispose(); + return new ImageIcon(redImg); + } +} diff --git a/test/jdk/javax/swing/JButton/bug4415505.java b/test/jdk/javax/swing/JButton/bug4415505.java new file mode 100644 index 0000000000000..58ba56e1b74e8 --- /dev/null +++ b/test/jdk/javax/swing/JButton/bug4415505.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4415505 + * @requires (os.family == "windows") + * @summary Tests JButton appearance under Windows LAF + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4415505 + */ + +import java.awt.FlowLayout; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JToggleButton; +import javax.swing.UIManager; + +public class bug4415505 { + private static final String INSTRUCTIONS = """ + +

This test is for Windows LaF. + Press the button named "Button" using mouse and check that it has + "pressed" look. It should look like the selected toggle button + near it.

+ +

If above is true press PASS else FAIL.

+ + """; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .rows(5) + .columns(40) + .testUI(bug4415505::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createAndShowUI() { + JButton button = new JButton("Button"); + button.setFocusPainted(false); + JToggleButton tbutton = new JToggleButton("ToggleButton"); + tbutton.setSelected(true); + + JFrame jFrame = new JFrame("bug4415505"); + jFrame.setLayout(new FlowLayout(FlowLayout.CENTER)); + jFrame.add(button); + jFrame.add(tbutton); + jFrame.setSize(300, 100); + return jFrame; + } +} diff --git a/test/jdk/javax/swing/JButton/bug4978274.java b/test/jdk/javax/swing/JButton/bug4978274.java new file mode 100644 index 0000000000000..6b152259caaed --- /dev/null +++ b/test/jdk/javax/swing/JButton/bug4978274.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4978274 + * @summary Tests that JButton is painted with same visible height + * as toggle buttons + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4978274 + */ + +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JToggleButton; +import javax.swing.UIManager; +import javax.swing.border.EmptyBorder; +import javax.swing.plaf.metal.MetalLookAndFeel; +import javax.swing.plaf.metal.OceanTheme; + +public class bug4978274 { + private static final String INSTRUCTIONS = """ + The toggle buttons must be painted to the same visible + height as button. In addition to that verify the following: + + a) All three buttons - "Button", "Toggle Btn" and + "Selected Toggle Btn" have the same border. + + b) Verify that when "Button" is pressed and moused over + it has the EXACT same border as "Toggle Btn" and + "Selected Toggle Btn" on press & mouse over. + + c) Click to the test window (panel) to disable/enable all + three buttons. In disabled state verify that all three + buttons have the exact same border. + + If all of the above conditions are true press PASS, else FAIL. + """; + + public static void main(String[] args) throws Exception { + MetalLookAndFeel.setCurrentTheme(new OceanTheme()); + UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(createAndShowUI()) + .build() + .awaitAndCheck(); + } + + private static JFrame createAndShowUI() { + JFrame frame = new JFrame("bug4978274"); + frame.setLayout(new BorderLayout()); + + JPanel panel = new JPanel(); + panel.setLayout(new FlowLayout()); + panel.setBorder(new EmptyBorder(12, 12, 12, 12)); + JButton jButton = new JButton("Button"); + JToggleButton jToggleButton = new JToggleButton("Selected Toggle Btn"); + jToggleButton.setSelected(true); + + panel.add(jButton); + panel.add(new JToggleButton("Toggle Btn")); + panel.add(jToggleButton); + + panel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent event) { + jButton.setEnabled(!jButton.isEnabled()); + jToggleButton.setEnabled(jButton.isEnabled()); + for(int i = 0; i < panel.getComponentCount(); i++) { + panel.getComponent(i).setEnabled(jButton.isEnabled()); + } + } + }); + + frame.add(panel); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/javax/swing/JRadioButton/bug4673850.java b/test/jdk/javax/swing/JRadioButton/bug4673850.java new file mode 100644 index 0000000000000..4f9058e978eeb --- /dev/null +++ b/test/jdk/javax/swing/JRadioButton/bug4673850.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4673850 + * @summary Tests that JRadioButton and JCheckBox checkmarks are painted entirely + * inside circular/rectangle checkboxes for Motif LaF. + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @run main/manual bug4673850 + */ + +import java.awt.FlowLayout; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JRadioButton; +import javax.swing.SwingConstants; +import javax.swing.UIManager; +import jtreg.SkippedException; + +public class bug4673850 { + private static final String INSTRUCTIONS = """ + + + + + +

This test is for Motif LaF.

+ +

+ When the test starts, you'll see 2 radio buttons and 2 check boxes + with the checkmarks painted.

+ +

+ Ensure that all the button's checkmarks are painted entirely + within the circular/rectangle checkbox, NOT over them or outside them. +

+ + """; + + public static void main(String[] args) throws Exception { + try { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); + } catch (Exception e) { + throw new SkippedException("Unsupported LaF", e); + } + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .rows(10) + .columns(45) + .testUI(createAndShowUI()) + .build() + .awaitAndCheck(); + } + + private static JFrame createAndShowUI() { + JFrame frame = new JFrame("bug4673850"); + frame.setLayout(new FlowLayout()); + + JRadioButton rb = new JRadioButton("RadioButt"); + rb.setSelected(true); + frame.add(rb); + JRadioButton rb2 = new JRadioButton("RadioButt"); + rb2.setHorizontalTextPosition(SwingConstants.LEFT); + rb2.setSelected(true); + frame.add(rb2); + + JCheckBox cb = new JCheckBox("CheckBox"); + cb.setSelected(true); + frame.add(cb); + JCheckBox cb2 = new JCheckBox("CheckBox"); + cb2.setHorizontalTextPosition(SwingConstants.LEFT); + cb2.setSelected(true); + frame.add(cb2); + frame.setSize(200, 150); + return frame; + } +} \ No newline at end of file diff --git a/test/jdk/javax/swing/JTable/bug4188504.java b/test/jdk/javax/swing/JTable/bug4188504.java new file mode 100644 index 0000000000000..b58ee7def0387 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4188504.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4188504 + * @summary setResizable for specified column. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4188504 + */ + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; + +public class bug4188504 { + private static final String INSTRUCTIONS = """ + 1. A table is displayed with 3 columns - A, B, C. + + 2. Try to resize second column of table (Move mouse to the position + between "B" and "C" headers, press left mouse button and move to + right/left). + PLEASE NOTE: You may be able to swap the columns but make sure the + width of column B stays the same. + + 3. If the second column does not change its width then press PASS + otherwise press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(createAndShowUI()) + .build() + .awaitAndCheck(); + } + + private static JFrame createAndShowUI() { + JFrame jFrame = new JFrame("bug4188504"); + JTable tableView = new JTable(4, 3); + tableView.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + tableView.getColumnModel().getColumn(1).setResizable(false); + + jFrame.add(new JScrollPane(tableView)); + jFrame.setSize(300, 150); + return jFrame; + } +} From 9a0cff692d6f96b8c89b1510cd2b4b1a8e318b6e Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Mon, 21 Apr 2025 23:11:03 +0000 Subject: [PATCH 0677/1101] 8353942: Open source Swing Tests - Set 5 Reviewed-by: serb, dnguyen --- .../DataTransfer/DragOverFeedbackTest.java | 117 +++++++++++++++++ .../ListDragOverFeedbackTest.java | 119 ++++++++++++++++++ .../javax/swing/DataTransfer/bug4655513.java | 106 ++++++++++++++++ .../swing/SwingUtilities/bug4369355.java | 87 +++++++++++++ .../swing/SwingUtilities/bug4967768.java | 66 ++++++++++ 5 files changed, 495 insertions(+) create mode 100644 test/jdk/javax/swing/DataTransfer/DragOverFeedbackTest.java create mode 100644 test/jdk/javax/swing/DataTransfer/ListDragOverFeedbackTest.java create mode 100644 test/jdk/javax/swing/DataTransfer/bug4655513.java create mode 100644 test/jdk/javax/swing/SwingUtilities/bug4369355.java create mode 100644 test/jdk/javax/swing/SwingUtilities/bug4967768.java diff --git a/test/jdk/javax/swing/DataTransfer/DragOverFeedbackTest.java b/test/jdk/javax/swing/DataTransfer/DragOverFeedbackTest.java new file mode 100644 index 0000000000000..824f651a1a097 --- /dev/null +++ b/test/jdk/javax/swing/DataTransfer/DragOverFeedbackTest.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4514071 + * @summary Tests that JTable, JList and JTree provide drag-over feedback. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DragOverFeedbackTest + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.awt.datatransfer.DataFlavor; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.JTree; +import javax.swing.TransferHandler; + +public class DragOverFeedbackTest { + private static final String INSTRUCTIONS = """ + This test is designed to make sure that JTable, JTree, and JList + provide visual feedback when a DnD drag operation occurs over them. + + Click on the label where it says "DRAG FROM HERE" and begin dragging. + Drag over each of the three components (JTable, JTree, JList). + While you're dragging over them, they should visually indicate the + location where a drop would occur. This visual indication may use the + selection but could be some other visual. + + If above is true press PASS else press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(DragOverFeedbackTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static final TransferHandler handler = new TransferHandler() { + public boolean canImport(JComponent comp, DataFlavor[] flavors) { + return true; + } + }; + + private static JFrame createTestUI() { + JFrame frame = new JFrame("DragOverFeedbackTest"); + final JLabel label = new JLabel("DRAG FROM HERE"); + label.setPreferredSize(new Dimension(400, 25)); + label.setTransferHandler(new TransferHandler("text")); + label.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent me) { + label.getTransferHandler().exportAsDrag(label, me, TransferHandler.COPY); + } + }); + JTable table = new JTable( + new String[][] {{"one"}, {"two"}, {"three"}, {"four"}}, + new String[] {"1"}); + table.setRowSelectionInterval(1, 1); + table.setTransferHandler(handler); + + JList list = new JList(new String[] {"one", "two", "three", "four"}); + list.setSelectedIndex(1); + list.setTransferHandler(handler); + + JTree tree = new JTree(); + tree.setSelectionRow(1); + tree.setTransferHandler(handler); + + frame.add(label, BorderLayout.NORTH); + + JPanel wrapper = new JPanel(); + wrapper.setLayout(new GridLayout(3, 1)); + table.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + wrapper.add(table); + list.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + wrapper.add(list); + tree.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + wrapper.add(tree); + frame.add(wrapper); + frame.setSize(500, 500); + return frame; + } +} diff --git a/test/jdk/javax/swing/DataTransfer/ListDragOverFeedbackTest.java b/test/jdk/javax/swing/DataTransfer/ListDragOverFeedbackTest.java new file mode 100644 index 0000000000000..b41327a106ed6 --- /dev/null +++ b/test/jdk/javax/swing/DataTransfer/ListDragOverFeedbackTest.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4546134 + * @summary Tests that JList shows the right drop location when it has multiple columns. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ListDragOverFeedbackTest + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.awt.datatransfer.DataFlavor; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.TransferHandler; + +public class ListDragOverFeedbackTest { + private static final String INSTRUCTIONS = """ + JList should provide visual feedback when a DnD drag operation is + occurring over it. This test is to check that it provides the + feedback about the drop location correctly. + + Click on the label where it says "DRAG FROM HERE" and begin dragging. + Drag over each column in each of the three JLists and make sure that + the drop location indicated is appropriate for the mouse location. For + instance, if the mouse is in the first column, the drop location should + also be indicated in that first column. + + If above is true press PASS else press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(ListDragOverFeedbackTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static final TransferHandler handler = new TransferHandler() { + public boolean canImport(JComponent comp, DataFlavor[] flavors) { + return true; + } + }; + + private static JFrame createTestUI() { + String[] vals = new String[] { + "one", "two", "three", "four", "five", "six", "seven", "eight", + "nine", "ten", "eleven", "twelve", "thirteen", "fourteen"}; + + JFrame frame = new JFrame("ListDragOverFeedbackTest"); + final JLabel label = new JLabel("DRAG FROM HERE"); + label.setPreferredSize(new Dimension(400, 25)); + label.setTransferHandler(new TransferHandler("text")); + label.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent me) { + label.getTransferHandler().exportAsDrag(label, me, + TransferHandler.COPY); + } + }); + + JList list1 = new JList(vals); + list1.setTransferHandler(handler); + list1.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + + JList list2 = new JList(vals); + list2.setLayoutOrientation(JList.VERTICAL_WRAP); + list2.setTransferHandler(handler); + list2.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + + JList list3 = new JList(vals); + list3.setLayoutOrientation(JList.HORIZONTAL_WRAP); + list3.setTransferHandler(handler); + list3.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + + JPanel wrapper = new JPanel(); + wrapper.setLayout(new GridLayout(3, 1)); + wrapper.add(list1); + wrapper.add(list2); + wrapper.add(list3); + + frame.add(label, BorderLayout.NORTH); + frame.add(wrapper); + frame.setSize(400, 500); + return frame; + } +} diff --git a/test/jdk/javax/swing/DataTransfer/bug4655513.java b/test/jdk/javax/swing/DataTransfer/bug4655513.java new file mode 100644 index 0000000000000..c9f49f98939eb --- /dev/null +++ b/test/jdk/javax/swing/DataTransfer/bug4655513.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @key headful + * @bug 4655513 + * @summary TransferHandler doesn't recognize ACTION_LINK + as a valid drop action + * @library /javax/swing/regtesthelpers + * @build Util + * @run main bug4655513 + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.StringSelection; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureRecognizer; +import java.awt.dnd.DragSource; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; + +public class bug4655513 { + private static final String LINK_URL = "http://www.example.com"; + private static volatile JEditorPane editor; + private static volatile JLabel dragSource; + private static JFrame frame; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + SwingUtilities.invokeAndWait(bug4655513::createAndShowGUI); + robot.waitForIdle(); + robot.delay(1000); + + Point dragStartLoc = Util.getCenterPoint(dragSource); + Point dragEndLoc = Util.getCenterPoint(editor); + robot.mouseMove(dragStartLoc.x, dragStartLoc.y); + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); + for (int y = dragStartLoc.y; y < dragEndLoc.y; y += 3) { + robot.mouseMove(dragStartLoc.x, y); + robot.delay(50); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(500); + + SwingUtilities.invokeAndWait(() -> { + if (!editor.getText().contains(LINK_URL)) { + throw new RuntimeException("Test Failed! Drag & Drop did not work."); + } + }); + } finally { + SwingUtilities.invokeAndWait(frame::dispose); + } + } + + private static void createAndShowGUI() { + frame = new JFrame("Bug4655513 - Data Transfer"); + dragSource = new JLabel("To Test DnD, drag this label."); + dragSource.setForeground(Color.RED); + dragSource.setPreferredSize(new Dimension(250, 50)); + frame.add(dragSource, BorderLayout.NORTH); + + editor = new JEditorPane("text/plain", "Drop here."); + editor.setPreferredSize(new Dimension(250, 50)); + frame.add(new JScrollPane(editor), BorderLayout.CENTER); + + DragSource ds = new DragSource(); + DragGestureRecognizer rec = + ds.createDefaultDragGestureRecognizer(dragSource, + DnDConstants.ACTION_LINK, + dge -> dge.startDrag(null, new StringSelection(LINK_URL))); + frame.setSize(300, 150); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } +} diff --git a/test/jdk/javax/swing/SwingUtilities/bug4369355.java b/test/jdk/javax/swing/SwingUtilities/bug4369355.java new file mode 100644 index 0000000000000..f55d888ef3179 --- /dev/null +++ b/test/jdk/javax/swing/SwingUtilities/bug4369355.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @key headful + * @bug 4369355 + * @summary To verify if SwingUtilities.convertPointToScreen() (for invisible frame) + * and SwingUtilities.convertPointFromScreen() return correct values + * @run main bug4369355 + */ + +import java.awt.Point; +import java.awt.Robot; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +public class bug4369355 { + private static JFrame frame; + + private static volatile Point frameToScreenLoc; + private static volatile Point frameFromScreenLoc; + + private static final Point EXPECTED_FROM_SCREEN_LOC = new Point(0, 0); + private static final Point EXPECTED_TO_SCREEN_LOC = new Point(100, 100); + + public static void main (String[] args) throws Exception { + try { + Robot robot = new Robot(); + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("bug4369355"); + frame.setBounds(100, 100, 100, 100); + }); + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + frameToScreenLoc = new Point(0, 0); + SwingUtilities.convertPointToScreen(frameToScreenLoc, frame); + }); + robot.delay(100); + + if (!frameToScreenLoc.equals(EXPECTED_TO_SCREEN_LOC)) { + throw new RuntimeException("SwingUtilities.convertPointToScreen()" + + " returns incorrect point " + frameToScreenLoc + "\n" + + "Should be " + EXPECTED_TO_SCREEN_LOC); + } + + SwingUtilities.invokeAndWait(() -> frame.setVisible(true)); + robot.delay(500); + + SwingUtilities.invokeAndWait(() -> { + frameFromScreenLoc = frame.getLocationOnScreen(); + SwingUtilities.convertPointFromScreen(frameFromScreenLoc, frame); + }); + robot.delay(100); + + if (!frameFromScreenLoc.equals(EXPECTED_FROM_SCREEN_LOC)) { + throw new RuntimeException("SwingUtilities.convertPointFromScreen()" + + " returns incorrect point " + frameFromScreenLoc + "\n" + + "Should be " + EXPECTED_FROM_SCREEN_LOC); + } + } finally { + SwingUtilities.invokeAndWait(frame::dispose); + } + } +} diff --git a/test/jdk/javax/swing/SwingUtilities/bug4967768.java b/test/jdk/javax/swing/SwingUtilities/bug4967768.java new file mode 100644 index 0000000000000..43f9f7cabfbeb --- /dev/null +++ b/test/jdk/javax/swing/SwingUtilities/bug4967768.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4967768 + * @requires (os.family != "mac") + * @summary Tests that underline is painted correctly in mnemonics + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4967768 + */ + +import java.awt.Font; +import javax.swing.JButton; +import javax.swing.JPanel; + +public class bug4967768 { + private static final String INSTRUCTIONS = """ + When the test starts you'll see a button "Oops" + with the "p" letter underlined at the bottom + of the instruction frame. + + Ensure the underline cuts through the descender + of letter "p", i.e. the underline is painted + not below the letter but below the baseline. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .splitUIBottom(bug4967768::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JPanel createTestUI() { + JPanel panel = new JPanel(); + JButton but = new JButton("Oops"); + but.setFont(new Font("Dialog", Font.BOLD, 24)); + but.setMnemonic('p'); + panel.add(but); + return panel; + } +} From 47f78a7529a2b290a07394e053bcfaff4907b7e5 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 22 Apr 2025 00:27:25 +0000 Subject: [PATCH 0678/1101] 8354990: Improve negative tests coverage for jpackage signing 8354989: Bug in MacCertificate class Reviewed-by: almatvee --- .../jdk/jpackage/internal/MacAppBundler.java | 2 +- .../jdk/jpackage/internal/MacCertificate.java | 18 +- .../jdk/jpackage/internal/MacPkgBundler.java | 2 +- .../helpers/jdk/jpackage/test/MacSign.java | 375 +++++++++++++++--- .../jdk/jpackage/test/MacSignVerify.java | 226 +++++++++++ .../tools/jpackage/macosx/MacSignTest.java | 193 ++++++++- .../jpackage/macosx/base/SigningBase.java | 248 +++++------- 7 files changed, 823 insertions(+), 241 deletions(-) create mode 100644 test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index 5da01aa293c9e..733321dec46da 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -74,7 +74,7 @@ public MacAppBundler() { } if (result != null) { - MacCertificate certificate = new MacCertificate(result); + MacCertificate certificate = new MacCertificate(result, keychain); if (!certificate.isValid()) { Log.error(MessageFormat.format(I18N.getString( diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificate.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificate.java index 90f3a8c765b44..c9dab481e0eac 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificate.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,21 +39,25 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Date; +import java.util.HexFormat; import java.util.List; import java.util.Locale; -import java.util.HexFormat; +import java.util.Objects; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; public final class MacCertificate { private final String certificate; + private final Optional keychainName; - public MacCertificate(String certificate) { - this.certificate = certificate; + public MacCertificate(String certificate, String keychainName) { + this.certificate = Objects.requireNonNull(certificate); + this.keychainName = Optional.ofNullable(keychainName); } public boolean isValid() { - return verifyCertificate(this.certificate); + return verifyCertificate(); } public static String findCertificateKey(String keyPrefix, String teamName, @@ -295,7 +299,7 @@ private Date findCertificateDate(String filename) { return result; } - private boolean verifyCertificate(String certificate) { + private boolean verifyCertificate() { boolean result = false; try { @@ -303,7 +307,7 @@ private boolean verifyCertificate(String certificate) { Date certificateDate = null; try { - file = getFindCertificateOutputPEM(certificate, null); + file = getFindCertificateOutputPEM(certificate, keychainName.orElse(null)); if (file != null) { certificateDate = findCertificateDate( diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 2aca9bd0e1f0b..8328fa07851a3 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -130,7 +130,7 @@ public class MacPkgBundler extends MacBaseInstallerBundler { } if (result != null) { - MacCertificate certificate = new MacCertificate(result); + MacCertificate certificate = new MacCertificate(result, keychain); if (!certificate.isValid()) { Log.error(MessageFormat.format( diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java index 1d5dd16fe3730..67ac921b919d0 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java @@ -29,9 +29,9 @@ import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; import static java.util.stream.Collectors.toSet; -import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; +import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.UncheckedIOException; @@ -42,7 +42,9 @@ import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.security.MessageDigest; +import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateFactory; +import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Base64; @@ -63,6 +65,7 @@ import javax.naming.ldap.Rdn; import jdk.jpackage.internal.util.function.ExceptionBox; import jdk.jpackage.internal.util.function.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingSupplier; /** * Utilities to setup identities and keychains for sign testing. @@ -393,15 +396,52 @@ Keychain createKeyPair(String name) { } List findCertificates() { - final var in = new ByteArrayInputStream( - security("find-certificate", "-ap", name).saveOutput().execute().getOutput().stream().collect(joining("\n")).getBytes(StandardCharsets.UTF_8)); - return toFunction(CERT_FACTORY::generateCertificates).apply(in).stream().map(X509Certificate.class::cast).toList(); + final List certs = new ArrayList<>(); + try (final var in = new BufferedInputStream(new ByteArrayInputStream( + security("find-certificate", "-ap", name).executeAndGetOutput().stream().collect(joining("\n")).getBytes(StandardCharsets.UTF_8)))) { + while (in.available() > 0) { + final X509Certificate cert; + try { + cert = (X509Certificate) CERT_FACTORY.generateCertificate(in); + } catch (Exception ex) { + TKit.trace("Failed to parse certificate data: " + ex); + continue; + } + certs.add(cert); + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + return certs; } public static void addToSearchList(Collection keychains) { security("list-keychains", "-d", "user", "-s", "login.keychain") - .addArguments(keychains.stream().map(Keychain::name).toList()) - .execute(); + .addArguments(keychains.stream().map(Keychain::name).toList()) + .execute(); + } + + public static void withAddedKeychains(Collection keychains, Runnable runnable) { + final var curKeychains = activeKeychainFiles(); + addToSearchList(keychains); + try { + runnable.run(); + } finally { + security("list-keychains", "-d", "user", "-s") + .addArguments(curKeychains.stream().map(Path::toString).toList()) + .execute(); + } + } + + private static List activeKeychainFiles() { + // $ security list-keychains + // "/Users/alexeysemenyuk/Library/Keychains/login.keychain-db" + // "/Library/Keychains/System.keychain" + return security("list-keychains", "-d", "user").executeAndGetOutput().stream().map(line -> { + return line.stripLeading(); + }).filter(line -> { + return line.charAt(0) == '"' && line.charAt(line.length() - 1) == '"'; + }).map(line -> line.substring(1, line.length() - 1)).map(Path::of).toList(); } private Executor createExecutor(String command) { @@ -409,40 +449,57 @@ private Executor createExecutor(String command) { } } - record ResolvedCertificateRequest(CertificateRequest request, X509Certificate cert, VerifyStatus verifyStatus) { + private enum VerifyStatus { + VERIFY_OK, + VERIFY_EXPIRED, + VERIFY_ERROR, + VERIFY_UNTRUSTED, + VERIFY_EXPIRED_UNTRUSTED, + UNVERIFIED + } + + private record ResolvedCertificateRequest(InstalledCertificate installed, X509Certificate cert, VerifyStatus verifyStatus) { ResolvedCertificateRequest { - Objects.requireNonNull(request); + Objects.requireNonNull(installed); Objects.requireNonNull(cert); Objects.requireNonNull(verifyStatus); } - enum VerifyStatus { - VERIFY_OK, - VERIFY_ERROR, - UNVERIFIED + CertificateRequest request() { + if (!verified()) { + throw new IllegalStateException(); + } + return new CertificateRequest(installed.name(), installed.type(), installed.days(), installed.expired(), + Set.of(VerifyStatus.VERIFY_OK, VerifyStatus.VERIFY_EXPIRED).contains(verifyStatus)); } ResolvedCertificateRequest(X509Certificate cert) { - this(new CertificateRequest(cert), cert, VerifyStatus.UNVERIFIED); + this(new InstalledCertificate(cert), cert, VerifyStatus.UNVERIFIED); } - ResolvedCertificateRequest copyVerified(boolean verifySuccess) { - return new ResolvedCertificateRequest(request, cert, - verifySuccess ? VerifyStatus.VERIFY_OK : VerifyStatus.VERIFY_ERROR); + ResolvedCertificateRequest copyVerified(VerifyStatus verifyStatus) { + if (verifyStatus == VerifyStatus.UNVERIFIED) { + throw new IllegalArgumentException(); + } + return new ResolvedCertificateRequest(installed, cert, verifyStatus); + } + + private boolean verified() { + return verifyStatus != VerifyStatus.UNVERIFIED; } } - record CertificateStats(List allResolvedCertificateRequests, - List allCertificates, List knownCertificateRequests, + private record CertificateStats(List allResolvedCertificateRequests, + List knownCertificateRequests, Map unmappedCertificates) { - private static CertificateStats get(KeychainWithCertsSpec spec) { + static CertificateStats get(KeychainWithCertsSpec spec) { return CACHE.computeIfAbsent(spec, CertificateStats::create); } Map> mapKnownCertificateRequests() { return knownCertificateRequests.stream().collect(groupingBy(x -> x, mapping(certificateRequest -> { - return allResolvedCertificateRequests.stream().filter(v -> { + return allVerifiedResolvedCertificateRequest().filter(v -> { return v.request().equals(certificateRequest); }).map(ResolvedCertificateRequest::cert); }, flatMapping(x -> x, toList())))); @@ -450,15 +507,19 @@ Map> mapKnownCertificateRequests() { Set verifyFailedCertificateRequests() { return knownCertificateRequests.stream().filter(certificateRequest -> { - return allResolvedCertificateRequests.stream().anyMatch(v -> { - return v.request().equals(certificateRequest) && v.verifyStatus() == ResolvedCertificateRequest.VerifyStatus.VERIFY_ERROR; + return allVerifiedResolvedCertificateRequest().anyMatch(v -> { + return v.request().equals(certificateRequest) && v.verifyStatus() != certificateRequest.expectedVerifyStatus(); }); }).collect(toSet()); } Set unmappedCertificateRequests() { return Comm.compare(Set.copyOf(knownCertificateRequests), - allResolvedCertificateRequests.stream().map(ResolvedCertificateRequest::request).collect(toSet())).unique1(); + allVerifiedResolvedCertificateRequest().map(ResolvedCertificateRequest::request).collect(toSet())).unique1(); + } + + private Stream allVerifiedResolvedCertificateRequest() { + return allResolvedCertificateRequests.stream().filter(ResolvedCertificateRequest::verified); } private static CertificateStats create(KeychainWithCertsSpec spec) { @@ -482,24 +543,24 @@ private static CertificateStats create(KeychainWithCertsSpec spec) { continue; } - if (spec.certificateRequests().contains(resolvedCertificateRequest.request)) { + if (spec.certificateRequests().stream().anyMatch(resolvedCertificateRequest.installed()::match)) { final var certFile = workDir.resolve(CertificateHash.of(cert).toString() + ".pem"); - final var verifySuccess = verifyCertificate(resolvedCertificateRequest, spec.keychain(), certFile); - resolvedCertificateRequest = resolvedCertificateRequest.copyVerified(verifySuccess); + final var verifyStatus = verifyCertificate(resolvedCertificateRequest, spec.keychain(), certFile); + resolvedCertificateRequest = resolvedCertificateRequest.copyVerified(verifyStatus); } allResolvedCertificateRequests.add(resolvedCertificateRequest); } }); - return new CertificateStats(allResolvedCertificateRequests, List.copyOf(allCertificates), + return new CertificateStats(allResolvedCertificateRequests, List.copyOf(spec.certificateRequests()), unmappedCertificates); } private static final Map CACHE = new ConcurrentHashMap<>(); } - record PemData(String label, byte[] data) { + private record PemData(String label, byte[] data) { PemData { Objects.requireNonNull(label); Objects.requireNonNull(data); @@ -532,23 +593,41 @@ private static String frame(String str) { return String.format("-----%s-----\n", Objects.requireNonNull(str)); } - private final static Base64.Encoder ENCODER = Base64.getMimeEncoder(64, "\n".getBytes()); + private static final Base64.Encoder ENCODER = Base64.getMimeEncoder(64, "\n".getBytes()); } - public record CertificateHash(byte[] value) { + public enum DigestAlgorithm { + SHA1(20, () -> MessageDigest.getInstance("SHA-1")), + SHA256(32, () -> MessageDigest.getInstance("SHA-256")); + + DigestAlgorithm(int hashLength, ThrowingSupplier createDigest) { + this.hashLength = hashLength; + this.createDigest = createDigest; + } + + final int hashLength; + final ThrowingSupplier createDigest; + } + + public record CertificateHash(byte[] value, DigestAlgorithm alg) { public CertificateHash { Objects.requireNonNull(value); - if (value.length != 20) { - throw new IllegalArgumentException("Invalid SHA-1 hash"); + Objects.requireNonNull(alg); + if (value.length != alg.hashLength) { + throw new IllegalArgumentException(String.format("Invalid %s hash", alg)); } } public static CertificateHash of(X509Certificate cert) { + return of(cert, DigestAlgorithm.SHA1); + } + + public static CertificateHash of(X509Certificate cert, DigestAlgorithm alg) { return new CertificateHash(toSupplier(() -> { - final MessageDigest md = MessageDigest.getInstance("SHA-1"); + final MessageDigest md = alg.createDigest.get(); md.update(cert.getEncoded()); return md.digest(); - }).get()); + }).get(), alg); } @Override @@ -601,14 +680,61 @@ String verifyPolicy() { private final String verifyPolicy; } - public record CertificateRequest(String name, CertificateType type, int days) implements Comparable{ + public enum StandardCertificateNamePrefix { + CODE_SIGND("Developer ID Application: "), + INSTALLER("Developer ID Installer: "); + + StandardCertificateNamePrefix(String value) { + this.value = Objects.requireNonNull(value); + } + + public String value() { + return value; + } + + private final String value; + } + + public record NameWithPrefix(String prefix, String name) { + public NameWithPrefix { + Objects.requireNonNull(prefix); + Objects.requireNonNull(name); + } + } + + public record CertificateRequest(String name, CertificateType type, int days, boolean expired, boolean trusted) + implements Comparable { + public CertificateRequest { Objects.requireNonNull(name); Objects.requireNonNull(type); + if (days <= 0) { + throw new IllegalArgumentException(); + } } - CertificateRequest(X509Certificate cert) { - this(getSubjectCN(cert), getType(cert), getDurationInDays(cert)); + public String shortName() { + return nameWithPrefix().map(NameWithPrefix::name).orElseThrow(); + } + + public Optional nameWithPrefix() { + return Stream.of(StandardCertificateNamePrefix.values()).map(StandardCertificateNamePrefix::value).filter(prefix -> { + return name.startsWith(prefix); + }).map(prefix -> { + return new NameWithPrefix(prefix, name.substring(prefix.length())); + }).findAny(); + } + + VerifyStatus expectedVerifyStatus() { + if (expired && !trusted) { + return VerifyStatus.VERIFY_EXPIRED_UNTRUSTED; + } else if (!trusted) { + return VerifyStatus.VERIFY_UNTRUSTED; + } else if (expired) { + return VerifyStatus.VERIFY_EXPIRED; + } else { + return VerifyStatus.VERIFY_OK; + } } @Override @@ -623,8 +749,8 @@ public Builder userName(String v) { return this; } - public Builder commonName(String v) { - commonName = v; + public Builder subjectCommonName(String v) { + subjectCommonName = v; return this; } @@ -638,8 +764,26 @@ public Builder days(int v) { return this; } + public Builder expired(boolean v) { + expired = v; + return this; + } + + public Builder expired() { + return expired(true); + } + + public Builder trusted(boolean v) { + trusted = v; + return this; + } + + public Builder untrusted() { + return trusted(false); + } + public CertificateRequest create() { - return new CertificateRequest(validatedCN(), type, days); + return new CertificateRequest(validatedCN(), type, days, expired, trusted); } private String validatedUserName() { @@ -647,13 +791,13 @@ private String validatedUserName() { } private String validatedCN() { - return Optional.ofNullable(commonName).orElseGet(() -> { + return Optional.ofNullable(subjectCommonName).orElseGet(() -> { switch (type) { case CODE_SIGN -> { - return "Developer ID Application: " + validatedUserName(); + return StandardCertificateNamePrefix.CODE_SIGND.value() + validatedUserName(); } case INSTALLER -> { - return "Developer ID Installer: " + validatedUserName(); + return StandardCertificateNamePrefix.INSTALLER.value() + validatedUserName(); } default -> { throw new UnsupportedOperationException(); @@ -663,9 +807,41 @@ private String validatedCN() { } private String userName; - private String commonName; // CN + private String subjectCommonName; // CN private CertificateType type = CertificateType.CODE_SIGN; private int days = 365; + private boolean expired; + private boolean trusted = true; + } + + private static final Comparator COMPARATOR = + Comparator.comparing(CertificateRequest::name) + .thenComparing(Comparator.comparing(CertificateRequest::type)) + .thenComparing(Comparator.comparingInt(CertificateRequest::days)) + .thenComparing(Comparator.comparing(CertificateRequest::expired, Boolean::compare)) + .thenComparing(Comparator.comparing(CertificateRequest::trusted, Boolean::compare)); + } + + private record InstalledCertificate(String name, CertificateType type, int days, boolean expired) implements Comparable { + InstalledCertificate { + Objects.requireNonNull(name); + Objects.requireNonNull(type); + if (days <= 0) { + throw new IllegalArgumentException(); + } + } + + InstalledCertificate(X509Certificate cert) { + this(getSubjectCN(cert), getType(cert), getDurationInDays(cert), getExpired(cert)); + } + + boolean match(CertificateRequest request) { + return name.equals(request.name()) && type.equals(request.type()) && days == request.days() && expired == request.expired(); + } + + @Override + public int compareTo(InstalledCertificate o) { + return COMPARATOR.compare(this, o); } private static String getSubjectCN(X509Certificate cert) { @@ -697,13 +873,23 @@ private static CertificateType getType(X509Certificate cert) { private static int getDurationInDays(X509Certificate cert) { final var notBefore = cert.getNotBefore(); final var notAfter = cert.getNotAfter(); - return (int)TimeUnit.DAYS.convert(notAfter.getTime() - notBefore.getTime(), TimeUnit.MILLISECONDS); + return (int) TimeUnit.DAYS.convert(notAfter.getTime() - notBefore.getTime(), TimeUnit.MILLISECONDS); } - private static final Comparator COMPARATOR = - Comparator.comparing(CertificateRequest::name) - .thenComparing(Comparator.comparing(CertificateRequest::type)) - .thenComparing(Comparator.comparingInt(CertificateRequest::days)); + private static boolean getExpired(X509Certificate cert) { + try { + cert.checkValidity(); + return false; + } catch (CertificateExpiredException | CertificateNotYetValidException ex) { + return true; + } + } + + private static final Comparator COMPARATOR = + Comparator.comparing(InstalledCertificate::name) + .thenComparing(Comparator.comparing(InstalledCertificate::type)) + .thenComparing(Comparator.comparingInt(InstalledCertificate::days)) + .thenComparing(Comparator.comparing(InstalledCertificate::expired, Boolean::compare)); } /** @@ -715,8 +901,10 @@ private static int getDurationInDays(X509Certificate cert) { * Created certificates will be imported into the keychains, and every * certificate will be marked as trusted. *

- * The user will be prompted to enter the user login password as - * many times as the number of unique certificates this function will create. + * The user will be prompted to enter the user login password as many times as + * the number of unique certificates this function will create. + *

+ * Created keychains will NOT be added to the keychain search list. * * @param specs the keychains and signing identities configuration */ @@ -767,14 +955,14 @@ public static void setUp(List specs) { "-A").execute(); }); - trustConfig.put(certPemFile.getValue(), keychains.getFirst()); + if (certPemFile.getKey().trusted()) { + trustConfig.put(certPemFile.getValue(), keychains.getFirst()); + } } // Trust certificates. trustCertificates(trustConfig); }); - - Keychain.addToSearchList(specs.stream().map(KeychainWithCertsSpec::keychain).toList()); } /** @@ -820,11 +1008,11 @@ public static boolean isDeployed(List specs) { TKit.trace(String.format("In [%s] keychain:", keychain.name())); final var certificateStat = certificateStats.get(keychain); final var resolvedCertificateRequests = certificateStat.allResolvedCertificateRequests().stream() - .sorted(Comparator.comparing(ResolvedCertificateRequest::request)).toList(); + .sorted(Comparator.comparing(ResolvedCertificateRequest::installed)).toList(); for (final var resolvedCertificateRequest : resolvedCertificateRequests) { TKit.trace(String.format(" Certificate with hash=%s: %s[%s]", CertificateHash.of(resolvedCertificateRequest.cert()), - resolvedCertificateRequest.request(), + resolvedCertificateRequest.installed(), resolvedCertificateRequest.verifyStatus())); } @@ -849,7 +1037,31 @@ public static boolean isDeployed(List specs) { return !missingKeychain && !missingCertificates && !invalidCertificates; } - public static Map mapCertificateRequests(KeychainWithCertsSpec spec) { + public final static class ResolvedKeychain { + public ResolvedKeychain(KeychainWithCertsSpec spec) { + this.spec = Objects.requireNonNull(spec); + } + + public KeychainWithCertsSpec spec() { + return spec; + } + + public Map mapCertificateRequests() { + if (certMap == null) { + synchronized (this) { + if (certMap == null) { + certMap = MacSign.mapCertificateRequests(spec); + } + } + } + return certMap; + } + + private final KeychainWithCertsSpec spec; + private volatile Map certMap; + } + + private static Map mapCertificateRequests(KeychainWithCertsSpec spec) { return CertificateStats.get(spec).mapKnownCertificateRequests().entrySet().stream().collect(toMap(Map.Entry::getKey, e -> { return e.getValue().stream().reduce((x, y) -> { throw new IllegalStateException(String.format( @@ -876,18 +1088,39 @@ private static void validate(List specs) { }); } - private static boolean verifyCertificate(ResolvedCertificateRequest resolvedCertificateRequest, Keychain keychain, Path certFile) { + private static VerifyStatus verifyCertificate(ResolvedCertificateRequest resolvedCertificateRequest, Keychain keychain, Path certFile) { PemData.of(resolvedCertificateRequest.cert()).save(certFile, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); - for (final var mode : List.of("-q", "-v")) { - final var ok = security("verify-cert", "-L", "-n", mode, + Executor.Result result = null; + for (final var quite : List.of(true, false)) { + result = security("verify-cert", "-L", "-n", + quite ? "-q" : "-v", "-c", certFile.normalize().toString(), "-k", keychain.name(), - "-p", resolvedCertificateRequest.request().type().verifyPolicy()).executeWithoutExitCodeCheck().getExitCode() == 0; - if (ok) { - return true; + "-p", resolvedCertificateRequest.installed().type().verifyPolicy()).saveOutput(!quite).executeWithoutExitCodeCheck(); + if (result.exitCode() == 0) { + return VerifyStatus.VERIFY_OK; } } - return false; + + final var expired = result.getOutput().stream().anyMatch(line -> { + // Look up for "Certificate has expired, or is not yet valid (check date) [TemporalValidity]" string + return line.contains(" Certificate has expired, or is not yet valid (check date) [TemporalValidity]"); + }); + + final var untrusted = result.getOutput().stream().anyMatch(line -> { + // Look up for "The root of the certificate chain is not trusted [AnchorTrusted]" string + return line.contains(" The root of the certificate chain is not trusted [AnchorTrusted]"); + }); + + if (expired && untrusted) { + return VerifyStatus.VERIFY_EXPIRED_UNTRUSTED; + } else if (untrusted) { + return VerifyStatus.VERIFY_UNTRUSTED; + } else if (expired) { + return VerifyStatus.VERIFY_EXPIRED; + } else { + return VerifyStatus.VERIFY_ERROR; + } } private static void traceSigningEnvironment(Collection specs) { @@ -968,7 +1201,15 @@ private static Map createCertificates(Keychain private "CN=" + certificateRequest.name() )); - final var openssl = Executor.of(OPENSSL.toString(), "req", + final Executor openssl; + if (certificateRequest.expired()) { + final var format = String.format("-%dd", certificateRequest.days + 1); + openssl = Executor.of(FAKETIME.toString(), "-f", format, OPENSSL.toString()); + } else { + openssl = Executor.of(OPENSSL.toString()); + } + + openssl.addArguments("req", "-x509", "-utf8", "-sha256", "-nodes", "-new", // Prevents LibreSSL variant of openssl command from hanging "-days", Integer.toString(certificateRequest.days()), @@ -1040,4 +1281,8 @@ static Executor security(String... args) { // /usr/bin/openssl will preempt /usr/local/bin/openssl. // To workaround this jtreg behavior support specifying path to openssl command. private static final Path OPENSSL = Path.of(Optional.ofNullable(TKit.getConfigProperty("openssl")).orElse("openssl")); + + // faketime is not a standard macOS command. + // One way to get it is with Homebrew. + private static final Path FAKETIME = Path.of(Optional.ofNullable(TKit.getConfigProperty("faketime")).orElse("faketime")); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java new file mode 100644 index 0000000000000..9fcd54d156687 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; +import static jdk.jpackage.test.MacSign.DigestAlgorithm.SHA256; + +import java.nio.file.Path; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.HexFormat; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Pattern; +import jdk.jpackage.internal.util.PListReader; +import jdk.jpackage.test.MacSign.CertificateHash; +import jdk.jpackage.test.MacSign.CertificateRequest; + +/** + * Utilities to verify sign signatures. + */ +public final class MacSignVerify { + + public static void assertSigned(Path path, CertificateRequest certRequest) { + assertSigned(path); + TKit.assertEquals(certRequest.name(), findCodesignSignOrigin(path).orElse(null), + String.format("Check [%s] signed with certificate", path)); + } + + public static void assertAdhocSigned(Path path) { + assertSigned(path); + TKit.assertEquals(ADHOC_SIGN_ORIGIN, findCodesignSignOrigin(path).orElse(null), + String.format("Check [%s] signed with adhoc signature", path)); + } + + public static void assertUnsigned(Path path) { + TKit.assertTrue(findSpctlSignOrigin(SpctlType.EXEC, path).isEmpty(), + String.format("Check [%s] unsigned", path)); + } + + public static void assertPkgSigned(Path path, CertificateRequest certRequest, X509Certificate cert) { + final var expectedCertChain = List.of(new SignIdentity(certRequest.name(), CertificateHash.of(cert, SHA256))); + final var actualCertChain = getPkgCertificateChain(path); + TKit.assertStringListEquals( + expectedCertChain.stream().map(SignIdentity::toString).toList(), + actualCertChain.stream().map(SignIdentity::toString).toList(), + String.format("Check certificate chain of [%s] is as expected", path)); + TKit.assertEquals(certRequest.name(), findSpctlSignOrigin(SpctlType.INSTALL, path).orElse(null), + String.format("Check [%s] signed for installation", path)); + } + + public enum SpctlType { + EXEC("exec"), INSTALL("install"); + + SpctlType(String value) { + this.value = Objects.requireNonNull(value); + } + + public String value() { + return value; + } + + final private String value; + } + + public static final String ADHOC_SIGN_ORIGIN = "-"; + + public static Optional findSpctlSignOrigin(SpctlType type, Path path) { + final var exec = Executor.of("/usr/sbin/spctl", "-vv", "--raw", "--assess", "--type", type.value(), path.toString()).saveOutput().discardStderr(); + final var result = exec.executeWithoutExitCodeCheck(); + TKit.assertTrue(Set.of(0, 3).contains(result.exitCode()), + String.format("Check exit code of command %s is either 0 or 3", exec.getPrintableCommandLine())); + return toSupplier(() -> { + try { + return Optional.of(new PListReader(String.join("", result.getOutput()).getBytes()).queryValue("assessment:originator")); + } catch (NoSuchElementException ex) { + return Optional.empty(); + } + }).get(); + } + + public static Optional findCodesignSignOrigin(Path path) { + final var exec = Executor.of("/usr/bin/codesign", "--display", "--verbose=4", path.toString()).saveOutput(); + final var result = exec.executeWithoutExitCodeCheck(); + if (result.getExitCode() == 0) { + return Optional.of(result.getOutput().stream().map(line -> { + if (line.equals("Signature=adhoc")) { + return ADHOC_SIGN_ORIGIN; + } else if (line.startsWith("Authority=")) { + return line.substring("Authority=".length()); + } else { + return null; + } + }).filter(Objects::nonNull).reduce((x, y) -> { + throw new UnsupportedOperationException(String.format( + "Both adhoc [%s] and certificate [%s] signatures found in codesign output", x, y)); + }).orElseThrow(() -> { + final var msg = "Neither adhoc nor certificate signatures found in codesign output"; + TKit.trace(msg + ":"); + result.getOutput().forEach(TKit::trace); + TKit.trace("Done"); + return new UnsupportedOperationException(msg); + })); + } else if (result.getExitCode() == 1 && result.getFirstLineOfOutput().endsWith("code object is not signed at all")) { + return Optional.empty(); + } else { + reportUnexpectedCommandOutcome(exec.getPrintableCommandLine(), result); + return null; // Unreachable + } + } + + public static void assertSigned(Path path) { + final var verifier = TKit.assertTextStream(": valid on disk").predicate(String::endsWith).andThen(TKit.assertTextStream(": satisfies its Designated Requirement").predicate(String::endsWith)); + verifier.apply(Executor.of("/usr/bin/codesign", "--verify", "--deep", + "--strict", "--verbose=2", path.toString()).executeAndGetOutput().stream()); + } + + public static List getPkgCertificateChain(Path path) { + // + // Typical output of `/usr/sbin/pkgutil --check-signature`: + // Package "foo.pkg": + // Status: signed by a developer certificate issued by Apple for distribution + // Notarization: trusted by the Apple notary service + // Signed with a trusted timestamp on: 2022-05-10 19:54:56 +0000 + // Certificate Chain: + // 1. Developer ID Installer: Foo + // SHA256 Fingerprint: + // 4A A9 4A 85 20 2A DE 02 B2 9B 36 DA 45 00 B4 40 CF 31 43 4E 96 02 + // 60 6A 6D BC 02 F4 5D 3A 86 4A + // ------------------------------------------------------------------------ + // 2. Developer ID Certification Authority + // Expires: 2027-02-01 22:12:15 +0000 + // SHA256 Fingerprint: + // 7A FC 9D 01 A6 2F 03 A2 DE 96 37 93 6D 4A FE 68 09 0D 2D E1 8D 03 + // F2 9C 88 CF B0 B1 BA 63 58 7F + // ------------------------------------------------------------------------ + // 3. Apple Root CA + // Expires: 2035-02-09 21:40:36 +0000 + // SHA256 Fingerprint: + // B0 B1 73 0E CB C7 FF 45 05 14 2C 49 F1 29 5E 6E DA 6B CA ED 7E 2C + // 68 C5 BE 91 B5 A1 10 01 F0 24 + final var exec = Executor.of("/usr/sbin/pkgutil", "--check-signature", path.toString()).saveOutput(); + final var result = exec.executeWithoutExitCodeCheck(); + if (result.getExitCode() == 0) { + try { + final List signIdentities = new ArrayList<>(); + final var lineIt = result.getOutput().iterator(); + while (!lineIt.next().endsWith("Certificate Chain:")) { + + } + do { + final var m = SIGN_IDENTITY_NAME_REGEXP.matcher(lineIt.next()); + m.find(); + final var name = m.group(1); + while (!lineIt.next().endsWith("SHA256 Fingerprint:")) { + + } + final var digest = new StringBuilder(); + do { + final var line = lineIt.next().strip(); + if (line.endsWith("----") || line.isEmpty()) { + break; + } + digest.append(" " + line.strip()); + } while (lineIt.hasNext()); + final var fingerprint = new CertificateHash( + FINGERPRINT_FORMAT.parseHex(digest.substring(1)), SHA256); + signIdentities.add(new SignIdentity(name, fingerprint)); + } while (lineIt.hasNext()); + return signIdentities; + } catch (Throwable t) { + t.printStackTrace(); + reportUnexpectedCommandOutcome(exec.getPrintableCommandLine(), result); + return null; // Unreachable + } + } else if (result.getExitCode() == 1 && result.getOutput().getLast().endsWith("Status: no signature")) { + return List.of(); + } else { + reportUnexpectedCommandOutcome(exec.getPrintableCommandLine(), result); + return null; // Unreachable + } + } + + public record SignIdentity(String name, CertificateHash fingerprint) { + public SignIdentity { + Objects.requireNonNull(name); + Objects.requireNonNull(fingerprint); + } + } + + private static void reportUnexpectedCommandOutcome(String printableCommandLine, Executor.Result result) { + Objects.requireNonNull(printableCommandLine); + Objects.requireNonNull(result); + TKit.trace(String.format("Command %s exited with exit code %d and the following output:", + printableCommandLine, result.getExitCode())); + result.getOutput().forEach(TKit::trace); + TKit.trace("Done"); + TKit.assertUnexpected(String.format("Outcome of command %s", printableCommandLine)); + } + + private static final Pattern SIGN_IDENTITY_NAME_REGEXP = Pattern.compile("^\\s+\\d+\\.\\s+(.*)$"); + private static final HexFormat FINGERPRINT_FORMAT = HexFormat.ofDelimiter(" ").withUpperCase(); +} diff --git a/test/jdk/tools/jpackage/macosx/MacSignTest.java b/test/jdk/tools/jpackage/macosx/MacSignTest.java index 4313f1900e294..7b2e06dc7ca65 100644 --- a/test/jdk/tools/jpackage/macosx/MacSignTest.java +++ b/test/jdk/tools/jpackage/macosx/MacSignTest.java @@ -24,12 +24,23 @@ import java.io.IOException; import java.nio.file.Files; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Stream; +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.JPackageCommand; import jdk.jpackage.test.JPackageStringBundle; import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.MacSign; +import jdk.jpackage.test.MacSign.CertificateRequest; +import jdk.jpackage.test.MacSignVerify; +import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; /* @@ -64,23 +75,173 @@ public static void testAppContentWarning() throws IOException { expectedStrings.add(xcodeWarning); } - // --app-content and --type app-image - // Expect `message.codesign.failed.reason.app.content` message in the log. - // This is not a fatal error, just a warning. - // To make jpackage fail, specify bad additional content. - final var cmd = JPackageCommand.helloAppImage() - .ignoreDefaultVerbose(true) - .validateOutput(expectedStrings.toArray(CannedFormattedString[]::new)) - .addArguments("--app-content", appContent) - .addArguments("--mac-sign") - .addArguments("--mac-signing-keychain", SigningBase.StandardKeychain.MAIN.spec().keychain().name()) - .addArguments("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.APP_IMAGE.spec().name()); - - if (MacHelper.isXcodeDevToolsInstalled()) { - // Check there is no warning about missing xcode command line developer tools. - cmd.validateOutput(TKit.assertTextStream(xcodeWarning.getValue()).negate()); + final var keychain = SigningBase.StandardKeychain.EXPIRED.spec().keychain(); + + MacSign.Keychain.withAddedKeychains(List.of(keychain), () -> { + // --app-content and --type app-image + // Expect `message.codesign.failed.reason.app.content` message in the log. + // This is not a fatal error, just a warning. + // To make jpackage fail, specify bad additional content. + final var cmd = JPackageCommand.helloAppImage() + .ignoreDefaultVerbose(true) + .validateOutput(expectedStrings.toArray(CannedFormattedString[]::new)) + .addArguments("--app-content", appContent) + .addArguments("--mac-sign") + .addArguments("--mac-signing-keychain", keychain.name()) + .addArguments("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.CODESIGN.spec().name()); + + if (MacHelper.isXcodeDevToolsInstalled()) { + // Check there is no warning about missing xcode command line developer tools. + cmd.validateOutput(TKit.assertTextStream(xcodeWarning.getValue()).negate()); + } + + cmd.execute(1); + }); + } + + @Test + @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({"IMAGE", "EXPIRED_SIGN_IDENTITY"}) + @Parameter({"MAC_DMG", "EXPIRED_SIGN_IDENTITY"}) + @Parameter({"MAC_PKG", "EXPIRED_SIGN_IDENTITY"}) + + @Parameter({"IMAGE", "EXPIRED_CODESIGN_SIGN_IDENTITY"}) + @Parameter({"MAC_DMG", "EXPIRED_CODESIGN_SIGN_IDENTITY"}) + @Parameter({"MAC_PKG", "EXPIRED_CODESIGN_SIGN_IDENTITY"}) + + @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) { + + final var keychain = SigningBase.StandardKeychain.EXPIRED.spec().keychain(); + + MacSign.Keychain.withAddedKeychains(List.of(keychain), () -> { + final var cmd = JPackageCommand.helloAppImage() + .ignoreDefaultVerbose(true) + .addArguments("--mac-sign") + .addArguments("--mac-signing-keychain", keychain.name()) + .addArguments(Stream.of(options).map(SignOption::args).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()); + }).execute(1); + }); + } + + @Test + @Parameter({"IMAGE", "GOOD_SIGNING_KEY_USER_NAME"}) + @Parameter({"MAC_DMG", "GOOD_SIGNING_KEY_USER_NAME"}) + @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) { + + final var keychain = SigningBase.StandardKeychain.DUPLICATE.spec().keychain(); + + MacSign.Keychain.withAddedKeychains(List.of(keychain), () -> { + final var cmd = JPackageCommand.helloAppImage() + .ignoreDefaultVerbose(true) + .addArguments("--mac-sign") + .addArguments("--mac-signing-keychain", keychain.name()) + .addArguments(Stream.of(options).map(SignOption::args).flatMap(List::stream).toList()) + .setPackageType(type); + + SignOption.configureOutputValidation(cmd, List.of(options), opt -> { + return JPackageStringBundle.MAIN.cannedFormattedString("error.multiple.certs.found", opt.identityName(), keychain.name()); + }).execute(1); + }); + } + + @Test + @ParameterSupplier + public static void testSelectSigningIdentity(String signingKeyUserName, CertificateRequest certRequest) { + + final var keychain = SigningBase.StandardKeychain.MAIN.spec().keychain(); + + MacSign.Keychain.withAddedKeychains(List.of(keychain), () -> { + final var cmd = JPackageCommand.helloAppImage() + .setFakeRuntime() + .addArguments("--mac-sign") + .addArguments("--mac-signing-keychain", keychain.name()) + .addArguments("--mac-signing-key-user-name", signingKeyUserName); + + cmd.executeAndAssertHelloAppImageCreated(); + + MacSignVerify.assertSigned(cmd.outputBundle(), certRequest); + }); + } + + public static Collection testSelectSigningIdentity() { + return Stream.of( + SigningBase.StandardCertificateRequest.CODESIGN, + SigningBase.StandardCertificateRequest.CODESIGN_UNICODE + ).map(SigningBase.StandardCertificateRequest::spec).mapMulti((certRequest, acc) -> { + acc.accept(new Object[] {certRequest.shortName(), certRequest}); + acc.accept(new Object[] {certRequest.name(), certRequest}); + }).toList(); + } + + enum SignOption { + EXPIRED_SIGNING_KEY_USER_NAME("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED.spec(), true, false), + EXPIRED_SIGNING_KEY_USER_NAME_PKG("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.PKG_EXPIRED.spec(), true, false), + EXPIRED_SIGN_IDENTITY("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED.spec(), false, false), + EXPIRED_CODESIGN_SIGN_IDENTITY("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED.spec(), false, true), + EXPIRED_PKG_SIGN_IDENTITY("--mac-installer-sign-identity", SigningBase.StandardCertificateRequest.PKG_EXPIRED.spec(), false, true), + GOOD_SIGNING_KEY_USER_NAME("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.CODESIGN.spec(), true, false), + GOOD_SIGNING_KEY_USER_NAME_PKG("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.PKG.spec(), true, false), + GOOD_CODESIGN_SIGN_IDENTITY("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.CODESIGN.spec(), false, true), + GOOD_PKG_SIGN_IDENTITY("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.PKG.spec(), false, true); + + SignOption(String option, MacSign.CertificateRequest cert, boolean shortName, boolean passThrough) { + this.option = Objects.requireNonNull(option); + this.cert = Objects.requireNonNull(cert); + this.shortName = shortName; + this.passThrough = passThrough; + } + + boolean passThrough() { + return passThrough; + } + + boolean expired() { + return cert.expired(); + } + + String identityName() { + return cert.name(); + } + + List args() { + return List.of(option, shortName ? cert.shortName() : cert.name()); + } + + 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; } - cmd.execute(1); + private final String option; + private final MacSign.CertificateRequest cert; + private final boolean shortName; + private final boolean passThrough; } } diff --git a/test/jdk/tools/jpackage/macosx/base/SigningBase.java b/test/jdk/tools/jpackage/macosx/base/SigningBase.java index e3237197c7422..5484245f111dd 100644 --- a/test/jdk/tools/jpackage/macosx/base/SigningBase.java +++ b/test/jdk/tools/jpackage/macosx/base/SigningBase.java @@ -22,16 +22,18 @@ */ import java.nio.file.Path; +import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.stream.Stream; -import jdk.jpackage.test.Executor; -import jdk.jpackage.test.Executor.Result; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.MacSign; -import jdk.jpackage.test.MacSign.CertificateType; import jdk.jpackage.test.MacSign.CertificateRequest; +import jdk.jpackage.test.MacSign.CertificateType; import jdk.jpackage.test.MacSign.KeychainWithCertsSpec; +import jdk.jpackage.test.MacSign.ResolvedKeychain; +import jdk.jpackage.test.MacSignVerify; import jdk.jpackage.test.TKit; @@ -64,10 +66,14 @@ public class SigningBase { public enum StandardCertificateRequest { - APP_IMAGE(cert().userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), - INSTALLER(cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), - APP_IMAGE_UNICODE(cert().userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()])), - INSTALLER_UNICODE(cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()])); + CODESIGN(cert().userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), + CODESIGN_COPY(cert().days(100).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), + PKG(cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), + PKG_COPY(cert().type(CertificateType.INSTALLER).days(100).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), + CODESIGN_UNICODE(cert().userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()])), + PKG_UNICODE(cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()])), + CODESIGN_EXPIRED(cert().expired().userName("expired jpackage test")), + PKG_EXPIRED(cert().expired().type(CertificateType.INSTALLER).userName("expired jpackage test")); StandardCertificateRequest(CertificateRequest.Builder specBuilder) { this.spec = specBuilder.create(); @@ -85,7 +91,21 @@ private static CertificateRequest.Builder cert() { } public enum StandardKeychain { - MAIN(DEFAULT_KEYCHAIN, StandardCertificateRequest.values()); + MAIN(DEFAULT_KEYCHAIN, + StandardCertificateRequest.CODESIGN, + StandardCertificateRequest.PKG, + StandardCertificateRequest.CODESIGN_UNICODE, + StandardCertificateRequest.PKG_UNICODE), + EXPIRED("jpackagerTest-expired.keychain", + StandardCertificateRequest.CODESIGN, + StandardCertificateRequest.PKG, + StandardCertificateRequest.CODESIGN_EXPIRED, + StandardCertificateRequest.PKG_EXPIRED), + DUPLICATE("jpackagerTest-duplicate.keychain", + StandardCertificateRequest.CODESIGN, + StandardCertificateRequest.PKG, + StandardCertificateRequest.CODESIGN_COPY, + StandardCertificateRequest.PKG_COPY); StandardKeychain(String keychainName, StandardCertificateRequest... certs) { this(keychainName, certs[0].spec(), Stream.of(certs).skip(1).map(StandardCertificateRequest::spec).toArray(CertificateRequest[]::new)); @@ -94,11 +114,15 @@ public enum StandardKeychain { StandardKeychain(String keychainName, CertificateRequest cert, CertificateRequest... otherCerts) { final var builder = keychain(keychainName).addCert(cert); List.of(otherCerts).forEach(builder::addCert); - this.spec = builder.create(); + this.spec = new ResolvedKeychain(builder.create()); } public KeychainWithCertsSpec spec() { - return spec; + return spec.spec(); + } + + public X509Certificate mapCertificateRequest(CertificateRequest certRequest) { + return Objects.requireNonNull(spec.mapCertificateRequests().get(certRequest)); } private static KeychainWithCertsSpec.Builder keychain(String name) { @@ -113,7 +137,7 @@ private static List signingEnv() { return Stream.of(values()).map(StandardKeychain::spec).toList(); } - private final KeychainWithCertsSpec spec; + private final ResolvedKeychain spec; } public static void setUp() { @@ -131,7 +155,7 @@ public static void verifySignTestEnvReady() { } private final class Inner { - private final static boolean SIGN_ENV_READY = MacSign.isDeployed(StandardKeychain.signingEnv()); + private static final boolean SIGN_ENV_READY = MacSign.isDeployed(StandardKeychain.signingEnv()); } enum CertIndex { @@ -199,165 +223,60 @@ public static String getKeyChain() { return DEFAULT_KEYCHAIN; } - // Note: It is not clear if we can combine "--verify" and "--display", so - // we testing them separately. Since JDK-8298488 unsigned app images are - // actually signed with adhoc signature and it will pass "--verify", so in - // addition we will check certificate name which was used to sign. - private static enum CodesignCheckType { - VERIFY, // Runs codesign with "--verify" to check signature and 0 exit code - VERIFY_UNSIGNED, // Runs codesign with "--verify" to check signature and 1 exit code - DISPLAY // Runs codesign with "--display --verbose=4" to get info about signature - }; - - private static void checkString(List result, String lookupString) { - TKit.assertTextStream(lookupString).predicate( - (line, what) -> line.trim().contains(what)).apply(result.stream()); - } - - @SuppressWarnings("fallthrough") - private static List codesignResult(Path target, CodesignCheckType type) { - int exitCode = 0; - Executor executor = new Executor().setExecutable("/usr/bin/codesign"); - switch (type) { - case VERIFY_UNSIGNED: - exitCode = 1; - case VERIFY: - executor.addArguments("--verify", "--deep", "--strict", - "--verbose=2", target.toString()); - break; - case DISPLAY: - executor.addArguments("--display", "--verbose=4", target.toString()); - break; - default: - TKit.error("Unknown CodesignCheckType: " + type); - break; - } - return executor.saveOutput().execute(exitCode).getOutput(); - } - - private static void verifyCodesignResult(List result, Path target, - boolean signed, CodesignCheckType type, int certIndex) { - result.stream().forEachOrdered(TKit::trace); - String lookupString; - switch (type) { - case VERIFY: - lookupString = target.toString() + ": valid on disk"; - checkString(result, lookupString); - lookupString = target.toString() + ": satisfies its Designated Requirement"; - checkString(result, lookupString); - break; - case VERIFY_UNSIGNED: - lookupString = target.toString() + ": code object is not signed at all"; - checkString(result, lookupString); - break; - case DISPLAY: - if (signed) { - lookupString = "Authority=" + getAppCert(certIndex); - } else { - lookupString = "Signature=adhoc"; - } - checkString(result, lookupString); - break; - default: - TKit.error("Unknown CodesignCheckType: " + type); - break; - } - } - - private static Result spctlResult(Path target, String type) { - Result result = new Executor() - .setExecutable("/usr/sbin/spctl") - .addArguments("-vvv", "--assess", "--type", type, - target.toString()) - .saveOutput() - .executeWithoutExitCodeCheck(); - - // allow exit code 3 for not being notarized - if (result.getExitCode() != 3) { - result.assertExitCodeIsZero(); - } - return result; - } - - private static void verifySpctlResult(List output, Path target, - String type, int exitCode, int certIndex) { - output.stream().forEachOrdered(TKit::trace); - String lookupString; - - if (exitCode == 0) { - lookupString = target.toString() + ": accepted"; - checkString(output, lookupString); - } else if (exitCode == 3) { - // allow failure purely for not being notarized - lookupString = target.toString() + ": rejected"; - checkString(output, lookupString); - } - - if (type.equals("install")) { - lookupString = "origin=" + getInstallerCert(certIndex); - } else { - lookupString = "origin=" + getAppCert(certIndex); - } - checkString(output, lookupString); - } - - private static List pkgutilResult(Path target, boolean signed) { - List result = new Executor() - .setExecutable("/usr/sbin/pkgutil") - .addArguments("--check-signature", - target.toString()) - .saveOutput() - .execute(signed ? 0 : 1) - .getOutput(); - - return result; - } - - private static void verifyPkgutilResult(List result, boolean signed, - int certIndex) { - result.stream().forEachOrdered(TKit::trace); + public static void verifyCodesign(Path target, boolean signed, int certIndex) { if (signed) { - String lookupString = "Status: signed by"; - checkString(result, lookupString); - lookupString = "1. " + getInstallerCert(certIndex); - checkString(result, lookupString); + final var certRequest = getCertRequest(certIndex); + MacSignVerify.assertSigned(target, certRequest); } else { - String lookupString = "Status: no signature"; - checkString(result, lookupString); + MacSignVerify.assertAdhocSigned(target); } } - public static void verifyCodesign(Path target, boolean signed, int certIndex) { - List result = codesignResult(target, CodesignCheckType.VERIFY); - verifyCodesignResult(result, target, signed, CodesignCheckType.VERIFY, certIndex); - - result = codesignResult(target, CodesignCheckType.DISPLAY); - verifyCodesignResult(result, target, signed, CodesignCheckType.DISPLAY, certIndex); - } - // Since we no longer have unsigned app image, but we need to check // DMG which is not adhoc or certificate signed and we cannot use verifyCodesign // for this. verifyDMG() is introduced to check that DMG is unsigned. // Should not be used to validated anything else. public static void verifyDMG(Path target) { if (!target.toString().toLowerCase().endsWith(".dmg")) { - TKit.error("Unexpected target: " + target); + throw new IllegalArgumentException("Unexpected target: " + target); } - List result = codesignResult(target, CodesignCheckType.VERIFY_UNSIGNED); - verifyCodesignResult(result, target, false, CodesignCheckType.VERIFY_UNSIGNED, -1); + MacSignVerify.assertUnsigned(target); } public static void verifySpctl(Path target, String type, int certIndex) { - Result result = spctlResult(target, type); - List output = result.getOutput(); + final var standardCertIndex = Stream.of(CertIndex.values()).filter(v -> { + return v.value() == certIndex; + }).findFirst().orElseThrow(); + + final var standardType = Stream.of(MacSignVerify.SpctlType.values()).filter(v -> { + return v.value().equals(type); + }).findFirst().orElseThrow(); + + final String expectedSignOrigin; + if (standardCertIndex == CertIndex.INVALID_INDEX) { + expectedSignOrigin = null; + } else if (standardType == MacSignVerify.SpctlType.EXEC) { + expectedSignOrigin = getCertRequest(certIndex).name(); + } else if (standardType == MacSignVerify.SpctlType.INSTALL) { + expectedSignOrigin = getPkgCertRequest(certIndex).name(); + } else { + throw new IllegalArgumentException(); + } + + final var signOrigin = MacSignVerify.findSpctlSignOrigin(standardType, target).orElse(null); - verifySpctlResult(output, target, type, result.getExitCode(), certIndex); + TKit.assertEquals(signOrigin, expectedSignOrigin, + String.format("Check [%s] has sign origin as expected", target)); } public static void verifyPkgutil(Path target, boolean signed, int certIndex) { - List result = pkgutilResult(target, signed); - verifyPkgutilResult(result, signed, certIndex); + if (signed) { + final var certRequest = getPkgCertRequest(certIndex); + MacSignVerify.assertPkgSigned(target, certRequest, StandardKeychain.MAIN.mapCertificateRequest(certRequest)); + } else { + MacSignVerify.assertUnsigned(target); + } } public static void verifyAppImageSignature(JPackageCommand appImageCmd, @@ -378,4 +297,31 @@ public static void verifyAppImageSignature(JPackageCommand appImageCmd, } } + private static CertificateRequest getCertRequest(int certIndex) { + switch (CertIndex.values()[certIndex]) { + case ASCII_INDEX -> { + return StandardCertificateRequest.CODESIGN.spec(); + } + case UNICODE_INDEX -> { + return StandardCertificateRequest.CODESIGN_UNICODE.spec(); + } + default -> { + throw new IllegalArgumentException(); + } + } + } + + private static CertificateRequest getPkgCertRequest(int certIndex) { + switch (CertIndex.values()[certIndex]) { + case ASCII_INDEX -> { + return StandardCertificateRequest.PKG.spec(); + } + case UNICODE_INDEX -> { + return StandardCertificateRequest.PKG_UNICODE.spec(); + } + default -> { + throw new IllegalArgumentException(); + } + } + } } From 7a72f0fac9a0704c4a0ada781f1cadd7c4903b3e Mon Sep 17 00:00:00 2001 From: Alisen Chung Date: Tue, 22 Apr 2025 01:03:45 +0000 Subject: [PATCH 0679/1101] 8354465: Open some JTable bugs 8 Reviewed-by: serb, kizune --- .../swing/JTable/CheckBoxFirstClick.java | 185 +++++++++++++++++ .../swing/JTable/IllegalStateException.java | 187 ++++++++++++++++++ test/jdk/javax/swing/JTable/bug4139910.java | 68 +++++++ test/jdk/javax/swing/JTable/bug4226181.java | 87 ++++++++ test/jdk/javax/swing/JTable/bug4239157.java | 85 ++++++++ 5 files changed, 612 insertions(+) create mode 100644 test/jdk/javax/swing/JTable/CheckBoxFirstClick.java create mode 100644 test/jdk/javax/swing/JTable/IllegalStateException.java create mode 100644 test/jdk/javax/swing/JTable/bug4139910.java create mode 100644 test/jdk/javax/swing/JTable/bug4226181.java create mode 100644 test/jdk/javax/swing/JTable/bug4239157.java diff --git a/test/jdk/javax/swing/JTable/CheckBoxFirstClick.java b/test/jdk/javax/swing/JTable/CheckBoxFirstClick.java new file mode 100644 index 0000000000000..91f8930103eea --- /dev/null +++ b/test/jdk/javax/swing/JTable/CheckBoxFirstClick.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Color; +import java.awt.Dimension; +import javax.swing.DefaultCellEditor; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.border.BevelBorder; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.table.TableModel; + +/* + * @test + * @bug 4115930 + * @summary Verify checkboxes in the table respond to first click. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CheckBoxFirstClick + */ + +public class CheckBoxFirstClick { + private static final String INSTRUCTIONS = """ + Click over the checkbox in the table. It should change state + on the first click. If not - press 'fail'. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(CheckBoxFirstClick::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("ListSizeBug"); + + // Take the dummy data from SwingSet. + final String[] names = {"First Name", "Last Name", "Favorite Color", + "Favorite Number", "Vegetarian"}; + final Object[][] data = { + {"Mark", "Andrews", "Red", 2, true}, + {"Tom", "Ball", "Blue", 99, false}, + {"Alan", "Chung", "Green", 838, false}, + {"Jeff", "Dinkins", "Turquois", 8, true}, + {"Amy", "Fowler", "Yellow", 3, false}, + {"Brian", "Gerhold", "Green", 0, false}, + {"James", "Gosling", "Pink", 21, false}, + {"David", "Karlton", "Red", 1, false}, + {"Dave", "Kloba", "Yellow", 14, false}, + {"Peter", "Korn", "Purple", 12, false}, + {"Phil", "Milne", "Purple", 3, false}, + {"Dave", "Moore", "Green", 88, false}, + {"Hans", "Muller", "Maroon", 5, false}, + {"Rick", "Levenson", "Blue", 2, false}, + {"Tim", "Prinzing", "Blue", 22, false}, + {"Chester", "Rose", "Black", 0, false}, + {"Ray", "Ryan", "Gray", 77, false}, + {"Georges", "Saab", "Red", 4, false}, + {"Willie", "Walker", "Phthalo Blue", 4, false}, + {"Kathy", "Walrath", "Blue", 8, false}, + {"Arnaud", "Weber", "Green", 44, false} + }; + + // Create a model of the data. + TableModel dataModel = new AbstractTableModel() { + // These methods always need to be implemented. + public int getColumnCount() { + return names.length; + } + + public int getRowCount() { + return data.length; + } + + public Object getValueAt(int row, int col) { + return data[row][col]; + } + + // The default implementations of these methods in + // AbstractTableModel would work, but we can refine them. + public String getColumnName(int column) { + return names[column]; + } + + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } + + public boolean isCellEditable(int row, int col) { + return true; + } + + public void setValueAt(Object aValue, int row, int column) { + System.out.println("Setting value to: " + aValue); + data[row][column] = aValue; + } + }; + + // Create the table + JTable tableView = new JTable(dataModel); + // Turn off auto-resizing so that we can set column sizes programmatically. + // In this mode, all columns will get their preferred widths, as set blow. + tableView.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + + // Create a combo box to show that you can use one in a table. + JComboBox comboBox = new JComboBox(); + comboBox.addItem("Red"); + comboBox.addItem("Orange"); + comboBox.addItem("Yellow"); + comboBox.addItem("Green"); + comboBox.addItem("Blue"); + comboBox.addItem("Indigo"); + comboBox.addItem("Violet"); + + TableColumn colorColumn = tableView.getColumn("Favorite Color"); + // Use the combo box as the editor in the "Favorite Color" column. + colorColumn.setCellEditor(new DefaultCellEditor(comboBox)); + + // Set a pink background and tooltip for the Color column renderer. + DefaultTableCellRenderer colorColumnRenderer = new DefaultTableCellRenderer(); + colorColumnRenderer.setBackground(Color.pink); + colorColumnRenderer.setToolTipText("Click for combo box"); + colorColumn.setCellRenderer(colorColumnRenderer); + + // Set a tooltip for the header of the colors column. + TableCellRenderer headerRenderer = colorColumn.getHeaderRenderer(); + if (headerRenderer instanceof DefaultTableCellRenderer) + ((DefaultTableCellRenderer) headerRenderer).setToolTipText("Hi Mom!"); + + // Set the width of the "Vegetarian" column. + TableColumn vegetarianColumn = tableView.getColumn("Vegetarian"); + vegetarianColumn.setPreferredWidth(100); + + // Show the values in the "Favorite Number" column in different colors. + TableColumn numbersColumn = tableView.getColumn("Favorite Number"); + DefaultTableCellRenderer numberColumnRenderer = new DefaultTableCellRenderer() { + public void setValue(Object value) { + int cellValue = (value instanceof Number) ? ((Number) value).intValue() : 0; + setForeground((cellValue > 30) ? Color.black : Color.red); + setText((value == null) ? "" : value.toString()); + } + }; + numberColumnRenderer.setHorizontalAlignment(JLabel.RIGHT); + numbersColumn.setCellRenderer(numberColumnRenderer); + numbersColumn.setPreferredWidth(110); + + // Finish setting up the table. + JScrollPane scrollpane = new JScrollPane(tableView); + scrollpane.setBorder(new BevelBorder(BevelBorder.LOWERED)); + scrollpane.setPreferredSize(new Dimension(430, 200)); + + frame.add(scrollpane); + frame.setSize(500, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/IllegalStateException.java b/test/jdk/javax/swing/JTable/IllegalStateException.java new file mode 100644 index 0000000000000..427b81ab2d90b --- /dev/null +++ b/test/jdk/javax/swing/JTable/IllegalStateException.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Color; +import java.awt.Dimension; +import javax.swing.DefaultCellEditor; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.border.BevelBorder; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.table.TableModel; + +/* + * @test + * @bug 4133143 + * @summary Illegal State exception in ComboBox editor in table + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual IllegalStateException + */ + +public class IllegalStateException { + private static final String INSTRUCTIONS = """ + Click on a cell in the first column, delete the contents but leave the editor with focus. + Click on the third column popping up a combo box. + Verify that the text editor loses focus. + If it does, press "pass", otherwise press "fail". + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(IllegalStateException::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("IllegalStateException"); + + // Take the dummy data from SwingSet. + final String[] names = {"First Name", "Last Name", "Favorite Color", + "Favorite Number", "Vegetarian"}; + final Object[][] data = { + {"Mark", "Andrews", "Red", 2, true}, + {"Tom", "Ball", "Blue", 99, false}, + {"Alan", "Chung", "Green", 838, false}, + {"Jeff", "Dinkins", "Turquois", 8, true}, + {"Amy", "Fowler", "Yellow", 3, false}, + {"Brian", "Gerhold", "Green", 0, false}, + {"James", "Gosling", "Pink", 21, false}, + {"David", "Karlton", "Red", 1, false}, + {"Dave", "Kloba", "Yellow", 14, false}, + {"Peter", "Korn", "Purple", 12, false}, + {"Phil", "Milne", "Purple", 3, false}, + {"Dave", "Moore", "Green", 88, false}, + {"Hans", "Muller", "Maroon", 5, false}, + {"Rick", "Levenson", "Blue", 2, false}, + {"Tim", "Prinzing", "Blue", 22, false}, + {"Chester", "Rose", "Black", 0, false}, + {"Ray", "Ryan", "Gray", 77, false}, + {"Georges", "Saab", "Red", 4, false}, + {"Willie", "Walker", "Phthalo Blue", 4, false}, + {"Kathy", "Walrath", "Blue", 8, false}, + {"Arnaud", "Weber", "Green", 44, false} + }; + + // Create a model of the data. + TableModel dataModel = new AbstractTableModel() { + // These methods always need to be implemented. + public int getColumnCount() { + return names.length; + } + + public int getRowCount() { + return data.length; + } + + public Object getValueAt(int row, int col) { + return data[row][col]; + } + + // The default implementations of these methods in + // AbstractTableModel would work, but we can refine them. + public String getColumnName(int column) { + return names[column]; + } + + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } + + public boolean isCellEditable(int row, int col) { + return true; + } + + public void setValueAt(Object aValue, int row, int column) { + System.out.println("Setting value to: " + aValue); + data[row][column] = aValue; + } + }; + + // Create the table + JTable tableView = new JTable(dataModel); + // Turn off auto-resizing so that we can set column sizes programmatically. + // In this mode, all columns will get their preferred widths, as set blow. + tableView.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + + // Create a combo box to show that you can use one in a table. + JComboBox comboBox = new JComboBox(); + comboBox.addItem("Red"); + comboBox.addItem("Orange"); + comboBox.addItem("Yellow"); + comboBox.addItem("Green"); + comboBox.addItem("Blue"); + comboBox.addItem("Indigo"); + comboBox.addItem("Violet"); + + TableColumn colorColumn = tableView.getColumn("Favorite Color"); + // Use the combo box as the editor in the "Favorite Color" column. + colorColumn.setCellEditor(new DefaultCellEditor(comboBox)); + + // Set a pink background and tooltip for the Color column renderer. + DefaultTableCellRenderer colorColumnRenderer = new DefaultTableCellRenderer(); + colorColumnRenderer.setBackground(Color.pink); + colorColumnRenderer.setToolTipText("Click for combo box"); + colorColumn.setCellRenderer(colorColumnRenderer); + + // Set a tooltip for the header of the colors column. + TableCellRenderer headerRenderer = colorColumn.getHeaderRenderer(); + if (headerRenderer instanceof DefaultTableCellRenderer) + ((DefaultTableCellRenderer) headerRenderer).setToolTipText("Hi Mom!"); + + // Set the width of the "Vegetarian" column. + TableColumn vegetarianColumn = tableView.getColumn("Vegetarian"); + vegetarianColumn.setPreferredWidth(100); + + // Show the values in the "Favorite Number" column in different colors. + TableColumn numbersColumn = tableView.getColumn("Favorite Number"); + DefaultTableCellRenderer numberColumnRenderer = new DefaultTableCellRenderer() { + public void setValue(Object value) { + int cellValue = (value instanceof Number) ? ((Number) value).intValue() : 0; + setForeground((cellValue > 30) ? Color.black : Color.red); + setText((value == null) ? "" : value.toString()); + } + }; + numberColumnRenderer.setHorizontalAlignment(JLabel.RIGHT); + numbersColumn.setCellRenderer(numberColumnRenderer); + numbersColumn.setPreferredWidth(110); + + // Finish setting up the table. + JScrollPane scrollpane = new JScrollPane(tableView); + scrollpane.setBorder(new BevelBorder(BevelBorder.LOWERED)); + scrollpane.setPreferredSize(new Dimension(430, 200)); + + frame.add(scrollpane); + frame.setSize(500, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/bug4139910.java b/test/jdk/javax/swing/JTable/bug4139910.java new file mode 100644 index 0000000000000..c9d6d62cf0c99 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4139910.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.DefaultTableModel; + +/* + * @test + * @bug 4139910 + * @summary Column resize mouse pointer doesn't display in non-resizable JTable. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4139910 + */ + +public class bug4139910 { + private static final String INSTRUCTIONS = """ + Move mouse pointer to the position between "A" and "B" headers. + If mouse pointer does not change its shape then test passes. If + it does then test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4139910::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4139910"); + + String[] colName = {"A", "B"}; + JTable tbl = new JTable(new DefaultTableModel(colName, 6)); + tbl.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + tbl.getTableHeader().setReorderingAllowed(false); + tbl.getTableHeader().setResizingAllowed(false); + JScrollPane sp = new JScrollPane(tbl); + frame.add(sp); + + frame.pack(); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/bug4226181.java b/test/jdk/javax/swing/JTable/bug4226181.java new file mode 100644 index 0000000000000..70749cf5d5599 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4226181.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.BorderLayout; +import java.awt.GridLayout; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; + +/* + * @test + * @bug 4226181 + * @summary Tests that JTable setModel() correctly re-sizes and counts columns + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4226181 + */ + +public class bug4226181 { + private static final String INSTRUCTIONS = """ + Take a look at the table and remember the number of columns you see. + Now press the "setModel" button. If the number of columns has changed, + then test fails, otherwise it passes. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4226181::createTestUI) + .build() + .awaitAndCheck(); + } + + static class TestModel extends AbstractTableModel { + public int getRowCount() { + return 5; + } + + public int getColumnCount() { + return 7; + } + + public Object getValueAt(int row, int column) { + return row + ":" + column; + } + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4226181"); + TestModel testModel = new TestModel(); + final JTable t = new JTable(testModel); + JButton b = new JButton("setModel"); + b.addActionListener(ae -> t.setModel(new TestModel())); + t.setCellSelectionEnabled(true); + JPanel p1 = new JPanel(new GridLayout(1, 2)); + p1.add(new JLabel("dummy")); + p1.add(t); + frame.add(p1); + frame.add(b, BorderLayout.SOUTH); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/bug4239157.java b/test/jdk/javax/swing/JTable/bug4239157.java new file mode 100644 index 0000000000000..025af1615e037 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4239157.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import javax.swing.DefaultCellEditor; +import javax.swing.JFrame; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableColumn; + +/* + * @test + * @bug 4239157 + * @summary Tests that JTable performs cell validation properly + * (i.e. does not accept entries for which stopCellEditing() + * returns false) + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4239157 + */ + +public class bug4239157 { + private static final String INSTRUCTIONS = """ + You see a JTable having one row and two columns. + Click in the very first cell (where "click here" is displayed). + Edit its content (e.g. type some letters) and press right arrow key. + The edited cell should stay active, its content shouldn't change. + The right cell (that with text "inactive forever") shouldn't become active. + The same should be true when you press Tab key. + If it is so, test passes, otherwise it fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4239157::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4239157"); + JTable table = new JTable(new Object[][]{{"click here", + "inactive forever"}}, + new Object[]{"1", "2"}); + frame.add("Center", table); + TableColumn column = table.getColumn("1"); + TableCellEditor editor = new TestEditor(new JTextField()); + column.setCellEditor(editor); + + frame.pack(); + return frame; + } + + static class TestEditor extends DefaultCellEditor { + public TestEditor(JTextField tf) { + super(tf); + } + + public boolean stopCellEditing() { + return false; + } + } +} From ade67df0f363cb95434832f750ac901c1c75c29c Mon Sep 17 00:00:00 2001 From: Alisen Chung Date: Tue, 22 Apr 2025 01:04:48 +0000 Subject: [PATCH 0680/1101] 8354233: Open some JTable bugs 6 Reviewed-by: kizune --- test/jdk/javax/swing/JTable/bug4129401.java | 87 ++++++++++++ test/jdk/javax/swing/JTable/bug4193727.java | 135 ++++++++++++++++++ test/jdk/javax/swing/JTable/bug4242631.java | 144 ++++++++++++++++++++ 3 files changed, 366 insertions(+) create mode 100644 test/jdk/javax/swing/JTable/bug4129401.java create mode 100644 test/jdk/javax/swing/JTable/bug4193727.java create mode 100644 test/jdk/javax/swing/JTable/bug4242631.java diff --git a/test/jdk/javax/swing/JTable/bug4129401.java b/test/jdk/javax/swing/JTable/bug4129401.java new file mode 100644 index 0000000000000..37765d34698a3 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4129401.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import javax.swing.DefaultCellEditor; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.TableColumn; + +/* + * @test + * @bug 4129401 + * @summary Tests that keystroking for combobox cell editor in JTable works + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4129401 + */ + +public class bug4129401 { + private static final String INSTRUCTIONS = """ + 1. Move the mouse cursor to the cell "CELL 2 1", + which contains JComboBox and click left mouse button + to drop down combobox list. + 2. Change selected item in the combobox list + using up and down arrows. + 3. Press Esc. JComboBox drop down list should hide. + If all was successful then test passes, else test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4129401::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + Object data[][] = new Object[4][2]; + JComboBox cb = new JComboBox(); + cb.addItem("Item1"); + cb.addItem("Item2"); + cb.addItem("Item3"); + cb.addItem("Item4"); + data[0][0] = "CELL 0 0"; + data[0][1] = "CELL 0 1"; + data[1][0] = "CELL 1 0"; + data[1][1] = "CELL 1 1"; + data[2][0] = "CELL 2 0"; + data[2][1] = "CELL 2 1"; + data[3][0] = "CELL 3 0"; + data[3][1] = "CELL 3 1"; + String[] str = {"Column 0", "Column 1"}; + JTable tbl = new JTable(data, str); + JScrollPane sp = new JScrollPane(tbl); + + TableColumn col = tbl.getColumn("Column 1"); + col.setCellEditor(new DefaultCellEditor(cb)); + + JFrame f = new JFrame("4129401 test"); + f.getContentPane().add(sp); + f.setBounds(100, 100, 300, 300); + return f; + } +} diff --git a/test/jdk/javax/swing/JTable/bug4193727.java b/test/jdk/javax/swing/JTable/bug4193727.java new file mode 100644 index 0000000000000..2ef4159e90c0a --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4193727.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.FontMetrics; +import java.util.Vector; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; + +/* + * @test + * @bug 4193727 + * @summary Tests that resizing JTable via TableColumn's + * setWidth(int) repaints correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4193727 + */ + +public class bug4193727 { + static EnhancedJTable tblResults; + static JButton bTest = new JButton("Resize"); + + private static final String INSTRUCTIONS = """ + Push button "Resize". + If either of the following happen, test fails: + 1) The size of the columns change + 2) The JTable is not repainted correctly + + Otherwise test passes. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4193727::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4193727"); + Vector v = new Vector(); + Vector data = new Vector(); + Vector cols = new Vector(); + + cols.add("Name"); + cols.add("Address"); + data.add("Steve"); + data.add("100 East Main Street"); + v.add(data); + + data.add("Richard"); + data.add("99 Main Road"); + v.add(data); + + frame.setLayout(new BorderLayout()); + tblResults = new EnhancedJTable(v, cols); + MyTableHeader mth = new MyTableHeader(); + for (int i = 0; i < tblResults.getColumnCount(); i++) + tblResults.getColumnModel().getColumn(i).setHeaderRenderer(mth.getTHR()); + tblResults.setAutoResizeMode(EnhancedJTable.AUTO_RESIZE_OFF); + + JScrollPane pane = new JScrollPane(tblResults); + frame.add(pane, BorderLayout.CENTER); + JPanel panel = new JPanel(); + panel.add(bTest); + frame.add(panel, BorderLayout.EAST); + bTest.addActionListener(e -> tblResults.autoSizeColumns()); + frame.setSize(300, 200); + return frame; + } +} + +class MyTableHeader extends TableColumn { + public TableCellRenderer getTHR() { + return createDefaultHeaderRenderer(); + } +} + +class EnhancedJTable extends JTable { + public EnhancedJTable(Vector data, Vector colNames) { + super(data, colNames); + } + + public synchronized void autoSizeColumns() { + setAutoResizeMode(AUTO_RESIZE_OFF); + int colcnt = getColumnCount(); + int rowcnt = getRowCount(); + + for (int i = 0; i < colcnt; i++) { + // get the max column width needed + Component cell = getColumnModel().getColumn(i).getHeaderRenderer() + .getTableCellRendererComponent(this, null, false, false, -1, i); + FontMetrics fm = cell.getFontMetrics(cell.getFont()); + int max = SwingUtilities.computeStringWidth(fm, getColumnModel().getColumn(i).getHeaderValue() + .toString() + " "); + for (int j = 0; j < rowcnt; j++) { + // add 2 spaces to account for gutter + int width = SwingUtilities.computeStringWidth(fm, getValueAt(j, i).toString() + " "); + if (max < width) max = width; + } + // set the new column width + getColumnModel().getColumn(i).setWidth(max); + } + } +} diff --git a/test/jdk/javax/swing/JTable/bug4242631.java b/test/jdk/javax/swing/JTable/bug4242631.java new file mode 100644 index 0000000000000..6e9d1eddc32a7 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4242631.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.util.ArrayList; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; + +/* + * @test + * @bug 4242631 + * @summary Tests that JTable repaints itself correctly after a record + * has been removed and added to the table model. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4242631 + */ + +public class bug4242631 { + private static JButton addButton; + private static JButton removeButton; + private static JButton bothButton; + private static SimpleTableModel tableModel; + + private static final String INSTRUCTIONS = """ + Press Add button to add a record to the table. The record added should + have number 0. Then press Remove/Add button some times. The record number + should increase as you press. If it does not, test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4242631::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4242631"); + GridBagLayout grid = new GridBagLayout(); + + frame.setLayout(grid); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2, 2, 2, 2); + + // Add button. + c.gridx = 0; + c.gridy = 0; + grid.setConstraints(addButton = new JButton("Add"), c); + frame.add(addButton); + + // Edit button. + c.gridx = 1; + c.gridy = 0; + grid.setConstraints(removeButton = new JButton("Remove"), c); + frame.add(removeButton); + + // Remove button. + c.gridx = 2; + c.gridy = 0; + grid.setConstraints(bothButton = new JButton("Remove/Add"), c); + frame.add(bothButton); + + // Table. + c.gridx = 0; + c.gridy = 1; + c.gridwidth = 6; + c.gridheight = 0; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1.0; + c.weighty = 1.0; + JScrollPane scroll = null; + tableModel = new SimpleTableModel(); + grid.setConstraints(scroll = new JScrollPane(new JTable(tableModel)), c); + frame.add(scroll); + + // Create some action listeners. + addButton.addActionListener(event -> tableModel.addRow()); + removeButton.addActionListener(event -> tableModel.removeRow()); + bothButton.addActionListener(event -> tableModel.removeThenAddRow()); + + frame.pack(); + return frame; + } + + static class SimpleTableModel extends AbstractTableModel { + int counter = 0; + ArrayList list = new ArrayList(); + + public SimpleTableModel() {} + public int getColumnCount() { return 1; } + public int getRowCount() { return list.size(); } + + public Object getValueAt(int row, int col) { + String str = (String) list.get(row); + return str;// + "." + col; + } + + public void addRow() { + list.add("" + counter++); + fireTableRowsInserted(list.size() - 1, list.size() - 1); + } + + public void removeRow() { + if (list.size() == 0) return; + list.remove(list.size() - 1); + fireTableRowsDeleted(list.size(), list.size()); + } + + public void removeThenAddRow() { + if (list.size() == 0) return; + removeRow(); + addRow(); + } + } +} From f880fa91dce7b8844cfa4e95caa3a982e280165a Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Tue, 22 Apr 2025 03:09:45 +0000 Subject: [PATCH 0681/1101] 8352793: Open source several AWT TextComponent tests - Batch 1 Reviewed-by: prr, serb --- .../awt/TextComponent/BackgroundTest.java | 127 ++++++++++++++++++ .../java/awt/TextComponent/DisableTest.java | 98 ++++++++++++++ .../java/awt/TextComponent/ModifiersTest.java | 85 ++++++++++++ .../awt/TextComponent/TextFieldMargin.java | 67 +++++++++ 4 files changed, 377 insertions(+) create mode 100644 test/jdk/java/awt/TextComponent/BackgroundTest.java create mode 100644 test/jdk/java/awt/TextComponent/DisableTest.java create mode 100644 test/jdk/java/awt/TextComponent/ModifiersTest.java create mode 100644 test/jdk/java/awt/TextComponent/TextFieldMargin.java diff --git a/test/jdk/java/awt/TextComponent/BackgroundTest.java b/test/jdk/java/awt/TextComponent/BackgroundTest.java new file mode 100644 index 0000000000000..543f2cfd89311 --- /dev/null +++ b/test/jdk/java/awt/TextComponent/BackgroundTest.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4258667 4405602 + * @summary Make sure TextComponents are grayed out when non-editable + * if the background color has not been set by client code. + * Make sure TextComponents are not grayed out when non-editable + * if the background color has been set by client code. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual BackgroundTest + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.TextArea; +import java.awt.TextField; + +public class BackgroundTest { + private static final String enableString = "EnableText"; + private static final String disableString = "DisableText"; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. When the frame appears, it should have a blue background. + 2. The first TextField and TextArea will be the default color. + The second TextField and TextArea will be green. + 3. Press the "DisableText" button. + The first TextField and TextArea should change colors to the + default disabled color. On Windows, this is usually gray. + On linux and macos it will match the environment settings. + If the TextField or the TextArea do not change colors as described, + the test FAILS. + 4. The second TextField and TextArea should still be green. + If either of them are not green, the test FAILS. + Press the "EnableText" button (same button as before). + The first TextField and TextArea should return to their + original colors as described in the first paragraph. If they + do not, the test FAILS. + 5. The second TextField and TextArea should still be green. + If either of them are not green, the test FAILS. + Otherwise, the test PASSES. + """; + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(BackgroundTest::initialize) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + Frame frame = new Frame("Background Test"); + frame.setLayout(new FlowLayout()); + TextField tf = new TextField(30); + TextArea ta = new TextArea(4, 30); + TextField setTf = new TextField(30); + TextArea setTa = new TextArea(4, 30); + Button enableButton = new Button(disableString); + + enableButton.setBackground(Color.red); + frame.setSize(500, 250); + + frame.setBackground(Color.blue); + + tf.setText("Background not set - should be default"); + tf.setEditable(true); + frame.add(tf); + ta.setText("Background not set - should be default"); + ta.setEditable(true); + frame.add(ta); + + setTf.setText("Background is set - should be Green"); + setTf.setBackground(Color.green); + setTf.setEditable(true); + frame.add(setTf); + setTa.setText("Background is set - should be Green"); + setTa.setBackground(Color.green); + setTa.setEditable(true); + frame.add(setTa); + + enableButton.addActionListener(e -> { + boolean currentlyEditable = tf.isEditable(); + + if (currentlyEditable) { + tf.setEditable(false); + ta.setEditable(false); + setTf.setEditable(false); + setTa.setEditable(false); + enableButton.setLabel(enableString); + } else { + tf.setEditable(true); + ta.setEditable(true); + setTf.setEditable(true); + setTa.setEditable(true); + enableButton.setLabel(disableString); + } + }); + frame.add(enableButton); + return frame; + } +} \ No newline at end of file diff --git a/test/jdk/java/awt/TextComponent/DisableTest.java b/test/jdk/java/awt/TextComponent/DisableTest.java new file mode 100644 index 0000000000000..820b9c8bd3034 --- /dev/null +++ b/test/jdk/java/awt/TextComponent/DisableTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5042122 + * @summary Verifies the TextComponent is grayed out when disabled + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DisableTest + */ + +import javax.swing.BoxLayout; +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Component; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.event.ActionListener; +import java.util.Vector; +import java.util.Iterator; + +public class DisableTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Click "Enable" and "Disable" buttons and verify the text + components are disabled and enabled correctly. + 2. Verify that the disabled text components are grayed + out and are uneditable. + 3. Click PASS or FAIL accordingly. + """; + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(DisableTest::initialize) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + Frame frame = new Frame("TextComponent Disabled test"); + frame.setLayout(new BorderLayout()); + frame.setSize(200, 200); + final Vector comps = new Vector(); + comps.add(new TextField("TextField")); + TextArea ta = new TextArea("TextArea", 2, 100, TextArea.SCROLLBARS_NONE); + comps.add(ta); + Panel pc = new Panel(); + pc.setLayout(new BoxLayout(pc, BoxLayout.Y_AXIS)); + Iterator iter = comps.iterator(); + while (iter.hasNext()) { + Component c = (Component) iter.next(); + c.setEnabled(false); + pc.add(c); + } + frame.add(pc, BorderLayout.CENTER); + Panel p = new Panel(); + final Button be = new Button("Enable"); + final Button bd = new Button("Disable"); + p.add(be); + p.add(bd); + ActionListener al = ev -> { + boolean enable = (ev.getSource() == be); + Iterator iterator = comps.iterator(); + while (iterator.hasNext()) { + Component c = (Component) iterator.next(); + c.setEnabled(enable); + } + }; + be.addActionListener(al); + bd.addActionListener(al); + frame.add(p, BorderLayout.SOUTH); + return frame; + } +} diff --git a/test/jdk/java/awt/TextComponent/ModifiersTest.java b/test/jdk/java/awt/TextComponent/ModifiersTest.java new file mode 100644 index 0000000000000..e9e76a9b694b3 --- /dev/null +++ b/test/jdk/java/awt/TextComponent/ModifiersTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4035364 + * @summary Checks that Caps Lock key works + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ModifiersTest + */ + +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.TextArea; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; + +public class ModifiersTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Type some text in the TextArea in upper and lowercase, + using the Caps Lock ON/OFF. + 2. If Caps Lock toggles correctly and you are able to type in + both cases, the test PASS. Else Test FAILS. + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(ModifiersTest::initialize) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + Frame frame = new Frame("Modifiers Test"); + frame.setLayout(new GridLayout(1, 1)); + frame.addKeyListener(new KeyChecker()); + frame.setLayout(new GridLayout(2, 1)); + Label label = new Label("See if you can type in upper and lowercase using Caps Lock:"); + frame.add(label); + TextArea ta = new TextArea(); + frame.add(ta); + ta.addKeyListener(new KeyChecker()); + ta.requestFocus(); + frame.setSize(400, 300); + return frame; + } +} + +// a KeyListener for debugging purposes +class KeyChecker extends KeyAdapter { + public void keyPressed(KeyEvent ev) { + System.out.println(ev); + } + + public void keyReleased(KeyEvent ev) { + System.out.println(ev); + } + + public void keyTyped(KeyEvent ev) { + System.out.println(ev); + } +} diff --git a/test/jdk/java/awt/TextComponent/TextFieldMargin.java b/test/jdk/java/awt/TextComponent/TextFieldMargin.java new file mode 100644 index 0000000000000..6baf144254c1f --- /dev/null +++ b/test/jdk/java/awt/TextComponent/TextFieldMargin.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4129511 + * @summary Tests that TextField margins are not exceedingly wide + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TextFieldMargin + */ + +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.TextArea; +import java.awt.TextField; + +public class TextFieldMargin { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Examine the TextField, Label, and TextArea to see + that the text is vertically aligned along the left + 2. If all are aligned along the left, then test PASS, + else test FAILS. + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(TextFieldMargin::initialize) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + Frame frame = new Frame("Frame with a text field & a label"); + frame.setLayout(new GridLayout(5, 1)); + TextField text_field = new TextField("Left Textfield"); + frame.add(text_field); + Label label = new Label("Left Label"); + frame.add(label); + TextArea text_area = new TextArea("Left Textfield"); + frame.add(text_area); + frame.setBounds(50, 50, 300, 300); + return frame; + } +} From 0be3f163ed12db305673928d97f975d6f6bb6b1c Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 22 Apr 2025 03:29:59 +0000 Subject: [PATCH 0682/1101] 8341608: jdeps in JDK 23 crashes when parsing signatures while jdeps in JDK 22 works fine Reviewed-by: jpai, henryjen --- .../com/sun/tools/jdeps/ClassFileReader.java | 190 +++++------------- .../com/sun/tools/jdeps/Dependencies.java | 2 +- .../com/sun/tools/jdeps/DependencyFinder.java | 12 +- .../tools/jdeps/MalformedClassesTest.java | 129 ++++++++++++ test/langtools/tools/jdeps/TEST.properties | 2 + .../com/sun/tools/jdeps/JdepsAccess.java | 34 ++++ .../lib/compiler/InMemoryJavaCompiler.java | 8 +- test/lib/jdk/test/lib/util/JarUtils.java | 20 +- 8 files changed, 241 insertions(+), 156 deletions(-) create mode 100644 test/langtools/tools/jdeps/MalformedClassesTest.java create mode 100644 test/langtools/tools/jdeps/TEST.properties create mode 100644 test/langtools/tools/jdeps/jdk.jdeps/com/sun/tools/jdeps/JdepsAccess.java diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java index fc1bf5302d6dd..72dc4e728990b 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,10 +41,9 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; -import java.util.Iterator; import java.util.List; -import java.util.NoSuchElementException; import java.util.Set; +import java.util.function.Consumer; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.stream.Collectors; @@ -102,6 +101,10 @@ public List skippedEntries() { return skippedEntries; } + protected void skipEntry(Throwable ex, String entryPath) { + skippedEntries.add(String.format("%s: %s", ex.toString(), entryPath)); + } + /** * Returns all entries in this archive. */ @@ -135,8 +138,15 @@ public ClassModel getClassFile(String name) throws IOException { return null; } - public Iterable getClassFiles() throws IOException { - return FileIterator::new; + public void forEachClassFile(Consumer handler) throws IOException { + if (baseFileName.endsWith(".class")) { + // propagate ClassFileError for single file + try { + handler.accept(readClassFile(path)); + } catch (ClassFileError ex) { + skipEntry(ex, path.toString()); + } + } } protected ClassModel readClassFile(Path p) throws IOException { @@ -167,33 +177,6 @@ static boolean isClass(Path file) { public void close() throws IOException { } - class FileIterator implements Iterator { - int count; - FileIterator() { - this.count = 0; - } - public boolean hasNext() { - return count == 0 && baseFileName.endsWith(".class"); - } - - public ClassModel next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - try { - ClassModel cf = readClassFile(path); - count++; - return cf; - } catch (IOException e) { - throw new ClassFileError(e); - } - } - - public void remove() { - throw new UnsupportedOperationException("Not supported yet."); - } - } - public String toString() { return path.toString(); } @@ -241,42 +224,17 @@ public ClassModel getClassFile(String name) throws IOException { return null; } - public Iterable getClassFiles() throws IOException { - final Iterator iter = new DirectoryIterator(); - return () -> iter; - } - - class DirectoryIterator implements Iterator { - private final List entries; - private int index = 0; - DirectoryIterator() throws IOException { - List paths = null; - try (Stream stream = Files.walk(path, Integer.MAX_VALUE)) { - paths = stream.filter(ClassFileReader::isClass).toList(); - - } - this.entries = paths; - this.index = 0; - } - - public boolean hasNext() { - return index != entries.size(); - } - - public ClassModel next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - Path path = entries.get(index++); - try { - return readClassFile(path); - } catch (IOException e) { - throw new ClassFileError(e); - } - } - - public void remove() { - throw new UnsupportedOperationException("Not supported yet."); + @Override + public void forEachClassFile(Consumer handler) throws IOException { + try (Stream stream = Files.walk(path, Integer.MAX_VALUE)) { + stream.filter(ClassFileReader::isClass) + .forEach(e -> { + try { + handler.accept(readClassFile(e)); + } catch (ClassFileError | IOException ex) { + skipEntry(ex, e.toString()); + } + }); } } } @@ -314,14 +272,15 @@ private static JarFile openJarFile(File f, Runtime.Version version) return jf; } + private static boolean isJarEntryClass(JarEntry e) { + return e.getName().endsWith(".class"); + } + protected Set scan() { - try (JarFile jf = openJarFile(path.toFile(), version)) { - return jf.versionedStream().map(JarEntry::getName) - .filter(n -> n.endsWith(".class")) - .collect(Collectors.toSet()); - } catch (IOException e) { - throw new UncheckedIOException(e); - } + return jarfile.versionedStream() + .filter(JarFileReader::isJarEntryClass) + .map(JarEntry::getName) + .collect(Collectors.toSet()); } public ClassModel getClassFile(String name) throws IOException { @@ -358,76 +317,17 @@ protected ClassModel readClassFile(JarFile jarfile, JarEntry e) throws IOExcepti } } - public Iterable getClassFiles() throws IOException { - final Iterator iter = new JarFileIterator(this, jarfile); - return () -> iter; - } - } - - class JarFileIterator implements Iterator { - protected final JarFileReader reader; - protected Iterator entries; - protected JarFile jf; - protected JarEntry nextEntry; - protected ClassModel cf; - JarFileIterator(JarFileReader reader) { - this(reader, null); - } - JarFileIterator(JarFileReader reader, JarFile jarfile) { - this.reader = reader; - setJarFile(jarfile); - } - - void setJarFile(JarFile jarfile) { - if (jarfile == null) return; - - this.jf = jarfile; - this.entries = jarfile.versionedStream().iterator(); - this.nextEntry = nextEntry(); - } - - public boolean hasNext() { - if (nextEntry != null && cf != null) { - return true; - } - while (nextEntry != null) { - try { - cf = reader.readClassFile(jf, nextEntry); - return true; - } catch (ClassFileError | IOException ex) { - skippedEntries.add(String.format("%s: %s (%s)", - ex.getMessage(), - nextEntry.getName(), - jf.getName())); - } - nextEntry = nextEntry(); - } - return false; - } - - public ClassModel next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - ClassModel classFile = cf; - cf = null; - nextEntry = nextEntry(); - return classFile; - } - - protected JarEntry nextEntry() { - while (entries.hasNext()) { - JarEntry e = entries.next(); - String name = e.getName(); - if (name.endsWith(".class")) { - return e; - } - } - return null; - } - - public void remove() { - throw new UnsupportedOperationException("Not supported yet."); + @Override + public void forEachClassFile(Consumer handler) throws IOException { + jarfile.versionedStream() + .filter(JarFileReader::isJarEntryClass) + .forEach(e -> { + try { + handler.accept(readClassFile(jarfile, e)); + } catch (ClassFileError | IOException ex) { + skipEntry(ex, e.getName() + " (" + jarfile.getName() + ")"); + } + }); } } } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java index 90682c478c781..d7df5ba77c210 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java @@ -79,7 +79,7 @@ public static class ClassFileError extends Error { private static final long serialVersionUID = 4111110813961313203L; public ClassFileError(Throwable cause) { - initCause(cause); + super(cause.getMessage(), cause); } } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java index 179043bc5788b..d2bf83a50b0f2 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -173,9 +173,9 @@ private Optional>> parse(Archive archive, Finder finder trace("parsing %s %s%n", archive.getName(), archive.getPathName()); FutureTask> task = new FutureTask<>(() -> { Set targets = new HashSet<>(); - for (var cf : archive.reader().getClassFiles()) { + archive.reader().forEachClassFile(cf -> { if (cf.isModuleInfo()) - continue; + return; String classFileName; try { @@ -187,11 +187,11 @@ private Optional>> parse(Archive archive, Finder finder // filter source class/archive String cn = classFileName.replace('/', '.'); if (!finder.accept(archive, cn, cf.flags())) - continue; + return; // tests if this class matches the -include if (!filter.matches(cn)) - continue; + return; for (Dependency d : finder.findDependencies(cf)) { if (filter.accepts(d)) { @@ -203,7 +203,7 @@ private Optional>> parse(Archive archive, Finder finder } parsedClasses.putIfAbsent(d.getOrigin(), archive); } - } + }); return targets; }); tasks.add(task); diff --git a/test/langtools/tools/jdeps/MalformedClassesTest.java b/test/langtools/tools/jdeps/MalformedClassesTest.java new file mode 100644 index 0000000000000..baa94ad78e2a4 --- /dev/null +++ b/test/langtools/tools/jdeps/MalformedClassesTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8341608 + * @summary Tests for jdeps tool with jar files with malformed classes + * @library lib /test/lib + * @build jdk.jdeps/com.sun.tools.jdeps.* + * @run junit MalformedClassesTest + */ + +import java.io.IOException; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.attribute.SignatureAttribute; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +import com.sun.tools.jdeps.JdepsAccess; +import jdk.test.lib.compiler.InMemoryJavaCompiler; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.util.JarUtils; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class MalformedClassesTest { + + static Stream invalidArchives() throws Exception { + var jarPath = Path.of("malformed-signature.jar"); + var compiledClasses = InMemoryJavaCompiler.compile(Map.ofEntries( + Map.entry("one.One", """ + package one; + + import java.util.Optional; + + class One { + Optional st = Optional.empty(); + } + """), + Map.entry("two.Two", """ + package two; + + import java.lang.invoke.*; + + class Two { + int i; + static final VarHandle I; + + static { + try { + I = MethodHandles.lookup().findVarHandle(Two.class, "i", int.class); + } catch (ReflectiveOperationException ex) { + throw new ExceptionInInitializerError(ex); + } + } + } + """) + )); + var updated = ClassFile.of().transformClass(ClassFile.of().parse(compiledClasses.get("one.One")), + ClassTransform.transformingFields((fb, fe) -> { + if (fe instanceof SignatureAttribute) { + fb.with(SignatureAttribute.of(fb.constantPool().utf8Entry("Invalid string"))); + } else { + fb.with(fe); + } + })); + var classes = new HashMap<>(compiledClasses); + classes.put("one.One", updated); + JarUtils.createJarFromClasses(jarPath, classes); + + Path flatDir = Path.of("flatDir"); + Files.createDirectories(flatDir); + for (var entry : classes.entrySet()) { + ClassFileInstaller.writeClassToDisk(entry.getKey(), entry.getValue(), flatDir.toString()); + } + + return Stream.of( + Arguments.of("directory", flatDir, "One.class"), + Arguments.of("jar", jarPath, "one/One.class (malformed-signature.jar)") + ); + } + + @ParameterizedTest + @MethodSource("invalidArchives") + public void testMalformedSignature(String kind, Path path, String entryName) throws IOException { + try (var jdeps = JdepsUtil.newCommand("jdeps")) { + jdeps.addRoot(path); + var analyzer = jdeps.getDepsAnalyzer(); + analyzer.run(); + var archives = JdepsAccess.depsAnalyzerArchives(analyzer); + assertEquals(1, archives.size(), archives::toString); + var archive = archives.iterator().next(); + var skippedEntries = archive.reader().skippedEntries(); + assertEquals(1, skippedEntries.size(), skippedEntries::toString); + var message = skippedEntries.getFirst(); + assertTrue(message.contains("ClassFileError"), message); + assertTrue(message.contains("Invalid string"), message); + assertTrue(message.contains(entryName), "\"" + message + "\" does not contain \"" + entryName + "\""); + } + } +} diff --git a/test/langtools/tools/jdeps/TEST.properties b/test/langtools/tools/jdeps/TEST.properties new file mode 100644 index 0000000000000..56b5043d3c17f --- /dev/null +++ b/test/langtools/tools/jdeps/TEST.properties @@ -0,0 +1,2 @@ +modules = \ + jdk.jdeps/com.sun.tools.jdeps diff --git a/test/langtools/tools/jdeps/jdk.jdeps/com/sun/tools/jdeps/JdepsAccess.java b/test/langtools/tools/jdeps/jdk.jdeps/com/sun/tools/jdeps/JdepsAccess.java new file mode 100644 index 0000000000000..16229153e13aa --- /dev/null +++ b/test/langtools/tools/jdeps/jdk.jdeps/com/sun/tools/jdeps/JdepsAccess.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.jdeps; + +import java.util.Set; + +public final class JdepsAccess { + public static Set depsAnalyzerArchives(DepsAnalyzer analyzer) { + return analyzer.archives; + } + + private JdepsAccess() {} +} diff --git a/test/lib/jdk/test/lib/compiler/InMemoryJavaCompiler.java b/test/lib/jdk/test/lib/compiler/InMemoryJavaCompiler.java index 4722ef3b67a95..7a289bbcce5b0 100644 --- a/test/lib/jdk/test/lib/compiler/InMemoryJavaCompiler.java +++ b/test/lib/jdk/test/lib/compiler/InMemoryJavaCompiler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -208,8 +208,10 @@ public String getClassName() { } /** - * Compiles the list of classes with the given map of name and source code. - * This overloaded version of compile is useful for batch compile use cases. + * Compiles the list of classes with the given map of binary name and source code. + * This overloaded version of compile is useful for batch compile use cases, or + * if a compilation unit produces multiple class files. Returns a map from + * class binary names to class file content. * * @param inputMap The map containing the name of the class and corresponding source code * @throws RuntimeException if the compilation did not succeed diff --git a/test/lib/jdk/test/lib/util/JarUtils.java b/test/lib/jdk/test/lib/util/JarUtils.java index 3aa4ada5197ad..9a3d73ee41046 100644 --- a/test/lib/jdk/test/lib/util/JarUtils.java +++ b/test/lib/jdk/test/lib/util/JarUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -131,6 +131,24 @@ public static void createJarFile(Path jarfile, Path dir, String... input) createJarFile(jarfile, dir, paths); } + + /** + * Creates a JAR file from a map of class binary name to class bytes. + * + * @see jdk.test.lib.compiler.InMemoryJavaCompiler#compile(Map) + */ + public static void createJarFromClasses(Path jarfile, Map classes) throws IOException { + try (OutputStream out = Files.newOutputStream(jarfile); + JarOutputStream jos = new JarOutputStream(out)) { + for (var entry : classes.entrySet()) { + String name = entry.getKey().replace('.', '/') + ".class"; + jos.putNextEntry(new JarEntry(name)); + jos.write(entry.getValue()); + jos.closeEntry(); + } + } + } + /** * Updates a JAR file. * From e2cb64674f5b6b4f000ab1e903fbb75416218bb3 Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Tue, 22 Apr 2025 05:56:07 +0000 Subject: [PATCH 0683/1101] 8343977: Convert java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest to main Reviewed-by: prr, achung --- .../HoveringAndDraggingTest.html | 43 --- .../HoveringAndDraggingTest.java | 285 ++++++------------ 2 files changed, 99 insertions(+), 229 deletions(-) delete mode 100644 test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.html diff --git a/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.html b/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.html deleted file mode 100644 index 9fc7f55ceba29..0000000000000 --- a/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - HoveringAndDraggingTest - - - -

HoveringAndDraggingTest
Bug ID: 6497109

- -

See the dialog box (usually in upper left corner) for instructions

- - - - diff --git a/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.java b/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.java index 753fc4909674a..646bc6aa6b976 100644 --- a/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.java +++ b/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,71 +21,122 @@ * questions. */ -/* - test - @bug 6497109 - @summary Mouse cursor icons for TextArea should be correct in case of hovering or dragging mouse over different subcomponents. - @author Konstantin Voloshin: area=awt.TextArea - @run applet/manual=yesno HoveringAndDraggingTest.html -*/ - -/** - * HoveringAndDraggingTest.java - * - * summary: Mouse cursor icons for TextArea should be correct in case - * of hovering or dragging mouse over different subcomponents. - */ - +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; import java.awt.Frame; -import java.awt.Panel; +import java.awt.GridBagLayout; import java.awt.GridLayout; +import java.awt.Panel; import java.awt.TextArea; -import java.awt.Dialog; +import java.util.concurrent.CountDownLatch; -public class HoveringAndDraggingTest extends java.applet.Applet { - public void start() { - String[] instructions = new String[] { - "1. Notice components in test window: main-panel, box-for-text," - +" 2 scroll-sliders, and 4 scroll-buttons.", - "2. Hover mouse over box-for-text." - +" Make sure, that mouse cursor is TextCursor (a.k.a. \"beam\").", - "3. Hover mouse over each of components (see item 1), except for box-for-text." - +" Make sure, that cursor is DefaultCursor (arrow).", - "4. Drag mouse (using any mouse button) from box-for-text to every" - +" component in item 1, and also outside application window." - +" Make sure, that cursor remains TextCursor while mouse button is pressed.", - "5. Repeat item 4 for each other component in item 1, except for box-for-text," - +" _but_ now make sure that cursor is DefaultCursor.", - "6. If cursor behaves as described in items 2-3-4-5, then test passed; otherwise it failed." - }; - Sysout.createDialogWithInstructions( instructions ); +/* + * @test + * @bug 6497109 + * @summary Mouse cursor icons for TextArea should be correct in case of + * hovering or dragging mouse over different subcomponents. + * @run main/manual HoveringAndDraggingTest + */ + +public class HoveringAndDraggingTest { + static Frame frame; + static Frame instructionsFrame; + static CountDownLatch countDownLatch; + public static CountDownLatch createCountDownLatch() { + return new CountDownLatch(1); + } + public static void main(String[] args) throws Exception { + countDownLatch = createCountDownLatch(); + EventQueue.invokeAndWait(() -> { + initialize(); + showInstructionFrame(); + }); + countDownLatch.await(); + System.out.println("Test Pass"); + } + + public static void initialize() { Panel panel = new Panel(); - panel.setLayout( new GridLayout(3,3) ); + panel.setLayout(new GridLayout(3, 3)); - for( int y=0; y<3; ++y ) { - for( int x=0; x<3; ++x ) { - if( x==1 && y==1 ) { - panel.add( new TextArea( bigString() ) ); + for (int y = 0; y < 3; ++y) { + for (int x = 0; x < 3; ++x) { + if (x == 1 && y == 1) { + panel.add(new TextArea(bigString())); } else { - panel.add( new Panel() ); + panel.add(new Panel()); } } } - Frame frame = new Frame( "TextArea cursor icon test" ); - frame.setSize( 300, 300 ); - frame.add( panel ); - frame.setVisible( true ); + frame = new Frame("TextArea cursor icon test"); + frame.setSize(300, 300); + frame.setLocation(450, 400); + frame.add(panel); + frame.setVisible(true); + } + + static void showInstructionFrame() { + String INSTRUCTIONS = """ + 1. Notice components in test window: main-panel,box-for-text, + 2 scroll-sliders, and 4 scroll-buttons. + 2. Hover mouse over box-for-text. + Make sure, that mouse cursor is TextCursor(a.k.a. \"beam\"). + 3. Hover mouse over each of components (see item 1), + except for box-for-text. + Make sure, that cursor is DefaultCursor (arrow). + 4. Drag mouse (using any mouse button) from box-for-text to every" + component in item 1, and also outside application window." + Make sure, that cursor remains TextCursor + while mouse button is pressed. + 5. Repeat item 4 for each other component in item 1, + except for box-for-text + _but_ now make sure that cursor is DefaultCursor. + 6. If cursor behaves as described in items 2-3-4-5, + then test is PASS otherwise it FAILED. + """; + TextArea textArea = new TextArea(INSTRUCTIONS, 16, 65, TextArea.SCROLLBARS_NONE); + Button passBtn = new Button("PASS"); + Button failBtn = new Button("FAIL"); + Panel btnPanel = new Panel(new GridBagLayout()); + Panel panel = new Panel(new GridBagLayout()); + instructionsFrame = new Frame("Test Instructions"); + passBtn.setMaximumSize(new Dimension(100, 30)); + failBtn.setMaximumSize(new Dimension(100, 30)); + btnPanel.add(passBtn); + btnPanel.add(failBtn); + passBtn.addActionListener(e -> disposeFrames()); + failBtn.addActionListener(e -> { + disposeFrames(); + throw new RuntimeException("Test Failed"); + }); + panel.add(textArea); + panel.add(btnPanel); + instructionsFrame.add(panel); + instructionsFrame.pack(); + instructionsFrame.setLocation(300, 100); + instructionsFrame.setVisible(true); + } + + static void disposeFrames() { + countDownLatch.countDown(); + if (frame != null) { + frame.dispose(); + } + if (instructionsFrame != null) { + instructionsFrame.dispose(); + } } static String bigString() { String s = ""; - for( int lines=0; ; ++lines ) { - for( int symbols=0; symbols<100; ++symbols ) { + for (int lines = 0; ; ++lines) { + for (int symbols = 0; symbols < 100; ++symbols) { s += "0"; } - if( lines<50 ) { + if (lines < 50) { s += "\n"; } else { break; @@ -94,141 +145,3 @@ static String bigString() { return s; } } - - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); - } - -}// TestDialog class From d1d7d2569c1745aef778c9b5a62c1bd50735e8a7 Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Tue, 22 Apr 2025 06:23:24 +0000 Subject: [PATCH 0684/1101] 8353957: Open source several AWT ScrollPane tests - Batch 1 Reviewed-by: psadhukhan --- test/jdk/ProblemList.txt | 1 + .../awt/ScrollPane/ScrollPaneFlicker.java | 215 ++++++++++++++++++ .../java/awt/ScrollPane/ScrollPanePaint.java | 132 +++++++++++ .../awt/ScrollPane/ScrollPositionTest.java | 100 ++++++++ .../ScrollPane/ScrollbarsAsNeededTest.java | 72 ++++++ 5 files changed, 520 insertions(+) create mode 100644 test/jdk/java/awt/ScrollPane/ScrollPaneFlicker.java create mode 100644 test/jdk/java/awt/ScrollPane/ScrollPanePaint.java create mode 100644 test/jdk/java/awt/ScrollPane/ScrollPositionTest.java create mode 100644 test/jdk/java/awt/ScrollPane/ScrollbarsAsNeededTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index e1e0a695ebca5..3fe0bcf8cdcd7 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -443,6 +443,7 @@ java/awt/Focus/TranserFocusToWindow/TranserFocusToWindow.java 6848810 macosx-all java/awt/FileDialog/ModalFocus/FileDialogModalFocusTest.java 8194751 linux-all java/awt/image/VolatileImage/BitmaskVolatileImage.java 8133102 linux-all java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java 8203004 linux-all +java/awt/ScrollPane/ScrollPositionTest.java 8040070 linux-all java/awt/ScrollPane/ScrollPaneScrollType/ScrollPaneEventType.java 8296516 macosx-all java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java 7107528 linux-all,macosx-all java/awt/Mouse/MouseDragEvent/MouseDraggedTest.java 8080676 linux-all diff --git a/test/jdk/java/awt/ScrollPane/ScrollPaneFlicker.java b/test/jdk/java/awt/ScrollPane/ScrollPaneFlicker.java new file mode 100644 index 0000000000000..3594ff50f54c9 --- /dev/null +++ b/test/jdk/java/awt/ScrollPane/ScrollPaneFlicker.java @@ -0,0 +1,215 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4073822 + * @summary ScrollPane repaints entire window when scrolling fast + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ScrollPaneFlicker + */ + +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollBar; +import javax.swing.JTextArea; +import javax.swing.JTextField; + +public class ScrollPaneFlicker { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + When scrolling a ScrollPane fast(i.e. holding the down/up arrow + down for a while), the ScrollPane would inexplicably refresh + the entire window. + + 1. Select a type of ScrollPane content from the content menu. + 2. Scroll the content using the up/down/left/right arrows on + the scroll bar. Try scrolling the entire content area using + the scroll arrows-- from top to bottom and left to right. + 3. Verify that the entire pane does not refresh when scrolling + - only the newly exposed areas should be repainting. + 4. Repeat for all content types. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(ScrollPaneFlicker::initialize) + .build() + .awaitAndCheck(); + } + + static Frame initialize() { + return new FlickerFrame(); + } +} + +class FlickerFrame extends Frame { + ScrollPane pane; + + public FlickerFrame() { + super("ScrollPane Flicker Test"); + TextPanel textPanel = new TextPanel(); + GradientPanel gradientPanel = new GradientPanel(); + ComponentPanel componentPanel = new ComponentPanel(); + SwingPanel swingPanel = new SwingPanel(); + MenuBar menubar = new MenuBar(); + Menu testMenu = new Menu("Test Options"); + + pane = new ScrollPane(); + pane.getHAdjustable().setUnitIncrement(8); + pane.getVAdjustable().setUnitIncrement(16); + pane.add(textPanel); + add(pane); + + testMenu.add(makeContentItem("Text Lines", textPanel)); + testMenu.add(makeContentItem("Gradient Fill", gradientPanel)); + testMenu.add(makeContentItem("AWT Components", componentPanel)); + testMenu.add(makeContentItem("Swing Components", swingPanel)); + menubar.add(testMenu); + + setMenuBar(menubar); + setSize(400, 300); + } + + public MenuItem makeContentItem(String title, final Component content) { + MenuItem menuItem = new MenuItem(title); + menuItem.addActionListener( + ev -> { + pane.add(content); + pane.validate(); + } + ); + return menuItem; + } +} + +class GradientPanel extends Canvas { + public void paint(Graphics g) { + // just paint something that'll take a while + int x, y; + int width = getSize().width; + int height = getSize().height; + int step = 8; + + for (x = 0; x < width; x += step) { + for (y = 0; y < height; y += step) { + int red = (255 * y) / height; + int green = (255 * x * y) / (width * height); + int blue = (255 * x) / width; + Rectangle bounds = g.getClipBounds(); + Rectangle fbounds = new Rectangle(x, y, x + step, y + step); + if (bounds.intersects(fbounds)) { + Color color = new Color(red, green, blue); + g.setColor(color); + g.fillRect(x, y, x + step, y + step); + } + } + } + } + + public Dimension getPreferredSize() { + return new Dimension(200, 1000); + } +} + +class TextPanel extends Canvas { + public void paint(Graphics g) { + Font font = new Font("SanSerif", Font.ITALIC, 12); + + g.setFont(font); + // just paint something that'll take a while + int x, y; + int width = getWidth(); + int height = getHeight(); + int step = 16; + + for (x = y = 0; y < height; y += step) { + Rectangle bounds = g.getClipBounds(); + Rectangle tbounds = new Rectangle(x, y - 16, x + width, y); + if (bounds.intersects(tbounds)) { + g.drawString(y + " : The quick brown fox jumps over the lazy dog. " + + "The rain in Spain falls mainly on the plain.", x, y); + } + } + } + + public Dimension getPreferredSize() { + return new Dimension(640, 1000); + } +} + +class ComponentPanel extends Panel { + ComponentPanel() { + add(new Label("Label")); + add(new Button("Button")); + add(new Checkbox("Checkbox")); + Choice c = new Choice(); + c.add("choice"); + java.awt.List l = new java.awt.List(); + l.add("list"); + add(new Scrollbar()); + add(new TextField("TextField")); + add(new TextArea("TextArea")); + add(new Panel()); + add(new Canvas()); + } +} + +class SwingPanel extends JPanel { + SwingPanel() { + add(new JLabel("JLabel")); + add(new JButton("JButton")); + add(new JCheckBox("JCheckBox")); + JComboBox c = new JComboBox(); + JList l = new JList(); + add(new JScrollBar()); + add(new JTextField("This is a JTextField with some text in it to make it longer.")); + add(new JTextArea("This is a JTextArea with some text in it to make it longer.")); + } +} diff --git a/test/jdk/java/awt/ScrollPane/ScrollPanePaint.java b/test/jdk/java/awt/ScrollPane/ScrollPanePaint.java new file mode 100644 index 0000000000000..0d7b7779018e7 --- /dev/null +++ b/test/jdk/java/awt/ScrollPane/ScrollPanePaint.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +/* + * Licensed Materials - Property of IBM + * + * (C) Copyright IBM Corporation 1998 All Rights Reserved. + * + * US Government Users Restricted Rights - Use, duplication or disclosure + * restricted by GSA ADP Schedule Contract with IBM Corp. + */ + +/* + * @test + * @bug 4160721 + * @summary AWT ScrollPane painting problem + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ScrollPanePaint + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.ScrollPane; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; + +public class ScrollPanePaint { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Press the button marked "Toggle" a few times. + 2. The contents of the frame should alternate between + a red panel and a scroll pane containing a green panel. + If this does not happen (specifically, if the scroll + pane does not consistently contain a green panel), + then the test has FAILED. + """; + ScrollPaintTest scrollPaintTest = new ScrollPaintTest(); + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(scrollPaintTest::initialize) + .positionTestUI(WindowLayouts::rightOneColumn) + .build() + .awaitAndCheck(); + } + + private static class ScrollPaintTest implements ActionListener { + static Frame f; + static boolean showScroll; + + public List initialize() { + Frame frame = new Frame("Scrollpane paint test"); + frame.setLayout(new BorderLayout()); + f = new Frame("Scrollpane paint test"); + f.setLayout(new GridLayout(0, 1)); + + Button b = new Button("Toggle"); + b.addActionListener(this); + + frame.add(b, BorderLayout.CENTER); + frame.pack(); + + showScroll = false; + actionPerformed(null); + return List.of(frame, f); + } + + public void actionPerformed(ActionEvent e) { + Container c; + if (!showScroll) { + c = (Container) new TestPanel(new Dimension(100, 100)); + c.setBackground(Color.red); + } else { + c = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS); + Panel p = new TestPanel(new Dimension(20, 20)); + p.setBackground(Color.green); + c.add(p); + } + + f.removeAll(); + f.add("Center", c); + f.pack(); + showScroll = !showScroll; + } + } + + private static class TestPanel extends Panel { + Dimension dim; + + TestPanel(Dimension d) { + dim = d; + } + + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + public Dimension getPreferredSize() { + return dim; + } + } + +} diff --git a/test/jdk/java/awt/ScrollPane/ScrollPositionTest.java b/test/jdk/java/awt/ScrollPane/ScrollPositionTest.java new file mode 100644 index 0000000000000..9c082a8dfc910 --- /dev/null +++ b/test/jdk/java/awt/ScrollPane/ScrollPositionTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4008152 + * @summary ScrollPane position does not return correct values + * @key headful + * @run main ScrollPositionTest + */ + +import java.awt.Adjustable; +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.ScrollPane; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; + +public class ScrollPositionTest { + static Frame frame; + static int i = 0; + static Point p; + static ScrollPane sp; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + try { + EventQueue.invokeAndWait(() -> { + frame = new Frame("Scroll Position Test"); + frame.setLayout(new BorderLayout()); + frame.setSize(200, 200); + sp = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED); + Canvas canvas = new Canvas(); + canvas.setSize(300, 300); + sp.add(canvas); + frame.add("Center", sp); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(1000); + EventQueue.invokeAndWait(() -> { + Adjustable saH = sp.getHAdjustable(); + saH.addAdjustmentListener(new TestAdjustmentListener()); + }); + for (i = 0; i < 1000; i++) { + EventQueue.invokeAndWait(() -> { + p = new Point(i % 100, i % 100); + sp.setScrollPosition(p); + }); + + robot.waitForIdle(); + robot.delay(10); + EventQueue.invokeAndWait(() -> { + if (!sp.getScrollPosition().equals(p)) { + throw new RuntimeException("Test failed. " + i + " : " + + "Expected " + p + ", but Returned: " + sp.getScrollPosition()); + } + }); + } + System.out.println("Test Passed."); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static class TestAdjustmentListener implements AdjustmentListener { + public void adjustmentValueChanged(AdjustmentEvent e) { + System.out.println("AdjEvent caught:" + e); + } + } +} diff --git a/test/jdk/java/awt/ScrollPane/ScrollbarsAsNeededTest.java b/test/jdk/java/awt/ScrollPane/ScrollbarsAsNeededTest.java new file mode 100644 index 0000000000000..c5f48f8000701 --- /dev/null +++ b/test/jdk/java/awt/ScrollPane/ScrollbarsAsNeededTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4094248 + * @summary Test initial appearance of SCROLLBARS_AS_NEEDED policy + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ScrollbarsAsNeededTest + */ + +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.ScrollPane; + +public class ScrollbarsAsNeededTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. A Frame window with a ScrollPane that is + initially created with the SCROLLBARS_AS_NEEDED policy. + 2. If there are no scrollbars around the ScrollPane then + the test PASS. Otherwise the test FAILS. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(ScrollbarsAsNeededTest::initialize) + .build() + .awaitAndCheck(); + } + + static Frame initialize() { + Frame frame = new Frame("Scrollbar as needed test"); + ScrollPane scrollPane = new ScrollPane() { + @Override + public void paint(Graphics g) { + super.paint(g); + g.drawString("ScrollPane", 10, 50); + } + }; + scrollPane.setBackground(Color.WHITE); + frame.setBackground(Color.GRAY); + frame.setSize(200, 200); + frame.setLayout(new FlowLayout()); + frame.add(scrollPane); + return frame; + } +} From 33bdc807b18914bb57ca7853ab45d4fa8fdefd47 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 22 Apr 2025 06:51:18 +0000 Subject: [PATCH 0685/1101] 8355241: Move NativeDialogToFrontBackTest.java PL test to manual category Reviewed-by: psadhukhan --- test/jdk/ProblemList.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 3fe0bcf8cdcd7..841b1110506b8 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -392,7 +392,6 @@ java/awt/Modal/MultipleDialogs/MultipleDialogs2Test.java 8198665 macosx-all java/awt/Modal/MultipleDialogs/MultipleDialogs3Test.java 8198665 macosx-all java/awt/Modal/MultipleDialogs/MultipleDialogs4Test.java 8198665 macosx-all java/awt/Modal/MultipleDialogs/MultipleDialogs5Test.java 8198665 macosx-all -java/awt/Modal/NativeDialogToFrontBackTest.java 7188049 windows-all,linux-all java/awt/Mouse/EnterExitEvents/DragWindowOutOfFrameTest.java 8177326 macosx-all java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java 8005021 macosx-all java/awt/Mouse/EnterExitEvents/FullscreenEnterEventTest.java 8051455 macosx-all @@ -820,3 +819,4 @@ java/awt/Checkbox/CheckboxBoxSizeTest.java 8340870 windows-all java/awt/Checkbox/CheckboxIndicatorSizeTest.java 8340870 windows-all java/awt/Checkbox/CheckboxNullLabelTest.java 8340870 windows-all java/awt/dnd/WinMoveFileToShellTest.java 8341665 windows-all +java/awt/Modal/NativeDialogToFrontBackTest.java 7188049 windows-all,linux-all From a55ccd267cdfbb7a52c0647fa3b2f93b36b1805f Mon Sep 17 00:00:00 2001 From: Alisen Chung Date: Tue, 22 Apr 2025 07:04:26 +0000 Subject: [PATCH 0686/1101] 8352905: Open some JComboBox bugs 1 Reviewed-by: honkar, psadhukhan --- .../jdk/javax/swing/JComboBox/bug4166593.java | 98 ++++++++++++ .../jdk/javax/swing/JComboBox/bug4180054.java | 112 +++++++++++++ .../jdk/javax/swing/JComboBox/bug4530952.java | 147 ++++++++++++++++++ .../jdk/javax/swing/JComboBox/bug4530953.java | 98 ++++++++++++ 4 files changed, 455 insertions(+) create mode 100644 test/jdk/javax/swing/JComboBox/bug4166593.java create mode 100644 test/jdk/javax/swing/JComboBox/bug4180054.java create mode 100644 test/jdk/javax/swing/JComboBox/bug4530952.java create mode 100644 test/jdk/javax/swing/JComboBox/bug4530953.java diff --git a/test/jdk/javax/swing/JComboBox/bug4166593.java b/test/jdk/javax/swing/JComboBox/bug4166593.java new file mode 100644 index 0000000000000..850aab2261f96 --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4166593.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Robot; +import java.awt.event.ActionListener; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4166593 + * @summary Tests that JComboBox fires action events every time the user does an action + * @key headful + * @run main bug4166593 + */ + +public class bug4166593 { + static JFrame frame; + static JComboBox comboBox; + static volatile int numberOfActionEvents = 0; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + SwingUtilities.invokeAndWait(() -> createTestUI()); + robot.waitForIdle(); + robot.delay(250); + + // change selected index 3 times + SwingUtilities.invokeAndWait(() -> { + comboBox.setSelectedIndex(1); + comboBox.setSelectedIndex(3); + comboBox.setSelectedIndex(2); + }); + robot.waitForIdle(); + robot.delay(250); + + if (numberOfActionEvents != 3) { + throw new RuntimeException("Unexpected number of Action Events!\n" + + "Expected: 3\nActual: " + numberOfActionEvents); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static void createTestUI() { + comboBox = new JComboBox(new Object[]{ + "Bob", "Fred", "Hank", "Joe", "Mildred", "Agatha", "Buffy" + }); + JPanel panel = new JPanel(); + JLabel label = new JLabel("0"); + frame = new JFrame("bug4166593"); + comboBox.setEditable(true); + + ActionListener actionCounter = e -> { + ++numberOfActionEvents; + label.setText(Integer.toString(numberOfActionEvents)); + }; + + comboBox.addActionListener(actionCounter); + + panel.add(comboBox); + panel.add(label); + + frame.add(panel); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } +} diff --git a/test/jdk/javax/swing/JComboBox/bug4180054.java b/test/jdk/javax/swing/JComboBox/bug4180054.java new file mode 100644 index 0000000000000..cee68dfcb9ce6 --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4180054.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Robot; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; + +/* + * @test + * @bug 4180054 + * @summary Tests that DefaultComboBoxModel doesn't fire a "contents changed" unnecessarily + * @key headful + * @run main bug4180054 + */ + +public class bug4180054 { + static JFrame frame; + static JComboBox comboBox; + static volatile int numberOfContentsChangedEvents = 0; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + SwingUtilities.invokeAndWait(() -> createTestUI()); + robot.waitForIdle(); + robot.delay(250); + + // change selected index 3 times + SwingUtilities.invokeAndWait(() -> { + comboBox.setSelectedIndex(1); + comboBox.setSelectedIndex(3); + comboBox.setSelectedIndex(2); + comboBox.setSelectedIndex(2); + }); + robot.waitForIdle(); + robot.delay(250); + + if (numberOfContentsChangedEvents != 3) { + throw new RuntimeException("Unexpected number of Contents Changed Events!\n" + + "Expected: 3\nActual: " + numberOfContentsChangedEvents); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static void createTestUI() { + frame = new JFrame("bug4180054"); + JPanel panel = new JPanel(); + JLabel label = new JLabel("0"); + + DefaultComboBoxModel model = new DefaultComboBoxModel(); + for (int i = 0; i < 100; ++i) { + model.addElement(Integer.toString(i)); + } + comboBox = new JComboBox(model); + comboBox.setEditable(true); + + ListDataListener contentsCounter = new ListDataListener() { + public void contentsChanged(ListDataEvent e) { + ++numberOfContentsChangedEvents; + label.setText(Integer.toString(numberOfContentsChangedEvents)); + } + + public void intervalAdded(ListDataEvent e) { + } + + public void intervalRemoved(ListDataEvent e) { + } + }; + + comboBox.getModel().addListDataListener(contentsCounter); + + panel.add(comboBox); + panel.add(label); + + frame.add(panel); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } +} diff --git a/test/jdk/javax/swing/JComboBox/bug4530952.java b/test/jdk/javax/swing/JComboBox/bug4530952.java new file mode 100644 index 0000000000000..cf960d64c9a90 --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4530952.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +/* + * @test + * @bug 4530952 + * @summary Tests that double mouse clicks invoke Event + * @key headful + * @run main bug4530952 + */ + +public class bug4530952 { + static JFrame frame; + static JButton btnAction; + static JComboBox cmbAction; + static volatile Point loc; + static volatile Dimension btnSize; + + private static volatile boolean flag; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + SwingUtilities.invokeAndWait(() -> createTestUI()); + robot.waitForIdle(); + robot.delay(1000); + + // enter some text in combo box + robot.keyPress(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_A); + robot.keyPress(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_A); + robot.waitForIdle(); + robot.delay(250); + + // find and click action button + SwingUtilities.invokeAndWait(() -> { + loc = btnAction.getLocationOnScreen(); + btnSize = btnAction.getSize(); + }); + robot.waitForIdle(); + robot.delay(250); + + robot.mouseMove(loc.x + btnSize.width / 2, + loc.y + btnSize.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(1000); + + if (!flag) { + throw new RuntimeException("Failed: button action was not fired"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static void createTestUI() { + frame = new JFrame("bug4530952"); + frame.setLayout(new FlowLayout()); + + btnAction = new JButton("Action"); + cmbAction = new JComboBox(); + + flag = false; + + ActionListener al = e -> flag = true; + DocumentListener dl = new DocumentListener() { + @Override + public void changedUpdate(DocumentEvent evt) { + resetButtons(); + } + + @Override + public void insertUpdate(DocumentEvent evt) { + resetButtons(); + } + + @Override + public void removeUpdate(DocumentEvent evt) { + resetButtons(); + } + }; + + // Add an editable combo box + cmbAction.setEditable(true); + frame.add(cmbAction); + + btnAction.setEnabled(false); + frame.add(btnAction); + + btnAction.addActionListener(al); + ((JTextField) cmbAction.getEditor().getEditorComponent()). + getDocument().addDocumentListener(dl); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void resetButtons() { + int length = ((JTextField) cmbAction.getEditor().getEditorComponent()). + getDocument().getLength(); + btnAction.setEnabled(length > 0); + } +} diff --git a/test/jdk/javax/swing/JComboBox/bug4530953.java b/test/jdk/javax/swing/JComboBox/bug4530953.java new file mode 100644 index 0000000000000..a9f0c70b9bc2c --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4530953.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.FlowLayout; +import java.awt.Robot; +import java.awt.event.KeyEvent; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4530953 + * @summary Tests that highlighted Item appears after automatically scrolling to the item + * @key headful + * @run main bug4530953 + */ + +public class bug4530953 { + static JFrame frame; + static JComboBox combo; + static String[] data = {"Apple", "Orange", "Cherry"}; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + SwingUtilities.invokeAndWait(() -> createTestUI()); + robot.waitForIdle(); + robot.delay(250); + + // enter some text in combo box editor + robot.keyPress(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_A); + robot.keyPress(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_A); + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.waitForIdle(); + robot.delay(250); + + // select orange in combo box + robot.keyPress(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_DOWN); + robot.keyPress(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_DOWN); + robot.keyPress(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_DOWN); + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.waitForIdle(); + robot.delay(250); + + String currSelection = (String) combo.getEditor().getItem(); + if (!currSelection.equals("Orange")) { + throw new RuntimeException("Unexpected Selection.\n" + + "Expected: Orange\nActual: " + currSelection); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static void createTestUI() { + frame = new JFrame("bug4530953"); + combo = new JComboBox(data); + combo.setEditable(true); + combo.setSelectedIndex(1); + frame.setLayout(new FlowLayout()); + frame.add(combo); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } +} From 2f7806ffe5b5b4b2f7caa14d4559943968c34678 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 22 Apr 2025 07:07:31 +0000 Subject: [PATCH 0687/1101] 8355034: [JVMCI] assert(static_cast(_jvmci_data_size) == align_up(compiler->is_jvmci() ? jvmci_data->size() : 0, oopSize)) failed: failed: 104 != 16777320 Reviewed-by: never, yzheng, cslucas --- src/hotspot/share/code/nmethod.cpp | 2 +- .../share/jvmci/jvmciCodeInstaller.cpp | 8 ++- .../classes/jdk/vm/ci/code/InstalledCode.java | 19 ++++++- .../vm/ci/code/test/InstalledCodeTest.java | 57 +++++++++++++++++++ 4 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/InstalledCodeTest.java diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 01ace66f4dee4..56ba76a806e4f 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -112,7 +112,7 @@ // Cast from int value to narrow type #define CHECKED_CAST(result, T, thing) \ result = static_cast(thing); \ - assert(static_cast(result) == thing, "failed: %d != %d", static_cast(result), thing); + guarantee(static_cast(result) == thing, "failed: %d != %d", static_cast(result), thing); //--------------------------------------------------------------------------------- // NMethod statistics diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp index 79aaacec8098b..3a9fbc54bf941 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp @@ -825,7 +825,13 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, // Since this compilation didn't pass through the broker it wasn't logged yet. if (PrintCompilation) { ttyLocker ttyl; - CompileTask::print(tty, nm, "(hosted JVMCI compilation)"); + if (name != nullptr) { + stringStream st; + st.print_cr("(hosted JVMCI compilation: %s)", name); + CompileTask::print(tty, nm, st.as_string()); + } else { + CompileTask::print(tty, nm, "(hosted JVMCI compilation)"); + } } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/InstalledCode.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/InstalledCode.java index 489cca81c7bff..62c0b6091468e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/InstalledCode.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/InstalledCode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,24 @@ public class InstalledCode { protected final String name; + /** + * The maximum length of an InstalledCode name. This name is typically installed into + * the code cache so it should have a reasonable limit. + */ + public static final int MAX_NAME_LENGTH = 2048; + + /** + * @param name the name to be associated with the installed code. Can be null and + * must be no longer than {@link #MAX_NAME_LENGTH}. + * + * @throws IllegalArgumentException if {@code name.length >} {@link #MAX_NAME_LENGTH} + */ public InstalledCode(String name) { + if (name != null && name.length() > MAX_NAME_LENGTH) { + String msg = String.format("name length (%d) is greater than %d (name[0:%s] = %s)", + name.length(), MAX_NAME_LENGTH, MAX_NAME_LENGTH, name.substring(0, MAX_NAME_LENGTH)); + throw new IllegalArgumentException(msg); + } this.name = name; } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/InstalledCodeTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/InstalledCodeTest.java new file mode 100644 index 0000000000000..f7e68043da785 --- /dev/null +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/InstalledCodeTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test 8355034 + * @requires vm.jvmci + * @modules jdk.internal.vm.ci/jdk.vm.ci.code + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.code.test.InstalledCodeTest + */ + +package jdk.vm.ci.code.test; + +import jdk.vm.ci.code.InstalledCode; +import org.junit.Assert; +import org.junit.Test; + +public class InstalledCodeTest { + + @Test + public void testNullName() { + new InstalledCode(null); + } + + @Test + public void testTooLongName() { + String longName = new String(new char[InstalledCode.MAX_NAME_LENGTH]).replace('\0', 'A'); + new InstalledCode(longName); + try { + String tooLongName = longName + "X"; + new InstalledCode(tooLongName); + } catch (IllegalArgumentException iae) { + // Threw IllegalArgumentException as expected. + return; + } + Assert.fail("expected IllegalArgumentException"); + } +} From 17b080b2c90f7fd9986fe38daebb76363d012469 Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Tue, 22 Apr 2025 07:44:44 +0000 Subject: [PATCH 0688/1101] 8353446: Open source several AWT Menu tests - Batch 2 Reviewed-by: abhiscxk --- .../Menu/DestroyMenuTest/DestroyMenuTest.java | 139 ++++++++++++++ .../awt/Menu/DestroyMenuTest/MenuTest.java | 172 ++++++++++++++++++ .../jdk/java/awt/Menu/MenuAddRemoveCrash.java | 102 +++++++++++ test/jdk/java/awt/Menu/MenuZOrderTest.java | 80 ++++++++ .../java/awt/Menu/OnFlyRepaintMenuTest.java | 103 +++++++++++ 5 files changed, 596 insertions(+) create mode 100644 test/jdk/java/awt/Menu/DestroyMenuTest/DestroyMenuTest.java create mode 100644 test/jdk/java/awt/Menu/DestroyMenuTest/MenuTest.java create mode 100644 test/jdk/java/awt/Menu/MenuAddRemoveCrash.java create mode 100644 test/jdk/java/awt/Menu/MenuZOrderTest.java create mode 100644 test/jdk/java/awt/Menu/OnFlyRepaintMenuTest.java diff --git a/test/jdk/java/awt/Menu/DestroyMenuTest/DestroyMenuTest.java b/test/jdk/java/awt/Menu/DestroyMenuTest/DestroyMenuTest.java new file mode 100644 index 0000000000000..b75ba047dfbe2 --- /dev/null +++ b/test/jdk/java/awt/Menu/DestroyMenuTest/DestroyMenuTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4209511 + * @summary Regression test DestroyMenuTest.java Failing + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DestroyMenuTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Label; +import java.awt.Panel; +import java.awt.Scrollbar; +import java.awt.TextField; + +public class DestroyMenuTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Create many windows by randomly clicking 'Show Menu Test 1', + 'Show Menu Test 2', 'Show Menu Test 3' buttons. + 2. Ignore the contents of the windows. + Go to the windows created and select menu items inside the menus. + 3. Close the windows by selecting menu item File--> Quit. + 4. Do the above menu item selections as quickly as possible. + If the program crashes when you select File--> Quit, + then the test FAILS. Otherwise the test is PASS. + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(38) + .testUI(DestroyMenuTest::initialize) + .build() + .awaitAndCheck(); + } + + static Frame initialize() { + Frame f = new Frame("Destroy Menu Test"); + Button launchButton = new Button("Show Menu Test 1..."); + Button launchButton2 = new Button("Show Menu Test 2..."); + Button launchButton3 = new Button("Show Menu Test 3..."); + f.setLayout(new FlowLayout()); + f.add(launchButton); + f.add(launchButton2); + f.add(launchButton3); + + launchButton.addActionListener(event -> { + MenuTest frame = new MenuTest("Menu Test 1"); + frame.setBounds(300, 300, 300, 300); + frame.setVisible(true); + }); + + launchButton2.addActionListener(event -> { + MenuTest frame = new MenuTest("Menu Test 2"); + + Button closeButton = new Button("Close"); + + Panel X = new Panel(); + X.setLayout(new BorderLayout()); + + Panel topPanel = new Panel(); + Panel bottomPanel = new Panel(); + + bottomPanel.add(closeButton); + + Scrollbar vScrollbar = new Scrollbar(Scrollbar.VERTICAL); + Scrollbar hScrollbar = new Scrollbar(Scrollbar.HORIZONTAL); + hScrollbar.setValues(hScrollbar.getValue(), 0, 0, 50); + vScrollbar.setValues(vScrollbar.getValue(), 0, 0, 50); + topPanel.setLayout(new BorderLayout()); + topPanel.add(vScrollbar, BorderLayout.EAST); + topPanel.add(hScrollbar, BorderLayout.SOUTH); + + X.add(topPanel, BorderLayout.NORTH); + X.add(bottomPanel, BorderLayout.SOUTH); + frame.add(X, BorderLayout.SOUTH); + frame.setBounds(350, 350, 300, 250); + frame.setVisible(true); + }); + + launchButton3.addActionListener(event -> { + MenuTest frame = new MenuTest("Menu Test 3"); + frame.setBounds(400, 400, 300, 300); + + mySimpleCanvas clock = new mySimpleCanvas(); + frame.add(clock, BorderLayout.CENTER); + + Panel p = new Panel(); + Button closeButton = new Button("Close"); + p.add(closeButton); + + p.add(new Label("Label")); + TextField textField = new TextField(8); + p.add(textField); + f.add(p, BorderLayout.EAST); + + frame.add(p, BorderLayout.SOUTH); + frame.setVisible(true); + }); + f.pack(); + return f; + } + + static class mySimpleCanvas extends Canvas { + @Override + public void paint(Graphics g) { + g.drawOval(0, 0, 100, 100); + g.drawOval(2, 2, 100, 100); + g.drawOval(4, 4, 100, 100); + } + } +} diff --git a/test/jdk/java/awt/Menu/DestroyMenuTest/MenuTest.java b/test/jdk/java/awt/Menu/DestroyMenuTest/MenuTest.java new file mode 100644 index 0000000000000..95569f13fa22e --- /dev/null +++ b/test/jdk/java/awt/Menu/DestroyMenuTest/MenuTest.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Canvas; +import java.awt.CardLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; + +public class MenuTest extends Frame { + private MenuItem quitItem; + private final Panel cards; + private final CardLayout layout; + + public MenuTest(String s) { + super(s); + MenuBar mbar = new MenuBar(); + createMenus(mbar); + setMenuBar(mbar); + + cards = new Panel(); + layout = new CardLayout(); + cards.setLayout(layout); + + cards.add(new MyPanelOne("Options"), "Options"); + cards.add(new MyRectCanvas(), "MyRectCanvas"); + cards.add(new MycircleCanvas(), "MyCircleCanvas"); + + add(cards, "Center"); + } + + public void createMenus(MenuBar mbar) { + mbar.add(createFileMenu()); + mbar.add(createEditMenu()); + mbar.add(createOptionMenu1()); + mbar.add(createOptionMenu2()); + mbar.add(createOptionMenu3()); + mbar.add(createOptionMenu4()); + } + + private Menu createFileMenu() { + Menu fileMenu = new Menu("File"); + fileMenu.add(quitItem = new MenuItem("Quit")); + + quitItem.addActionListener(event -> { + MenuItem item = (MenuItem) event.getSource(); + if (item == quitItem) { + dispose(); + } + }); + return fileMenu; + } + + private Menu createEditMenu() { + Menu editMenu = new Menu("Edit"); + + editMenu.add("Cut"); + editMenu.add("Copy"); + editMenu.add("Paste"); + editMenu.addSeparator(); + editMenu.add("Select all"); + editMenu.addSeparator(); + editMenu.add("Find"); + editMenu.add("Find again"); + + return editMenu; + } + + private Menu createOptionMenu1() { + Menu optionMenu1 = new Menu("Option1"); + MenuItem item1, item2, item3; + optionMenu1.add(item1 = new MenuItem("Item1")); + optionMenu1.add(item2 = new MenuItem("Item2")); + optionMenu1.add(item3 = new MenuItem("Item3")); + + item1.addActionListener(event -> { + MenuItem mItem = (MenuItem) event.getSource(); + if (mItem == item1) { + layout.show(cards, "Options"); + } + }); + item2.addActionListener(event -> { + MenuItem mItem = (MenuItem) event.getSource(); + if (mItem == item2) { + layout.show(cards, "MyRectCanvas"); + } + }); + item3.addActionListener(event -> { + MenuItem mItem = (MenuItem) event.getSource(); + if (mItem == item3) { + layout.show(cards, "MyCircleCanvas"); + } + }); + return optionMenu1; + } + + private Menu createOptionMenu2() { + Menu optionMenu2 = new Menu("Option2"); + + optionMenu2.add("Item1"); + optionMenu2.add("Item2"); + + return optionMenu2; + } + + private Menu createOptionMenu3() { + Menu optionMenu3 = new Menu("Option3"); + + optionMenu3.add("Item1"); + optionMenu3.add("Item2"); + optionMenu3.add("Item3"); + optionMenu3.add("Item4"); + + return optionMenu3; + } + + private Menu createOptionMenu4() { + Menu optionMenu4 = new Menu("Option3"); + + optionMenu4.add("Item1"); + optionMenu4.add("Item2"); + optionMenu4.add("Item3"); + + return optionMenu4; + } +} + +class MyRectCanvas extends Canvas { + @Override + public void paint(Graphics g) { + g.drawRect(0, 0, 100, 100); + } +} + +class MyPanelOne extends Panel { + MyPanelOne(String name) { + add(new Label(name + " panel goes here")); + } +} + +class MycircleCanvas extends Canvas { + @Override + public void paint(Graphics g) { + g.drawOval(0, 0, 100, 100); + g.drawOval(2, 2, 100, 100); + g.drawOval(4, 4, 100, 100); + } +} diff --git a/test/jdk/java/awt/Menu/MenuAddRemoveCrash.java b/test/jdk/java/awt/Menu/MenuAddRemoveCrash.java new file mode 100644 index 0000000000000..d5c80c27a4f25 --- /dev/null +++ b/test/jdk/java/awt/Menu/MenuAddRemoveCrash.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4410477 + * @summary Tests that menu does not crash during simultaneous drawing + * and removal of items. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuAddRemoveCrash + */ + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; + +public class MenuAddRemoveCrash { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Move and resize the frame. + 2. If the test crashes the test is FAILED. + Otherwise it is PASSED. + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(MenuAddRemoveCrash::initialize) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + final TestGui myTestGui = new TestGui(); + Thread test = new Thread() { + public void run() { + while (!Thread.interrupted()) { + myTestGui.changeMenuItems(); + } + } + }; + test.setDaemon(true); + test.start(); + return myTestGui; + } +} + +class TestGui extends Frame { + Menu myMenu1; + Menu myMenu2; + + public TestGui() { + this.setTitle("Try to resize this frame!"); + + this.setSize(300, 300); + this.setVisible(true); + + MenuBar myMenuBar = new MenuBar(); + myMenu1 = new Menu("DemoMenu1"); + myMenu2 = new Menu("DemoMenu2"); + + myMenuBar.add(myMenu1); + myMenuBar.add(myMenu2); + + this.setMenuBar(myMenuBar); + } + + public void changeMenuItems() { + myMenu1.removeAll(); + + for (int i = 0; i < 10; i++) { + MenuItem myMenuItem1 = new MenuItem("DemoMenuItem" + i); + myMenu1.add(myMenuItem1); + } + try { + Thread.sleep(100); + } catch (Exception e) { + throw new RuntimeException("Failed :" + e); + } + } +} diff --git a/test/jdk/java/awt/Menu/MenuZOrderTest.java b/test/jdk/java/awt/Menu/MenuZOrderTest.java new file mode 100644 index 0000000000000..fefd3d64c28f9 --- /dev/null +++ b/test/jdk/java/awt/Menu/MenuZOrderTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6267182 + * @summary Menu is not visible after showing and disposing a file dialog. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuZOrderTest + */ + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class MenuZOrderTest { + static class Listener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + Frame f = new Frame("Menu Z order test frame"); + f.setBounds(200, 200, 200, 200); + f.setVisible(true); + } + } + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Choose Menu 1 --> Menu Item 1 several times. + 2. If menu window is shown correctly and each click + creates new frame - press PASS. + 3. If menu window is obscured by frame - press FAIL. + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(MenuZOrderTest::initialize) + .build() + .awaitAndCheck(); + } + + static Frame initialize() { + Frame mf = new Frame("Menu Z order test"); + Listener l = new Listener(); + MenuBar mb = new MenuBar(); + Menu m1 = new Menu("Menu 1"); + MenuItem mi1 = new MenuItem("Menu Item 1"); + + mf.setSize(200, 200); + mi1.addActionListener(l); + m1.add(mi1); + mb.add(m1); + mf.setMenuBar(mb); + mf.setVisible(true); + return mf; + } +} diff --git a/test/jdk/java/awt/Menu/OnFlyRepaintMenuTest.java b/test/jdk/java/awt/Menu/OnFlyRepaintMenuTest.java new file mode 100644 index 0000000000000..617d640d90732 --- /dev/null +++ b/test/jdk/java/awt/Menu/OnFlyRepaintMenuTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5024051 + * @summary Tests if menu is repainted in enabling/disabling it and + * changing its label while it is visible, either on MenuBar + * or in other Menu. Menu items are covered as well + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual OnFlyRepaintMenuTest + */ + +import java.awt.Button; +import java.awt.CheckboxMenuItem; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; + +public class OnFlyRepaintMenuTest { + static boolean menuEnabled = true; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Click the button 'Change state' and wait for 5 secs. + 2. If menu is repainted correctly after its setLabel() + and setEnabled() methods called test PASSED, else FAILED. + (During a 5 secs delay you may select the menu to see + the effect for menu items and submenu) + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(OnFlyRepaintMenuTest::initialize) + .build() + .awaitAndCheck(); + } + + static Frame initialize() { + Frame f = new Frame("OnFly Menu Repaint Test"); + + f.setSize(200, 100); + + MenuBar mb = new MenuBar(); + Menu menu = new Menu("Menu"); + MenuItem menuItem = new MenuItem("MenuItem"); + menu.add(menuItem); + Menu submenu = new Menu("SubMenu"); + MenuItem submenuItem = new MenuItem("SubmenuItem"); + submenu.add(submenuItem); + CheckboxMenuItem checkMenuItem = new CheckboxMenuItem("CheckboxmenuItem"); + checkMenuItem.setState(true); + menu.add(checkMenuItem); + menu.add(submenu); + mb.add(menu); + f.setMenuBar(mb); + + Button b = new Button("Change state"); + b.addActionListener(ev -> new Thread(() -> { + try { + Thread.sleep(5000); + } catch (Exception e) { + } + menuEnabled = !menuEnabled; + String label = menuEnabled ? "Enabled" : "Disabled"; + menu.setLabel(label); + menuItem.setLabel(label); + submenu.setLabel(label); + submenuItem.setLabel(label); + checkMenuItem.setLabel(label); + checkMenuItem.setEnabled(menuEnabled); + checkMenuItem.setState(menuEnabled); + submenuItem.setEnabled(menuEnabled); + submenu.setEnabled(menuEnabled); + menuItem.setEnabled(menuEnabled); + menu.setEnabled(menuEnabled); + }).start()); + f.add(b); + return f; + } +} From 0b2a2f38d0b0133a562a898836d7a1b2dbd73a5e Mon Sep 17 00:00:00 2001 From: Alisen Chung Date: Tue, 22 Apr 2025 07:45:56 +0000 Subject: [PATCH 0689/1101] 8353685: Open some JComboBox bugs 4 Reviewed-by: honkar, kizune --- .../jdk/javax/swing/JComboBox/bug4212498.java | 86 +++++++++++++++++ .../jdk/javax/swing/JComboBox/bug4459267.java | 75 +++++++++++++++ .../jdk/javax/swing/JComboBox/bug4519269.java | 94 +++++++++++++++++++ 3 files changed, 255 insertions(+) create mode 100644 test/jdk/javax/swing/JComboBox/bug4212498.java create mode 100644 test/jdk/javax/swing/JComboBox/bug4459267.java create mode 100644 test/jdk/javax/swing/JComboBox/bug4519269.java diff --git a/test/jdk/javax/swing/JComboBox/bug4212498.java b/test/jdk/javax/swing/JComboBox/bug4212498.java new file mode 100644 index 0000000000000..b60470fdd327c --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4212498.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.event.ActionListener; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; + +/* + * @test + * @bug 4212498 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4212498 + */ + +public class bug4212498 { + static JPanel panel = new JPanel(); + static JComboBox comboBox = new JComboBox(new Object[]{ + "Coma Berenices", + "Triangulum", + "Camelopardis", + "Cassiopea"}); + + private static final String INSTRUCTIONS = """ + Edit the value in the text field (without using the popup) + and then press the tab key. If the number doesn't increase, + then test fails. + + Also, try tabbing out without making a change. The number + should NOT increase unless the user changes something. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4212498::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4212498"); + comboBox.setEditable(true); + + final JLabel label = new JLabel("0"); + + ActionListener actionListener = + e -> label.setText("" + (Integer.parseInt(label.getText()) + 1)); + + comboBox.addActionListener(actionListener); + + panel.add(comboBox); + panel.add(label); + panel.add(new JButton("B")); + + frame.getContentPane().add(panel); + frame.pack(); + frame.setLocationRelativeTo(null); + return frame; + } +} diff --git a/test/jdk/javax/swing/JComboBox/bug4459267.java b/test/jdk/javax/swing/JComboBox/bug4459267.java new file mode 100644 index 0000000000000..85049936ea7fd --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4459267.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Robot; +import java.awt.event.KeyEvent; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4459267 + * @summary Tests that pressing PageUp in combo popup list doesn't cause + * stack overflow + * @key headful + * @run main bug4459267 + */ + +public class bug4459267 { + static JFrame frame; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(250); + + SwingUtilities.invokeAndWait(() -> createTestUI()); + robot.waitForIdle(); + robot.delay(1000); + + robot.keyPress(KeyEvent.VK_PAGE_UP); + robot.keyRelease(KeyEvent.VK_PAGE_UP); + robot.waitForIdle(); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static void createTestUI() { + frame = new JFrame("bug4459267"); + JComboBox jcmb = new JComboBox(); + jcmb.addItem("JComobo1"); + jcmb.addItem("Item2"); + jcmb.addItem("Item3"); + frame.getContentPane().add(jcmb, BorderLayout.NORTH); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } +} diff --git a/test/jdk/javax/swing/JComboBox/bug4519269.java b/test/jdk/javax/swing/JComboBox/bug4519269.java new file mode 100644 index 0000000000000..29147998d0a4c --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4519269.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4519269 + * @summary Tests that DefaultKeySelectionManager doesn't throw NPE + * @key headful + * @run main bug4519269 + */ + +public class bug4519269 { + static JFrame frame; + static JComboBox combo; + static Point p; + static Object[] data = {new CustomString("Item 1"), new CustomString("Item 2"), + new CustomString("Item 3"), new CustomString("Item 4")}; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(250); + + SwingUtilities.invokeAndWait(() -> createTestUI()); + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> p = combo.getLocationOnScreen()); + robot.mouseMove(p.x + 5, p.y + 5); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.waitForIdle(); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static void createTestUI() { + frame = new JFrame("bug4519269"); + combo = new JComboBox(data); + frame.getContentPane().add(combo); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + static class CustomString { + String string; + + public CustomString(String s) { + string = s; + } + + public String toString() { + return null; + } + } +} From 7eab2d9f9140a27f7a5c5e0a57b9e6a256558690 Mon Sep 17 00:00:00 2001 From: Alisen Chung Date: Tue, 22 Apr 2025 07:58:30 +0000 Subject: [PATCH 0690/1101] 8354095: Open some JTable bugs 5 Reviewed-by: kizune, honkar --- .../swing/JTable/InternationalCharacters.java | 172 +++++++++++++++++ .../javax/swing/JTable/NullTableHeader.java | 44 +++++ test/jdk/javax/swing/JTable/bug4118307.java | 182 ++++++++++++++++++ test/jdk/javax/swing/JTable/bug4138158.java | 62 ++++++ 4 files changed, 460 insertions(+) create mode 100644 test/jdk/javax/swing/JTable/InternationalCharacters.java create mode 100644 test/jdk/javax/swing/JTable/NullTableHeader.java create mode 100644 test/jdk/javax/swing/JTable/bug4118307.java create mode 100644 test/jdk/javax/swing/JTable/bug4138158.java diff --git a/test/jdk/javax/swing/JTable/InternationalCharacters.java b/test/jdk/javax/swing/JTable/InternationalCharacters.java new file mode 100644 index 0000000000000..1d8fc2c4576e0 --- /dev/null +++ b/test/jdk/javax/swing/JTable/InternationalCharacters.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import javax.swing.DefaultCellEditor; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.border.BevelBorder; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.table.TableModel; + +/* + * @test + * @bug 4179066 + * @summary Tests that JTable prints AltGr characters (~\@|{}[]²µ³) + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual InternationalCharacters + */ + +public class InternationalCharacters { + private static final String INSTRUCTIONS = """ + Double-click an entry in the JTable. + Press Alt-Gr or Option with any key to type an international character. + Verify that the international character appears in the table. + If it does, press "pass", otherwise press "fail". + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(InternationalCharacters::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("InternationalCharacters test"); + // Take the dummy data from SwingSet. + final String[] names = {"First Name", "Last Name", "Favorite Color", + "Favorite Number", "Vegetarian"}; + final Object[][] data = { + {"Mark", "Andrews", "Red", 2, true}, + {"Tom", "Ball", "Blue", 99, false}, + {"Alan", "Chung", "Green", 838, false}, + {"Jeff", "Dinkins", "Turquois", 8, true}, + {"Amy", "Fowler", "Yellow", 3, false}, + {"Brian", "Gerhold", "Green", 0, false}, + {"James", "Gosling", "Pink", 21, false}, + {"David", "Karlton", "Red", 1, false}, + {"Dave", "Kloba", "Yellow", 14, false}, + {"Peter", "Korn", "Purple", 12, false}, + {"Phil", "Milne", "Purple", 3, false}, + {"Dave", "Moore", "Green", 88, false}, + {"Hans", "Muller", "Maroon", 5, false}, + {"Rick", "Levenson", "Blue", 2, false}, + {"Tim", "Prinzing", "Blue", 22, false}, + {"Chester", "Rose", "Black", 0, false}, + {"Ray", "Ryan", "Gray", 77, false}, + {"Georges", "Saab", "Red", 4, false}, + {"Willie", "Walker", "Phthalo Blue", 4, false}, + {"Kathy", "Walrath", "Blue", 8, false}, + {"Arnaud", "Weber", "Green", 44, false} + }; + + // Create a model of the data. + TableModel dataModel = new AbstractTableModel() { + // These methods always need to be implemented. + public int getColumnCount() { return names.length; } + public int getRowCount() { return data.length;} + public Object getValueAt(int row, int col) {return data[row][col];} + + // The default implementations of these methods in + // AbstractTableModel would work, but we can refine them. + public String getColumnName(int column) {return names[column];} + public Class getColumnClass(int c) {return getValueAt(0, c).getClass();} + public boolean isCellEditable(int row, int col) {return true;} + public void setValueAt(Object aValue, int row, int column) { + System.out.println("Setting value to: " + aValue); + data[row][column] = aValue; + } + }; + + // Create the table + JTable tableView = new JTable(dataModel); + // Turn off auto-resizing so that we can set column sizes programmatically. + // In this mode, all columns will get their preferred widths, as set blow. + tableView.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + + // Create a combo box to show that you can use one in a table. + JComboBox comboBox = new JComboBox(); + comboBox.addItem("Red"); + comboBox.addItem("Orange"); + comboBox.addItem("Yellow"); + comboBox.addItem("Green"); + comboBox.addItem("Blue"); + comboBox.addItem("Indigo"); + comboBox.addItem("Violet"); + + TableColumn colorColumn = tableView.getColumn("Favorite Color"); + // Use the combo box as the editor in the "Favorite Color" column. + colorColumn.setCellEditor(new DefaultCellEditor(comboBox)); + + // Set a pink background and tooltip for the Color column renderer. + DefaultTableCellRenderer colorColumnRenderer = new DefaultTableCellRenderer(); + colorColumnRenderer.setBackground(Color.pink); + colorColumnRenderer.setToolTipText("Click for combo box"); + colorColumn.setCellRenderer(colorColumnRenderer); + + // Set a tooltip for the header of the colors column. + TableCellRenderer headerRenderer = colorColumn.getHeaderRenderer(); + if (headerRenderer instanceof DefaultTableCellRenderer) + ((DefaultTableCellRenderer)headerRenderer).setToolTipText("Hi Mom!"); + + // Set the width of the "Vegetarian" column. + TableColumn vegetarianColumn = tableView.getColumn("Vegetarian"); + vegetarianColumn.setPreferredWidth(100); + + // Show the values in the "Favorite Number" column in different colors. + TableColumn numbersColumn = tableView.getColumn("Favorite Number"); + DefaultTableCellRenderer numberColumnRenderer = new DefaultTableCellRenderer() { + public void setValue(Object value) { + int cellValue = (value instanceof Number) ? ((Number)value).intValue() : 0; + setForeground((cellValue > 30) ? Color.black : Color.red); + setText((value == null) ? "" : value.toString()); + } + }; + numberColumnRenderer.setHorizontalAlignment(JLabel.RIGHT); + numbersColumn.setCellRenderer(numberColumnRenderer); + numbersColumn.setPreferredWidth(110); + + // Finish setting up the table. + JScrollPane scrollpane = new JScrollPane(tableView); + scrollpane.setBorder(new BevelBorder(BevelBorder.LOWERED)); + scrollpane.setPreferredSize(new Dimension(430, 200)); + + frame.add(scrollpane); + frame.setSize(500, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/NullTableHeader.java b/test/jdk/javax/swing/JTable/NullTableHeader.java new file mode 100644 index 0000000000000..dc62b975d045d --- /dev/null +++ b/test/jdk/javax/swing/JTable/NullTableHeader.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import javax.swing.JFrame; +import javax.swing.JTable; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4129409 + * @summary Tests that JTable.setTableHeader(null) doesn't break AutoResize + * @key headful + * @run main NullTableHeader + */ + +public class NullTableHeader { + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> { + JTable tableView = new JTable(); + tableView.setTableHeader(null); + tableView.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + }); + } +} diff --git a/test/jdk/javax/swing/JTable/bug4118307.java b/test/jdk/javax/swing/JTable/bug4118307.java new file mode 100644 index 0000000000000..537e92176efa7 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4118307.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableModel; + +/* + * @test + * @bug 4118307 + * @summary Tests that JTable's cell editor for Number and Date work correctly + * @key headful + * @run main bug4118307 + */ + +public class bug4118307 { + static JFrame frame; + static MyTable tbl; + static Point tableLoc; + static Point p; + private static volatile boolean flag; + static final String[] columnNames = {"Integer", "Double"}; + static final Object[][] data = { + {5, 3.14}, + {10, 2.71}, + {70, 3.14}, + {200, 2.71}, + }; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(250); + SwingUtilities.invokeAndWait(() -> createTestUI()); + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + tableLoc = tbl.getLocationOnScreen(); + p = tbl.getCellRect(0, 0, true).getLocation(); + }); + robot.waitForIdle(); + + robot.mouseMove(tableLoc.x + p.x + 10, tableLoc.y + p.y + 10); + robot.waitForIdle(); + + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(() -> + p = tbl.getCellRect(1, 1, true).getLocation()); + robot.waitForIdle(); + + robot.mouseMove(tableLoc.x + p.x + 10, tableLoc.y + p.y + 10); + robot.waitForIdle(); + + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(() -> + p = tbl.getCellRect(1, 0, true).getLocation()); + robot.waitForIdle(); + + robot.mouseMove(tableLoc.x + p.x + 10, tableLoc.y + p.y + 10); + robot.waitForIdle(); + + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(5000); + + if (!flag) { + throw new RuntimeException("Test Failed."); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static void createTestUI() { + frame = new JFrame("bug4118307"); + MyTableModel myModel = new MyTableModel(); + tbl = new MyTable(myModel); + JScrollPane sp = new JScrollPane(tbl); + flag = true; + + frame.add(sp, BorderLayout.CENTER); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + static class MyTable extends JTable { + public MyTable(TableModel tm) { + super(tm); + } + + public Component prepareRenderer(TableCellRenderer rend, int row, int col) { + try { + return super.prepareRenderer(rend, row, col); + } catch (Exception e) { + e.printStackTrace(); + flag = false; + return null; + } + } + } + + static class MyTableModel extends AbstractTableModel { + public int getColumnCount() { + return columnNames.length; + } + + public int getRowCount() { + return data.length; + } + + @Override + public String getColumnName(int col) { + return columnNames[col]; + } + + public Object getValueAt(int row, int col) { + return data[row][col]; + } + + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } + + @Override + public boolean isCellEditable(int row, int col) { + return true; + } + + @Override + public void setValueAt(Object value, int row, int col) { + data[row][col] = value; + } + } +} diff --git a/test/jdk/javax/swing/JTable/bug4138158.java b/test/jdk/javax/swing/JTable/bug4138158.java new file mode 100644 index 0000000000000..400b8b1952ef0 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4138158.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; + +/* + * @test + * @bug 4138158 + * @summary Tests that setAutoscrolls(false) locks autoscroll + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4138158 + */ + +public class bug4138158 { + private static final String INSTRUCTIONS = """ + Move mouse to beginning of table, press left mouse button and drag mouse down + below the frame. If the table isn't scrolled down then test passes. + If the table is scrolled then test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4138158::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4138158"); + JTable table = new JTable(20, 3); + table.setAutoscrolls(false); + JScrollPane sp = new JScrollPane(table); + frame.add(sp); + frame.setSize(200, 200); + return frame; + } +} From 367bcc5df83722231106b635068a17f92404477b Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Tue, 22 Apr 2025 07:59:45 +0000 Subject: [PATCH 0691/1101] 8353445: Open source several AWT Menu tests - Batch 1 Reviewed-by: abhiscxk, prr --- test/jdk/ProblemList.txt | 1 + .../java/awt/Menu/MenuActionEventTest.java | 98 +++++++++++ .../jdk/java/awt/Menu/MenuVisibilityTest.java | 71 ++++++++ test/jdk/java/awt/Menu/RmInHideTest.java | 152 ++++++++++++++++++ test/jdk/java/awt/Menu/SetShortCutTest.java | 132 +++++++++++++++ 5 files changed, 454 insertions(+) create mode 100644 test/jdk/java/awt/Menu/MenuActionEventTest.java create mode 100644 test/jdk/java/awt/Menu/MenuVisibilityTest.java create mode 100644 test/jdk/java/awt/Menu/RmInHideTest.java create mode 100644 test/jdk/java/awt/Menu/SetShortCutTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 841b1110506b8..fe0657ff1650d 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -819,4 +819,5 @@ java/awt/Checkbox/CheckboxBoxSizeTest.java 8340870 windows-all java/awt/Checkbox/CheckboxIndicatorSizeTest.java 8340870 windows-all java/awt/Checkbox/CheckboxNullLabelTest.java 8340870 windows-all java/awt/dnd/WinMoveFileToShellTest.java 8341665 windows-all +java/awt/Menu/MenuVisibilityTest.java 8161110 macosx-all java/awt/Modal/NativeDialogToFrontBackTest.java 7188049 windows-all,linux-all diff --git a/test/jdk/java/awt/Menu/MenuActionEventTest.java b/test/jdk/java/awt/Menu/MenuActionEventTest.java new file mode 100644 index 0000000000000..70fcc81ac864c --- /dev/null +++ b/test/jdk/java/awt/Menu/MenuActionEventTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4094620 + * @summary MenuItem.enableEvents does not work + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuActionEventTest + */ + +import java.awt.AWTEvent; +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.event.ActionEvent; + +public class MenuActionEventTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Click on the Menu and then on Menuitem on the frame. + 2. If you find the following message being printed in + the test log area:, + _MenuItem: action event", + click PASS, else click FAIL" + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(MenuActionEventTest::initialize) + .logArea() + .build() + .awaitAndCheck(); + } + + static Frame initialize() { + Frame f = new Frame("Menu Action Event Test"); + f.setLayout(new BorderLayout()); + f.setMenuBar(new MenuBar()); + Menu m = new _Menu("Menu"); + MenuBar mb = f.getMenuBar(); + mb.add(m); + MenuItem mi = new _MenuItem("Menuitem"); + m.add(mi); + f.setBounds(204, 152, 396, 300); + return f; + } + + static class _Menu extends Menu { + public _Menu(String text) { + super(text); + enableEvents(AWTEvent.ACTION_EVENT_MASK); + } + + @Override + protected void processActionEvent(ActionEvent e) { + PassFailJFrame.log("_Menu: action event"); + super.processActionEvent(e); + } + } + + static class _MenuItem extends MenuItem { + public _MenuItem(String text) { + super(text); + enableEvents(AWTEvent.ACTION_EVENT_MASK); + } + + @Override + protected void processActionEvent(ActionEvent e) { + PassFailJFrame.log("_MenuItem: action event"); + super.processActionEvent(e); + } + } + +} diff --git a/test/jdk/java/awt/Menu/MenuVisibilityTest.java b/test/jdk/java/awt/Menu/MenuVisibilityTest.java new file mode 100644 index 0000000000000..cb74cd56e1a1f --- /dev/null +++ b/test/jdk/java/awt/Menu/MenuVisibilityTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5046491 6423258 + * @summary CheckboxMenuItem: menu text is missing from test frame + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuVisibilityTest +*/ + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; + +public class MenuVisibilityTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Press on a MenuBar with a long name. + 2. Select "First item" in an opened menu. + If you see that "First menu item was pressed" in + the test log area, press PASS + Otherwise press FAIL" + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(MenuVisibilityTest::initialize) + .logArea() + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + Frame frame = new Frame("Menu visibility test"); + String menuTitle = "I_have_never_seen_so_long_Menu_Title_" + + "!_ehe-eha-ehu-ehi_ugu-gu!!!_;)_BANG_BANG..."; + MenuBar menubar = new MenuBar(); + Menu menu = new Menu(menuTitle); + MenuItem menuItem = new MenuItem("First item"); + menuItem.addActionListener(e -> + PassFailJFrame.log("First menu item was pressed.")); + menu.add(menuItem); + menubar.add(menu); + frame.setMenuBar(menubar); + frame.setSize(100, 200); + return frame; + } +} diff --git a/test/jdk/java/awt/Menu/RmInHideTest.java b/test/jdk/java/awt/Menu/RmInHideTest.java new file mode 100644 index 0000000000000..b2d6840064749 --- /dev/null +++ b/test/jdk/java/awt/Menu/RmInHideTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4039387 + * @summary Checks that calling Frame.remove() within hide() doesn't + * cause SEGV + * @key headful + * @run main RmInHideTest + */ + +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; + +public class RmInHideTest { + static volatile Point point; + static RmInHideTestFrame frame; + static volatile Dimension dimension; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + try { + EventQueue.invokeAndWait(() -> { + frame = new RmInHideTestFrame(); + frame.setSize(200, 200); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(1000); + EventQueue.invokeAndWait(() -> { + point = frame.getButtonLocation(); + dimension = frame.getButtonDimension(); + }); + robot.mouseMove(point.x + dimension.width / 2, point.y + dimension.height / 2); + robot.mousePress(MouseEvent.BUTTON2_DOWN_MASK); + robot.mouseRelease(MouseEvent.BUTTON2_DOWN_MASK); + robot.waitForIdle(); + robot.delay(100); + System.out.println("Test pass"); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + static class RmInHideTestFrame extends Frame implements ActionListener { + MenuBar menubar = null; + Button b; + + public RmInHideTestFrame() { + super("RmInHideTest"); + b = new Button("Hide"); + b.setActionCommand("hide"); + b.addActionListener(this); + add("Center", b); + + MenuBar bar = new MenuBar(); + + Menu menu = new Menu("Test1", true); + menu.add(new MenuItem("Test1A")); + menu.add(new MenuItem("Test1B")); + menu.add(new MenuItem("Test1C")); + bar.add(menu); + + menu = new Menu("Test2", true); + menu.add(new MenuItem("Test2A")); + menu.add(new MenuItem("Test2B")); + menu.add(new MenuItem("Test2C")); + bar.add(menu); + setMenuBar(bar); + } + + @Override + public Dimension minimumSize() { + return new Dimension(200, 200); + } + + @Override + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + if (cmd.equals("hide")) { + hide(); + try { + Thread.currentThread().sleep(2000); + } catch (InterruptedException ex) { + // do nothing + } + show(); + } + } + + @Override + public void hide() { + menubar = getMenuBar(); + if (menubar != null) { + remove(menubar); + } + super.hide(); + } + + + @Override + public void show() { + if (menubar != null) { + setMenuBar(menubar); + } + super.show(); + } + + public Point getButtonLocation() { + return b.getLocationOnScreen(); + } + + public Dimension getButtonDimension() { + return b.getSize(); + } + } +} diff --git a/test/jdk/java/awt/Menu/SetShortCutTest.java b/test/jdk/java/awt/Menu/SetShortCutTest.java new file mode 100644 index 0000000000000..b60b83dff9a9f --- /dev/null +++ b/test/jdk/java/awt/Menu/SetShortCutTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4203208 + * @summary setShortcut method does not display proper text on Menu component + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetShortCutTest + */ + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; + +import static java.awt.event.KeyEvent.VK_META; +import static java.awt.event.KeyEvent.VK_SHIFT; + +public class SetShortCutTest { + public static void main(String[] args) throws Exception { + boolean isMac = System.getProperty("os.name").startsWith("Mac"); + String shortcut = "Ctrl+Shift+"; + if (isMac) { + shortcut = KeyEvent.getKeyText(VK_SHIFT) + "+" + KeyEvent.getKeyText(VK_META); + } + + String INSTRUCTIONS = """ + 1. Select menuitem 'Stuff -> Second' once to remove 'File -> First'. + 2. Select menuitem 'Stuff -> Second' again to add 'File -> First'. + 3. If menuitem 'File -> First' reads First """ + shortcut + """ + 'C', press PASS. Otherwise press FAIL. + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(SetShortCutTest::initialize) + .build() + .awaitAndCheck(); + } + + static Frame initialize() { + return new TestMenuShortCut(); + } + + static class TestMenuShortCut extends Frame implements ActionListener { + Menu menu1; + MenuItem item1; + MenuItem item2; + boolean beenHere; + + public TestMenuShortCut() { + setTitle("Set ShortCut test"); + beenHere = false; + MenuBar mTopMenu = buildMenu(); + setSize(300, 300); + this.setMenuBar(mTopMenu); + } + + public MenuBar buildMenu() { + MenuBar bar; + bar = new MenuBar(); + menu1 = new Menu("File"); + item1 = new MenuItem("First"); + menu1.add(item1); + item1.setShortcut(new MenuShortcut(KeyEvent.VK_C, true)); + bar.add(menu1); + + // Stuff menu + item2 = new MenuItem("Second"); + Menu menu2 = new Menu("Stuff"); + menu2.add(item2); + item2.setShortcut(new MenuShortcut(KeyEvent.VK_C, false)); + bar.add(menu2); + + item1.addActionListener(this); + item2.addActionListener(this); + return bar; + } + + @Override + public void actionPerformed(ActionEvent event) { + if (event.getSource() == item1) { + Frame temp = new Frame("Accelerator key is working for 'First'"); + temp.setSize(300, 50); + temp.setVisible(true); + } + + // Click on the "Stuff" menu to remove the "first" menu item + else if (event.getSource() == item2) { + // If the item has not been removed from the menu, + // then remove "First" from the "File" menu + if (beenHere == false) { + item1.removeActionListener(this); + menu1.remove(item1); + beenHere = true; + } else { + item1 = new MenuItem("First"); + menu1.add(item1); + item1.addActionListener(this); + item1.setShortcut(new MenuShortcut(KeyEvent.VK_C, true)); + beenHere = false; + } + } + } + } +} From 50358d1ca49c26d100c5c658de29c75f864fdc60 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Tue, 22 Apr 2025 08:00:01 +0000 Subject: [PATCH 0692/1101] 8354929: ZGC: Update collection stats while holding page allocator lock Reviewed-by: stefank, tschatzl, aboldtch --- src/hotspot/share/gc/z/zGeneration.cpp | 5 +-- src/hotspot/share/gc/z/zPageAllocator.cpp | 49 ++++++++++++----------- src/hotspot/share/gc/z/zPageAllocator.hpp | 6 ++- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index f3cd3393fc502..e74d7a8e9f3e0 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -279,7 +279,6 @@ void ZGeneration::reset_statistics() { _freed = 0; _promoted = 0; _compacted = 0; - _page_allocator->reset_statistics(_id); } size_t ZGeneration::freed() const { @@ -860,7 +859,7 @@ void ZGenerationYoung::mark_start() { _remembered.flip(); // Update statistics - stat_heap()->at_mark_start(_page_allocator->stats(this)); + stat_heap()->at_mark_start(_page_allocator->update_and_stats(this)); } void ZGenerationYoung::mark_roots() { @@ -1209,7 +1208,7 @@ void ZGenerationOld::mark_start() { _mark.start(); // Update statistics - stat_heap()->at_mark_start(_page_allocator->stats(this)); + stat_heap()->at_mark_start(_page_allocator->update_and_stats(this)); // Note that we start a marking cycle. // Unlike other GCs, the color switch implicitly changes the nmethods diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index a0d2c46c414dc..7bb1dcdcf81d4 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -1373,9 +1373,25 @@ size_t ZPageAllocator::unused() const { return unused > 0 ? (size_t)unused : 0; } -ZPageAllocatorStats ZPageAllocator::stats(ZGeneration* generation) const { - ZLocker locker(&_lock); +void ZPageAllocator::update_collection_stats(ZGenerationId id) { + assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); +#ifdef ASSERT + size_t total_used = 0; + + ZPartitionIterator iter(&_partitions); + for (ZPartition* partition; iter.next(&partition);) { + total_used += partition->_used; + } + + assert(total_used == _used, "Must be consistent %zu == %zu", total_used, _used); +#endif + + _collection_stats[(int)id]._used_high = _used; + _collection_stats[(int)id]._used_low = _used; +} + +ZPageAllocatorStats ZPageAllocator::stats_inner(ZGeneration* generation) const { return ZPageAllocatorStats(_min_capacity, _max_capacity, soft_max_capacity(), @@ -1390,29 +1406,16 @@ ZPageAllocatorStats ZPageAllocator::stats(ZGeneration* generation) const { _stalled.size()); } -void ZPageAllocator::reset_statistics(ZGenerationId id) { - assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); -#ifdef ASSERT - { - // We may free without safepoint synchronization, take the lock to get - // consistent values. - ZLocker locker(&_lock); - size_t total_used = 0; - - ZPartitionIterator iter(&_partitions); - for (ZPartition* partition; iter.next(&partition);) { - total_used += partition->_used; - } - - assert(total_used == _used, "Must be consistent at safepoint %zu == %zu", total_used, _used); - } -#endif +ZPageAllocatorStats ZPageAllocator::stats(ZGeneration* generation) const { + ZLocker locker(&_lock); + return stats_inner(generation); +} - // Read once, we may have concurrent writers. - const size_t used = Atomic::load(&_used); +ZPageAllocatorStats ZPageAllocator::update_and_stats(ZGeneration* generation) { + ZLocker locker(&_lock); - _collection_stats[(int)id]._used_high = used; - _collection_stats[(int)id]._used_low = used; + update_collection_stats(generation->id()); + return stats_inner(generation); } void ZPageAllocator::increase_used_generation(ZGenerationId id, size_t size) { diff --git a/src/hotspot/share/gc/z/zPageAllocator.hpp b/src/hotspot/share/gc/z/zPageAllocator.hpp index 05b0d6774d9d3..5cd08aee94cda 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.hpp +++ b/src/hotspot/share/gc/z/zPageAllocator.hpp @@ -235,6 +235,9 @@ class ZPageAllocator { void notify_out_of_memory(); void restart_gc() const; + void update_collection_stats(ZGenerationId id); + ZPageAllocatorStats stats_inner(ZGeneration* generation) const; + void print_on_inner(outputStream* st) const; public: @@ -262,8 +265,7 @@ class ZPageAllocator { void promote_used(const ZPage* from, const ZPage* to); ZPageAllocatorStats stats(ZGeneration* generation) const; - - void reset_statistics(ZGenerationId id); + ZPageAllocatorStats update_and_stats(ZGeneration* generation); ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age); void safe_destroy_page(ZPage* page); From bcc33d5ef3bdbfaee51c45014851c54028da03f1 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 22 Apr 2025 08:32:03 +0000 Subject: [PATCH 0693/1101] 8352504: RISC-V: implement and enable CMoveI/L 8346786: RISC-V: Reconsider ConditionalMoveLimit when adding conditional move Reviewed-by: fyang, fjiang --- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 30 ++++ .../cpu/riscv/c2_MacroAssembler_riscv.hpp | 4 + src/hotspot/cpu/riscv/c2_globals_riscv.hpp | 2 +- .../cpu/riscv/macroAssembler_riscv.cpp | 124 ++++++++++++++ .../cpu/riscv/macroAssembler_riscv.hpp | 5 + src/hotspot/cpu/riscv/riscv.ad | 103 ++++++++++-- src/hotspot/cpu/riscv/vm_version_riscv.cpp | 8 - .../os_cpu/linux_riscv/riscv_hwprobe.cpp | 5 +- .../c2/irTests/ModINodeIdealizationTests.java | 6 +- .../c2/irTests/ModLNodeIdealizationTests.java | 6 +- .../c2/irTests/TestConv2BExpansion.java | 8 + .../compiler/c2/irTests/TestFPComparison.java | 1 - .../compiler/c2/irTests/TestIfMinMax.java | 17 +- .../lib/ir_framework/TestFramework.java | 1 + .../compiler/vectorapi/TestVectorTest.java | 3 +- .../bench/java/lang/ClassComparison.java | 101 +++++++++++ .../openjdk/bench/java/lang/FPComparison.java | 159 +++++++++++++++++- .../bench/java/lang/IntegerComparison.java | 153 +++++++++++++++++ .../bench/java/lang/LongComparison.java | 152 +++++++++++++++++ .../bench/java/lang/PointerComparison.java | 101 +++++++++++ 20 files changed, 940 insertions(+), 49 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/lang/ClassComparison.java create mode 100644 test/micro/org/openjdk/bench/java/lang/IntegerComparison.java create mode 100644 test/micro/org/openjdk/bench/java/lang/LongComparison.java create mode 100644 test/micro/org/openjdk/bench/java/lang/PointerComparison.java diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 39a49f8f1eb85..0dc39744741f4 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2156,6 +2156,36 @@ void C2_MacroAssembler::enc_cmove(int cmpFlag, Register op1, Register op2, Regis } } +void C2_MacroAssembler::enc_cmove_cmp_fp(int cmpFlag, FloatRegister op1, FloatRegister op2, Register dst, Register src, bool is_single) { + int op_select = cmpFlag & (~unsigned_branch_mask); + + switch (op_select) { + case BoolTest::eq: + cmov_cmp_fp_eq(op1, op2, dst, src, is_single); + break; + case BoolTest::ne: + cmov_cmp_fp_ne(op1, op2, dst, src, is_single); + break; + case BoolTest::le: + cmov_cmp_fp_le(op1, op2, dst, src, is_single); + break; + case BoolTest::ge: + assert(false, "Should go to BoolTest::le case"); + ShouldNotReachHere(); + break; + case BoolTest::lt: + cmov_cmp_fp_lt(op1, op2, dst, src, is_single); + break; + case BoolTest::gt: + assert(false, "Should go to BoolTest::lt case"); + ShouldNotReachHere(); + break; + default: + assert(false, "unsupported compare condition"); + ShouldNotReachHere(); + } +} + // Set dst to NaN if any NaN input. void C2_MacroAssembler::minmax_fp(FloatRegister dst, FloatRegister src1, FloatRegister src2, FLOAT_TYPE ft, bool is_min) { diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index a650174d90f08..73fceea38051e 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -129,6 +129,10 @@ Register op1, Register op2, Register dst, Register src); + void enc_cmove_cmp_fp(int cmpFlag, + FloatRegister op1, FloatRegister op2, + Register dst, Register src, bool is_single); + void spill(Register r, bool is64, int offset) { is64 ? sd(r, Address(sp, offset)) : sw(r, Address(sp, offset)); diff --git a/src/hotspot/cpu/riscv/c2_globals_riscv.hpp b/src/hotspot/cpu/riscv/c2_globals_riscv.hpp index de3c1b17c8eab..79bdc4917c9ed 100644 --- a/src/hotspot/cpu/riscv/c2_globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_globals_riscv.hpp @@ -43,7 +43,7 @@ define_pd_global(bool, TieredCompilation, COMPILER1_PRESENT(true) NOT define_pd_global(intx, CompileThreshold, 10000); define_pd_global(intx, OnStackReplacePercentage, 140); -define_pd_global(intx, ConditionalMoveLimit, 0); +define_pd_global(intx, ConditionalMoveLimit, 3); define_pd_global(intx, FreqInlineSize, 325); define_pd_global(intx, MinJumpTableSize, 10); define_pd_global(intx, InteriorEntryAlignment, 16); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index c6393be071401..218da7cde03cf 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1267,6 +1267,130 @@ void MacroAssembler::cmov_gtu(Register cmp1, Register cmp2, Register dst, Regist bind(no_set); } +// ----------- cmove, compare float ----------- + +// Move src to dst only if cmp1 == cmp2, +// otherwise leave dst unchanged, including the case where one of them is NaN. +// Clarification: +// java code : cmp1 != cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 eq cmp2), dst, src +void MacroAssembler::cmov_cmp_fp_eq(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single) { + if (UseZicond) { + if (is_single) { + feq_s(t0, cmp1, cmp2); + } else { + feq_d(t0, cmp1, cmp2); + } + czero_nez(dst, dst, t0); + czero_eqz(t0 , src, t0); + orr(dst, dst, t0); + return; + } + Label no_set; + if (is_single) { + // jump if cmp1 != cmp2, including the case of NaN + // not jump (i.e. move src to dst) if cmp1 == cmp2 + float_bne(cmp1, cmp2, no_set); + } else { + double_bne(cmp1, cmp2, no_set); + } + mv(dst, src); + bind(no_set); +} + +// Keep dst unchanged only if cmp1 == cmp2, +// otherwise move src to dst, including the case where one of them is NaN. +// Clarification: +// java code : cmp1 == cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 ne cmp2), dst, src +void MacroAssembler::cmov_cmp_fp_ne(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single) { + if (UseZicond) { + if (is_single) { + feq_s(t0, cmp1, cmp2); + } else { + feq_d(t0, cmp1, cmp2); + } + czero_eqz(dst, dst, t0); + czero_nez(t0 , src, t0); + orr(dst, dst, t0); + return; + } + Label no_set; + if (is_single) { + // jump if cmp1 == cmp2 + // not jump (i.e. move src to dst) if cmp1 != cmp2, including the case of NaN + float_beq(cmp1, cmp2, no_set); + } else { + double_beq(cmp1, cmp2, no_set); + } + mv(dst, src); + bind(no_set); +} + +// When cmp1 <= cmp2 or any of them is NaN then dst = src, otherwise, dst = dst +// Clarification +// scenario 1: +// java code : cmp2 < cmp1 ? dst : src +// transformed to : CMove dst, (cmp1 le cmp2), dst, src +// scenario 2: +// java code : cmp1 > cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 le cmp2), dst, src +void MacroAssembler::cmov_cmp_fp_le(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single) { + if (UseZicond) { + if (is_single) { + flt_s(t0, cmp2, cmp1); + } else { + flt_d(t0, cmp2, cmp1); + } + czero_eqz(dst, dst, t0); + czero_nez(t0 , src, t0); + orr(dst, dst, t0); + return; + } + Label no_set; + if (is_single) { + // jump if cmp1 > cmp2 + // not jump (i.e. move src to dst) if cmp1 <= cmp2 or either is NaN + float_bgt(cmp1, cmp2, no_set); + } else { + double_bgt(cmp1, cmp2, no_set); + } + mv(dst, src); + bind(no_set); +} + +// When cmp1 < cmp2 or any of them is NaN then dst = src, otherwise, dst = dst +// Clarification +// scenario 1: +// java code : cmp2 <= cmp1 ? dst : src +// transformed to : CMove dst, (cmp1 lt cmp2), dst, src +// scenario 2: +// java code : cmp1 >= cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 lt cmp2), dst, src +void MacroAssembler::cmov_cmp_fp_lt(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single) { + if (UseZicond) { + if (is_single) { + fle_s(t0, cmp2, cmp1); + } else { + fle_d(t0, cmp2, cmp1); + } + czero_eqz(dst, dst, t0); + czero_nez(t0 , src, t0); + orr(dst, dst, t0); + return; + } + Label no_set; + if (is_single) { + // jump if cmp1 >= cmp2 + // not jump (i.e. move src to dst) if cmp1 < cmp2 or either is NaN + float_bge(cmp1, cmp2, no_set); + } else { + double_bge(cmp1, cmp2, no_set); + } + mv(dst, src); + bind(no_set); +} + // Float compare branch instructions #define INSN(NAME, FLOATCMP, BRANCH) \ diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index b390fb236c273..c47200579c785 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -657,6 +657,11 @@ class MacroAssembler: public Assembler { void cmov_gt(Register cmp1, Register cmp2, Register dst, Register src); void cmov_gtu(Register cmp1, Register cmp2, Register dst, Register src); + void cmov_cmp_fp_eq(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single); + void cmov_cmp_fp_ne(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single); + void cmov_cmp_fp_le(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single); + void cmov_cmp_fp_lt(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single); + public: // We try to follow risc-v asm menomics. // But as we don't layout a reachable GOT, diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 1eb1464e7d938..2e9d25c81560d 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1933,6 +1933,12 @@ bool Matcher::match_rule_supported(int opcode) { case Op_SubHF: case Op_SqrtHF: return UseZfh; + + case Op_CMoveF: + case Op_CMoveD: + case Op_CMoveP: + case Op_CMoveN: + return false; } return true; // Per default match rules are supported. @@ -9938,12 +9944,15 @@ instruct far_cmpP_narrowOop_imm0_branch(cmpOpEqNe cmp, iRegN op1, immP0 zero, la // ============================================================================ // Conditional Move Instructions + +// --------- CMoveI --------- + instruct cmovI_cmpI(iRegINoSp dst, iRegI src, iRegI op1, iRegI op2, cmpOp cop) %{ match(Set dst (CMoveI (Binary cop (CmpI op1 op2)) (Binary dst src))); ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpI\n\t" + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpI\n\t" %} ins_encode %{ @@ -9960,7 +9969,7 @@ instruct cmovI_cmpU(iRegINoSp dst, iRegI src, iRegI op1, iRegI op2, cmpOpU cop) ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpU\n\t" + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpU\n\t" %} ins_encode %{ @@ -9977,7 +9986,7 @@ instruct cmovI_cmpL(iRegINoSp dst, iRegI src, iRegL op1, iRegL op2, cmpOp cop) % ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpL\n\t" + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpL\n\t" %} ins_encode %{ @@ -9994,7 +10003,7 @@ instruct cmovI_cmpUL(iRegINoSp dst, iRegI src, iRegL op1, iRegL op2, cmpOpU cop) ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpUL\n\t" + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpUL\n\t" %} ins_encode %{ @@ -10006,12 +10015,46 @@ instruct cmovI_cmpUL(iRegINoSp dst, iRegI src, iRegL op1, iRegL op2, cmpOpU cop) ins_pipe(pipe_class_compare); %} +instruct cmovI_cmpF(iRegINoSp dst, iRegI src, fRegF op1, fRegF op2, cmpOp cop) %{ + match(Set dst (CMoveI (Binary cop (CmpF op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpF\n\t" + %} + + ins_encode %{ + __ enc_cmove_cmp_fp($cop$$cmpcode, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_Register($dst$$reg), as_Register($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovI_cmpD(iRegINoSp dst, iRegI src, fRegD op1, fRegD op2, cmpOp cop) %{ + match(Set dst (CMoveI (Binary cop (CmpD op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpD\n\t" + %} + + ins_encode %{ + __ enc_cmove_cmp_fp($cop$$cmpcode | C2_MacroAssembler::double_branch_mask, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_Register($dst$$reg), as_Register($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + instruct cmovI_cmpN(iRegINoSp dst, iRegI src, iRegN op1, iRegN op2, cmpOpU cop) %{ match(Set dst (CMoveI (Binary cop (CmpN op1 op2)) (Binary dst src))); ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpN\n\t" + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpN\n\t" %} ins_encode %{ @@ -10028,7 +10071,7 @@ instruct cmovI_cmpP(iRegINoSp dst, iRegI src, iRegP op1, iRegP op2, cmpOpU cop) ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpP\n\t" + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpP\n\t" %} ins_encode %{ @@ -10040,12 +10083,14 @@ instruct cmovI_cmpP(iRegINoSp dst, iRegI src, iRegP op1, iRegP op2, cmpOpU cop) ins_pipe(pipe_class_compare); %} +// --------- CMoveL --------- + instruct cmovL_cmpL(iRegLNoSp dst, iRegL src, iRegL op1, iRegL op2, cmpOp cop) %{ match(Set dst (CMoveL (Binary cop (CmpL op1 op2)) (Binary dst src))); ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpL\n\t" + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpL\n\t" %} ins_encode %{ @@ -10062,7 +10107,7 @@ instruct cmovL_cmpUL(iRegLNoSp dst, iRegL src, iRegL op1, iRegL op2, cmpOpU cop) ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpUL\n\t" + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpUL\n\t" %} ins_encode %{ @@ -10079,7 +10124,7 @@ instruct cmovL_cmpI(iRegLNoSp dst, iRegL src, iRegI op1, iRegI op2, cmpOp cop) % ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpI\n\t" + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpI\n\t" %} ins_encode %{ @@ -10096,7 +10141,7 @@ instruct cmovL_cmpU(iRegLNoSp dst, iRegL src, iRegI op1, iRegI op2, cmpOpU cop) ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpU\n\t" + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpU\n\t" %} ins_encode %{ @@ -10108,12 +10153,46 @@ instruct cmovL_cmpU(iRegLNoSp dst, iRegL src, iRegI op1, iRegI op2, cmpOpU cop) ins_pipe(pipe_class_compare); %} +instruct cmovL_cmpF(iRegLNoSp dst, iRegL src, fRegF op1, fRegF op2, cmpOp cop) %{ + match(Set dst (CMoveL (Binary cop (CmpF op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpF\n\t" + %} + + ins_encode %{ + __ enc_cmove_cmp_fp($cop$$cmpcode, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_Register($dst$$reg), as_Register($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovL_cmpD(iRegLNoSp dst, iRegL src, fRegD op1, fRegD op2, cmpOp cop) %{ + match(Set dst (CMoveL (Binary cop (CmpD op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpD\n\t" + %} + + ins_encode %{ + __ enc_cmove_cmp_fp($cop$$cmpcode | C2_MacroAssembler::double_branch_mask, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_Register($dst$$reg), as_Register($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + instruct cmovL_cmpN(iRegLNoSp dst, iRegL src, iRegN op1, iRegN op2, cmpOpU cop) %{ match(Set dst (CMoveL (Binary cop (CmpN op1 op2)) (Binary dst src))); ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpN\n\t" + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpN\n\t" %} ins_encode %{ @@ -10130,7 +10209,7 @@ instruct cmovL_cmpP(iRegLNoSp dst, iRegL src, iRegP op1, iRegP op2, cmpOpU cop) ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpP\n\t" + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpP\n\t" %} ins_encode %{ diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index a0de9d767bfb2..8dcffc9c646fc 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -248,14 +248,6 @@ void VM_Version::common_initialize() { #ifdef COMPILER2 void VM_Version::c2_initialize() { - if (UseCMoveUnconditionally) { - FLAG_SET_DEFAULT(UseCMoveUnconditionally, false); - } - - if (ConditionalMoveLimit > 0) { - FLAG_SET_DEFAULT(ConditionalMoveLimit, 0); - } - if (!UseRVV) { FLAG_SET_DEFAULT(MaxVectorSize, 0); } else { diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp index 06d6aaf109f86..d19128cafc2d2 100644 --- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp @@ -233,10 +233,13 @@ void RiscvHwprobe::add_features_from_query_result() { if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZACAS)) { VM_Version::ext_Zacas.enable_feature(); } -#endif + // Currently tests shows that cmove using Zicond instructions will bring + // performance regression, but to get a test coverage all the time, will + // still prefer to enabling it in debug version. if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZICOND)) { VM_Version::ext_Zicond.enable_feature(); } +#endif if (is_valid(RISCV_HWPROBE_KEY_CPUPERF_0)) { VM_Version::unaligned_access.enable_feature( query[RISCV_HWPROBE_KEY_CPUPERF_0].value & RISCV_HWPROBE_MISALIGNED_MASK); diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ModINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/ModINodeIdealizationTests.java index dffafea7ea8cf..d19e25627794b 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ModINodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ModINodeIdealizationTests.java @@ -121,10 +121,8 @@ public int powerOf2Random(int x) { } @Test - @IR(applyIfPlatform = {"riscv64", "false"}, - failOn = {IRNode.MOD_I}) - @IR(applyIfPlatform = {"riscv64", "false"}, - counts = {IRNode.AND_I, ">=1", IRNode.RSHIFT, ">=1", IRNode.CMP_I, "2"}) + @IR(failOn = {IRNode.MOD_I}) + @IR(counts = {IRNode.AND_I, ">=1", IRNode.RSHIFT, ">=1", IRNode.CMP_I, "2"}) // Special optimization for the case 2^k-1 for bigger k public int powerOf2Minus1(int x) { return x % 127; diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ModLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/ModLNodeIdealizationTests.java index e931ff87c093d..fc08ef60603ee 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ModLNodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ModLNodeIdealizationTests.java @@ -105,10 +105,8 @@ public long powerOf2Random(long x) { } @Test - @IR(applyIfPlatform = {"riscv64", "false"}, - failOn = {IRNode.MOD_L}) - @IR(applyIfPlatform = {"riscv64", "false"}, - counts = {IRNode.AND_L, ">=1", IRNode.RSHIFT, ">=1", IRNode.CMP_L, "2"}) + @IR(failOn = {IRNode.MOD_L}) + @IR(counts = {IRNode.AND_L, ">=1", IRNode.RSHIFT, ">=1", IRNode.CMP_L, "2"}) // Special optimization for the case 2^k-1 for bigger k public long powerOf2Minus1(long x) { return x % ((1L << 33) - 1); diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestConv2BExpansion.java b/test/hotspot/jtreg/compiler/c2/irTests/TestConv2BExpansion.java index de32b7b21f606..35d676b6ddb02 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestConv2BExpansion.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestConv2BExpansion.java @@ -42,6 +42,14 @@ public static void main(String[] args) { TestFramework.run(); } + // These IR checks do not apply on riscv64, as riscv64 supports Conv2B, e.g. for `return x == 0`, + // the graph looks like: + // Return (XorI (Conv2B ConI(#int: 1))) + // On other platforms, e.g. x86_64 which does not supports Conv2B, the graph looks like: + // Return (CMoveI (Bool (CompI (Param1 ConI(#int: 0))) ConI(#int: 1) ConI(#int: 0))) + // On riscv64, current graph is more efficient than `CMoveI`, as it + // 1. generates less code + // 2. even when zicond is not supported, it does not introduce branches. @Test @IR(counts = {IRNode.CMOVE_I, "1"}, failOn = {IRNode.XOR}) public boolean testIntEquals0(int x) { diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison.java b/test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison.java index 8445c856b4e64..a06cb45d59ebc 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison.java @@ -31,7 +31,6 @@ * @summary Test that code generation for fp comparison works as intended * @library /test/lib / * @run driver compiler.c2.irTests.TestFPComparison - * @requires os.arch != "riscv64" */ public class TestFPComparison { static final double[] DOUBLES = new double[] { diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java b/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java index e232895257a48..bb0a1200a7ffc 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java @@ -33,7 +33,6 @@ * @bug 8324655 8329797 8331090 * @key randomness * @summary Test that if expressions are properly folded into min/max nodes - * @requires os.arch != "riscv64" * @library /test/lib / * @run driver compiler.c2.irTests.TestIfMinMax */ @@ -228,7 +227,7 @@ static Object[] setupLongArrays() { @Test @IR(applyIf = { "SuperWordReductions", "true" }, - applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"}, + applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true", "rvv", "true"}, counts = { IRNode.MAX_REDUCTION_V, "> 0" }) @Arguments(setup = "setupIntArrays") public Object[] testMaxIntReduction(int[] a, int[] b) { @@ -262,7 +261,7 @@ public void checkTestMaxIntReduction(Object[] vals) { @Test @IR(applyIf = { "SuperWordReductions", "true" }, - applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"}, + applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true", "rvv", "true"}, counts = { IRNode.MIN_REDUCTION_V, "> 0" }) @Arguments(setup = "setupIntArrays") public Object[] testMinIntReduction(int[] a, int[] b) { @@ -297,7 +296,7 @@ public void checkTestMinIntReduction(Object[] vals) { @Test @IR(applyIf = { "SuperWordReductions", "true" }, - applyIfCPUFeatureOr = { "avx512", "true" }, + applyIfCPUFeatureOr = { "avx512", "true", "rvv", "true" }, counts = { IRNode.MAX_REDUCTION_V, "> 0" }) @Arguments(setup = "setupLongArrays") public Object[] testMaxLongReduction(long[] a, long[] b) { @@ -332,7 +331,7 @@ public void checkTestMaxLongReduction(Object[] vals) { @Test @IR(applyIf = { "SuperWordReductions", "true" }, - applyIfCPUFeatureOr = { "avx512", "true" }, + applyIfCPUFeatureOr = { "avx512", "true", "rvv", "true" }, counts = { IRNode.MIN_REDUCTION_V, "> 0" }) @Arguments(setup = "setupLongArrays") public Object[] testMinLongReduction(long[] a, long[] b) { @@ -366,7 +365,7 @@ public void checkTestMinLongReduction(Object[] vals) { } @Test - @IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"}, + @IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true", "rvv", "true"}, counts = { IRNode.MAX_VI, "> 0" }) @Arguments(setup = "setupIntArrays") public Object[] testMaxIntVector(int[] a, int[] b) { @@ -401,7 +400,7 @@ public void checkTestMaxIntVector(Object[] vals) { } @Test - @IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"}, + @IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true", "rvv", "true"}, counts = { IRNode.MIN_VI, "> 0" }) @Arguments(setup = "setupIntArrays") public Object[] testMinIntVector(int[] a, int[] b) { @@ -436,7 +435,7 @@ public void checkTestMinIntVector(Object[] vals) { } @Test - @IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"}, + @IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true", "rvv", "true"}, counts = { IRNode.MAX_VL, "> 0" }) @Arguments(setup = "setupLongArrays") public Object[] testMaxLongVector(long[] a, long[] b) { @@ -471,7 +470,7 @@ public void checkTestMaxLongVector(Object[] vals) { } @Test - @IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"}, + @IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true", "rvv", "true"}, counts = { IRNode.MIN_VL, "> 0" }) @Arguments(setup = "setupLongArrays") public Object[] testMinLongVector(long[] a, long[] b) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java index 8f70ad9b7d0c0..a6d738b3a0962 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java @@ -146,6 +146,7 @@ public class TestFramework { "UseRVV", "UseZbb", "UseZfh", + "UseZicond", "UseZvbb" ) ); diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorTest.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorTest.java index 35f357c22f2a7..c6329c70f6594 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ * @library /test/lib / * @requires (os.simpleArch == "x64" & vm.cpu.features ~= ".*sse4.*" & (vm.opt.UseSSE == "null" | vm.opt.UseSSE > 3)) * | os.arch == "aarch64" + * | (os.arch == "riscv64" & vm.cpu.features ~= ".*rvv.*") * @run driver compiler.vectorapi.TestVectorTest */ public class TestVectorTest { diff --git a/test/micro/org/openjdk/bench/java/lang/ClassComparison.java b/test/micro/org/openjdk/bench/java/lang/ClassComparison.java new file mode 100644 index 0000000000000..2a768f243e2bf --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/ClassComparison.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2025, Rivos Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang; + +import org.openjdk.jmh.annotations.*; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.random.RandomGenerator; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(3) +public class ClassComparison { + static final int INVOCATIONS = 1024; + + Class[] c1; + Class[] c2; + int[] res; + long[] resLong; + Object[] resObject; + Object ro1; + Object ro2; + Object[] resClass; + Class rc1; + Class rc2; + + @Setup + public void setup() { + var random = RandomGenerator.getDefault(); + c1 = new Class[INVOCATIONS]; + c2 = new Class[INVOCATIONS]; + res = new int[INVOCATIONS]; + resLong = new long[INVOCATIONS]; + resObject = new Object[INVOCATIONS]; + ro1 = new Object(); + ro2 = new Object(); + resClass = new Class[INVOCATIONS]; + rc1 = Float.class; + rc2 = Double.class; + for (int i = 0; i < INVOCATIONS; i++) { + c1[i] = random.nextBoolean() ? Float.class : Double.class; + } + List list = Arrays.asList(c1); + Collections.shuffle(list); + list.toArray(c2); + } + + @Benchmark + public void equalClass() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (c1[i] == c2[i]) ? 1 : 2; + } + } + + @Benchmark + public void notEqualClass() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (c1[i] != c2[i]) ? 1 : 2; + } + } + + public void equalClassResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (c1[i] == c2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void notEqualClassResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (c1[i] != c2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/FPComparison.java b/test/micro/org/openjdk/bench/java/lang/FPComparison.java index 9fe88b934f848..8074ada325797 100644 --- a/test/micro/org/openjdk/bench/java/lang/FPComparison.java +++ b/test/micro/org/openjdk/bench/java/lang/FPComparison.java @@ -23,6 +23,7 @@ package org.openjdk.bench.java.lang; import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; import java.util.concurrent.TimeUnit; import java.util.random.RandomGenerator; @@ -41,6 +42,13 @@ public class FPComparison { float[] f2; double[] d2; int[] res; + long[] resLong; + Object[] resObject; + Object ro1; + Object ro2; + Class[] resClass; + Class rc1; + Class rc2; @Setup public void setup() { @@ -50,6 +58,13 @@ public void setup() { f2 = new float[INVOCATIONS]; d2 = new double[INVOCATIONS]; res = new int[INVOCATIONS]; + resLong = new long[INVOCATIONS]; + resObject = new Object[INVOCATIONS]; + ro1 = new Object(); + ro2 = new Object(); + resClass = new Class[INVOCATIONS]; + rc1 = Float.class; + rc2 = Double.class; for (int i = 0; i < INVOCATIONS; i++) { int type = random.nextInt(5); if (type == 1) { @@ -79,56 +94,184 @@ public void setup() { @Benchmark public void isNanFloat() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = Float.isNaN(f1[i]) ? 1 : 0; + res[i] = Float.isNaN(f1[i]) ? 1 : 2; } } @Benchmark public void isNanDouble() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = Double.isNaN(d1[i]) ? 1 : 0; + res[i] = Double.isNaN(d1[i]) ? 1 : 2; } } @Benchmark public void isInfiniteFloat() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = Float.isInfinite(f1[i]) ? 1 : 0; + res[i] = Float.isInfinite(f1[i]) ? 1 : 2; } } @Benchmark public void isInfiniteDouble() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = Double.isInfinite(d1[i]) ? 1 : 0; + res[i] = Double.isInfinite(d1[i]) ? 1 : 2; } } @Benchmark public void isFiniteFloat() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = Float.isFinite(f1[i]) ? 1 : 0; + res[i] = Float.isFinite(f1[i]) ? 1 : 2; } } @Benchmark public void isFiniteDouble() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = Double.isFinite(d1[i]) ? 1 : 0; + res[i] = Double.isFinite(d1[i]) ? 1 : 2; } } @Benchmark public void equalFloat() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = (f1[i] == f2[i]) ? 1 : 0; + res[i] = (f1[i] == f2[i]) ? 1 : 2; } } @Benchmark public void equalDouble() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = (d1[i] == d2[i]) ? 1 : 0; + res[i] = (d1[i] == d2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (f1[i] < f2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (d1[i] < d2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessEqualFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (f1[i] <= f2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessEqualDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (d1[i] <= d2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (f1[i] > f2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (d1[i] > d2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterEqualFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (f1[i] >= f2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterEqualDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (d1[i] >= d2[i]) ? 1 : 2; + } + } + + // --------- result: long --------- + + @Benchmark + public void equalFloatResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (f1[i] == f2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void equalDoubleResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (d1[i] == d2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessFloatResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (f1[i] < f2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessDoubleResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (d1[i] < d2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessEqualFloatResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (f1[i] <= f2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessEqualDoubleResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (d1[i] <= d2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterFloatResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (f1[i] > f2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterDoubleResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (d1[i] > d2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterEqualFloatResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (f1[i] >= f2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterEqualDoubleResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (d1[i] >= d2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; } } } diff --git a/test/micro/org/openjdk/bench/java/lang/IntegerComparison.java b/test/micro/org/openjdk/bench/java/lang/IntegerComparison.java new file mode 100644 index 0000000000000..1853be8497d87 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/IntegerComparison.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2025, Rivos Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.concurrent.TimeUnit; +import java.util.random.RandomGenerator; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(3) +public class IntegerComparison { + static final int INVOCATIONS = 1024; + + int[] i1; + int[] i2; + int[] res; + long[] resLong; + Object[] resObject; + Object ro1; + Object ro2; + Object[] resClass; + Class rc1; + Class rc2; + + @Setup + public void setup() { + var random = RandomGenerator.getDefault(); + i1 = new int[INVOCATIONS]; + i2 = new int[INVOCATIONS]; + res = new int[INVOCATIONS]; + resLong = new long[INVOCATIONS]; + resObject = new Object[INVOCATIONS]; + ro1 = new Object(); + ro2 = new Object(); + resClass = new Class[INVOCATIONS]; + rc1 = Float.class; + rc2 = Double.class; + for (int i = 0; i < INVOCATIONS; i++) { + i1[i] = random.nextInt(INVOCATIONS); + i2[i] = random.nextInt(INVOCATIONS); + } + } + + @Benchmark + public void equalInteger() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (i1[i] == i2[i]) ? 1 : 2; + } + } + + @Benchmark + public void notEqualInteger() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (i1[i] != i2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessInteger() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (i1[i] < i2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessEqualInteger() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (i1[i] <= i2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterInteger() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (i1[i] > i2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterEqualInteger() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (i1[i] >= i2[i]) ? 1 : 2; + } + } + + // --------- result: long --------- + + public void equalIntegerResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (i1[i] == i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void notEqualIntegerResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (i1[i] != i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + public void lessIntegerResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (i1[i] < i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessEqualIntegerResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (i1[i] <= i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + public void greaterIntegerResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (i1[i] > i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterEqualIntegerResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (i1[i] >= i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/LongComparison.java b/test/micro/org/openjdk/bench/java/lang/LongComparison.java new file mode 100644 index 0000000000000..bed5ee245b2a7 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/LongComparison.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2025, Rivos Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang; + +import org.openjdk.jmh.annotations.*; + +import java.util.concurrent.TimeUnit; +import java.util.random.RandomGenerator; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(3) +public class LongComparison { + static final int INVOCATIONS = 1024; + + long[] l1; + long[] l2; + int[] res; + long[] resLong; + Object[] resObject; + Object ro1; + Object ro2; + Object[] resClass; + Class rc1; + Class rc2; + + @Setup + public void setup() { + var random = RandomGenerator.getDefault(); + l1 = new long[INVOCATIONS]; + l2 = new long[INVOCATIONS]; + res = new int[INVOCATIONS]; + resLong = new long[INVOCATIONS]; + resObject = new Object[INVOCATIONS]; + ro1 = new Object(); + ro2 = new Object(); + resClass = new Class[INVOCATIONS]; + rc1 = Float.class; + rc2 = Double.class; + for (int i = 0; i < INVOCATIONS; i++) { + l1[i] = random.nextLong(INVOCATIONS); + l2[i] = random.nextLong(INVOCATIONS); + } + } + + @Benchmark + public void equalLong() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (l1[i] == l2[i]) ? 1 : 2; + } + } + + @Benchmark + public void notEqualLong() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (l1[i] != l2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessLong() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (l1[i] < l2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessEqualLong() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (l1[i] <= l2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterLong() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (l1[i] > l2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterEqualLong() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (l1[i] >= l2[i]) ? 1 : 2; + } + } + + // --------- result: long --------- + + public void equalLongResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (l1[i] == l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void notEqualLongResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (l1[i] != l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + public void lessLongResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (l1[i] < l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessEqualLongResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (l1[i] <= l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + public void greaterLongResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (l1[i] > l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterEqualLongResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (l1[i] >= l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/PointerComparison.java b/test/micro/org/openjdk/bench/java/lang/PointerComparison.java new file mode 100644 index 0000000000000..b6bcf00861923 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/PointerComparison.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2025, Rivos Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang; + +import org.openjdk.jmh.annotations.*; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.random.RandomGenerator; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(3) +public class PointerComparison { + static final int INVOCATIONS = 1024; + + Object[] o1; + Object[] o2; + int[] res; + long[] resLong; + Object[] resObject; + Object ro1; + Object ro2; + Object[] resClass; + Class rc1; + Class rc2; + + @Setup + public void setup() { + var random = RandomGenerator.getDefault(); + o1 = new Object[INVOCATIONS]; + o2 = new Object[INVOCATIONS]; + res = new int[INVOCATIONS]; + resLong = new long[INVOCATIONS]; + resObject = new Object[INVOCATIONS]; + ro1 = new Object(); + ro2 = new Object(); + resClass = new Class[INVOCATIONS]; + rc1 = Float.class; + rc2 = Double.class; + for (int i = 0; i < INVOCATIONS; i++) { + o1[i] = new Object(); + } + List list = Arrays.asList(o1); + Collections.shuffle(list); + list.toArray(o2); + } + + @Benchmark + public void equalObject() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (o1[i] == o2[i]) ? 1 : 2; + } + } + + @Benchmark + public void notEqualObject() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (o1[i] != o2[i]) ? 1 : 2; + } + } + + public void equalObjectResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (o1[i] == o2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void notEqualObjectResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (o1[i] != o2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } +} From 7cd084cf350f66fd6ed5b6f5ba9fda71072963fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=A0ipka?= Date: Tue, 22 Apr 2025 08:46:52 +0000 Subject: [PATCH 0694/1101] 8350442: Update copyright Reviewed-by: naoto, jlu --- test/jdk/sun/nio/cs/Test6392804.java | 2 +- test/jdk/sun/nio/cs/TestUTF_32.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/sun/nio/cs/Test6392804.java b/test/jdk/sun/nio/cs/Test6392804.java index a98428c3e7fb7..63da96162c46f 100644 --- a/test/jdk/sun/nio/cs/Test6392804.java +++ b/test/jdk/sun/nio/cs/Test6392804.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/sun/nio/cs/TestUTF_32.java b/test/jdk/sun/nio/cs/TestUTF_32.java index ba042494fd2ae..10de9084b00b8 100644 --- a/test/jdk/sun/nio/cs/TestUTF_32.java +++ b/test/jdk/sun/nio/cs/TestUTF_32.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it From 9eeb86d972ac4cc38d923b2b868b426bbd27a4e8 Mon Sep 17 00:00:00 2001 From: Alisen Chung Date: Tue, 22 Apr 2025 08:58:42 +0000 Subject: [PATCH 0695/1101] 8354341: Open some JTable bugs 7 Reviewed-by: kizune, serb --- test/jdk/javax/swing/JTable/ShiftClick.java | 187 ++++++++++++++++++++ test/jdk/javax/swing/JTable/bug4128506.java | 84 +++++++++ test/jdk/javax/swing/JTable/bug4190222.java | 103 +++++++++++ test/jdk/javax/swing/JTable/bug4224179.java | 74 ++++++++ 4 files changed, 448 insertions(+) create mode 100644 test/jdk/javax/swing/JTable/ShiftClick.java create mode 100644 test/jdk/javax/swing/JTable/bug4128506.java create mode 100644 test/jdk/javax/swing/JTable/bug4190222.java create mode 100644 test/jdk/javax/swing/JTable/bug4224179.java diff --git a/test/jdk/javax/swing/JTable/ShiftClick.java b/test/jdk/javax/swing/JTable/ShiftClick.java new file mode 100644 index 0000000000000..4d617b5eedaf5 --- /dev/null +++ b/test/jdk/javax/swing/JTable/ShiftClick.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Color; +import java.awt.Dimension; +import javax.swing.DefaultCellEditor; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.border.BevelBorder; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.table.TableModel; + +/* + * @test + * @bug 4201917 + * @summary Shift Click in table before making selection + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ShiftClick + */ + +public class ShiftClick { + private static final String INSTRUCTIONS = """ + Shift click in the table. Check that all cells + from the first through where you clicked are selected. + If the cells are selected, press pass, otherwise fail. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(ShiftClick::createTestUI) + .logArea(6) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("ShiftClick"); + + // Take the dummy data from SwingSet. + final String[] names = {"First Name", "Last Name", "Favorite Color", + "Favorite Number", "Vegetarian"}; + final Object[][] data = { + {"Mark", "Andrews", "Red", 2, true}, + {"Tom", "Ball", "Blue", 99, false}, + {"Alan", "Chung", "Green", 838, false}, + {"Jeff", "Dinkins", "Turquois", 8, true}, + {"Amy", "Fowler", "Yellow", 3, false}, + {"Brian", "Gerhold", "Green", 0, false}, + {"James", "Gosling", "Pink", 21, false}, + {"David", "Karlton", "Red", 1, false}, + {"Dave", "Kloba", "Yellow", 14, false}, + {"Peter", "Korn", "Purple", 12, false}, + {"Phil", "Milne", "Purple", 3, false}, + {"Dave", "Moore", "Green", 88, false}, + {"Hans", "Muller", "Maroon", 5, false}, + {"Rick", "Levenson", "Blue", 2, false}, + {"Tim", "Prinzing", "Blue", 22, false}, + {"Chester", "Rose", "Black", 0, false}, + {"Ray", "Ryan", "Gray", 77, false}, + {"Georges", "Saab", "Red", 4, false}, + {"Willie", "Walker", "Phthalo Blue", 4, false}, + {"Kathy", "Walrath", "Blue", 8, false}, + {"Arnaud", "Weber", "Green", 44, false} + }; + + // Create a model of the data. + TableModel dataModel = new AbstractTableModel() { + // These methods always need to be implemented. + public int getColumnCount() { + return names.length; + } + + public int getRowCount() { + return data.length; + } + + public Object getValueAt(int row, int col) { + return data[row][col]; + } + + // The default implementations of these methods in + // AbstractTableModel would work, but we can refine them. + public String getColumnName(int column) { + return names[column]; + } + + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } + + public boolean isCellEditable(int row, int col) { + return true; + } + + public void setValueAt(Object aValue, int row, int column) { + System.out.println("Setting value to: " + aValue); + data[row][column] = aValue; + } + }; + + // Create the table + JTable tableView = new JTable(dataModel); + // Turn off auto-resizing so that we can set column sizes programmatically. + // In this mode, all columns will get their preferred widths, as set blow. + tableView.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + + // Create a combo box to show that you can use one in a table. + JComboBox comboBox = new JComboBox(); + comboBox.addItem("Red"); + comboBox.addItem("Orange"); + comboBox.addItem("Yellow"); + comboBox.addItem("Green"); + comboBox.addItem("Blue"); + comboBox.addItem("Indigo"); + comboBox.addItem("Violet"); + + TableColumn colorColumn = tableView.getColumn("Favorite Color"); + // Use the combo box as the editor in the "Favorite Color" column. + colorColumn.setCellEditor(new DefaultCellEditor(comboBox)); + + // Set a pink background and tooltip for the Color column renderer. + DefaultTableCellRenderer colorColumnRenderer = new DefaultTableCellRenderer(); + colorColumnRenderer.setBackground(Color.pink); + colorColumnRenderer.setToolTipText("Click for combo box"); + colorColumn.setCellRenderer(colorColumnRenderer); + + // Set a tooltip for the header of the colors column. + TableCellRenderer headerRenderer = colorColumn.getHeaderRenderer(); + if (headerRenderer instanceof DefaultTableCellRenderer) + ((DefaultTableCellRenderer) headerRenderer).setToolTipText("Hi Mom!"); + + // Set the width of the "Vegetarian" column. + TableColumn vegetarianColumn = tableView.getColumn("Vegetarian"); + vegetarianColumn.setPreferredWidth(100); + + // Show the values in the "Favorite Number" column in different colors. + TableColumn numbersColumn = tableView.getColumn("Favorite Number"); + DefaultTableCellRenderer numberColumnRenderer = new DefaultTableCellRenderer() { + public void setValue(Object value) { + int cellValue = (value instanceof Number) ? ((Number) value).intValue() : 0; + setForeground((cellValue > 30) ? Color.black : Color.red); + setText((value == null) ? "" : value.toString()); + } + }; + numberColumnRenderer.setHorizontalAlignment(JLabel.RIGHT); + numbersColumn.setCellRenderer(numberColumnRenderer); + numbersColumn.setPreferredWidth(110); + + // Finish setting up the table. + JScrollPane scrollpane = new JScrollPane(tableView); + scrollpane.setBorder(new BevelBorder(BevelBorder.LOWERED)); + scrollpane.setPreferredSize(new Dimension(430, 200)); + + frame.add(scrollpane); + frame.setSize(500, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/bug4128506.java b/test/jdk/javax/swing/JTable/bug4128506.java new file mode 100644 index 0000000000000..21273c6f318e2 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4128506.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableModel; + +/* + * @test + * @bug 4128506 + * @summary Tests that JTable with AUTO_RESIZE_ALL_COLUMNS correctly compute width of columns + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4128506 + */ + +public class bug4128506 { + private static final String INSTRUCTIONS = """ + If the columns of JTable have the same width the test passes, else test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4128506::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + final Object[][] data = { + {"cell_1_1", "cell_1_2", "cell_1_3"}, + {"cell_2_1", "cell_2_2", "cell_2_3"}, + {"cell_3_1", "cell_3_2", "cell_3_3"}, + {"cell_4_1", "cell_4_2", "cell_4_3"}, + }; + + TableModel dataModel = new AbstractTableModel() { + public int getColumnCount() { + return 3; + } + + public int getRowCount() { + return data.length; + } + + public Object getValueAt(int row, int col) { + return data[row][col]; + } + }; + + JFrame frame = new JFrame("bug4128506"); + JTable tableView = new JTable(dataModel); + tableView.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + tableView.getColumnModel().getColumn(1).setMinWidth(5); + JScrollPane scrollpane = new JScrollPane(tableView); + frame.add(scrollpane); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/bug4190222.java b/test/jdk/javax/swing/JTable/bug4190222.java new file mode 100644 index 0000000000000..5d6fcd2b0ccdc --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4190222.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Dimension; +import java.awt.Robot; +import java.util.Vector; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.DefaultTableModel; + +/* + * @test + * @bug 4190222 + * @summary Setting data vector on the model correctly repaint table + * @key headful + * @run main bug4190222 + */ + +public class bug4190222 { + static JFrame frame; + static DefaultTableModel dtm; + static JTable tbl; + + static Vector data; + static Vector colNames; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(250); + + SwingUtilities.invokeAndWait(() -> createTestUI()); + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + Dimension preResize = tbl.getSize(); + dtm.setDataVector(data, colNames); + + if (!preResize.equals(tbl.getSize())) { + throw new RuntimeException("Size of table changed after resizing."); + } + }); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static void createTestUI() { + frame = new JFrame("bug4190222"); + + data = new Vector(1, 1); + colNames = new Vector(3); + for (int i = 1; i < 4; i++) { + Vector row = new Vector(1, 1); + row.addElement("Row " + i + ", Col 1"); + row.addElement("Row " + i + ", Col 2"); + row.addElement("Row " + i + ", Col 3"); + data.addElement(row); + } + colNames.addElement("Col 1"); + colNames.addElement("Col 2"); + colNames.addElement("Col 3"); + + dtm = new DefaultTableModel(data, colNames); + tbl = new JTable(dtm); + JScrollPane scrollPane = new JScrollPane(tbl); + frame.add("Center", scrollPane); + JPanel panel = new JPanel(); + frame.add("South", panel); + + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } +} diff --git a/test/jdk/javax/swing/JTable/bug4224179.java b/test/jdk/javax/swing/JTable/bug4224179.java new file mode 100644 index 0000000000000..b223f3f4716e7 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4224179.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.BorderLayout; +import java.awt.Dimension; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; + +/* + * @test + * @bug 4224179 + * @summary Tests if Table default cell editor doesn't handle % (percent) character correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4224179 + */ + +public class bug4224179 { + private static final String INSTRUCTIONS = """ + 1. Click ONCE on the center cell ("Huml") + 2. Type the following symbols one after another: a%b + + If the center cell doesn't read "Humla%b" the test fails. + + 3. After the above, press the ESCAPE key and note that the cell + reverts back to "Huml" + 4. Do the stuff in part 1 again + 5. Press the ESCAPE key + + If the center cell now reads "Huml" as it initially was, + the test passed and fails otherwise. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4224179::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4224179"); + JTable table = new JTable(3, 3); + table.setValueAt("Huml", 1, 1); + table.setPreferredScrollableViewportSize(new Dimension(500, 70)); + JScrollPane scrollPane = new JScrollPane(table); + frame.add(scrollPane, BorderLayout.CENTER); + frame.pack(); + return frame; + } +} From 0f1c448ca15485cd7270cf0607acfceacdcefaff Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Tue, 22 Apr 2025 11:23:40 +0000 Subject: [PATCH 0696/1101] 8354922: ZGC: Use MAP_FIXED_NOREPLACE when reserving memory Reviewed-by: aboldtch, eosterlund --- src/hotspot/os/linux/gc/z/zSyscall_linux.hpp | 4 ++++ src/hotspot/os/posix/gc/z/zVirtualMemoryManager_posix.cpp | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/hotspot/os/linux/gc/z/zSyscall_linux.hpp b/src/hotspot/os/linux/gc/z/zSyscall_linux.hpp index 1e1becf5a140f..e5978c8d93a1f 100644 --- a/src/hotspot/os/linux/gc/z/zSyscall_linux.hpp +++ b/src/hotspot/os/linux/gc/z/zSyscall_linux.hpp @@ -35,6 +35,10 @@ #define MPOL_F_ADDR (1<<1) #endif +#ifndef MAP_FIXED_NOREPLACE +#define MAP_FIXED_NOREPLACE 0x100000 +#endif + class ZSyscall : public AllStatic { public: static int memfd_create(const char* name, unsigned int flags); diff --git a/src/hotspot/os/posix/gc/z/zVirtualMemoryManager_posix.cpp b/src/hotspot/os/posix/gc/z/zVirtualMemoryManager_posix.cpp index 4eea35c8a2e9d..89bde0557ec36 100644 --- a/src/hotspot/os/posix/gc/z/zVirtualMemoryManager_posix.cpp +++ b/src/hotspot/os/posix/gc/z/zVirtualMemoryManager_posix.cpp @@ -24,6 +24,9 @@ #include "gc/z/zAddress.inline.hpp" #include "gc/z/zVirtualMemoryManager.hpp" #include "logging/log.hpp" +#ifdef LINUX +#include "gc/z/zSyscall_linux.hpp" +#endif #include @@ -32,7 +35,9 @@ void ZVirtualMemoryReserver::pd_register_callbacks(ZVirtualMemoryRegistry* regis } bool ZVirtualMemoryReserver::pd_reserve(zaddress_unsafe addr, size_t size) { - void* const res = mmap((void*)untype(addr), size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0); + const int flags = MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE LINUX_ONLY(|MAP_FIXED_NOREPLACE); + + void* const res = mmap((void*)untype(addr), size, PROT_NONE, flags, -1, 0); if (res == MAP_FAILED) { // Failed to reserve memory return false; From f2587d9bd2e86c46c49ad972790c60ec394848da Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Tue, 22 Apr 2025 11:48:46 +0000 Subject: [PATCH 0697/1101] 8354938: ZGC: Disable UseNUMA when ZFakeNUMA is used Reviewed-by: aboldtch, jsikstro --- src/hotspot/share/gc/z/zArguments.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/z/zArguments.cpp b/src/hotspot/share/gc/z/zArguments.cpp index 67b9f6f0bb918..2c70d8417c95d 100644 --- a/src/hotspot/share/gc/z/zArguments.cpp +++ b/src/hotspot/share/gc/z/zArguments.cpp @@ -121,9 +121,19 @@ void ZArguments::select_max_gc_threads() { void ZArguments::initialize() { GCArguments::initialize(); - // Enable NUMA by default - if (FLAG_IS_DEFAULT(UseNUMA) && FLAG_IS_DEFAULT(ZFakeNUMA)) { - FLAG_SET_DEFAULT(UseNUMA, true); + // NUMA settings + if (FLAG_IS_DEFAULT(ZFakeNUMA)) { + // Enable NUMA by default + if (FLAG_IS_DEFAULT(UseNUMA)) { + FLAG_SET_DEFAULT(UseNUMA, true); + } + } else { + if (UseNUMA) { + if (!FLAG_IS_DEFAULT(UseNUMA)) { + warning("ZFakeNUMA is enabled; turning off UseNUMA"); + } + FLAG_SET_ERGO(UseNUMA, false); + } } select_max_gc_threads(); From 5264d80bea25a1ef98dae4633b04b16e8de6120f Mon Sep 17 00:00:00 2001 From: Martin Balao Date: Tue, 22 Apr 2025 14:37:10 +0000 Subject: [PATCH 0698/1101] 8350661: PKCS11 HKDF throws ProviderException when requesting a 31-byte AES key Reviewed-by: fferrari, valeriep, djelinski --- .../classes/sun/security/pkcs11/P11HKDF.java | 43 ++++-- .../sun/security/pkcs11/P11KeyGenerator.java | 38 ++--- .../security/pkcs11/P11SecretKeyFactory.java | 138 ++++++++++++------ .../pkcs11/wrapper/PKCS11Constants.java | 4 - .../jdk/sun/security/pkcs11/KDF/TestHKDF.java | 49 +++++++ 5 files changed, 200 insertions(+), 72 deletions(-) diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11HKDF.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11HKDF.java index 43a036da6f35c..e8bef222d88d4 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11HKDF.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11HKDF.java @@ -38,6 +38,7 @@ import static sun.security.pkcs11.TemplateManager.*; import sun.security.pkcs11.wrapper.*; import static sun.security.pkcs11.wrapper.PKCS11Constants.*; +import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.CKR_KEY_SIZE_RANGE; final class P11HKDF extends KDFSpi { private final Token token; @@ -157,6 +158,15 @@ private T derive(String alg, AlgorithmParameterSpec derivationSpec, " instance, instead of " + derivationSpec.getClass()); } + P11SecretKeyFactory.KeyInfo ki = P11SecretKeyFactory.getKeyInfo(alg); + if (ki == null) { + throw new InvalidAlgorithmParameterException("A PKCS #11 key " + + "type (CKK_*) was not found for a key of the algorithm '" + + alg + "'."); + } + checkDerivedKeyType(ki, alg); + P11KeyGenerator.checkKeySize(ki.keyGenMech, outLen * 8, token); + P11Key p11BaseKey = convertKey(baseKey, (isExtract ? "IKM" : "PRK") + " could not be converted to a token key for HKDF derivation."); @@ -174,17 +184,10 @@ private T derive(String alg, AlgorithmParameterSpec derivationSpec, "token as service."; } - P11SecretKeyFactory.KeyInfo ki = P11SecretKeyFactory.getKeyInfo(alg); - if (ki == null) { - throw new InvalidAlgorithmParameterException("A PKCS #11 key " + - "type (CKK_*) was not found for a key of the algorithm '" + - alg + "'."); - } - long derivedKeyType = ki.keyType; long derivedKeyClass = isData ? CKO_DATA : CKO_SECRET_KEY; CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_CLASS, derivedKeyClass), - new CK_ATTRIBUTE(CKA_KEY_TYPE, derivedKeyType), + new CK_ATTRIBUTE(CKA_KEY_TYPE, ki.keyType), new CK_ATTRIBUTE(CKA_VALUE_LEN, outLen) }; Session session = null; @@ -195,7 +198,7 @@ private T derive(String alg, AlgorithmParameterSpec derivationSpec, svcKi.hmacMech, saltType, saltBytes, p11SaltKey != null ? p11SaltKey.getKeyID() : 0L, info); attrs = token.getAttributes(O_GENERATE, derivedKeyClass, - derivedKeyType, attrs); + ki.keyType, attrs); long derivedObjectID = token.p11.C_DeriveKey(session.id(), new CK_MECHANISM(mechanism, params), baseKeyID, attrs); Object ret; @@ -216,6 +219,11 @@ private T derive(String alg, AlgorithmParameterSpec derivationSpec, } return retType.cast(ret); } catch (PKCS11Exception e) { + if (e.match(CKR_KEY_SIZE_RANGE)) { + throw new InvalidAlgorithmParameterException("Invalid key " + + "size (" + outLen + " bytes) for algorithm '" + alg + + "'.", e); + } throw new ProviderException("HKDF derivation for algorithm '" + alg + "' failed.", e); } finally { @@ -227,6 +235,23 @@ private T derive(String alg, AlgorithmParameterSpec derivationSpec, } } + private static boolean canDeriveKeyInfoType(long t) { + return (t == CKK_DES || t == CKK_DES3 || t == CKK_AES || + t == CKK_RC4 || t == CKK_BLOWFISH || t == CKK_CHACHA20 || + t == CKK_GENERIC_SECRET); + } + + private void checkDerivedKeyType(P11SecretKeyFactory.KeyInfo ki, String alg) + throws InvalidAlgorithmParameterException { + Class kiClass = ki.getClass(); + if (!kiClass.equals(P11SecretKeyFactory.TLSKeyInfo.class) && + !(kiClass.equals(P11SecretKeyFactory.KeyInfo.class) && + canDeriveKeyInfoType(ki.keyType))) { + throw new InvalidAlgorithmParameterException("A key of algorithm " + + "'" + alg + "' is not valid for derivation."); + } + } + private P11Key.P11SecretKey convertKey(SecretKey key, String errorMessage) { try { return (P11Key.P11SecretKey) P11SecretKeyFactory.convertKey(token, diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyGenerator.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyGenerator.java index 3ec2cfba6553e..9bfe55b2509d4 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyGenerator.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,9 +75,10 @@ final class P11KeyGenerator extends KeyGeneratorSpi { // java-specific lower limit; returned values are in bits private static CK_MECHANISM_INFO getSupportedRange(Token token, long mech) throws ProviderException { - // No need to query for fix-length algorithms - if (mech == CKM_DES_KEY_GEN || mech == CKM_DES2_KEY_GEN || - mech == CKM_DES3_KEY_GEN) { + // No need to query if the mechanism is not available or for + // fix-length algorithms + if (mech == CK_UNAVAILABLE_INFORMATION || mech == CKM_DES_KEY_GEN || + mech == CKM_DES2_KEY_GEN || mech == CKM_DES3_KEY_GEN) { return null; } @@ -115,7 +116,7 @@ private static CK_MECHANISM_INFO getSupportedRange(Token token, * and within the supported range. Return the significant key size * upon successful validation. * @param keyGenMech the PKCS#11 key generation mechanism. - * @param keySize the to-be-checked key size for this mechanism. + * @param keySize the to-be-checked key size (in bits) for this mechanism. * @param token token which provides this mechanism. * @return the significant key size (in bits) corresponding to the * specified key size. @@ -123,7 +124,7 @@ private static CK_MECHANISM_INFO getSupportedRange(Token token, * @throws ProviderException if this mechanism isn't supported by SunPKCS11 * or underlying native impl. */ - // called by P11SecretKeyFactory to check key size + // called by P11SecretKeyFactory and P11HKDF to check key size static int checkKeySize(long keyGenMech, int keySize, Token token) throws InvalidAlgorithmParameterException, ProviderException { CK_MECHANISM_INFO range = getSupportedRange(token, keyGenMech); @@ -136,8 +137,8 @@ private static int checkKeySize(long keyGenMech, int keySize, switch ((int)keyGenMech) { case (int)CKM_DES_KEY_GEN: if ((keySize != 64) && (keySize != 56)) { - throw new InvalidAlgorithmParameterException - ("DES key length must be 56 bits"); + throw new InvalidAlgorithmParameterException("DES key " + + "length was " + keySize + " but must be 56 bits"); } sigKeySize = 56; break; @@ -148,23 +149,26 @@ private static int checkKeySize(long keyGenMech, int keySize, } else if ((keySize == 168) || (keySize == 192)) { sigKeySize = 168; } else { - throw new InvalidAlgorithmParameterException - ("DESede key length must be 112, or 168 bits"); + throw new InvalidAlgorithmParameterException("DESede key " + + "length was " + keySize + " but must be 112, or " + + "168 bits"); } break; default: // Handle all variable-key-length algorithms here - if (range != null && keySize < range.iMinKeySize - || keySize > range.iMaxKeySize) { - throw new InvalidAlgorithmParameterException - ("Key length must be between " + range.iMinKeySize + - " and " + range.iMaxKeySize + " bits"); + if (range != null && (keySize < range.iMinKeySize + || keySize > range.iMaxKeySize)) { + throw new InvalidAlgorithmParameterException("Key length " + + "was " + keySize + " but must be between " + + range.iMinKeySize + " and " + range.iMaxKeySize + + " bits"); } if (keyGenMech == CKM_AES_KEY_GEN) { if ((keySize != 128) && (keySize != 192) && (keySize != 256)) { - throw new InvalidAlgorithmParameterException - ("AES key length must be 128, 192, or 256 bits"); + throw new InvalidAlgorithmParameterException("AES key" + + " length was " + keySize + " but must be 128," + + " 192, or 256 bits"); } } sigKeySize = keySize; diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java index 6c67e64143851..bc0a7d10cf10c 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java @@ -103,13 +103,37 @@ private static void putKeyInfo(KeyInfo ki) { keyInfo.put(ki.algo.toUpperCase(Locale.ENGLISH), ki); } - static sealed class KeyInfo permits PBEKeyInfo, HMACKeyInfo, HKDFKeyInfo { + /* + * The KeyInfo class represents information about a symmetric PKCS #11 key + * type or about the output of a key-based computation (e.g. HMAC). A + * KeyInfo instance may describe the key/output itself, or the type of + * key/output that a service accepts/produces. Used by P11SecretKeyFactory, + * P11PBECipher, P11Mac, and P11HKDF. + */ + static sealed class KeyInfo permits PBEKeyInfo, HMACKeyInfo, HKDFKeyInfo, + TLSKeyInfo { + // Java Standard Algorithm Name. public final String algo; + + // Key type (CKK_*). public final long keyType; + // Mechanism for C_GenerateKey to generate a key of this type (CKM_*). + // While keys may be generated with other APIs and mechanisms (e.g. AES + // key generated with C_DeriveKey and CKM_HKDF_DERIVE instead of + // C_GenerateKey and CKM_AES_KEY_GEN), this information is used by + // P11KeyGenerator::checkKeySize in a best-effort attempt to validate + // that the key size is within a valid range (see CK_MECHANISM_INFO). + public final long keyGenMech; + KeyInfo(String algo, long keyType) { + this(algo, keyType, CK_UNAVAILABLE_INFORMATION); + } + + KeyInfo(String algo, long keyType, long keyGenMech) { this.algo = algo; this.keyType = keyType; + this.keyGenMech = keyGenMech; } // The P11SecretKeyFactory::convertKey method needs to know if a service @@ -134,8 +158,26 @@ static boolean checkUse(KeyInfo ki, KeyInfo si) { } } + /* + * KeyInfo specialization for keys that are either input or result of a TLS + * key derivation. Keys of this type are typically handled by JSSE and their + * algorithm name start with "Tls". Used by P11HKDF. + */ + static final class TLSKeyInfo extends KeyInfo { + TLSKeyInfo(String algo) { + super(algo, CKK_GENERIC_SECRET); + } + } + + /* + * KeyInfo specialization for outputs of a HMAC computation. Used by + * P11SecretKeyFactory and P11Mac. + */ static final class HMACKeyInfo extends KeyInfo { + // HMAC mechanism (CKM_*) to generate the output. public final long mech; + + // HMAC output length (in bits). public final int keyLen; HMACKeyInfo(String algo, long mech, int keyLen) { @@ -145,6 +187,10 @@ static final class HMACKeyInfo extends KeyInfo { } } + /* + * KeyInfo specialization for HKDF key derivation. Used by + * P11SecretKeyFactory and P11HKDF. + */ static final class HKDFKeyInfo extends KeyInfo { public static final long UNKNOWN_KEY_TYPE = -1; public final long hmacMech; @@ -157,6 +203,10 @@ static final class HKDFKeyInfo extends KeyInfo { } } + /* + * KeyInfo specialization for PBE key derivation. Used by + * P11SecretKeyFactory, P11PBECipher and P11Mac. + */ abstract static sealed class PBEKeyInfo extends KeyInfo permits AESPBEKeyInfo, PBKDF2KeyInfo, P12MacPBEKeyInfo { public static final long INVALID_PRF = -1; @@ -204,24 +254,39 @@ static final class P12MacPBEKeyInfo extends PBEKeyInfo { } static { - putKeyInfo(new KeyInfo("RC4", CKK_RC4)); - putKeyInfo(new KeyInfo("ARCFOUR", CKK_RC4)); - putKeyInfo(new KeyInfo("DES", CKK_DES)); - putKeyInfo(new KeyInfo("DESede", CKK_DES3)); - putKeyInfo(new KeyInfo("AES", CKK_AES)); - putKeyInfo(new KeyInfo("Blowfish", CKK_BLOWFISH)); - putKeyInfo(new KeyInfo("ChaCha20", CKK_CHACHA20)); - putKeyInfo(new KeyInfo("ChaCha20-Poly1305", CKK_CHACHA20)); + putKeyInfo(new KeyInfo("RC4", CKK_RC4, CKM_RC4_KEY_GEN)); + putKeyInfo(new KeyInfo("ARCFOUR", CKK_RC4, CKM_RC4_KEY_GEN)); + putKeyInfo(new KeyInfo("DES", CKK_DES, CKM_DES_KEY_GEN)); + putKeyInfo(new KeyInfo("DESede", CKK_DES3, CKM_DES3_KEY_GEN)); + putKeyInfo(new KeyInfo("AES", CKK_AES, CKM_AES_KEY_GEN)); + putKeyInfo(new KeyInfo("Blowfish", CKK_BLOWFISH, CKM_BLOWFISH_KEY_GEN)); + putKeyInfo(new KeyInfo("ChaCha20", CKK_CHACHA20, CKM_CHACHA20_KEY_GEN)); + putKeyInfo(new KeyInfo("ChaCha20-Poly1305", CKK_CHACHA20, + CKM_CHACHA20_KEY_GEN)); // we don't implement RC2 or IDEA, but we want to be able to generate // keys for those SSL/TLS ciphersuites. - putKeyInfo(new KeyInfo("RC2", CKK_RC2)); - putKeyInfo(new KeyInfo("IDEA", CKK_IDEA)); - - putKeyInfo(new KeyInfo("TlsPremasterSecret", PCKK_TLSPREMASTER)); - putKeyInfo(new KeyInfo("TlsRsaPremasterSecret", PCKK_TLSRSAPREMASTER)); - putKeyInfo(new KeyInfo("TlsMasterSecret", PCKK_TLSMASTER)); - putKeyInfo(new KeyInfo("Generic", CKK_GENERIC_SECRET)); + putKeyInfo(new KeyInfo("RC2", CKK_RC2, CKM_RC2_KEY_GEN)); + putKeyInfo(new KeyInfo("IDEA", CKK_IDEA, CKM_IDEA_KEY_GEN)); + + putKeyInfo(new TLSKeyInfo("TlsPremasterSecret")); + putKeyInfo(new TLSKeyInfo("TlsRsaPremasterSecret")); + putKeyInfo(new TLSKeyInfo("TlsMasterSecret")); + putKeyInfo(new TLSKeyInfo("TlsBinderKey")); + putKeyInfo(new TLSKeyInfo("TlsClientAppTrafficSecret")); + putKeyInfo(new TLSKeyInfo("TlsClientHandshakeTrafficSecret")); + putKeyInfo(new TLSKeyInfo("TlsEarlySecret")); + putKeyInfo(new TLSKeyInfo("TlsFinishedSecret")); + putKeyInfo(new TLSKeyInfo("TlsHandshakeSecret")); + putKeyInfo(new TLSKeyInfo("TlsKey")); + putKeyInfo(new TLSKeyInfo("TlsResumptionMasterSecret")); + putKeyInfo(new TLSKeyInfo("TlsSaltSecret")); + putKeyInfo(new TLSKeyInfo("TlsServerAppTrafficSecret")); + putKeyInfo(new TLSKeyInfo("TlsServerHandshakeTrafficSecret")); + putKeyInfo(new TLSKeyInfo("TlsUpdateNplus1")); + + putKeyInfo(new KeyInfo("Generic", CKK_GENERIC_SECRET, + CKM_GENERIC_SECRET_KEY_GEN)); HMACKeyInfo hmacSHA1 = new HMACKeyInfo("HmacSHA1", CKM_SHA_1_HMAC, 160); @@ -549,34 +614,23 @@ private static P11Key createKey(Token token, byte[] encoded, long keyType = ki.keyType; try { switch ((int) keyType) { - case (int) CKK_DES -> { - keyLength = - P11KeyGenerator.checkKeySize(CKM_DES_KEY_GEN, n, token); - fixDESParity(encoded, 0); - } - case (int) CKK_DES3 -> { - keyLength = - P11KeyGenerator.checkKeySize(CKM_DES3_KEY_GEN, n, token); - fixDESParity(encoded, 0); - fixDESParity(encoded, 8); - if (keyLength == 112) { - keyType = CKK_DES2; - } else { - keyType = CKK_DES3; - fixDESParity(encoded, 16); + case (int) CKK_DES, (int) CKK_DES3, (int) CKK_AES, (int) CKK_RC4, + (int) CKK_BLOWFISH, (int) CKK_CHACHA20 -> { + keyLength = P11KeyGenerator.checkKeySize(ki.keyGenMech, n, + token); + if (keyType == CKK_DES || keyType == CKK_DES3) { + fixDESParity(encoded, 0); + if (keyType == CKK_DES3) { + fixDESParity(encoded, 8); + if (keyLength == 112) { + keyType = CKK_DES2; + } else { + fixDESParity(encoded, 16); + } + } } } - case (int) CKK_AES -> keyLength = - P11KeyGenerator.checkKeySize(CKM_AES_KEY_GEN, n, token); - case (int) CKK_RC4 -> keyLength = - P11KeyGenerator.checkKeySize(CKM_RC4_KEY_GEN, n, token); - case (int) CKK_BLOWFISH -> keyLength = - P11KeyGenerator.checkKeySize(CKM_BLOWFISH_KEY_GEN, n, - token); - case (int) CKK_CHACHA20 -> keyLength = P11KeyGenerator.checkKeySize( - CKM_CHACHA20_KEY_GEN, n, token); - case (int) CKK_GENERIC_SECRET, (int) PCKK_TLSPREMASTER, (int) PCKK_TLSRSAPREMASTER, (int) PCKK_TLSMASTER -> - keyType = CKK_GENERIC_SECRET; + case (int) CKK_GENERIC_SECRET -> {} default -> throw new InvalidKeyException("Unknown algorithm " + algorithm); } diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11Constants.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11Constants.java index 3cd1ca125631a..924bfbcc22670 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11Constants.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11Constants.java @@ -311,10 +311,6 @@ public interface PKCS11Constants { // pseudo key type ANY (for template manager) public static final long PCKK_ANY = 0x7FFFFF22L; - public static final long PCKK_TLSPREMASTER = 0x7FFFFF25L; - public static final long PCKK_TLSRSAPREMASTER = 0x7FFFFF26L; - public static final long PCKK_TLSMASTER = 0x7FFFFF27L; - /* Uncomment when actually used public static final long CK_CERTIFICATE_CATEGORY_UNSPECIFIED = 0L; public static final long CK_CERTIFICATE_CATEGORY_TOKEN_USER = 1L; diff --git a/test/jdk/sun/security/pkcs11/KDF/TestHKDF.java b/test/jdk/sun/security/pkcs11/KDF/TestHKDF.java index 5a3e816360058..638d4aa2bb1b1 100644 --- a/test/jdk/sun/security/pkcs11/KDF/TestHKDF.java +++ b/test/jdk/sun/security/pkcs11/KDF/TestHKDF.java @@ -302,6 +302,23 @@ private static void executeTest(String testHeader, String hkdfAlg, executeDerivation(ctx, KdfParamSpecType.EXPAND); } + private static void executeInvalidKeyDerivationTest(String testHeader, + String keyAlg, int keySize, String errorMsg) { + printTestHeader(testHeader); + try { + KDF k = KDF.getInstance("HKDF-SHA256", p11Provider); + k.deriveKey(keyAlg, HKDFParameterSpec.ofExtract() + .thenExpand(null, keySize)); + throw new Exception("No exception thrown."); + } catch (InvalidAlgorithmParameterException iape) { + // Expected. + } catch (Exception e) { + reportTestFailure(new Exception(errorMsg + " expected to throw " + + "InvalidAlgorithmParameterException for key algorithm '" + + keyAlg + "'.", e)); + } + } + private static void printTestHeader(String testHeader) { debugPrinter.println(); debugPrinter.println("=".repeat(testHeader.length())); @@ -610,6 +627,38 @@ private static void test_HKDF_after_ECDH_HkdfSHA256() throws Exception { "6e09"); } + private static void test_unknown_key_algorithm_derivation() { + executeInvalidKeyDerivationTest( + "Test derivation of an unknown key algorithm", + "UnknownAlgorithm", + 32, + "Derivation of an unknown key algorithm"); + } + + private static void test_invalid_key_algorithm_derivation() { + executeInvalidKeyDerivationTest( + "Test derivation of an invalid key algorithm", + "PBKDF2WithHmacSHA1", + 32, + "Derivation of an invalid key algorithm"); + } + + private static void test_invalid_aes_key_algorithm_derivation() { + executeInvalidKeyDerivationTest( + "Test derivation of an invalid AES key", + "PBEWithHmacSHA224AndAES_256", + 32, + "Derivation of an invalid AES key"); + } + + private static void test_invalid_AES_key_size() { + executeInvalidKeyDerivationTest( + "Test derivation of an invalid AES key size", + "AES", + 31, + "Derivation of an AES key of invalid size (31 bytes)"); + } + public void main(Provider p) throws Exception { p11Provider = p; p11GenericSkf = SecretKeyFactory.getInstance("Generic", p11Provider); From 072b8273a4c7bd75bce440e5f1184e2926ed0f78 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Tue, 22 Apr 2025 15:10:26 +0000 Subject: [PATCH 0699/1101] 8354300: Mark String.hash field @Stable Reviewed-by: liach, shade, vlivanov --- .../share/classes/java/lang/String.java | 7 +- .../bench/java/lang/StringHashCodeStatic.java | 93 +++++++++++++++++++ 2 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/lang/StringHashCodeStatic.java diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 033d32611b0f3..0632785d89931 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -173,11 +173,14 @@ public final class String private final byte coder; /** Cache the hash code for the string */ + @Stable private int hash; // Default to 0 /** * Cache if the hash has been calculated as actually being zero, enabling - * us to avoid recalculating this. + * us to avoid recalculating this. This field is _not_ annotated @Stable as + * the `hashCode()` method reads the field `hash` first anyhow and if `hash` + * is the default zero value, is not trusted. */ private boolean hashIsZero; // Default to false; diff --git a/test/micro/org/openjdk/bench/java/lang/StringHashCodeStatic.java b/test/micro/org/openjdk/bench/java/lang/StringHashCodeStatic.java new file mode 100644 index 0000000000000..8f4d22a1d86cc --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/StringHashCodeStatic.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * Performance test of String.hashCode() function with constant folding. + * The tests are using a Map that holds a MethodHandle to better expose + * any potential lack of constant folding. + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(value = 3) +public class StringHashCodeStatic { + + private static final String HASHCODE = "abcdefghijkl"; + private static final String HASHCODE_0 = new String(new char[]{72, 90, 100, 89, 105, 2, 72, 90, 100, 89, 105, 2}); + private static final String EMPTY = new String(); + + private static final Map MAP = Map.of( + HASHCODE, mh(HASHCODE.hashCode()), + HASHCODE_0, mh(HASHCODE_0.hashCode()), + EMPTY, mh(EMPTY.hashCode())); + + /** + * Benchmark testing String.hashCode() with a regular 12 char string with + * the result possibly cached in String + */ + @Benchmark + public int nonZero() throws Throwable { + return (int)MAP.get(HASHCODE).invokeExact(); + } + + /** + * Benchmark testing String.hashCode() with a 12 char string with the + * hashcode = 0. + */ + @Benchmark + public int zero() throws Throwable { + return (int)MAP.get(HASHCODE_0).invokeExact(); + } + + /** + * Benchmark testing String.hashCode() with the empty string. an + * empty String has hashCode = 0. + */ + @Benchmark + public int empty() throws Throwable { + return (int)MAP.get(EMPTY).invokeExact(); + } + + static MethodHandle mh(int value) { + return MethodHandles.constant(int.class, value); + } + +} \ No newline at end of file From da16c839735bbf79ece4967f95a98208f74b7f73 Mon Sep 17 00:00:00 2001 From: Alisen Chung Date: Tue, 22 Apr 2025 15:26:59 +0000 Subject: [PATCH 0700/1101] 8354466: Open some misc Swing bugs 9 Reviewed-by: kizune, honkar --- .../swing/JPasswordField/bug4382819.java | 86 +++++++++++++++++ .../javax/swing/JSplitPane/bug4820080.java | 94 +++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 test/jdk/javax/swing/JPasswordField/bug4382819.java create mode 100644 test/jdk/javax/swing/JSplitPane/bug4820080.java diff --git a/test/jdk/javax/swing/JPasswordField/bug4382819.java b/test/jdk/javax/swing/JPasswordField/bug4382819.java new file mode 100644 index 0000000000000..3a8799a2d521e --- /dev/null +++ b/test/jdk/javax/swing/JPasswordField/bug4382819.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.FlowLayout; +import java.awt.event.ItemListener; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JPasswordField; + +/* + * @test + * @bug 4382819 + * @summary Tests the correctness of color used for the disabled passwordField. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4382819 + */ + +public class bug4382819 { + static JCheckBox enabledCheckBox; + static JPasswordField passwordField; + + private static final String INSTRUCTIONS = """ + Clear the "enabled" checkbox. + If the JPasswordField's foreground color changes to + light gray press Pass. If it stays black press Fail. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4382819::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame mainFrame = new JFrame("bug4382819"); + enabledCheckBox = new javax.swing.JCheckBox(); + enabledCheckBox.setSelected(true); + enabledCheckBox.setText("enabled"); + enabledCheckBox.setActionCommand("enabled"); + mainFrame.add(enabledCheckBox); + + passwordField = new javax.swing.JPasswordField(); + passwordField.setText("blahblahblah"); + mainFrame.add(passwordField); + SymItem lSymItem = new SymItem(); + enabledCheckBox.addItemListener(lSymItem); + + mainFrame.setSize(300, 100); + mainFrame.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); + return mainFrame; + } + + static class SymItem implements ItemListener { + public void itemStateChanged(java.awt.event.ItemEvent event) { + Object object = event.getSource(); + if (object == enabledCheckBox) { + passwordField.setEnabled(enabledCheckBox.isSelected()); + } + } + } +} + diff --git a/test/jdk/javax/swing/JSplitPane/bug4820080.java b/test/jdk/javax/swing/JSplitPane/bug4820080.java new file mode 100644 index 0000000000000..0702a3a2f5950 --- /dev/null +++ b/test/jdk/javax/swing/JSplitPane/bug4820080.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Panel; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import javax.swing.JSplitPane; +import javax.swing.UIManager; + +/* + * @test + * @bug 4820080 7175397 + * @summary RFE: Cannot Change the JSplitPane Divider Color while dragging + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4820080 + */ + +public class bug4820080 { + private static final String INSTRUCTIONS = """ + Drag the dividers of the splitpanes (both top and bottom). If the divider + color is green while dragging then test passes, otherwise test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4820080::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4820080"); + UIManager.put("SplitPaneDivider.draggingColor", Color.GREEN); + + Box box = new Box(BoxLayout.Y_AXIS); + frame.add(box); + + JPanel jleft = new JPanel(); + jleft.setBackground(Color.DARK_GRAY); + jleft.setPreferredSize(new Dimension(100, 100)); + JPanel jright = new JPanel(); + jright.setBackground(Color.DARK_GRAY); + jright.setPreferredSize(new Dimension(100, 100)); + + JSplitPane jsp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, jleft, jright); + jsp.setContinuousLayout(false); + box.add(jsp); + + box.add(Box.createVerticalStrut(5)); + box.add(new JSeparator()); + box.add(Box.createVerticalStrut(5)); + + Panel left = new Panel(); + left.setBackground(Color.DARK_GRAY); + left.setPreferredSize(new Dimension(100, 100)); + Panel right = new Panel(); + right.setBackground(Color.DARK_GRAY); + right.setPreferredSize(new Dimension(100, 100)); + + JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, right); + sp.setContinuousLayout(false); + box.add(sp); + frame.pack(); + return frame; + } +} From a4c5ed8144376f7ba0d2cb992da63b3e53d51f8b Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Tue, 22 Apr 2025 15:46:04 +0000 Subject: [PATCH 0701/1101] 8354561: Open source several swing tests batch0 Reviewed-by: prr, psadhukhan --- .../jdk/javax/swing/JComboBox/bug4139900.java | 119 +++++++++++++++++ .../jdk/javax/swing/JComboBox/bug4174876.java | 78 +++++++++++ .../jdk/javax/swing/JComboBox/bug4474400.java | 78 +++++++++++ .../swing/border/TransparentTitleTest.java | 122 ++++++++++++++++++ 4 files changed, 397 insertions(+) create mode 100644 test/jdk/javax/swing/JComboBox/bug4139900.java create mode 100644 test/jdk/javax/swing/JComboBox/bug4174876.java create mode 100644 test/jdk/javax/swing/JComboBox/bug4474400.java create mode 100644 test/jdk/javax/swing/border/TransparentTitleTest.java diff --git a/test/jdk/javax/swing/JComboBox/bug4139900.java b/test/jdk/javax/swing/JComboBox/bug4139900.java new file mode 100644 index 0000000000000..a9ed685d5ab2f --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4139900.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4139900 + * @summary height of combobox may differ + * @key headful + * @run main bug4139900 +*/ + +import java.awt.Dimension; +import java.awt.Robot; +import java.awt.event.ActionListener; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +public class bug4139900 { + static JButton button; + static JFrame frame; + static JComboBox comboBox; + static int initialHeight; + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(bug4139900::init); + test(); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void test() throws Exception { + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(500); + + SwingUtilities.invokeAndWait(() -> initialHeight = comboBox.getHeight()); + + for (int i = 0; i < 10; i++) { + SwingUtilities.invokeAndWait(() -> button.doClick()); + robot.waitForIdle(); + robot.delay(200); + SwingUtilities.invokeAndWait(() -> { + if (comboBox.getHeight() != initialHeight) { + throw new RuntimeException( + "Test failed: height differs from initial %d != %d" + .formatted(comboBox.getHeight(), initialHeight) + ); + } + }); + } + } + + public static void init() { + frame = new JFrame("bug4139900"); + + DefaultComboBoxModel model = + new DefaultComboBoxModel<>(new String[]{ + "Coma Berenices", + "Triangulum", + "Camelopardis", + "Cassiopea" + }); + + comboBox = new JComboBox<>(); + comboBox.setEditable(true); + + button = new JButton("Add/Remove Items"); + + ActionListener actionListener = e -> { + if (comboBox.getModel() == model) { + comboBox.setModel(new DefaultComboBoxModel<>()); + } else { + comboBox.setModel(model); + } + }; + + button.addActionListener(actionListener); + + JPanel panel = new JPanel(); + panel.setPreferredSize(new Dimension(300, 100)); + panel.add(comboBox); + panel.add(button); + + frame.add(panel); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } +} diff --git a/test/jdk/javax/swing/JComboBox/bug4174876.java b/test/jdk/javax/swing/JComboBox/bug4174876.java new file mode 100644 index 0000000000000..349dfa4b159b8 --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4174876.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4174876 + * @summary JComboBox tooltips do not work properly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4174876 + */ + +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JPanel; + +public class bug4174876 { + private static final String INSTRUCTIONS = """ + Hold the mouse over both combo boxes. + A tool tip should appear over every area of both of them. + Notably, if you hold the mouse over the button on the right one, + a tool tip should appear. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TransparentTitleTest Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .splitUIBottom(bug4174876::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JComponent createTestUI() { + JComboBox comboBox1 = new JComboBox<>(new String[]{ + "Coma Berenices", + "Triangulum", + "Camelopardis", + "Cassiopea" + }); + JComboBox comboBox2 = new JComboBox<>(new String[]{ + "Coma Berenices", + "Triangulum", + "Camelopardis", + "Cassiopea" + }); + + comboBox1.setToolTipText("Combo Box #1"); + comboBox2.setToolTipText("Combo Box #2"); + comboBox2.setEditable(true); + + JPanel panel = new JPanel(); + panel.add(comboBox1); + panel.add(comboBox2); + return panel; + } +} diff --git a/test/jdk/javax/swing/JComboBox/bug4474400.java b/test/jdk/javax/swing/JComboBox/bug4474400.java new file mode 100644 index 0000000000000..ea52d0c71b541 --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4474400.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4474400 + * @summary Tests JTextArea wrapping with font change + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4474400 + */ + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Font; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JTextArea; + +public class bug4474400 { + private static final String INSTRUCTIONS = """ + Press the "Change Font" button. The two lines of text should be + properly drawn using the larger font, there should be empty line + between them. If display is garbled, test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4474400 Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .splitUIRight(bug4474400::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JComponent createTestUI() { + Font smallFont = new Font("SansSerif", Font.PLAIN, 12); + Font largeFont = new Font("SansSerif", Font.PLAIN, 36); + + JTextArea textArea = new JTextArea("This is the first line\n\nThis is the third line"); + textArea.setFont(smallFont); + textArea.setEditable(false); + textArea.setLineWrap(true); + textArea.setWrapStyleWord(true); + + JButton b = new JButton("Change Font"); + b.addActionListener((e) -> textArea.setFont(largeFont)); + + JPanel panel = new JPanel(new BorderLayout()); + panel.setPreferredSize(new Dimension(200, 300)); + panel.add(textArea, BorderLayout.CENTER); + panel.add(b, BorderLayout.SOUTH); + + return panel; + } +} diff --git a/test/jdk/javax/swing/border/TransparentTitleTest.java b/test/jdk/javax/swing/border/TransparentTitleTest.java new file mode 100644 index 0000000000000..49a32a5890c2b --- /dev/null +++ b/test/jdk/javax/swing/border/TransparentTitleTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4154572 + * @summary Tests that the area behind a TitledBorder's title string is transparent, + * allowing the component's background to show through + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TransparentTitleTest + */ + +import java.awt.GridLayout; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Color; +import java.awt.image.BufferedImage; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.border.TitledBorder; +import javax.swing.border.LineBorder; + +public class TransparentTitleTest { + private static final String INSTRUCTIONS = """ + If all panels are correctly painted such that the title of the + border allows the underlying panel image (green rectangle) + to show through the background of the text, + then this test passes; else it fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TransparentTitleTest Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(TransparentTitleTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("TransparentTitleTest"); + + frame.setLayout(new GridLayout(3, 6, 5, 5)); + + frame.add(new ImagePanel(TitledBorder.TOP, TitledBorder.LEFT)); + frame.add(new ImagePanel(TitledBorder.TOP, TitledBorder.CENTER)); + frame.add(new ImagePanel(TitledBorder.TOP, TitledBorder.RIGHT)); + frame.add(new ImagePanel(TitledBorder.ABOVE_TOP, TitledBorder.LEFT)); + frame.add(new ImagePanel(TitledBorder.ABOVE_TOP, TitledBorder.CENTER)); + frame.add(new ImagePanel(TitledBorder.ABOVE_TOP, TitledBorder.RIGHT)); + frame.add(new ImagePanel(TitledBorder.BELOW_TOP, TitledBorder.LEFT)); + frame.add(new ImagePanel(TitledBorder.BELOW_TOP, TitledBorder.CENTER)); + frame.add(new ImagePanel(TitledBorder.BELOW_TOP, TitledBorder.RIGHT)); + frame.add(new ImagePanel(TitledBorder.BOTTOM, TitledBorder.LEFT)); + frame.add(new ImagePanel(TitledBorder.BOTTOM, TitledBorder.CENTER)); + frame.add(new ImagePanel(TitledBorder.BOTTOM, TitledBorder.RIGHT)); + frame.add(new ImagePanel(TitledBorder.ABOVE_BOTTOM, TitledBorder.LEFT)); + frame.add(new ImagePanel(TitledBorder.ABOVE_BOTTOM, TitledBorder.CENTER)); + frame.add(new ImagePanel(TitledBorder.ABOVE_BOTTOM, TitledBorder.RIGHT)); + frame.add(new ImagePanel(TitledBorder.BELOW_BOTTOM, TitledBorder.LEFT)); + frame.add(new ImagePanel(TitledBorder.BELOW_BOTTOM, TitledBorder.CENTER)); + frame.add(new ImagePanel(TitledBorder.BELOW_BOTTOM, TitledBorder.RIGHT)); + + frame.pack(); + return frame; + } +} + +class ImagePanel extends JPanel { + + private final ImageIcon imageIcon; + + private static final BufferedImage bufferedImage = + new BufferedImage(128, 128, BufferedImage.TYPE_INT_ARGB); + + static { + Graphics g = bufferedImage.getGraphics(); + g.setColor(Color.GREEN); + g.fillRect(0, 0, 128, 128); + } + + public ImagePanel(int titlePos, int titleJust) { + imageIcon = new ImageIcon(bufferedImage); + + TitledBorder b = new TitledBorder(new LineBorder(Color.black,3), "title text"); + b.setTitlePosition(titlePos); + b.setTitleJustification(titleJust); + b.setTitleColor(Color.black); + setBorder(b); + } + + public Dimension getPreferredSize() { + return new Dimension(imageIcon.getIconWidth(), imageIcon.getIconHeight()); + } + + public void paintComponent(Graphics g) { + imageIcon.paintIcon(this, g, 0, 0); + } +} From 477da161e62040d77079196ea27d24b27de75b64 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Tue, 22 Apr 2025 15:50:58 +0000 Subject: [PATCH 0702/1101] 8352638: Enhance code consistency: java.desktop/windows Reviewed-by: prr --- .../plaf/windows/AnimationController.java | 9 ++- .../sun/java/swing/plaf/windows/TMSchema.java | 3 + .../swing/plaf/windows/WindowsBorders.java | 17 +++-- .../swing/plaf/windows/WindowsButtonUI.java | 9 ++- .../windows/WindowsCheckBoxMenuItemUI.java | 5 +- .../swing/plaf/windows/WindowsCheckBoxUI.java | 5 +- .../windows/WindowsClassicLookAndFeel.java | 3 +- .../swing/plaf/windows/WindowsComboBoxUI.java | 32 +++++++--- .../plaf/windows/WindowsDesktopIconUI.java | 8 ++- .../plaf/windows/WindowsDesktopManager.java | 3 +- .../plaf/windows/WindowsDesktopPaneUI.java | 5 +- .../plaf/windows/WindowsEditorPaneUI.java | 3 +- .../plaf/windows/WindowsFileChooserUI.java | 62 ++++++++++++++++--- .../plaf/windows/WindowsGraphicsUtils.java | 2 +- .../plaf/windows/WindowsIconFactory.java | 56 +++++++++++++---- .../WindowsInternalFrameTitlePane.java | 24 ++++++- .../plaf/windows/WindowsInternalFrameUI.java | 12 +++- .../swing/plaf/windows/WindowsLabelUI.java | 4 +- .../plaf/windows/WindowsLookAndFeel.java | 58 ++++++++++++----- .../swing/plaf/windows/WindowsMenuBarUI.java | 5 +- .../swing/plaf/windows/WindowsMenuItemUI.java | 5 +- .../swing/plaf/windows/WindowsMenuUI.java | 13 +++- .../plaf/windows/WindowsOptionPaneUI.java | 2 +- .../plaf/windows/WindowsPasswordFieldUI.java | 3 +- .../windows/WindowsPopupMenuSeparatorUI.java | 4 +- .../plaf/windows/WindowsPopupMenuUI.java | 7 ++- .../plaf/windows/WindowsPopupWindow.java | 5 +- .../plaf/windows/WindowsProgressBarUI.java | 11 +++- .../windows/WindowsRadioButtonMenuItemUI.java | 5 +- .../plaf/windows/WindowsRadioButtonUI.java | 5 ++ .../swing/plaf/windows/WindowsRootPaneUI.java | 5 +- .../plaf/windows/WindowsScrollBarUI.java | 17 ++++- .../plaf/windows/WindowsScrollPaneUI.java | 2 +- .../plaf/windows/WindowsSeparatorUI.java | 2 +- .../swing/plaf/windows/WindowsSliderUI.java | 17 ++++- .../swing/plaf/windows/WindowsSpinnerUI.java | 5 +- .../plaf/windows/WindowsSplitPaneDivider.java | 3 +- .../plaf/windows/WindowsSplitPaneUI.java | 3 +- .../plaf/windows/WindowsTabbedPaneUI.java | 8 ++- .../plaf/windows/WindowsTableHeaderUI.java | 13 +++- .../swing/plaf/windows/WindowsTextAreaUI.java | 3 +- .../plaf/windows/WindowsTextFieldUI.java | 11 +++- .../swing/plaf/windows/WindowsTextPaneUI.java | 3 +- .../swing/plaf/windows/WindowsTextUI.java | 8 ++- .../plaf/windows/WindowsToggleButtonUI.java | 9 ++- .../windows/WindowsToolBarSeparatorUI.java | 5 +- .../swing/plaf/windows/WindowsToolBarUI.java | 7 ++- .../swing/plaf/windows/WindowsTreeUI.java | 11 +++- .../sun/java/swing/plaf/windows/XPStyle.java | 26 ++++++-- .../classes/sun/awt/PlatformGraphicsInfo.java | 2 +- .../classes/sun/awt/Win32ColorModel24.java | 4 +- .../classes/sun/awt/Win32FontManager.java | 5 ++ .../classes/sun/awt/Win32GraphicsConfig.java | 1 + .../classes/sun/awt/Win32GraphicsDevice.java | 2 +- .../sun/awt/Win32GraphicsEnvironment.java | 4 ++ .../sun/awt/shell/Win32ShellFolder2.java | 27 +++++++- .../awt/shell/Win32ShellFolderManager2.java | 8 ++- .../awt/windows/TranslucentWindowPainter.java | 4 +- .../sun/awt/windows/WComponentPeer.java | 1 + .../sun/awt/windows/WDataTransferer.java | 2 +- .../sun/awt/windows/WDefaultFontCharset.java | 2 +- .../sun/awt/windows/WDesktopProperties.java | 5 +- .../awt/windows/WDragSourceContextPeer.java | 3 + .../sun/awt/windows/WEmbeddedFrame.java | 7 ++- .../sun/awt/windows/WEmbeddedFramePeer.java | 2 +- .../classes/sun/awt/windows/WLabelPeer.java | 7 +++ .../awt/windows/WLightweightFramePeer.java | 3 +- .../sun/awt/windows/WMenuItemPeer.java | 4 ++ .../sun/awt/windows/WMouseInfoPeer.java | 2 + .../sun/awt/windows/WPopupMenuPeer.java | 1 + .../classes/sun/awt/windows/WPrinterJob.java | 4 +- .../sun/awt/windows/WScrollPanePeer.java | 4 +- .../sun/awt/windows/WScrollbarPeer.java | 7 +++ .../classes/sun/awt/windows/WToolkit.java | 2 +- .../sun/awt/windows/WTrayIconPeer.java | 2 +- .../classes/sun/awt/windows/WWindowPeer.java | 4 +- .../classes/sun/awt/windows/WingDings.java | 2 +- .../windows/classes/sun/font/NativeFont.java | 11 +++- .../classes/sun/font/NativeStrike.java | 8 +++ .../java2d/WindowsSurfaceManagerFactory.java | 3 +- .../classes/sun/java2d/d3d/D3DBlitLoops.java | 51 +++++++++------ .../classes/sun/java2d/d3d/D3DBufImgOps.java | 2 +- .../classes/sun/java2d/d3d/D3DContext.java | 2 +- .../classes/sun/java2d/d3d/D3DDrawImage.java | 2 +- .../sun/java2d/d3d/D3DGraphicsConfig.java | 4 +- .../sun/java2d/d3d/D3DGraphicsDevice.java | 4 +- .../classes/sun/java2d/d3d/D3DMaskBlit.java | 2 +- .../classes/sun/java2d/d3d/D3DMaskFill.java | 2 +- .../classes/sun/java2d/d3d/D3DPaints.java | 8 +-- .../sun/java2d/d3d/D3DRenderQueue.java | 4 +- .../classes/sun/java2d/d3d/D3DRenderer.java | 15 ++++- .../java2d/d3d/D3DScreenUpdateManager.java | 3 +- .../sun/java2d/d3d/D3DSurfaceData.java | 17 ++++- .../sun/java2d/d3d/D3DSurfaceDataProxy.java | 2 +- .../sun/java2d/d3d/D3DTextRenderer.java | 3 +- .../java2d/d3d/D3DVolatileSurfaceManager.java | 5 +- .../sun/java2d/opengl/WGLGraphicsConfig.java | 14 ++--- .../sun/java2d/opengl/WGLSurfaceData.java | 11 +++- .../opengl/WGLVolatileSurfaceManager.java | 4 +- .../sun/java2d/windows/GDIBlitLoops.java | 3 +- .../sun/java2d/windows/GDIRenderer.java | 29 ++++++++- .../java2d/windows/GDIWindowSurfaceData.java | 8 ++- .../sun/java2d/windows/WindowsFlags.java | 2 +- .../sun/print/PlatformPrinterJobProxy.java | 2 +- .../sun/print/PrintServiceLookupProvider.java | 6 +- .../classes/sun/print/Win32MediaTray.java | 4 +- .../classes/sun/print/Win32PrintJob.java | 10 ++- .../classes/sun/print/Win32PrintService.java | 33 ++++++++-- .../plaf/windows/ClassicSortArrowIcon.java | 5 +- 109 files changed, 743 insertions(+), 200 deletions(-) diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/AnimationController.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/AnimationController.java index a71b3b8367f5c..a91e1a97ee1ea 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/AnimationController.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/AnimationController.java @@ -62,7 +62,7 @@ * * @author Igor Kushnirskiy */ -class AnimationController implements ActionListener, PropertyChangeListener { +final class AnimationController implements ActionListener, PropertyChangeListener { private static final boolean VISTA_ANIMATION_DISABLED = Boolean.getBoolean("swing.disablevistaanimation"); @@ -253,6 +253,7 @@ static void paintSkin(JComponent component, Skin skin, } } + @Override public synchronized void propertyChange(PropertyChangeEvent e) { if ("lookAndFeel" == e.getPropertyName() && ! (e.getNewValue() instanceof WindowsLookAndFeel) ) { @@ -260,6 +261,7 @@ public synchronized void propertyChange(PropertyChangeEvent e) { } } + @Override public synchronized void actionPerformed(ActionEvent e) { java.util.List componentsToRemove = null; java.util.List partsToRemove = null; @@ -319,7 +321,7 @@ private synchronized void dispose() { } } - private static class AnimationState { + private static final class AnimationState { private final State startState; //animation duration in nanoseconds @@ -407,7 +409,7 @@ boolean isDone() { } } - private static class PartUIClientPropertyKey + private static final class PartUIClientPropertyKey implements UIClientPropertyKey { private static final Map map = @@ -426,6 +428,7 @@ static synchronized PartUIClientPropertyKey getKey(Part part) { private PartUIClientPropertyKey(Part part) { this.part = part; } + @Override public String toString() { return part.toString(); } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/TMSchema.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/TMSchema.java index 90c7f79704310..93628d8576600 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/TMSchema.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/TMSchema.java @@ -221,6 +221,7 @@ public String getControlName(Component component) { return str + control.toString(); } + @Override public String toString() { return control.toString()+"."+name(); } @@ -531,6 +532,7 @@ public int getValue() { return value; } + @Override public String toString() { return name()+"["+type.getName()+"] = "+value; } @@ -559,6 +561,7 @@ private TypeEnum(Prop prop, String enumName, int value) { private final String enumName; private final int value; + @Override public String toString() { return prop+"="+enumName+"="+value; } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsBorders.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsBorders.java index 1e10ccce1bf5a..31a490bebccc7 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsBorders.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsBorders.java @@ -43,7 +43,7 @@ * @author Rich Schiavi */ -public class WindowsBorders { +public final class WindowsBorders { /** * Returns a border instance for a Windows Progress Bar @@ -115,7 +115,7 @@ public static Border getInternalFrameBorder() { } @SuppressWarnings("serial") // Superclass is not serializable across versions - public static class ProgressBarBorder extends AbstractBorder implements UIResource { + public static final class ProgressBarBorder extends AbstractBorder implements UIResource { protected Color shadow; protected Color highlight; @@ -124,6 +124,7 @@ public ProgressBarBorder(Color shadow, Color highlight) { this.shadow = shadow; } + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { g.setColor(shadow); @@ -134,6 +135,7 @@ public void paintBorder(Component c, Graphics g, int x, int y, g.drawLine(width-1,y, width-1,height-1); // draw right } + @Override public Insets getBorderInsets(Component c, Insets insets) { insets.set(1,1,1,1); return insets; @@ -146,7 +148,7 @@ public Insets getBorderInsets(Component c, Insets insets) { * @since 1.4 */ @SuppressWarnings("serial") // Superclass is not serializable across versions - public static class ToolBarBorder extends AbstractBorder implements UIResource, SwingConstants { + public static final class ToolBarBorder extends AbstractBorder implements UIResource, SwingConstants { protected Color shadow; protected Color highlight; @@ -155,6 +157,7 @@ public ToolBarBorder(Color shadow, Color highlight) { this.shadow = shadow; } + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { if (!(c instanceof JToolBar)) { @@ -224,6 +227,7 @@ public void paintBorder(Component c, Graphics g, int x, int y, g.translate(-x, -y); } + @Override public Insets getBorderInsets(Component c, Insets insets) { insets.set(1,1,1,1); if (!(c instanceof JToolBar)) { @@ -259,6 +263,7 @@ public DashedBorder(Color color, int thickness) { super(color, thickness); } + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { Color oldColor = g.getColor(); int i; @@ -276,7 +281,7 @@ public void paintBorder(Component c, Graphics g, int x, int y, int width, int he * of the component's background color. */ @SuppressWarnings("serial") // Superclass is not serializable across versions - static class ComplementDashedBorder extends LineBorder implements UIResource { + static final class ComplementDashedBorder extends LineBorder implements UIResource { private Color origColor; private Color paintColor; @@ -284,6 +289,7 @@ public ComplementDashedBorder() { super(null); } + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { Color color = c.getBackground(); @@ -302,7 +308,7 @@ public void paintBorder(Component c, Graphics g, int x, int y, int width, int he * @since 1.4 */ @SuppressWarnings("serial") // Superclass is not serializable across versions - public static class InternalFrameLineBorder extends LineBorder implements + public static final class InternalFrameLineBorder extends LineBorder implements UIResource { protected Color activeColor; protected Color inactiveColor; @@ -315,6 +321,7 @@ public InternalFrameLineBorder(Color activeBorderColor, inactiveColor = inactiveBorderColor; } + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java index b1f7f3902e2cd..33dea2b3b082d 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java @@ -58,7 +58,7 @@ * * @author Jeff Dinkins */ -public class WindowsButtonUI extends BasicButtonUI +public final class WindowsButtonUI extends BasicButtonUI { protected int dashedRectGapX; protected int dashedRectGapY; @@ -89,6 +89,7 @@ public static ComponentUI createUI(JComponent c) { // ******************************** // Defaults // ******************************** + @Override protected void installDefaults(AbstractButton b) { super.installDefaults(b); if(!defaults_initialized) { @@ -108,6 +109,7 @@ protected void installDefaults(AbstractButton b) { } } + @Override protected void uninstallDefaults(AbstractButton b) { super.uninstallDefaults(b); defaults_initialized = false; @@ -124,10 +126,12 @@ protected Color getFocusColor() { /** * Overridden method to render the text without the mnemonic */ + @Override protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, String text) { WindowsGraphicsUtils.paintText(g, b, textRect, text, getTextShiftOffset()); } + @Override protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, Rectangle textRect, Rectangle iconRect){ // focus painted same color as text on Basic?? @@ -138,6 +142,7 @@ protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, Rect width - dashedRectGapWidth, height - dashedRectGapHeight); } + @Override protected void paintButtonPressed(Graphics g, AbstractButton b){ setTextShiftOffset(); } @@ -145,6 +150,7 @@ protected void paintButtonPressed(Graphics g, AbstractButton b){ // ******************************** // Layout Methods // ******************************** + @Override public Dimension getPreferredSize(JComponent c) { Dimension d = super.getPreferredSize(c); @@ -167,6 +173,7 @@ public Dimension getPreferredSize(JComponent c) { */ private Rectangle viewRect = new Rectangle(); + @Override public void paint(Graphics g, JComponent c) { if (XPStyle.getXP() != null) { WindowsButtonUI.paintXPButtonBackground(g, c); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java index c7007bec3db8e..6b85a88e50caf 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java @@ -41,11 +41,12 @@ /** * Windows check box menu item. */ -public class WindowsCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI { +public final class WindowsCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI { final WindowsMenuItemUIAccessor accessor = new WindowsMenuItemUIAccessor() { + @Override public JMenuItem getMenuItem() { return menuItem; } @@ -54,6 +55,7 @@ public State getState(JMenuItem menuItem) { return WindowsMenuItemUI.getState(this, menuItem); } + @Override public Part getPart(JMenuItem menuItem) { return WindowsMenuItemUI.getPart(this, menuItem); } @@ -80,6 +82,7 @@ protected void paintBackground(Graphics g, JMenuItem menuItem, * @param text String to render * @since 1.4 */ + @Override protected void paintText(Graphics g, JMenuItem menuItem, Rectangle textRect, String text) { if (WindowsMenuItemUI.isVistaPainting()) { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java index f94b58c56107d..3ead1228b0e6f 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java @@ -37,7 +37,7 @@ * * @author Jeff Dinkins */ -public class WindowsCheckBoxUI extends WindowsRadioButtonUI +public final class WindowsCheckBoxUI extends WindowsRadioButtonUI { // NOTE: WindowsCheckBoxUI inherits from WindowsRadioButtonUI instead // of BasicCheckBoxUI because we want to pick up all the @@ -64,6 +64,7 @@ public static ComponentUI createUI(JComponent c) { } + @Override public String getPropertyPrefix() { return propertyPrefix; } @@ -71,6 +72,7 @@ public String getPropertyPrefix() { // ******************************** // Defaults // ******************************** + @Override public void installDefaults(AbstractButton b) { super.installDefaults(b); if(!defaults_initialized) { @@ -79,6 +81,7 @@ public void installDefaults(AbstractButton b) { } } + @Override public void uninstallDefaults(AbstractButton b) { super.uninstallDefaults(b); defaults_initialized = false; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsClassicLookAndFeel.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsClassicLookAndFeel.java index 6a2c9eeae3181..59eace01a4c8f 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsClassicLookAndFeel.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsClassicLookAndFeel.java @@ -31,7 +31,8 @@ * @since 1.5 */ @SuppressWarnings("serial") // Superclass is not serializable across versions -public class WindowsClassicLookAndFeel extends WindowsLookAndFeel { +public final class WindowsClassicLookAndFeel extends WindowsLookAndFeel { + @Override public String getName() { return "Windows Classic"; } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsComboBoxUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsComboBoxUI.java index 1a601f40332b9..f37ce17d87632 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsComboBoxUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsComboBoxUI.java @@ -75,7 +75,7 @@ * @author Tom Santos * @author Igor Kushnirskiy */ -public class WindowsComboBoxUI extends BasicComboBoxUI { +public final class WindowsComboBoxUI extends BasicComboBoxUI { private static final MouseListener rolloverListener = new MouseAdapter() { @@ -162,6 +162,7 @@ public static ComponentUI createUI(JComponent c) { return new WindowsComboBoxUI(); } + @Override public void installUI( JComponent c ) { super.installUI( c ); isRollover = false; @@ -176,6 +177,7 @@ public void installUI( JComponent c ) { } } + @Override public void uninstallUI(JComponent c ) { comboBox.removeMouseListener(rolloverListener); if(arrowButton != null) { @@ -215,6 +217,7 @@ protected void uninstallListeners() { * {@inheritDoc} * @since 1.6 */ + @Override protected void configureEditor() { super.configureEditor(); if (XPStyle.getXP() != null) { @@ -226,6 +229,7 @@ protected void configureEditor() { * {@inheritDoc} * @since 1.6 */ + @Override protected void unconfigureEditor() { super.unconfigureEditor(); editor.removeMouseListener(rolloverListener); @@ -235,6 +239,7 @@ protected void unconfigureEditor() { * {@inheritDoc} * @since 1.6 */ + @Override public void paint(Graphics g, JComponent c) { if (XPStyle.getXP() != null) { paintXPComboBoxBackground(g, c); @@ -283,6 +288,7 @@ private void paintXPComboBoxBackground(Graphics g, JComponent c) { * @throws NullPointerException if any of the arguments are null. * @since 1.5 */ + @Override public void paintCurrentValue(Graphics g, Rectangle bounds, boolean hasFocus) { XPStyle xp = XPStyle.getXP(); @@ -347,6 +353,7 @@ public void paintCurrentValue(Graphics g, Rectangle bounds, * {@inheritDoc} * @since 1.6 */ + @Override public void paintCurrentValueBackground(Graphics g, Rectangle bounds, boolean hasFocus) { if (XPStyle.getXP() == null) { @@ -354,6 +361,7 @@ public void paintCurrentValueBackground(Graphics g, Rectangle bounds, } } + @Override public Dimension getMinimumSize( JComponent c ) { Dimension d = super.getMinimumSize(c); if (XPStyle.getXP() != null) { @@ -380,6 +388,7 @@ public Dimension getMinimumSize( JComponent c ) { * * @return an instance of a layout manager */ + @Override protected LayoutManager createLayoutManager() { return new BasicComboBoxUI.ComboBoxLayoutManager() { public void layoutContainer(Container parent) { @@ -407,10 +416,12 @@ public void layoutContainer(Container parent) { }; } + @Override protected void installKeyboardActions() { super.installKeyboardActions(); } + @Override protected ComboPopup createPopup() { return new WinComboPopUp(comboBox); } @@ -423,6 +434,7 @@ protected ComboPopup createPopup() { * @return a ComboBoxEditor used for the combo box * @see javax.swing.JComboBox#setEditor */ + @Override protected ComboBoxEditor createEditor() { return new WindowsComboBoxEditor(); } @@ -447,6 +459,7 @@ protected ListCellRenderer createRenderer() { * * @return a button which represents the popup control */ + @Override protected JButton createArrowButton() { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -457,7 +470,7 @@ protected JButton createArrowButton() { } @SuppressWarnings("serial") // Superclass is not serializable across versions - private class XPComboBoxButton extends XPStyle.GlyphButton { + private final class XPComboBoxButton extends XPStyle.GlyphButton { private State prevState = null; public XPComboBoxButton(XPStyle xp) { @@ -504,6 +517,7 @@ protected State getState() { return rv; } + @Override public Dimension getPreferredSize() { return new Dimension(17, 21); } @@ -518,7 +532,7 @@ WindowsComboBoxUI getWindowsComboBoxUI() { } @SuppressWarnings("serial") // Same-version serialization only - protected class WinComboPopUp extends BasicComboPopup { + protected final class WinComboPopUp extends BasicComboPopup { private Skin listBoxBorder = null; private XPStyle xp; @@ -531,16 +545,18 @@ public WinComboPopUp(JComboBox combo) { } } + @Override protected KeyListener createKeyListener() { return new InvocationKeyHandler(); } - protected class InvocationKeyHandler extends BasicComboPopup.InvocationKeyHandler { + protected final class InvocationKeyHandler extends BasicComboPopup.InvocationKeyHandler { protected InvocationKeyHandler() { WinComboPopUp.this.super(); } } + @Override protected void paintComponent(Graphics g) { super.paintComponent(g); if (this.listBoxBorder != null) { @@ -554,13 +570,14 @@ protected void paintComponent(Graphics g) { /** * Subclassed to highlight selected item in an editable combo box. */ - public static class WindowsComboBoxEditor + public static final class WindowsComboBoxEditor extends BasicComboBoxEditor.UIResource { /** * {@inheritDoc} * @since 1.6 */ + @Override protected JTextField createEditorComponent() { JTextField editor = super.createEditorComponent(); Border border = (Border)UIManager.get("ComboBox.editorBorder"); @@ -572,6 +589,7 @@ protected JTextField createEditorComponent() { return editor; } + @Override public void setItem(Object item) { super.setItem(item); Object focus = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); @@ -586,14 +604,14 @@ public void setItem(Object item) { * and to show border for focused cells. */ @SuppressWarnings("serial") // Superclass is not serializable across versions - private static class WindowsComboBoxRenderer + private static final class WindowsComboBoxRenderer extends BasicComboBoxRenderer.UIResource { private static final Object BORDER_KEY = new StringUIClientPropertyKey("BORDER_KEY"); private static final Border NULL_BORDER = new EmptyBorder(0, 0, 0, 0); // Create own version of DashedBorder with more space on left side - private static class WindowsComboBoxDashedBorder extends DashedBorder { + private static final class WindowsComboBoxDashedBorder extends DashedBorder { public WindowsComboBoxDashedBorder(Color color, int thickness) { super(color, thickness); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopIconUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopIconUI.java index 564ae5b9f712e..8da4bd7921b8e 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopIconUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopIconUI.java @@ -36,18 +36,20 @@ /** * Windows icon for a minimized window on the desktop. */ -public class WindowsDesktopIconUI extends BasicDesktopIconUI { +public final class WindowsDesktopIconUI extends BasicDesktopIconUI { private int width; public static ComponentUI createUI(JComponent c) { return new WindowsDesktopIconUI(); } + @Override public void installDefaults() { super.installDefaults(); width = UIManager.getInt("DesktopIcon.width"); } + @Override public void installUI(JComponent c) { super.installUI(c); @@ -55,6 +57,7 @@ public void installUI(JComponent c) { } // Uninstall the listeners added by the WindowsInternalFrameTitlePane + @Override public void uninstallUI(JComponent c) { WindowsInternalFrameTitlePane thePane = (WindowsInternalFrameTitlePane)iconPane; @@ -62,6 +65,7 @@ public void uninstallUI(JComponent c) { thePane.uninstallListeners(); } + @Override protected void installComponents() { iconPane = new WindowsInternalFrameTitlePane(frame); desktopIcon.setLayout(new BorderLayout()); @@ -72,6 +76,7 @@ protected void installComponents() { } } + @Override public Dimension getPreferredSize(JComponent c) { // Windows desktop icons can not be resized. Therefore, we should // always return the minimum size of the desktop icon. See @@ -83,6 +88,7 @@ public Dimension getPreferredSize(JComponent c) { * Windows desktop icons are restricted to a width of 160 pixels by * default. This value is retrieved by the DesktopIcon.width property. */ + @Override public Dimension getMinimumSize(JComponent c) { Dimension dim = super.getMinimumSize(c); dim.width = width; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java index 82708f571e5dc..355f70b46071d 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java @@ -52,7 +52,7 @@ * @author Thomas Ball */ @SuppressWarnings("serial") // JDK-implementation class -public class WindowsDesktopManager extends DefaultDesktopManager +public final class WindowsDesktopManager extends DefaultDesktopManager implements java.io.Serializable, javax.swing.plaf.UIResource { /* The frame which is currently selected/activated. @@ -60,6 +60,7 @@ public class WindowsDesktopManager extends DefaultDesktopManager */ private WeakReference currentFrameRef; + @Override public void activateFrame(JInternalFrame f) { JInternalFrame currentFrame = currentFrameRef != null ? currentFrameRef.get() : null; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopPaneUI.java index 3ceea2d31dca4..49ab809dddd19 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopPaneUI.java @@ -34,12 +34,13 @@ * * @author David Kloba */ -public class WindowsDesktopPaneUI extends BasicDesktopPaneUI +public final class WindowsDesktopPaneUI extends BasicDesktopPaneUI { public static ComponentUI createUI(JComponent c) { return new WindowsDesktopPaneUI(); } + @Override protected void installDesktopManager() { desktopManager = desktop.getDesktopManager(); if(desktopManager == null) { @@ -48,10 +49,12 @@ protected void installDesktopManager() { } } + @Override protected void installDefaults() { super.installDefaults(); } + @Override @SuppressWarnings("deprecation") protected void installKeyboardActions() { super.installKeyboardActions(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsEditorPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsEditorPaneUI.java index 2f5c45633d4c5..abccb6b9a4816 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsEditorPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsEditorPaneUI.java @@ -33,7 +33,7 @@ /** * Windows rendition of the component. */ -public class WindowsEditorPaneUI extends BasicEditorPaneUI +public final class WindowsEditorPaneUI extends BasicEditorPaneUI { /** @@ -54,6 +54,7 @@ public static ComponentUI createUI(JComponent c) { * * @return the caret object */ + @Override protected Caret createCaret() { return new WindowsTextUI.WindowsCaret(); } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java index 7065e3db19ba6..37d45bbf90220 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java @@ -101,7 +101,7 @@ * * @author Jeff Dinkins */ -public class WindowsFileChooserUI extends BasicFileChooserUI { +public final class WindowsFileChooserUI extends BasicFileChooserUI { // The following are private because the implementation of the // Windows FileChooser L&F is not complete yet. @@ -194,61 +194,75 @@ public WindowsFileChooserUI(JFileChooser filechooser) { super(filechooser); } + @Override public void installUI(JComponent c) { super.installUI(c); } + @Override public void uninstallComponents(JFileChooser fc) { fc.removeAll(); } - private class WindowsFileChooserUIAccessor implements FilePane.FileChooserUIAccessor { + private final class WindowsFileChooserUIAccessor implements FilePane.FileChooserUIAccessor { + @Override public JFileChooser getFileChooser() { return WindowsFileChooserUI.this.getFileChooser(); } + @Override public BasicDirectoryModel getModel() { return WindowsFileChooserUI.this.getModel(); } + @Override public JPanel createList() { return WindowsFileChooserUI.this.createList(getFileChooser()); } + @Override public JPanel createDetailsView() { return WindowsFileChooserUI.this.createDetailsView(getFileChooser()); } + @Override public boolean isDirectorySelected() { return WindowsFileChooserUI.this.isDirectorySelected(); } + @Override public File getDirectory() { return WindowsFileChooserUI.this.getDirectory(); } + @Override public Action getChangeToParentDirectoryAction() { return WindowsFileChooserUI.this.getChangeToParentDirectoryAction(); } + @Override public Action getApproveSelectionAction() { return WindowsFileChooserUI.this.getApproveSelectionAction(); } + @Override public Action getNewFolderAction() { return WindowsFileChooserUI.this.getNewFolderAction(); } + @Override public MouseListener createDoubleClickListener(JList list) { return WindowsFileChooserUI.this.createDoubleClickListener(getFileChooser(), list); } + @Override public ListSelectionListener createListSelectionListener() { return WindowsFileChooserUI.this.createListSelectionListener(getFileChooser()); } } + @Override public void installComponents(JFileChooser fc) { filePane = new FilePane(new WindowsFileChooserUIAccessor()); fc.addPropertyChangeListener(filePane); @@ -584,6 +598,7 @@ protected JPanel getBottomPanel() { return bottomPanel; } + @Override protected void installStrings(JFileChooser fc) { super.installStrings(fc); @@ -615,6 +630,7 @@ private Integer getMnemonic(String key, Locale l) { return SwingUtilities2.getUIDefaultsInt(key, l); } + @Override protected void installListeners(JFileChooser fc) { super.installListeners(fc); ActionMap actionMap = getActionMap(); @@ -645,10 +661,12 @@ protected JPanel createDetailsView(JFileChooser fc) { * @param fc a JFileChooser * @return a ListSelectionListener */ + @Override public ListSelectionListener createListSelectionListener(JFileChooser fc) { return super.createListSelectionListener(fc); } + @Override public void uninstallUI(JComponent c) { // Remove listeners c.removePropertyChangeListener(filterComboBoxModel); @@ -859,6 +877,7 @@ private void doControlButtonsChanged(PropertyChangeEvent e) { * Listen for filechooser property changes, such as * the selected file changing, or the type of the dialog changing. */ + @Override public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) { return new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent e) { @@ -913,14 +932,17 @@ protected void addControlButtons() { getBottomPanel().add(getButtonPanel()); } + @Override public void ensureFileIsVisible(JFileChooser fc, File f) { filePane.ensureFileIsVisible(fc, f); } + @Override public void rescanCurrentDirectory(JFileChooser fc) { filePane.rescanCurrentDirectory(); } + @Override public String getFileName() { if(filenameTextField != null) { return filenameTextField.getText(); @@ -929,6 +951,7 @@ public String getFileName() { } } + @Override public void setFileName(String filename) { if(filenameTextField != null) { filenameTextField.setText(filename); @@ -942,6 +965,7 @@ public void setFileName(String filename) { * @param directorySelected if a directory is currently selected. * @since 1.4 */ + @Override protected void setDirectorySelected(boolean directorySelected) { super.setDirectorySelected(directorySelected); JFileChooser chooser = getFileChooser(); @@ -956,11 +980,13 @@ protected void setDirectorySelected(boolean directorySelected) { } } + @Override public String getDirectoryName() { // PENDING(jeff) - get the name from the directory combobox return null; } + @Override public void setDirectoryName(String dirname) { // PENDING(jeff) - set the name in the directory combobox } @@ -1032,8 +1058,9 @@ public void focusLost(FocusEvent e) { // Renderer for DirectoryComboBox // @SuppressWarnings("serial") // Superclass is not serializable across versions - class DirectoryComboBoxRenderer extends DefaultListCellRenderer { + final class DirectoryComboBoxRenderer extends DefaultListCellRenderer { IndentIcon ii = new IndentIcon(); + @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { @@ -1056,11 +1083,12 @@ public Component getListCellRendererComponent(JList list, Object value, } static final int space = 10; - static class IndentIcon implements Icon { + static final class IndentIcon implements Icon { Icon icon = null; int depth = 0; + @Override public void paintIcon(Component c, Graphics g, int x, int y) { if (c.getComponentOrientation().isLeftToRight()) { icon.paintIcon(c, g, x+depth*space, y); @@ -1069,10 +1097,12 @@ public void paintIcon(Component c, Graphics g, int x, int y) { } } + @Override public int getIconWidth() { return icon.getIconWidth() + depth*space; } + @Override public int getIconHeight() { return icon.getIconHeight(); } @@ -1090,7 +1120,7 @@ protected DirectoryComboBoxModel createDirectoryComboBoxModel(JFileChooser fc) { * Data model for a type-face selection combo-box. */ @SuppressWarnings("serial") // Superclass is not serializable across versions - protected class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel { + protected final class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel { Vector directories = new Vector(); int[] depths = null; File selectedDirectory = null; @@ -1187,19 +1217,23 @@ public int getDepth(int i) { return (depths != null && i >= 0 && i < depths.length) ? depths[i] : 0; } + @Override public void setSelectedItem(Object selectedDirectory) { this.selectedDirectory = (File)selectedDirectory; fireContentsChanged(this, -1, -1); } + @Override public Object getSelectedItem() { return selectedDirectory; } + @Override public int getSize() { return directories.size(); } + @Override public File getElementAt(int index) { return directories.elementAt(index); } @@ -1216,7 +1250,8 @@ protected FilterComboBoxRenderer createFilterComboBoxRenderer() { * Render different type sizes and styles. */ @SuppressWarnings("serial") // Superclass is not serializable across versions - public class FilterComboBoxRenderer extends DefaultListCellRenderer { + public final class FilterComboBoxRenderer extends DefaultListCellRenderer { + @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { @@ -1242,7 +1277,7 @@ protected FilterComboBoxModel createFilterComboBoxModel() { * Data model for a type-face selection combo-box. */ @SuppressWarnings("serial") // Superclass is not serializable across versions - protected class FilterComboBoxModel extends AbstractListModel implements ComboBoxModel, + protected final class FilterComboBoxModel extends AbstractListModel implements ComboBoxModel, PropertyChangeListener { protected FileFilter[] filters; protected FilterComboBoxModel() { @@ -1250,6 +1285,7 @@ protected FilterComboBoxModel() { filters = getFileChooser().getChoosableFileFilters(); } + @Override public void propertyChange(PropertyChangeEvent e) { String prop = e.getPropertyName(); if(prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) { @@ -1260,6 +1296,7 @@ public void propertyChange(PropertyChangeEvent e) { } } + @Override public void setSelectedItem(Object filter) { if(filter != null) { getFileChooser().setFileFilter((FileFilter) filter); @@ -1267,6 +1304,7 @@ public void setSelectedItem(Object filter) { } } + @Override public Object getSelectedItem() { // Ensure that the current filter is in the list. // NOTE: we shouldn't have to do this, since JFileChooser adds @@ -1288,6 +1326,7 @@ public Object getSelectedItem() { return getFileChooser().getFileFilter(); } + @Override public int getSize() { if(filters != null) { return filters.length; @@ -1296,6 +1335,7 @@ public int getSize() { } } + @Override public FileFilter getElementAt(int index) { if(index > getSize() - 1) { // This shouldn't happen. Try to recover gracefully. @@ -1320,21 +1360,24 @@ public void valueChanged(ListSelectionEvent e) { /** * Acts when DirectoryComboBox has changed the selected item. */ - protected class DirectoryComboBoxAction implements ActionListener { + protected final class DirectoryComboBoxAction implements ActionListener { + @Override public void actionPerformed(ActionEvent e) { File f = (File)directoryComboBox.getSelectedItem(); getFileChooser().setCurrentDirectory(f); } } + @Override protected JButton getApproveButton(JFileChooser fc) { return approveButton; } + @Override public FileView getFileView(JFileChooser fc) { return fileView; } @@ -1342,9 +1385,10 @@ public FileView getFileView(JFileChooser fc) { // *********************** // * FileView operations * // *********************** - protected class WindowsFileView extends BasicFileView { + protected final class WindowsFileView extends BasicFileView { /* FileView type descriptions */ + @Override public Icon getIcon(File f) { Icon icon = getCachedIcon(f); if (icon != null) { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsGraphicsUtils.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsGraphicsUtils.java index cb4b5caa86de9..b5859b08ea8ad 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsGraphicsUtils.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsGraphicsUtils.java @@ -58,7 +58,7 @@ * @author Mark Davidson * @since 1.4 */ -public class WindowsGraphicsUtils { +public final class WindowsGraphicsUtils { /** * Renders a text String in Windows without the mnemonic. diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java index 072ff606b5b78..cf2fd119423ad 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java @@ -63,7 +63,7 @@ * @author Rich Schiavi */ @SuppressWarnings("serial") // Same-version serialization only -public class WindowsIconFactory implements Serializable +public final class WindowsIconFactory implements Serializable { private static Icon frame_closeIcon; private static Icon frame_iconifyIcon; @@ -173,13 +173,14 @@ public static Icon createFrameResizeIcon() { @SuppressWarnings("serial") // Same-version serialization only - private static class FrameButtonIcon implements Icon, Serializable { + private static final class FrameButtonIcon implements Icon, Serializable { private final Part part; private FrameButtonIcon(Part part) { this.part = part; } + @Override public void paintIcon(Component c, Graphics g, int x0, int y0) { int width = getIconWidth(); int height = getIconHeight(); @@ -281,6 +282,7 @@ public void paintIcon(Component c, Graphics g, int x0, int y0) { } } + @Override public int getIconWidth() { int width; if (XPStyle.getXP() != null) { @@ -293,6 +295,7 @@ public int getIconWidth() { return width; } + @Override public int getIconHeight() { int height = UIManager.getInt("InternalFrame.titleButtonHeight")-4; return height; @@ -302,7 +305,8 @@ public int getIconHeight() { @SuppressWarnings("serial") // Same-version serialization only - private static class ResizeIcon implements Icon, Serializable { + private static final class ResizeIcon implements Icon, Serializable { + @Override public void paintIcon(Component c, Graphics g, int x, int y) { g.setColor(UIManager.getColor("InternalFrame.resizeIconHighlight")); g.drawLine(0, 11, 11, 0); @@ -317,14 +321,17 @@ public void paintIcon(Component c, Graphics g, int x, int y) { g.drawLine(9, 11, 11, 9); g.drawLine(10, 11, 11, 10); } + @Override public int getIconWidth() { return 13; } + @Override public int getIconHeight() { return 13; } } @SuppressWarnings("serial") // Same-version serialization only - private static class CheckBoxIcon implements Icon, Serializable + private static final class CheckBoxIcon implements Icon, Serializable { static final int csize = 13; + @Override public void paintIcon(Component c, Graphics g, int x, int y) { JCheckBox cb = (JCheckBox) c; ButtonModel model = cb.getModel(); @@ -425,6 +432,7 @@ public void paintIcon(Component c, Graphics g, int x, int y) { } } + @Override public int getIconWidth() { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -434,6 +442,7 @@ public int getIconWidth() { } } + @Override public int getIconHeight() { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -445,8 +454,9 @@ public int getIconHeight() { } @SuppressWarnings("serial") // Same-version serialization only - private static class RadioButtonIcon implements Icon, UIResource, Serializable + private static final class RadioButtonIcon implements Icon, UIResource, Serializable { + @Override public void paintIcon(Component c, Graphics g, int x, int y) { AbstractButton b = (AbstractButton) c; ButtonModel model = b.getModel(); @@ -579,6 +589,7 @@ public void paintIcon(Component c, Graphics g, int x, int y) { } } + @Override public int getIconWidth() { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -588,6 +599,7 @@ public int getIconWidth() { } } + @Override public int getIconHeight() { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -600,8 +612,9 @@ public int getIconHeight() { @SuppressWarnings("serial") // Same-version serialization only - private static class CheckBoxMenuItemIcon implements Icon, UIResource, Serializable + private static final class CheckBoxMenuItemIcon implements Icon, UIResource, Serializable { + @Override public void paintIcon(Component c, Graphics g, int x, int y) { AbstractButton b = (AbstractButton) c; ButtonModel model = b.getModel(); @@ -619,15 +632,18 @@ public void paintIcon(Component c, Graphics g, int x, int y) { g.drawLine(x+3, y+6, x+4, y+6); } } + @Override public int getIconWidth() { return 9; } + @Override public int getIconHeight() { return 9; } } // End class CheckBoxMenuItemIcon @SuppressWarnings("serial") // Same-version serialization only - private static class RadioButtonMenuItemIcon implements Icon, UIResource, Serializable + private static final class RadioButtonMenuItemIcon implements Icon, UIResource, Serializable { + @Override public void paintIcon(Component c, Graphics g, int x, int y) { AbstractButton b = (AbstractButton) c; ButtonModel model = b.getModel(); @@ -636,14 +652,17 @@ public void paintIcon(Component c, Graphics g, int x, int y) { 4, 4); } } + @Override public int getIconWidth() { return 12; } + @Override public int getIconHeight() { return 12; } } // End class RadioButtonMenuItemIcon @SuppressWarnings("serial") // Same-version serialization only - private static class MenuItemCheckIcon implements Icon, UIResource, Serializable{ + private static final class MenuItemCheckIcon implements Icon, UIResource, Serializable{ + @Override public void paintIcon(Component c, Graphics g, int x, int y) { /* For debugging: Color oldColor = g.getColor(); @@ -652,13 +671,16 @@ public void paintIcon(Component c, Graphics g, int x, int y) { g.setColor(oldColor); */ } + @Override public int getIconWidth() { return 9; } + @Override public int getIconHeight() { return 9; } } // End class MenuItemCheckIcon @SuppressWarnings("serial") // Same-version serialization only - private static class MenuItemArrowIcon implements Icon, UIResource, Serializable { + private static final class MenuItemArrowIcon implements Icon, UIResource, Serializable { + @Override public void paintIcon(Component c, Graphics g, int x, int y) { /* For debugging: Color oldColor = g.getColor(); @@ -667,13 +689,16 @@ public void paintIcon(Component c, Graphics g, int x, int y) { g.setColor(oldColor); */ } + @Override public int getIconWidth() { return 4; } + @Override public int getIconHeight() { return 8; } } // End class MenuItemArrowIcon @SuppressWarnings("serial") // Same-version serialization only - private static class MenuArrowIcon implements Icon, UIResource, Serializable { + private static final class MenuArrowIcon implements Icon, UIResource, Serializable { + @Override public void paintIcon(Component c, Graphics g, int x, int y) { XPStyle xp = XPStyle.getXP(); if (WindowsMenuItemUI.isVistaPainting(xp)) { @@ -708,6 +733,7 @@ public void paintIcon(Component c, Graphics g, int x, int y) { g.translate(-x,-y); } } + @Override public int getIconWidth() { XPStyle xp = XPStyle.getXP(); if (WindowsMenuItemUI.isVistaPainting(xp)) { @@ -717,6 +743,7 @@ public int getIconWidth() { return 4; } } + @Override public int getIconHeight() { XPStyle xp = XPStyle.getXP(); if (WindowsMenuItemUI.isVistaPainting(xp)) { @@ -728,14 +755,16 @@ public int getIconHeight() { } } // End class MenuArrowIcon - static class VistaMenuItemCheckIconFactory + static final class VistaMenuItemCheckIconFactory implements MenuItemCheckIconFactory { private static final int OFFSET = 3; + @Override public Icon getIcon(JMenuItem component) { return new VistaMenuItemCheckIcon(component); } + @Override public boolean isCompatible(Object icon, String prefix) { return icon instanceof VistaMenuItemCheckIcon && ((VistaMenuItemCheckIcon) icon).type == getType(prefix); @@ -788,7 +817,7 @@ private static Class getType(String type) { * Note: to be used on Vista only. */ @SuppressWarnings("serial") // Same-version serialization only - private static class VistaMenuItemCheckIcon + private static final class VistaMenuItemCheckIcon implements Icon, UIResource, Serializable { private final JMenuItem menuItem; @@ -803,6 +832,7 @@ private static class VistaMenuItemCheckIcon this.menuItem = null; } + @Override public int getIconHeight() { Icon lafIcon = getLaFIcon(); if (lafIcon != null) { @@ -825,6 +855,7 @@ public int getIconHeight() { return height; } + @Override public int getIconWidth() { Icon lafIcon = getLaFIcon(); if (lafIcon != null) { @@ -840,6 +871,7 @@ public int getIconWidth() { return width; } + @Override public void paintIcon(Component c, Graphics g, int x, int y) { Icon lafIcon = getLaFIcon(); if (lafIcon != null) { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameTitlePane.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameTitlePane.java index 083563b4464df..ba4bde12122d9 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameTitlePane.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameTitlePane.java @@ -83,6 +83,7 @@ public WindowsInternalFrameTitlePane(JInternalFrame f) { super(f); } + @Override protected void addSubComponents() { add(systemLabel); add(iconButton); @@ -90,6 +91,7 @@ protected void addSubComponents() { add(closeButton); } + @Override protected void installDefaults() { super.installDefaults(); @@ -117,11 +119,13 @@ protected void installDefaults() { UIManager.getColor("InternalFrame.inactiveTitleGradient"); } + @Override protected void uninstallListeners() { // Get around protected method in superclass super.uninstallListeners(); } + @Override protected void createButtons() { super.createButtons(); if (XPStyle.getXP() != null) { @@ -131,6 +135,7 @@ protected void createButtons() { } } + @Override protected void setButtonIcons() { super.setButtonIcons(); @@ -142,6 +147,7 @@ protected void setButtonIcons() { } + @Override public void paintComponent(Graphics g) { XPStyle xp = XPStyle.getXP(); @@ -224,10 +230,12 @@ public void paintComponent(Graphics g) { } } + @Override public Dimension getPreferredSize() { return getMinimumSize(); } + @Override public Dimension getMinimumSize() { Dimension d = new Dimension(super.getMinimumSize()); d.height = titlePaneHeight + 2; @@ -245,6 +253,7 @@ public Dimension getMinimumSize() { return d; } + @Override protected void paintTitleBackground(Graphics g) { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -285,6 +294,7 @@ protected void paintTitleBackground(Graphics g) { } } + @Override protected void assembleSystemMenu() { systemPopupMenu = new JPopupMenu(); addSystemMenuItems(systemPopupMenu); @@ -372,6 +382,7 @@ private static int getButtonMnemonic(String button) { } } + @Override protected void showSystemMenu(){ showSystemPopupMenu(systemLabel); } @@ -397,15 +408,17 @@ private void showSystemPopupMenu(Component invoker){ } } + @Override protected PropertyChangeListener createPropertyChangeListener() { return new WindowsPropertyChangeHandler(); } + @Override protected LayoutManager createLayout() { return new WindowsTitlePaneLayout(); } - public class WindowsTitlePaneLayout extends BasicInternalFrameTitlePane.TitlePaneLayout { + public final class WindowsTitlePaneLayout extends BasicInternalFrameTitlePane.TitlePaneLayout { private Insets captionMargin = null; private Insets contentMargin = null; private XPStyle xp = XPStyle.getXP(); @@ -439,6 +452,7 @@ private int layoutButton(JComponent button, Part part, return x; } + @Override public void layoutContainer(Container c) { boolean leftToRight = WindowsGraphicsUtils.isLeftToRight(frame); int x, y; @@ -492,7 +506,8 @@ public void layoutContainer(Container c) { } } // end WindowsTitlePaneLayout - public class WindowsPropertyChangeHandler extends PropertyChangeHandler { + public final class WindowsPropertyChangeHandler extends PropertyChangeHandler { + @Override public void propertyChange(PropertyChangeEvent evt) { String prop = evt.getPropertyName(); @@ -515,7 +530,7 @@ public void propertyChange(PropertyChangeEvent evt) { *

* Note: We assume here that icons are square. */ - public static class ScalableIconUIResource implements Icon, UIResource { + public static final class ScalableIconUIResource implements Icon, UIResource { // We can use an arbitrary size here because we scale to it in paintIcon() private static final int SIZE = 16; @@ -562,6 +577,7 @@ protected Icon getBestIcon(int size) { } } + @Override public void paintIcon(Component c, Graphics g, int x, int y) { Graphics2D g2d = (Graphics2D)g.create(); // Calculate how big our drawing area is in pixels @@ -580,10 +596,12 @@ public void paintIcon(Component c, Graphics g, int x, int y) { g2d.dispose(); } + @Override public int getIconWidth() { return SIZE; } + @Override public int getIconHeight() { return SIZE; } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameUI.java index 19169f6e4241e..5c331533af947 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameUI.java @@ -45,10 +45,11 @@ /** * Windows rendition of the component. */ -public class WindowsInternalFrameUI extends BasicInternalFrameUI +public final class WindowsInternalFrameUI extends BasicInternalFrameUI { XPStyle xp = XPStyle.getXP(); + @Override public void installDefaults() { super.installDefaults(); @@ -59,6 +60,7 @@ public void installDefaults() { } } + @Override public void installUI(JComponent c) { super.installUI(c); @@ -66,6 +68,7 @@ public void installUI(JComponent c) { xp == null? Boolean.TRUE : Boolean.FALSE); } + @Override public void uninstallDefaults() { frame.setBorder(null); super.uninstallDefaults(); @@ -79,17 +82,19 @@ public WindowsInternalFrameUI(JInternalFrame w){ super(w); } + @Override protected DesktopManager createDesktopManager(){ return new WindowsDesktopManager(); } + @Override protected JComponent createNorthPane(JInternalFrame w) { titlePane = new WindowsInternalFrameTitlePane(w); return titlePane; } @SuppressWarnings("serial") // Superclass is not serializable across versions - private class XPBorder extends AbstractBorder { + private final class XPBorder extends AbstractBorder { private Skin leftSkin = xp.getSkin(frame, Part.WP_FRAMELEFT); private Skin rightSkin = xp.getSkin(frame, Part.WP_FRAMERIGHT); private Skin bottomSkin = xp.getSkin(frame, Part.WP_FRAMEBOTTOM); @@ -100,6 +105,7 @@ private class XPBorder extends AbstractBorder { * @param width the width of the painted border * @param height the height of the painted border */ + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { State state = ((JInternalFrame)c).isSelected() ? State.ACTIVE : State.INACTIVE; int topBorderHeight = (titlePane != null) ? titlePane.getSize().height : 0; @@ -118,6 +124,7 @@ public void paintBorder(Component c, Graphics g, int x, int y, int width, int he } + @Override public Insets getBorderInsets(Component c, Insets insets) { insets.top = 4; insets.left = leftSkin.getWidth(); @@ -127,6 +134,7 @@ public Insets getBorderInsets(Component c, Insets insets) { return insets; } + @Override public boolean isBorderOpaque() { return true; } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java index 6266772dcf4a2..d10f3f47c3c33 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java @@ -41,7 +41,7 @@ /** * Windows rendition of the component. */ -public class WindowsLabelUI extends BasicLabelUI { +public final class WindowsLabelUI extends BasicLabelUI { private static final Object WINDOWS_LABEL_UI_KEY = new Object(); @@ -59,6 +59,7 @@ public static ComponentUI createUI(JComponent c) { return windowsLabelUI; } + @Override protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, int textY) { int mnemonicIndex = l.getDisplayedMnemonicIndex(); @@ -72,6 +73,7 @@ protected void paintEnabledText(JLabel l, Graphics g, String s, textX, textY); } + @Override protected void paintDisabledText(JLabel l, Graphics g, String s, int textX, int textY) { int mnemonicIndex = l.getDisplayedMnemonicIndex(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java index 72ad51535ff2e..d1ee714f362e5 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java @@ -145,26 +145,32 @@ public class WindowsLookAndFeel extends BasicLookAndFeel */ private int baseUnitY; + @Override public String getName() { return "Windows"; } + @Override public String getDescription() { return "The Microsoft Windows Look and Feel"; } + @Override public String getID() { return "Windows"; } + @Override public boolean isNativeLookAndFeel() { return OSInfo.getOSType() == OSInfo.OSType.WINDOWS; } + @Override public boolean isSupportedLookAndFeel() { return isNativeLookAndFeel(); } + @Override public void initialize() { super.initialize(); @@ -206,6 +212,7 @@ public void initialize() { * * @see BasicLookAndFeel#getDefaults */ + @Override protected void initClassDefaults(UIDefaults table) { super.initClassDefaults(table); @@ -260,6 +267,7 @@ protected void initClassDefaults(UIDefaults table) * values, otherwise we create color objects whose values match * the defaults Windows95 colors. */ + @Override protected void initSystemColorDefaults(UIDefaults table) { String[] defaultSystemColors = { @@ -310,6 +318,7 @@ private void initResourceBundle(UIDefaults table) { // XXX - there are probably a lot of redundant values that could be removed. // ie. Take a look at RadioButtonBorder, etc... + @Override protected void initComponentDefaults(UIDefaults table) { super.initComponentDefaults( table ); @@ -1893,6 +1902,7 @@ public Object createValue(UIDefaults table) { return lazyDefaults; } + @Override public void uninitialize() { super.uninitialize(); @@ -1944,6 +1954,7 @@ public static boolean isClassicWindows() { * * @see javax.swing.LookAndFeel#provideErrorFeedback */ + @Override public void provideErrorFeedback(Component component) { super.provideErrorFeedback(component); } @@ -1951,6 +1962,7 @@ public void provideErrorFeedback(Component component) { /** * {@inheritDoc} */ + @Override public LayoutStyle getLayoutStyle() { LayoutStyle style = this.style; if (style == null) { @@ -1981,6 +1993,7 @@ public LayoutStyle getLayoutStyle() { * @see #playSound(Action) * @since 1.4 */ + @Override protected Action createAudioAction(Object key) { if (key != null) { String audioKey = (String)key; @@ -2018,7 +2031,7 @@ static void repaintRootPane(Component c) { * @since 1.4 */ @SuppressWarnings("serial") // Superclass is not serializable across versions - private static class AudioAction extends AbstractAction { + private static final class AudioAction extends AbstractAction { private Runnable audioRunnable; private String audioResource; /** @@ -2029,6 +2042,7 @@ public AudioAction(String name, String resource) { super(name); audioResource = resource; } + @Override public void actionPerformed(ActionEvent e) { if (audioRunnable == null) { audioRunnable = (Runnable)Toolkit.getDefaultToolkit().getDesktopProperty(audioResource); @@ -2045,7 +2059,7 @@ public void actionPerformed(ActionEvent e) { * Gets an Icon from the native libraries if available, * otherwise gets it from an image resource file. */ - private static class LazyWindowsIcon implements UIDefaults.LazyValue { + private static final class LazyWindowsIcon implements UIDefaults.LazyValue { private String nativeImage; private String resource; @@ -2054,6 +2068,7 @@ private static class LazyWindowsIcon implements UIDefaults.LazyValue { this.resource = resource; } + @Override public Object createValue(UIDefaults table) { if (nativeImage != null) { Image image = (Image)ShellFolder.get(nativeImage); @@ -2072,7 +2087,7 @@ public Object createValue(UIDefaults table) { * Gets an Icon from the native libraries if available. * A desktop property is used to trigger reloading the icon when needed. */ - private static class ActiveWindowsIcon implements UIDefaults.ActiveValue { + private static final class ActiveWindowsIcon implements UIDefaults.ActiveValue { private Icon icon; private String nativeImageName; private String fallbackName; @@ -2117,7 +2132,7 @@ public Object createValue(UIDefaults table) { /** * Icon backed-up by XP Skin. */ - private static class SkinIcon implements Icon, UIResource { + private static final class SkinIcon implements Icon, UIResource { private final Part part; private final State state; SkinIcon(Part part, State state) { @@ -2130,6 +2145,7 @@ private static class SkinIcon implements Icon, UIResource { * may use the Component argument to get properties useful for * painting, e.g. the foreground or background color. */ + @Override public void paintIcon(Component c, Graphics g, int x, int y) { XPStyle xp = XPStyle.getXP(); assert xp != null; @@ -2144,6 +2160,7 @@ public void paintIcon(Component c, Graphics g, int x, int y) { * * @return an int specifying the fixed width of the icon. */ + @Override public int getIconWidth() { int width = 0; XPStyle xp = XPStyle.getXP(); @@ -2160,6 +2177,7 @@ public int getIconWidth() { * * @return an int specifying the fixed height of the icon. */ + @Override public int getIconHeight() { int height = 0; XPStyle xp = XPStyle.getXP(); @@ -2176,11 +2194,12 @@ public int getIconHeight() { * WindowsDesktopProperty for fonts. If a font with the name 'MS Sans Serif' * is returned, it is mapped to 'Microsoft Sans Serif'. */ - private static class WindowsFontProperty extends WindowsDesktopProperty { + private static final class WindowsFontProperty extends WindowsDesktopProperty { WindowsFontProperty(String key, Object backup) { super(key, backup); } + @Override public void invalidate(LookAndFeel laf) { if ("win.defaultGUI.font.height".equals(getKey())) { ((WindowsLookAndFeel)laf).style = null; @@ -2188,6 +2207,7 @@ public void invalidate(LookAndFeel laf) { super.invalidate(laf); } + @Override protected Object configureValue(Object value) { if (value instanceof Font) { Font font = (Font)value; @@ -2236,7 +2256,7 @@ protected Object configureValue(Object value) { * WindowsDesktopProperty for fonts that only gets sizes from the desktop, * font name and style are passed into the constructor */ - private static class WindowsFontSizeProperty extends + private static final class WindowsFontSizeProperty extends WindowsDesktopProperty { private String fontName; private int fontSize; @@ -2250,6 +2270,7 @@ private static class WindowsFontSizeProperty extends this.fontStyle = fontStyle; } + @Override protected Object configureValue(Object value) { if (value == null) { value = new FontUIResource(fontName, fontStyle, fontSize); @@ -2278,6 +2299,7 @@ private static class XPValue implements UIDefaults.ActiveValue { this.classicValue = classicValue; } + @Override public Object createValue(UIDefaults table) { Object value = null; if (XPStyle.getXP() != null) { @@ -2313,7 +2335,7 @@ private Object recursiveCreateValue(Object value, UIDefaults table) { } } - private static class XPBorderValue extends XPValue { + private static final class XPBorderValue extends XPValue { private final Border extraMargin; XPBorderValue(Part xpValue, Object classicValue) { @@ -2325,6 +2347,7 @@ private static class XPBorderValue extends XPValue { this.extraMargin = extraMargin; } + @Override public Object getXPValue(UIDefaults table) { XPStyle xp = XPStyle.getXP(); Border xpBorder = xp != null ? xp.getBorder(null, (Part)xpValue) : null; @@ -2337,18 +2360,19 @@ public Object getXPValue(UIDefaults table) { } } - private static class XPColorValue extends XPValue { + private static final class XPColorValue extends XPValue { XPColorValue(Part part, State state, Prop prop, Object classicValue) { super(new XPColorValueKey(part, state, prop), classicValue); } + @Override public Object getXPValue(UIDefaults table) { XPColorValueKey key = (XPColorValueKey)xpValue; XPStyle xp = XPStyle.getXP(); return xp != null ? xp.getColor(key.skin, key.prop, null) : null; } - private static class XPColorValueKey { + private static final class XPColorValueKey { Skin skin; Prop prop; @@ -2359,7 +2383,7 @@ private static class XPColorValueKey { } } - private class XPDLUValue extends XPValue { + private final class XPDLUValue extends XPValue { private int direction; XPDLUValue(int xpdlu, int classicdlu, int direction) { @@ -2367,11 +2391,13 @@ private class XPDLUValue extends XPValue { this.direction = direction; } + @Override public Object getXPValue(UIDefaults table) { int px = dluToPixels(((Integer)xpValue).intValue(), direction); return Integer.valueOf(px); } + @Override public Object getClassicValue(UIDefaults table) { int px = dluToPixels(((Integer)classicValue).intValue(), direction); return Integer.valueOf(px); @@ -2387,6 +2413,7 @@ private static class TriggerDesktopProperty extends WindowsDesktopProperty { getValueFromDesktop(); } + @Override protected void updateUI() { super.updateUI(); @@ -2395,11 +2422,12 @@ protected void updateUI() { } } - private static class FontDesktopProperty extends TriggerDesktopProperty { + private static final class FontDesktopProperty extends TriggerDesktopProperty { FontDesktopProperty(String key) { super(key); } + @Override protected void updateUI() { UIDefaults defaults = UIManager.getLookAndFeelDefaults(); SwingUtilities2.putAATextInfo(true, defaults); @@ -2410,7 +2438,7 @@ protected void updateUI() { // Windows LayoutStyle. From: // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwue/html/ch14e.asp @SuppressWarnings("fallthrough") - private class WindowsLayoutStyle extends DefaultLayoutStyle { + private final class WindowsLayoutStyle extends DefaultLayoutStyle { @Override public int getPreferredGap(JComponent component1, JComponent component2, ComponentPlacement type, int position, @@ -2504,6 +2532,7 @@ private void calculateBaseUnits() { * * @since 1.6 */ + @Override public Icon getDisabledIcon(JComponent component, Icon icon) { // if the component has a HI_RES_DISABLED_ICON_CLIENT_KEY // client property set to Boolean.TRUE, then use the new @@ -2525,10 +2554,11 @@ public Icon getDisabledIcon(JComponent component, Icon icon) { return super.getDisabledIcon(component, icon); } - private static class RGBGrayFilter extends RGBImageFilter { + private static final class RGBGrayFilter extends RGBImageFilter { public RGBGrayFilter() { canFilterIndexColorModel = true; } + @Override public int filterRGB(int x, int y, int rgb) { // find the average of red, green, and blue float avg = (((rgb >> 16) & 0xff) / 255f + @@ -2547,7 +2577,7 @@ public int filterRGB(int x, int y, int rgb) { } } - private static class FocusColorProperty extends WindowsDesktopProperty { + private static final class FocusColorProperty extends WindowsDesktopProperty { public FocusColorProperty () { // Fallback value is never used because of the configureValue method doesn't return null super("win.3d.backgroundColor", Color.BLACK); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java index 8c6cbdff5412e..f663d8d1e908d 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java @@ -57,7 +57,7 @@ /** * Windows rendition of the component. */ -public class WindowsMenuBarUI extends BasicMenuBarUI +public final class WindowsMenuBarUI extends BasicMenuBarUI { /* to be accessed on the EDT only */ private WindowListener windowListener = null; @@ -125,6 +125,7 @@ public void hierarchyChanged(HierarchyEvent e) { super.installListeners(); } + @Override protected void installKeyboardActions() { super.installKeyboardActions(); ActionMap map = SwingUtilities.getUIActionMap(menuBar); @@ -140,7 +141,7 @@ protected void installKeyboardActions() { * Unlike BasicMenuBarUI.TakeFocus, this Action will not show menu popup. */ @SuppressWarnings("serial") // Superclass is not serializable across versions - private static class TakeFocus extends AbstractAction { + private static final class TakeFocus extends AbstractAction { @Override public void actionPerformed(ActionEvent e) { JMenuBar menuBar = (JMenuBar)e.getSource(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java index 2f76f9291332c..2ee1b2d119fb1 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java @@ -54,7 +54,7 @@ * * @author Igor Kushnirskiy */ -public class WindowsMenuItemUI extends BasicMenuItemUI { +public final class WindowsMenuItemUI extends BasicMenuItemUI { /** * The instance of {@code PropertyChangeListener}. */ @@ -63,6 +63,7 @@ public class WindowsMenuItemUI extends BasicMenuItemUI { final WindowsMenuItemUIAccessor accessor = new WindowsMenuItemUIAccessor() { + @Override public JMenuItem getMenuItem() { return menuItem; } @@ -71,6 +72,7 @@ public State getState(JMenuItem menuItem) { return WindowsMenuItemUI.getState(this, menuItem); } + @Override public Part getPart(JMenuItem menuItem) { return WindowsMenuItemUI.getPart(this, menuItem); } @@ -141,6 +143,7 @@ protected void uninstallListeners() { * @param textRect Bounding rectangle to render the text. * @param text String to render */ + @Override protected void paintText(Graphics g, JMenuItem menuItem, Rectangle textRect, String text) { if (WindowsMenuItemUI.isVistaPainting()) { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java index 4195b4e85cace..5562ce603881b 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java @@ -50,13 +50,14 @@ /** * Windows rendition of the component. */ -public class WindowsMenuUI extends BasicMenuUI { +public final class WindowsMenuUI extends BasicMenuUI { protected Integer menuBarHeight; protected boolean hotTrackingOn; final WindowsMenuItemUIAccessor accessor = new WindowsMenuItemUIAccessor() { + @Override public JMenuItem getMenuItem() { return menuItem; } @@ -106,6 +107,7 @@ public State getState(JMenuItem menu) { return state; } + @Override public Part getPart(JMenuItem menuItem) { return ((JMenu) menuItem).isTopLevelMenu() ? Part.MP_BARITEM : Part.MP_POPUPITEM; @@ -115,6 +117,7 @@ public static ComponentUI createUI(JComponent x) { return new WindowsMenuUI(); } + @Override protected void installDefaults() { super.installDefaults(); if (!WindowsLookAndFeel.isClassicWindows()) { @@ -131,6 +134,7 @@ protected void installDefaults() { * Draws the background of the menu. * @since 1.4 */ + @Override protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor) { if (WindowsMenuItemUI.isVistaPainting()) { WindowsMenuItemUI.paintBackground(accessor, g, menuItem, bgColor); @@ -210,6 +214,7 @@ protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor) { * @param text String to render * @since 1.4 */ + @Override protected void paintText(Graphics g, JMenuItem menuItem, Rectangle textRect, String text) { if (WindowsMenuItemUI.isVistaPainting()) { @@ -245,6 +250,7 @@ protected void paintText(Graphics g, JMenuItem menuItem, g.setColor(oldColor); } + @Override protected MouseInputListener createMouseInputListener(JComponent c) { return new WindowsMouseInputHandler(); } @@ -254,7 +260,8 @@ protected MouseInputListener createMouseInputListener(JComponent c) { * true when the mouse enters the menu and false when it exits. * @since 1.4 */ - protected class WindowsMouseInputHandler extends BasicMenuUI.MouseInputHandler { + protected final class WindowsMouseInputHandler extends BasicMenuUI.MouseInputHandler { + @Override public void mouseEntered(MouseEvent evt) { super.mouseEntered(evt); @@ -265,6 +272,7 @@ public void mouseEntered(MouseEvent evt) { } } + @Override public void mouseExited(MouseEvent evt) { super.mouseExited(evt); @@ -277,6 +285,7 @@ public void mouseExited(MouseEvent evt) { } } + @Override protected Dimension getPreferredMenuItemSize(JComponent c, Icon checkIcon, Icon arrowIcon, diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsOptionPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsOptionPaneUI.java index 2755cc76c96c5..5ced1659adfe2 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsOptionPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsOptionPaneUI.java @@ -30,5 +30,5 @@ /** * Windows rendition of the component. */ -public class WindowsOptionPaneUI extends BasicOptionPaneUI { +public final class WindowsOptionPaneUI extends BasicOptionPaneUI { } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPasswordFieldUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPasswordFieldUI.java index baf0997ceff30..1f64c18e61f61 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPasswordFieldUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPasswordFieldUI.java @@ -33,7 +33,7 @@ /** * Windows rendition of the component. */ -public class WindowsPasswordFieldUI extends BasicPasswordFieldUI { +public final class WindowsPasswordFieldUI extends BasicPasswordFieldUI { /** * Creates a UI for a JPasswordField @@ -54,6 +54,7 @@ public static ComponentUI createUI(JComponent c) { * * @return the caret object */ + @Override protected Caret createCaret() { return new WindowsTextUI.WindowsCaret(); } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuSeparatorUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuSeparatorUI.java index ed31f00a89ba6..9d67278526a95 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuSeparatorUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuSeparatorUI.java @@ -42,12 +42,13 @@ * @author Igor Kushnirskiy */ -public class WindowsPopupMenuSeparatorUI extends BasicPopupMenuSeparatorUI { +public final class WindowsPopupMenuSeparatorUI extends BasicPopupMenuSeparatorUI { public static ComponentUI createUI(JComponent c) { return new WindowsPopupMenuSeparatorUI(); } + @Override public void paint(Graphics g, JComponent c) { Dimension s = c.getSize(); XPStyle xp = XPStyle.getXP(); @@ -82,6 +83,7 @@ public void paint(Graphics g, JComponent c) { } } + @Override public Dimension getPreferredSize(JComponent c) { int fontHeight = 0; Font font = c.getFont(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuUI.java index 3bf214aff374d..4df236115fb24 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuUI.java @@ -57,7 +57,7 @@ * * @author Igor Kushnirskiy */ -public class WindowsPopupMenuUI extends BasicPopupMenuUI { +public final class WindowsPopupMenuUI extends BasicPopupMenuUI { static MnemonicListener mnemonicListener = null; static final Object GUTTER_OFFSET_KEY = @@ -67,6 +67,7 @@ public static ComponentUI createUI(JComponent c) { return new WindowsPopupMenuUI(); } + @Override public void installListeners() { super.installListeners(); if (! UIManager.getBoolean("Button.showMnemonics") && @@ -88,14 +89,16 @@ public void installListeners() { * @return Popup that will show the JPopupMenu * @since 1.4 */ + @Override public Popup getPopup(JPopupMenu popupMenu, int x, int y) { PopupFactory popupFactory = PopupFactory.getSharedInstance(); return popupFactory.getPopup(popupMenu.getInvoker(), popupMenu, x, y); } - static class MnemonicListener implements ChangeListener { + static final class MnemonicListener implements ChangeListener { JRootPane repaintRoot = null; + @Override public void stateChanged(ChangeEvent ev) { MenuSelectionManager msm = (MenuSelectionManager)ev.getSource(); MenuElement[] path = msm.getSelectedPath(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupWindow.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupWindow.java index f23cb31dff0ff..b58ad07a57b85 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupWindow.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupWindow.java @@ -45,7 +45,7 @@ * @author Amy Fowler */ @SuppressWarnings("serial") // Superclass is not serializable across versions -class WindowsPopupWindow extends JWindow { +final class WindowsPopupWindow extends JWindow { static final int UNDEFINED_WINDOW_TYPE = 0; static final int TOOLTIP_WINDOW_TYPE = 1; @@ -69,10 +69,12 @@ int getWindowType() { return windowType; } + @Override public void update(Graphics g) { paint(g); } + @Override @SuppressWarnings("deprecation") public void hide() { super.hide(); @@ -85,6 +87,7 @@ public void hide() { removeNotify(); } + @Override @SuppressWarnings("deprecation") public void show() { super.show(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsProgressBarUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsProgressBarUI.java index 790dc85166b62..9cc7d277ff185 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsProgressBarUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsProgressBarUI.java @@ -51,7 +51,7 @@ * * @author Michael C. Albers */ -public class WindowsProgressBarUI extends BasicProgressBarUI +public final class WindowsProgressBarUI extends BasicProgressBarUI { private Rectangle previousFullBox; @@ -62,6 +62,7 @@ public static ComponentUI createUI(JComponent x) { } + @Override protected void installDefaults() { super.installDefaults(); @@ -80,6 +81,7 @@ protected void installDefaults() { * @see javax.swing.JComponent#getBaseline(int, int) * @since 1.6 */ + @Override public int getBaseline(JComponent c, int width, int height) { int baseline = super.getBaseline(c, width, height); if (XPStyle.getXP() != null && progressBar.isStringPainted() && @@ -102,6 +104,7 @@ public int getBaseline(JComponent c, int width, int height) { return baseline; } + @Override protected Dimension getPreferredInnerHorizontal() { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -113,6 +116,7 @@ protected Dimension getPreferredInnerHorizontal() { return super.getPreferredInnerHorizontal(); } + @Override protected Dimension getPreferredInnerVertical() { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -124,6 +128,7 @@ protected Dimension getPreferredInnerVertical() { return super.getPreferredInnerVertical(); } + @Override protected void paintDeterminate(Graphics g, JComponent c) { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -218,6 +223,7 @@ protected void paintDeterminate(Graphics g, JComponent c) { * {@inheritDoc} * @since 1.6 */ + @Override protected void setAnimationIndex(int newValue) { super.setAnimationIndex(newValue); XPStyle xp = XPStyle.getXP(); @@ -241,6 +247,7 @@ protected void setAnimationIndex(int newValue) { * {@inheritDoc} * @since 1.6 */ + @Override protected int getBoxLength(int availableLength, int otherDimension) { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -253,6 +260,7 @@ protected int getBoxLength(int availableLength, int otherDimension) { * {@inheritDoc} * @since 1.6 */ + @Override protected Rectangle getBox(Rectangle r) { Rectangle rect = super.getBox(r); @@ -298,6 +306,7 @@ protected Rectangle getBox(Rectangle r) { } + @Override protected void paintIndeterminate(Graphics g, JComponent c) { XPStyle xp = XPStyle.getXP(); if (xp != null) { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java index 584a0f1622b1a..f6f3d4f06d11c 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java @@ -41,11 +41,12 @@ /** * Windows rendition of the component. */ -public class WindowsRadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI { +public final class WindowsRadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI { final WindowsMenuItemUIAccessor accessor = new WindowsMenuItemUIAccessor() { + @Override public JMenuItem getMenuItem() { return menuItem; } @@ -54,6 +55,7 @@ public State getState(JMenuItem menuItem) { return WindowsMenuItemUI.getState(this, menuItem); } + @Override public Part getPart(JMenuItem menuItem) { return WindowsMenuItemUI.getPart(this, menuItem); } @@ -81,6 +83,7 @@ protected void paintBackground(Graphics g, JMenuItem menuItem, * @param text String to render * @since 1.4 */ + @Override protected void paintText(Graphics g, JMenuItem menuItem, Rectangle textRect, String text) { if (WindowsMenuItemUI.isVistaPainting()) { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java index dd0a93c95a1f6..8fdc1a315c97a 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java @@ -73,6 +73,7 @@ public static ComponentUI createUI(JComponent c) { // ******************************** // Defaults // ******************************** + @Override public void installDefaults(AbstractButton b) { super.installDefaults(b); if(!initialized) { @@ -88,6 +89,7 @@ public void installDefaults(AbstractButton b) { } } + @Override protected void uninstallDefaults(AbstractButton b) { super.uninstallDefaults(b); initialized = false; @@ -104,11 +106,13 @@ protected Color getFocusColor() { /** * Overridden method to render the text without the mnemonic */ + @Override protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, String text) { WindowsGraphicsUtils.paintText(g, b, textRect, text, getTextShiftOffset()); } + @Override protected void paintFocus(Graphics g, Rectangle textRect, Dimension d){ g.setColor(getFocusColor()); BasicGraphicsUtils.drawDashedRect(g, textRect.x, textRect.y, textRect.width, textRect.height); @@ -117,6 +121,7 @@ protected void paintFocus(Graphics g, Rectangle textRect, Dimension d){ // ******************************** // Layout Methods // ******************************** + @Override public Dimension getPreferredSize(JComponent c) { Dimension d = super.getPreferredSize(c); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java index f05da909ac1db..19bfad0a1da84 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java @@ -70,7 +70,7 @@ * @author Mark Davidson * @since 1.4 */ -public class WindowsRootPaneUI extends BasicRootPaneUI { +public final class WindowsRootPaneUI extends BasicRootPaneUI { private static final WindowsRootPaneUI windowsRootPaneUI = new WindowsRootPaneUI(); static final AltProcessor altProcessor = new AltProcessor(); @@ -79,7 +79,7 @@ public static ComponentUI createUI(JComponent c) { return windowsRootPaneUI; } - static class AltProcessor implements KeyEventPostProcessor { + static final class AltProcessor implements KeyEventPostProcessor { static boolean altKeyPressed = false; static boolean menuCanceledOnPress = false; static JRootPane root = null; @@ -166,6 +166,7 @@ void altReleased(KeyEvent ev) { } + @Override public boolean postProcessKeyEvent(KeyEvent ev) { if (ev.isConsumed()) { if (ev.getKeyCode() != KeyEvent.VK_ALT) { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java index a3dd04362b9cd..c8d62e52834a6 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java @@ -55,7 +55,7 @@ /** * Windows rendition of the component. */ -public class WindowsScrollBarUI extends BasicScrollBarUI { +public final class WindowsScrollBarUI extends BasicScrollBarUI { private Grid thumbGrid; private Grid highlightGrid; private Dimension horizontalThumbSize; @@ -71,6 +71,7 @@ public static ComponentUI createUI(JComponent c) { return new WindowsScrollBarUI(); } + @Override protected void installDefaults() { super.installDefaults(); @@ -100,11 +101,13 @@ protected Dimension getMinimumThumbSize() { : verticalThumbSize; } + @Override public void uninstallUI(JComponent c) { super.uninstallUI(c); thumbGrid = highlightGrid = null; } + @Override protected void configureScrollBarColors() { super.configureScrollBarColors(); Color color = UIManager.getColor("ScrollBar.trackForeground"); @@ -118,6 +121,7 @@ protected void configureScrollBarColors() { } } + @Override protected JButton createDecreaseButton(int orientation) { return new WindowsArrowButton(orientation, UIManager.getColor("ScrollBar.thumb"), @@ -126,6 +130,7 @@ protected JButton createDecreaseButton(int orientation) { UIManager.getColor("ScrollBar.thumbHighlight")); } + @Override protected JButton createIncreaseButton(int orientation) { return new WindowsArrowButton(orientation, UIManager.getColor("ScrollBar.thumb"), @@ -161,6 +166,7 @@ private void repaint() { } } + @Override protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds){ boolean v = (scrollbar.getOrientation() == JScrollBar.VERTICAL); @@ -189,6 +195,7 @@ else if (trackHighlight == INCREASE_HIGHLIGHT) { } } + @Override protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) { boolean v = (scrollbar.getOrientation() == JScrollBar.VERTICAL); @@ -231,6 +238,7 @@ protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) { } + @Override protected void paintDecreaseHighlight(Graphics g) { if (highlightGrid == null) { super.paintDecreaseHighlight(g); @@ -257,6 +265,7 @@ protected void paintDecreaseHighlight(Graphics g) { } + @Override protected void paintIncreaseHighlight(Graphics g) { if (highlightGrid == null) { super.paintDecreaseHighlight(g); @@ -304,7 +313,7 @@ protected void setThumbRollover(boolean active) { * preferred size is always a square. */ @SuppressWarnings("serial") // Superclass is not serializable across versions - private class WindowsArrowButton extends BasicArrowButton { + private final class WindowsArrowButton extends BasicArrowButton { public WindowsArrowButton(int direction, Color background, Color shadow, Color darkShadow, Color highlight) { @@ -315,6 +324,7 @@ public WindowsArrowButton(int direction) { super(direction); } + @Override public void paint(Graphics g) { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -370,6 +380,7 @@ public void paint(Graphics g) { } } + @Override public Dimension getPreferredSize() { int size = 16; if (scrollbar != null) { @@ -398,7 +409,7 @@ public Dimension getPreferredSize() { * a WeakRef so that it can be freed when no longer needed. As the * Grid is rather expensive to draw, it is drawn in a BufferedImage. */ - private static class Grid { + private static final class Grid { private static final int BUFFER_SIZE = 64; private static HashMap> map; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollPaneUI.java index 6c89eabc89455..393f7595402a4 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollPaneUI.java @@ -30,5 +30,5 @@ /** * Windows rendition of the component. */ -public class WindowsScrollPaneUI extends BasicScrollPaneUI +public final class WindowsScrollPaneUI extends BasicScrollPaneUI {} diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSeparatorUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSeparatorUI.java index 65526a40c1b3a..9ce5db3b4ef8f 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSeparatorUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSeparatorUI.java @@ -30,4 +30,4 @@ /** * Windows Separator. */ -public class WindowsSeparatorUI extends BasicSeparatorUI { } +public final class WindowsSeparatorUI extends BasicSeparatorUI { } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSliderUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSliderUI.java index ceaf878cbca5f..88dc91d572b85 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSliderUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSliderUI.java @@ -44,7 +44,7 @@ /** * Windows rendition of the component. */ -public class WindowsSliderUI extends BasicSliderUI +public final class WindowsSliderUI extends BasicSliderUI { private boolean rollover = false; private boolean pressed = false; @@ -63,32 +63,38 @@ public static ComponentUI createUI(JComponent b) { * the HOT, PRESSED, and FOCUSED states. * @since 1.6 */ + @Override protected TrackListener createTrackListener(JSlider slider) { return new WindowsTrackListener(); } - private class WindowsTrackListener extends TrackListener { + private final class WindowsTrackListener extends TrackListener { + @Override public void mouseMoved(MouseEvent e) { updateRollover(thumbRect.contains(e.getX(), e.getY())); super.mouseMoved(e); } + @Override public void mouseEntered(MouseEvent e) { updateRollover(thumbRect.contains(e.getX(), e.getY())); super.mouseEntered(e); } + @Override public void mouseExited(MouseEvent e) { updateRollover(false); super.mouseExited(e); } + @Override public void mousePressed(MouseEvent e) { updatePressed(thumbRect.contains(e.getX(), e.getY())); super.mousePressed(e); } + @Override public void mouseReleased(MouseEvent e) { updatePressed(false); super.mouseReleased(e); @@ -119,6 +125,7 @@ public void updateRollover(boolean newRollover) { } + @Override public void paintTrack(Graphics g) { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -141,6 +148,7 @@ public void paintTrack(Graphics g) { } + @Override protected void paintMinorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -149,6 +157,7 @@ protected void paintMinorTickForHorizSlider( Graphics g, Rectangle tickBounds, i super.paintMinorTickForHorizSlider(g, tickBounds, x); } + @Override protected void paintMajorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -157,6 +166,7 @@ protected void paintMajorTickForHorizSlider( Graphics g, Rectangle tickBounds, i super.paintMajorTickForHorizSlider(g, tickBounds, x); } + @Override protected void paintMinorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -165,6 +175,7 @@ protected void paintMinorTickForVertSlider( Graphics g, Rectangle tickBounds, in super.paintMinorTickForVertSlider(g, tickBounds, y); } + @Override protected void paintMajorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -174,6 +185,7 @@ protected void paintMajorTickForVertSlider( Graphics g, Rectangle tickBounds, in } + @Override public void paintThumb(Graphics g) { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -199,6 +211,7 @@ public void paintThumb(Graphics g) { } } + @Override protected Dimension getThumbSize() { XPStyle xp = XPStyle.getXP(); if (xp != null) { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSpinnerUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSpinnerUI.java index c17328e50cca7..bad66ce3a047f 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSpinnerUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSpinnerUI.java @@ -37,7 +37,7 @@ import static com.sun.java.swing.plaf.windows.XPStyle.Skin; -public class WindowsSpinnerUI extends BasicSpinnerUI { +public final class WindowsSpinnerUI extends BasicSpinnerUI { public static ComponentUI createUI(JComponent c) { return new WindowsSpinnerUI(); } @@ -46,6 +46,7 @@ public static ComponentUI createUI(JComponent c) { * {@inheritDoc} * @since 1.6 */ + @Override public void paint(Graphics g, JComponent c) { if (XPStyle.getXP() != null) { paintXPBackground(g, c); @@ -71,6 +72,7 @@ private void paintXPBackground(Graphics g, JComponent c) { skin.paintSkin(g, 0, 0, c.getWidth(), c.getHeight(), state); } + @Override protected Component createPreviousButton() { if (XPStyle.getXP() != null) { JButton xpButton = new XPStyle.GlyphButton(spinner, Part.SPNP_DOWN); @@ -83,6 +85,7 @@ protected Component createPreviousButton() { return super.createPreviousButton(); } + @Override protected Component createNextButton() { if (XPStyle.getXP() != null) { JButton xpButton = new XPStyle.GlyphButton(spinner, Part.SPNP_UP); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneDivider.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneDivider.java index 04eeb726f9042..95062ef586ff8 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneDivider.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneDivider.java @@ -39,7 +39,7 @@ * @author Jeff Dinkins */ @SuppressWarnings("serial") // Superclass is not serializable across versions -public class WindowsSplitPaneDivider extends BasicSplitPaneDivider +public final class WindowsSplitPaneDivider extends BasicSplitPaneDivider { /** @@ -52,6 +52,7 @@ public WindowsSplitPaneDivider(BasicSplitPaneUI ui) { /** * Paints the divider. */ + @Override public void paint(Graphics g) { Color bgColor = (splitPane.hasFocus()) ? UIManager.getColor("SplitPane.shadow") : diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneUI.java index 9305e46c36ff9..8c50e39116487 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneUI.java @@ -33,7 +33,7 @@ /** * Windows rendition of the component. */ -public class WindowsSplitPaneUI extends BasicSplitPaneUI +public final class WindowsSplitPaneUI extends BasicSplitPaneUI { public WindowsSplitPaneUI() { @@ -50,6 +50,7 @@ public static ComponentUI createUI(JComponent x) { /** * Creates the default divider. */ + @Override public BasicSplitPaneDivider createDefaultDivider() { return new WindowsSplitPaneDivider(this); } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java index 9b4e22102eb1d..86e2ee1fc523c 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java @@ -48,7 +48,7 @@ /** * Windows rendition of the component. */ -public class WindowsTabbedPaneUI extends BasicTabbedPaneUI { +public final class WindowsTabbedPaneUI extends BasicTabbedPaneUI { /** * Keys to use for forward focus traversal when the JComponent is * managing focus. @@ -63,6 +63,7 @@ public class WindowsTabbedPaneUI extends BasicTabbedPaneUI { private boolean contentOpaque = true; + @Override @SuppressWarnings("deprecation") protected void installDefaults() { super.installDefaults(); @@ -82,6 +83,7 @@ protected void installDefaults() { tabPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, managingFocusBackwardTraversalKeys); } + @Override protected void uninstallDefaults() { // sets the focus forward and backward traversal keys to null // to restore the defaults @@ -94,6 +96,7 @@ public static ComponentUI createUI(JComponent c) { return new WindowsTabbedPaneUI(); } + @Override protected void setRolloverTab(int index) { // Rollover is only supported on XP if (XPStyle.getXP() != null) { @@ -119,6 +122,7 @@ protected void setRolloverTab(int index) { } } + @Override protected void paintContentBorder(Graphics g, int tabPlacement, int selectedIndex) { XPStyle xp = XPStyle.getXP(); if (xp != null && (contentOpaque || tabPane.isOpaque())) { @@ -155,6 +159,7 @@ protected void paintContentBorder(Graphics g, int tabPlacement, int selectedInde super.paintContentBorder(g, tabPlacement, selectedIndex); } + @Override protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected ) { if (XPStyle.getXP() == null) { @@ -162,6 +167,7 @@ protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex, } } + @Override protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected ) { XPStyle xp = XPStyle.getXP(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTableHeaderUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTableHeaderUI.java index 507990812cc00..b670bd294b0eb 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTableHeaderUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTableHeaderUI.java @@ -50,13 +50,14 @@ import static com.sun.java.swing.plaf.windows.TMSchema.State; import static com.sun.java.swing.plaf.windows.XPStyle.Skin; -public class WindowsTableHeaderUI extends BasicTableHeaderUI { +public final class WindowsTableHeaderUI extends BasicTableHeaderUI { private TableCellRenderer originalHeaderRenderer; public static ComponentUI createUI(JComponent h) { return new WindowsTableHeaderUI(); } + @Override public void installUI(JComponent c) { super.installUI(c); @@ -68,6 +69,7 @@ public void installUI(JComponent c) { } } + @Override public void uninstallUI(JComponent c) { if (header.getDefaultRenderer() instanceof XPDefaultRenderer) { header.setDefaultRenderer(originalHeaderRenderer); @@ -84,7 +86,7 @@ protected void rolloverColumnUpdated(int oldColumn, int newColumn) { } @SuppressWarnings("serial") // JDK-implementation class - private class XPDefaultRenderer extends DefaultTableCellHeaderRenderer { + private final class XPDefaultRenderer extends DefaultTableCellHeaderRenderer { Skin skin; boolean isSelected, hasFocus, hasRollover; int column; @@ -93,6 +95,7 @@ private class XPDefaultRenderer extends DefaultTableCellHeaderRenderer { setHorizontalAlignment(LEADING); } + @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { @@ -181,6 +184,7 @@ public Component getTableCellRendererComponent(JTable table, Object value, return this; } + @Override public void paint(Graphics g) { Dimension size = getSize(); State state = State.NORMAL; @@ -227,7 +231,7 @@ public void paint(Graphics g) { * A border with an Icon at the middle of the top side. * Outer insets can be provided for this border. */ - private static class IconBorder implements Border, UIResource{ + private static final class IconBorder implements Border, UIResource{ private final Icon icon; private final int top; private final int left; @@ -246,12 +250,15 @@ public IconBorder(Icon icon, int top, int left, this.bottom = bottom; this.right = right; } + @Override public Insets getBorderInsets(Component c) { return new Insets(icon.getIconHeight() + top, left, bottom, right); } + @Override public boolean isBorderOpaque() { return false; } + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { icon.paintIcon(c, g, diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextAreaUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextAreaUI.java index 6aca81225ea15..e695d9f670800 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextAreaUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextAreaUI.java @@ -33,7 +33,7 @@ /** * Windows rendition of the component. */ -public class WindowsTextAreaUI extends BasicTextAreaUI { +public final class WindowsTextAreaUI extends BasicTextAreaUI { /** * Creates the object to use for a caret. By default an * instance of WindowsCaret is created. This method @@ -42,6 +42,7 @@ public class WindowsTextAreaUI extends BasicTextAreaUI { * * @return the caret object */ + @Override protected Caret createCaret() { return new WindowsTextUI.WindowsCaret(); } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextFieldUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextFieldUI.java index be3e6276161c5..508d260895c64 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextFieldUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextFieldUI.java @@ -62,7 +62,7 @@ * * @author Timothy Prinzing */ -public class WindowsTextFieldUI extends BasicTextFieldUI +public final class WindowsTextFieldUI extends BasicTextFieldUI { /** * Creates a UI for a JTextField. @@ -82,6 +82,7 @@ public static ComponentUI createUI(JComponent c) { * * @param g the graphics context */ + @Override protected void paintBackground(Graphics g) { super.paintBackground(g); } @@ -91,6 +92,7 @@ protected void paintBackground(Graphics g) { * * @return the caret */ + @Override protected Caret createCaret() { return new WindowsFieldCaret(); } @@ -100,7 +102,7 @@ protected Caret createCaret() { * DefaultCaret. */ @SuppressWarnings("serial") // Superclass is not serializable across versions - static class WindowsFieldCaret extends DefaultCaret implements UIResource { + static final class WindowsFieldCaret extends DefaultCaret implements UIResource { public WindowsFieldCaret() { super(); @@ -112,6 +114,7 @@ public WindowsFieldCaret() { * caret out into the field by about a quarter of * a field length if not visible. */ + @Override protected void adjustVisibility(Rectangle r) { SwingUtilities.invokeLater(new SafeScroller(r)); } @@ -121,16 +124,18 @@ protected void adjustVisibility(Rectangle r) { * * @return the painter */ + @Override protected Highlighter.HighlightPainter getSelectionPainter() { return WindowsTextUI.WindowsPainter; } - private class SafeScroller implements Runnable { + private final class SafeScroller implements Runnable { SafeScroller(Rectangle r) { this.r = r; } + @Override @SuppressWarnings("deprecation") public void run() { JTextField field = (JTextField) getComponent(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextPaneUI.java index 372563f74f46e..7858a1195e80d 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextPaneUI.java @@ -33,7 +33,7 @@ /** * Windows rendition of the component. */ -public class WindowsTextPaneUI extends BasicTextPaneUI +public final class WindowsTextPaneUI extends BasicTextPaneUI { /** * Creates a UI for a JTextPane. @@ -53,6 +53,7 @@ public static ComponentUI createUI(JComponent c) { * * @return the caret object */ + @Override protected Caret createCaret() { return new WindowsTextUI.WindowsCaret(); } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextUI.java index b73b38385f22d..89180ffdd5f40 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextUI.java @@ -55,6 +55,7 @@ public abstract class WindowsTextUI extends BasicTextUI { * * @return the caret object */ + @Override protected Caret createCaret() { return new WindowsCaret(); } @@ -64,20 +65,21 @@ protected Caret createCaret() { /* public */ @SuppressWarnings("serial") // Superclass is not serializable across versions - static class WindowsCaret extends DefaultCaret + static final class WindowsCaret extends DefaultCaret implements UIResource { /** * Gets the painter for the Highlighter. * * @return the painter */ + @Override protected Highlighter.HighlightPainter getSelectionPainter() { return WindowsTextUI.WindowsPainter; } } /* public */ - static class WindowsHighlightPainter extends + static final class WindowsHighlightPainter extends DefaultHighlighter.DefaultHighlightPainter { WindowsHighlightPainter(Color c) { super(c); @@ -94,6 +96,7 @@ static class WindowsHighlightPainter extends * @param bounds the bounding box for the highlight * @param c the editor */ + @Override @SuppressWarnings("deprecation") public void paint(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c) { Rectangle alloc = bounds.getBounds(); @@ -167,6 +170,7 @@ else if (secondIsDot) { * @param view View painting for * @return region drawing occurred in */ + @Override public Shape paintLayer(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c, View view) { Color color = getColor(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java index feee0c0aaefec..0f468fdf6b109 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java @@ -45,7 +45,7 @@ * * @author Jeff Dinkins */ -public class WindowsToggleButtonUI extends BasicToggleButtonUI +public final class WindowsToggleButtonUI extends BasicToggleButtonUI { protected int dashedRectGapX; protected int dashedRectGapY; @@ -73,6 +73,7 @@ public static ComponentUI createUI(JComponent b) { // ******************************** // Defaults // ******************************** + @Override protected void installDefaults(AbstractButton b) { super.installDefaults(b); if(!defaults_initialized) { @@ -93,6 +94,7 @@ protected void installDefaults(AbstractButton b) { } } + @Override protected void uninstallDefaults(AbstractButton b) { super.uninstallDefaults(b); defaults_initialized = false; @@ -112,6 +114,7 @@ protected Color getFocusColor() { private transient Color cachedBackgroundColor = null; private transient Color cachedHighlightColor = null; + @Override protected void paintButtonPressed(Graphics g, AbstractButton b) { if (XPStyle.getXP() == null && b.isContentAreaFilled()) { Color oldColor = g.getColor(); @@ -135,6 +138,7 @@ protected void paintButtonPressed(Graphics g, AbstractButton b) { } } + @Override public void paint(Graphics g, JComponent c) { if (XPStyle.getXP() != null) { WindowsButtonUI.paintXPButtonBackground(g, c); @@ -146,10 +150,12 @@ public void paint(Graphics g, JComponent c) { /** * Overridden method to render the text without the mnemonic */ + @Override protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, String text) { WindowsGraphicsUtils.paintText(g, b, textRect, text, getTextShiftOffset()); } + @Override protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, Rectangle textRect, Rectangle iconRect) { g.setColor(getFocusColor()); @@ -161,6 +167,7 @@ protected void paintFocus(Graphics g, AbstractButton b, // ******************************** // Layout Methods // ******************************** + @Override public Dimension getPreferredSize(JComponent c) { Dimension d = super.getPreferredSize(c); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarSeparatorUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarSeparatorUI.java index ffd6daa3ad8c6..5350de9ae5c65 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarSeparatorUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarSeparatorUI.java @@ -40,12 +40,13 @@ * * @author Mark Davidson */ -public class WindowsToolBarSeparatorUI extends BasicToolBarSeparatorUI { +public final class WindowsToolBarSeparatorUI extends BasicToolBarSeparatorUI { public static ComponentUI createUI( JComponent c ) { return new WindowsToolBarSeparatorUI(); } + @Override public Dimension getPreferredSize(JComponent c) { Dimension size = ((JToolBar.Separator)c).getSeparatorSize(); @@ -71,6 +72,7 @@ public Dimension getPreferredSize(JComponent c) { return size; } + @Override public Dimension getMaximumSize(JComponent c) { Dimension pref = getPreferredSize(c); if (((JSeparator)c).getOrientation() == SwingConstants.VERTICAL) { @@ -80,6 +82,7 @@ public Dimension getMaximumSize(JComponent c) { } } + @Override public void paint( Graphics g, JComponent c ) { boolean vertical = ((JSeparator)c).getOrientation() == SwingConstants.VERTICAL; Dimension size = c.getSize(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarUI.java index a34ce0cf6a595..68e077fa35033 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarUI.java @@ -45,12 +45,13 @@ import static com.sun.java.swing.plaf.windows.TMSchema.Part; -public class WindowsToolBarUI extends BasicToolBarUI { +public final class WindowsToolBarUI extends BasicToolBarUI { public static ComponentUI createUI(JComponent c) { return new WindowsToolBarUI(); } + @Override protected void installDefaults() { if (XPStyle.getXP() != null) { setRolloverBorders(true); @@ -58,6 +59,7 @@ protected void installDefaults() { super.installDefaults(); } + @Override protected Border createRolloverBorder() { if (XPStyle.getXP() != null) { return new EmptyBorder(3, 3, 3, 3); @@ -66,6 +68,7 @@ protected Border createRolloverBorder() { } } + @Override protected Border createNonRolloverBorder() { if (XPStyle.getXP() != null) { return new EmptyBorder(3, 3, 3, 3); @@ -74,6 +77,7 @@ protected Border createNonRolloverBorder() { } } + @Override public void paint(Graphics g, JComponent c) { XPStyle xp = XPStyle.getXP(); if (xp != null) { @@ -88,6 +92,7 @@ public void paint(Graphics g, JComponent c) { * {@inheritDoc} * @since 1.6 */ + @Override protected Border getRolloverBorder(AbstractButton b) { XPStyle xp = XPStyle.getXP(); if (xp != null) { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java index 5bef0e075a44a..6ab2352641f32 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java @@ -60,6 +60,7 @@ public static ComponentUI createUI( JComponent c ) * Ensures that the rows identified by beginRow through endRow are * visible. */ + @Override protected void ensureRowsAreVisible(int beginRow, int endRow) { if(tree != null && beginRow >= 0 && endRow < getRowCount(tree)) { Rectangle visRect = tree.getVisibleRect(); @@ -108,6 +109,7 @@ protected void ensureRowsAreVisible(int beginRow, int endRow) { * Returns the default cell renderer that is used to do the * stamping of each node. */ + @Override protected TreeCellRenderer createDefaultCellRenderer() { return new WindowsTreeCellRenderer(); } @@ -127,6 +129,7 @@ Skin getSkin(Component c) { return (xp != null) ? xp.getSkin(c, Part.TVP_GLYPH) : null; } + @Override public void paintIcon(Component c, Graphics g, int x, int y) { Skin skin = getSkin(c); if (skin != null) { @@ -147,11 +150,13 @@ public void paintIcon(Component c, Graphics g, int x, int y) { g.drawLine(x + 2, y + HALF_SIZE, x + (SIZE - 3), y + HALF_SIZE); } + @Override public int getIconWidth() { Skin skin = getSkin(null); return (skin != null) ? skin.getWidth() : SIZE; } + @Override public int getIconHeight() { Skin skin = getSkin(null); return (skin != null) ? skin.getHeight() : SIZE; @@ -162,11 +167,12 @@ public int getIconHeight() { * The plus sign button icon */ @SuppressWarnings("serial") // Superclass is not serializable across versions - public static class CollapsedIcon extends ExpandedIcon { + public static final class CollapsedIcon extends ExpandedIcon { public static Icon createCollapsedIcon() { return new CollapsedIcon(); } + @Override public void paintIcon(Component c, Graphics g, int x, int y) { Skin skin = getSkin(c); if (skin != null) { @@ -179,7 +185,7 @@ public void paintIcon(Component c, Graphics g, int x, int y) { } @SuppressWarnings("serial") // Superclass is not serializable across versions - public class WindowsTreeCellRenderer extends DefaultTreeCellRenderer { + public final class WindowsTreeCellRenderer extends DefaultTreeCellRenderer { /** * Configures the renderer based on the passed in components. @@ -189,6 +195,7 @@ public class WindowsTreeCellRenderer extends DefaultTreeCellRenderer { * The foreground color is set based on the selection and the icon * is set based on on leaf and expanded. */ + @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/XPStyle.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/XPStyle.java index f8f5e3628fb06..89751f6dc94b7 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/XPStyle.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/XPStyle.java @@ -90,7 +90,7 @@ * * @author Leif Samuelsson */ -class XPStyle { +final class XPStyle { // Singleton instance of this class private static XPStyle xp; @@ -331,6 +331,7 @@ private static class XPFillBorder extends LineBorder implements UIResource { super(color, thickness); } + @Override public Insets getBorderInsets(Component c, Insets insets) { Insets margin = null; // @@ -355,7 +356,7 @@ public Insets getBorderInsets(Component c, Insets insets) { } @SuppressWarnings("serial") // Superclass is not serializable across versions - private class XPStatefulFillBorder extends XPFillBorder { + private final class XPStatefulFillBorder extends XPFillBorder { private final Part part; private final Prop prop; XPStatefulFillBorder(Color color, int thickness, Part part, Prop prop) { @@ -364,6 +365,7 @@ private class XPStatefulFillBorder extends XPFillBorder { this.prop = prop; } + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { State state = State.NORMAL; // special casing for comboboxes. @@ -383,18 +385,20 @@ public void paintBorder(Component c, Graphics g, int x, int y, int width, int he } @SuppressWarnings("serial") // Superclass is not serializable across versions - private class XPImageBorder extends AbstractBorder implements UIResource { + private final class XPImageBorder extends AbstractBorder implements UIResource { Skin skin; XPImageBorder(Component c, Part part) { this.skin = getSkin(c, part); } + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { skin.paintSkin(g, x, y, width, height, null); } + @Override public Insets getBorderInsets(Component c, Insets insets) { Insets margin = null; Insets borderInsets = skin.getContentMargin(); @@ -423,11 +427,12 @@ public Insets getBorderInsets(Component c, Insets insets) { } @SuppressWarnings("serial") // Superclass is not serializable across versions - private static class XPEmptyBorder extends EmptyBorder implements UIResource { + private static final class XPEmptyBorder extends EmptyBorder implements UIResource { XPEmptyBorder(Insets m) { super(m.top+2, m.left+2, m.bottom+2, m.right+2); } + @Override public Insets getBorderInsets(Component c, Insets insets) { insets = super.getBorderInsets(c, insets); @@ -494,7 +499,7 @@ long getThemeTransitionDuration(Component c, Part part, State stateFrom, * (component type) and which provides methods for painting backgrounds * and glyphs */ - static class Skin { + static final class Skin { final Component component; final Part part; final State state; @@ -566,14 +571,17 @@ int getHeight() { return getHeight((state != null) ? state : State.NORMAL); } + @Override public String toString() { return string; } + @Override public boolean equals(Object obj) { return (obj instanceof Skin && ((Skin)obj).string.equals(string)); } + @Override public int hashCode() { return string.hashCode(); } @@ -675,16 +683,18 @@ void paintSkin(Graphics g, int dx, int dy, int dw, int dh, State state, } } - private static class SkinPainter extends CachedPainter { + private static final class SkinPainter extends CachedPainter { SkinPainter() { super(30); flush(); } + @Override public void flush() { super.flush(); } + @Override protected void paintToImage(Component c, Image image, Graphics g, int w, int h, Object[] args) { Skin skin = (Skin)args[0]; @@ -717,6 +727,7 @@ protected void paintToImage(Component c, Image image, Graphics g, SunWritableRaster.markDirty(dbi); } + @Override protected Image createImage(Component c, int w, int h, GraphicsConfiguration config, Object[] args) { return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); @@ -737,6 +748,7 @@ public GlyphButton(Component parent, Part part) { setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE)); } + @Override @SuppressWarnings("deprecation") public boolean isFocusTraversable() { return false; @@ -754,6 +766,7 @@ protected State getState() { return state; } + @Override public void paintComponent(Graphics g) { if (XPStyle.getXP() == null || skin == null) { return; @@ -769,6 +782,7 @@ public void setPart(Component parent, Part part) { repaint(); } + @Override protected void paintBorder(Graphics g) { } diff --git a/src/java.desktop/windows/classes/sun/awt/PlatformGraphicsInfo.java b/src/java.desktop/windows/classes/sun/awt/PlatformGraphicsInfo.java index 642f98b0df238..c888106d77962 100644 --- a/src/java.desktop/windows/classes/sun/awt/PlatformGraphicsInfo.java +++ b/src/java.desktop/windows/classes/sun/awt/PlatformGraphicsInfo.java @@ -30,7 +30,7 @@ import sun.awt.windows.WToolkit; -public class PlatformGraphicsInfo { +public final class PlatformGraphicsInfo { private static final boolean hasDisplays; diff --git a/src/java.desktop/windows/classes/sun/awt/Win32ColorModel24.java b/src/java.desktop/windows/classes/sun/awt/Win32ColorModel24.java index ec86bce8c69e1..fe55cacf8339d 100644 --- a/src/java.desktop/windows/classes/sun/awt/Win32ColorModel24.java +++ b/src/java.desktop/windows/classes/sun/awt/Win32ColorModel24.java @@ -40,7 +40,7 @@ * in the reverse order from the base ComponentColorModel to match * the ordering on a Windows 24-bit display. */ -public class Win32ColorModel24 extends ComponentColorModel { +public final class Win32ColorModel24 extends ComponentColorModel { public Win32ColorModel24() { super(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] {8, 8, 8}, false, false, @@ -53,6 +53,7 @@ public Win32ColorModel24() { * @see WritableRaster * @see SampleModel */ + @Override public WritableRaster createCompatibleWritableRaster (int w, int h) { int[] bOffs = {2, 1, 0}; return Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, @@ -65,6 +66,7 @@ public WritableRaster createCompatibleWritableRaster (int w, int h) { * has a data layout compatible with this ColorModel. * @see SampleModel */ + @Override public SampleModel createCompatibleSampleModel(int w, int h) { int[] bOffs = {2, 1, 0}; return new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, diff --git a/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java b/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java index c2532ff38b381..5084d0bcabe02 100644 --- a/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java +++ b/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java @@ -70,6 +70,7 @@ public final class Win32FontManager extends SunFontManager { */ private static native String getEUDCFontFile(); + @Override public TrueTypeFont getEUDCFont() { return eudcFont; } @@ -88,6 +89,7 @@ public Win32FontManager() { * Whether registerFontFile expects absolute or relative * font file names. */ + @Override protected boolean useAbsoluteFontFileNames() { return false; } @@ -98,6 +100,7 @@ protected boolean useAbsoluteFontFileNames() { * class reports these back to the GraphicsEnvironment, so these * are the componentFileNames of CompositeFonts. */ + @Override protected void registerFontFile(String fontFileName, String[] nativeNames, int fontRank, boolean defer) { @@ -175,6 +178,7 @@ public FontConfiguration createFontConfiguration(boolean preferLocaleFonts, preferLocaleFonts,preferPropFonts); } + @Override protected void populateFontFileNameMap(HashMap fontToFileMap, HashMap fontToFamilyNameMap, @@ -194,6 +198,7 @@ public FontConfiguration createFontConfiguration(boolean preferLocaleFonts, familyToFontListMap, Locale locale); + @Override protected synchronized native String getFontPath(boolean noType1Fonts); @Override diff --git a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsConfig.java b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsConfig.java index 6e740de6a9bd4..31fc0847d3b24 100644 --- a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsConfig.java +++ b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsConfig.java @@ -214,6 +214,7 @@ public AffineTransform getNormalizingTransform() { return new AffineTransform(xscale, 0.0, 0.0, yscale, 0.0, 0.0); } + @Override public String toString() { return (super.toString()+"[dev="+device+",pixfmt="+visual+"]"); } diff --git a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java index 973eb916a5cab..865fe48085362 100644 --- a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java +++ b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java @@ -590,7 +590,7 @@ public ColorModel getColorModel() { * The listener restores the default display mode when window is iconified * and sets it back to the one set by the user on de-iconification. */ - private static class Win32FSWindowAdapter extends WindowAdapter { + private static final class Win32FSWindowAdapter extends WindowAdapter { private Win32GraphicsDevice device; private DisplayMode dm; diff --git a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java index cb7ab363cdfca..09768148f3dc9 100644 --- a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java +++ b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java @@ -92,9 +92,11 @@ public final class Win32GraphicsEnvironment extends SunGraphicsEnvironment { public Win32GraphicsEnvironment() { } + @Override protected native int getNumScreens(); private native int getDefaultScreen(); + @Override public GraphicsDevice getDefaultScreenDevice() { GraphicsDevice[] screens = getScreenDevices(); if (screens.length == 0) { @@ -207,6 +209,7 @@ public void displayChanged() { * ----END DISPLAY CHANGE SUPPORT---- */ + @Override protected GraphicsDevice makeScreenDevice(int screennum) { GraphicsDevice device = null; if (WindowsFlags.isD3DEnabled()) { @@ -218,6 +221,7 @@ protected GraphicsDevice makeScreenDevice(int screennum) { return device; } + @Override public boolean isDisplayLocal() { return true; } diff --git a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java index c85c2d4ced93a..1777e408ea6a7 100644 --- a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java +++ b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java @@ -212,7 +212,7 @@ static final class KnownLibraries { static final List INSTANCE = getLibraries(); } - static class FolderDisposer implements sun.java2d.DisposerRecord { + static final class FolderDisposer implements sun.java2d.DisposerRecord { /* * This is cached as a concession to getFolderType(), which needs * an absolute PIDL. @@ -226,6 +226,7 @@ static class FolderDisposer implements sun.java2d.DisposerRecord { long relativePIDL; boolean disposed; + @Override public void dispose() { if (disposed) return; invoke(new Callable() { @@ -387,6 +388,7 @@ public void setIsPersonal() { * is a not a normal directory, then returns the first non-removable * drive (normally "C:\"). */ + @Override @Serial protected Object writeReplace() throws java.io.ObjectStreamException { return invoke(new Callable() { @@ -541,6 +543,7 @@ private static boolean pathsEqual(String path1, String path2) { /** * Check to see if two ShellFolder objects are the same */ + @Override public boolean equals(Object o) { if (!(o instanceof Win32ShellFolder2 rhs)) { // Short-circuit circuitous delegation path @@ -588,6 +591,7 @@ public Boolean call() { /** * @return Whether this is a file system shell folder */ + @Override public boolean isFileSystem() { if (cachedIsFileSystem == null) { cachedIsFileSystem = hasAttribute(ATTRIB_FILESYSTEM); @@ -682,10 +686,12 @@ private static boolean isNetworkRoot(String path) { * @return The parent shell folder of this shell folder, null if * there is no parent */ + @Override public File getParentFile() { return parent; } + @Override public boolean isDirectory() { if (isDir == null) { // Folders with SFGAO_BROWSABLE have "shell extension" handlers and are @@ -742,6 +748,7 @@ private native long getEnumObjects(long pIShellFolder, boolean isDesktop, * object. The array will be empty if the folder is empty. Returns * {@code null} if this shellfolder does not denote a directory. */ + @Override public File[] listFiles(final boolean includeHiddenFiles) { try { @@ -851,6 +858,7 @@ public Win32ShellFolder2 call() throws InterruptedException { * symbolic links and junctions. */ + @Override public boolean isLink() { if (cachedIsLink == null) { cachedIsLink = hasAttribute(ATTRIB_LINK) @@ -864,6 +872,7 @@ public boolean isLink() { /** * @return Whether this shell folder is marked as hidden */ + @Override public boolean isHidden() { return hasAttribute(ATTRIB_HIDDEN); } @@ -878,6 +887,7 @@ private static native long getLinkLocation(long parentIShellFolder, * @return The shell folder linked to by this shell folder, or null * if this shell folder is not a link or is a broken or invalid link */ + @Override public ShellFolder getLinkLocation() { return getLinkLocation(true); } @@ -933,6 +943,7 @@ private static native String getDisplayNameOf(long parentIShellFolder, /** * @return The name used to display this shell folder */ + @Override public String getDisplayName() { if (displayName == null) { displayName = @@ -953,6 +964,7 @@ public String call() { /** * @return The type of shell folder as a string */ + @Override public String getFolderType() { if (folderType == null) { final long absolutePIDL = getAbsolutePIDL(); @@ -972,6 +984,7 @@ public String call() { /** * @return The executable type as a string */ + @Override public String getExecutableType() { if (!isFileSystem()) { return null; @@ -1047,6 +1060,7 @@ private static Image makeIcon(long hIcon) { /** * @return The icon image used to display this shell folder */ + @Override public Image getIcon(final boolean getLargeIcon) { Image icon = getLargeIcon ? largeIcon : smallIcon; int size = getLargeIcon ? LARGE_ICON_SIZE : SMALL_ICON_SIZE; @@ -1140,6 +1154,7 @@ public Image call() { /** * @return The icon image of specified size used to display this shell folder */ + @Override public Image getIcon(int width, int height) { int size = Math.max(width, height); return invoke(() -> { @@ -1236,6 +1251,7 @@ static Image getShell32Icon(int iconID, int size) { * * @see java.io.File#getCanonicalFile */ + @Override public File getCanonicalFile() throws IOException { return this; } @@ -1252,6 +1268,7 @@ public boolean isSpecial() { * * @see sun.awt.shell.ShellFolder#compareTo(File) */ + @Override public int compareTo(File file2) { if (!(file2 instanceof Win32ShellFolder2)) { if (isFileSystem() && !isSpecial()) { @@ -1268,6 +1285,7 @@ public int compareTo(File file2) { private static final int LVCFMT_RIGHT = 1; private static final int LVCFMT_CENTER = 2; + @Override public ShellFolderColumnInfo[] getFolderColumns() { ShellFolder library = resolveLibrary(); if (library != null) return library.getFolderColumns(); @@ -1300,6 +1318,7 @@ public ShellFolderColumnInfo[] call() { }); } + @Override public Object getFolderColumnValue(final int column) { if(!isLibrary()) { ShellFolder library = resolveLibrary(); @@ -1342,6 +1361,7 @@ private ShellFolder resolveLibrary() { private static native int compareIDsByColumn(long pParentIShellFolder, long pidl1, long pidl2, int columnIdx); + @Override public void sortChildren(final List files) { // To avoid loads of synchronizations with Invoker and improve performance we // synchronize the whole code of the sort method once @@ -1354,7 +1374,7 @@ public Void call() { }); } - private static class ColumnComparator implements Comparator { + private static final class ColumnComparator implements Comparator { private final Win32ShellFolder2 shellFolder; private final int columnIdx; @@ -1365,6 +1385,7 @@ public ColumnComparator(Win32ShellFolder2 shellFolder, int columnIdx) { } // compares 2 objects within this folder by the specified column + @Override public int compare(final File o, final File o1) { Integer result = invoke(new Callable() { public Integer call() { @@ -1405,7 +1426,7 @@ public List call() throws Exception { }); } - static class MultiResolutionIconImage extends AbstractMultiResolutionImage { + static final class MultiResolutionIconImage extends AbstractMultiResolutionImage { final int baseSize; final Map resolutionVariants = new HashMap<>(); diff --git a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java index d8bb2146798c9..075e3d0db50f5 100644 --- a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java +++ b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java @@ -75,6 +75,7 @@ final class Win32ShellFolderManager2 extends ShellFolderManager { sun.awt.windows.WToolkit.loadLibraries(); } + @Override public ShellFolder createShellFolder(File file) throws FileNotFoundException { try { return createShellFolder(getDesktop(), file); @@ -264,6 +265,7 @@ static Win32ShellFolder2 getPersonal() { * * @return An Object matching the key string. */ + @Override public Object get(String key) { if (key.equals("fileChooserDefaultFolder")) { File file = getPersonal(); @@ -408,6 +410,7 @@ public Object get(String key) { * Does {@code dir} represent a "computer" such as a node on the network, or * "My Computer" on the desktop. */ + @Override public boolean isComputerNode(final File dir) { if (dir != null && dir == getDrives()) { return true; @@ -418,6 +421,7 @@ public boolean isComputerNode(final File dir) { } } + @Override public boolean isFileSystemRoot(File dir) { //Note: Removable drives don't "exist" but are listed in "My Computer" if (dir != null) { @@ -498,7 +502,7 @@ protected Invoker createInvoker() { return new ComInvoker(); } - private static class ComInvoker extends ThreadPoolExecutor implements ThreadFactory, ShellFolder.Invoker { + private static final class ComInvoker extends ThreadPoolExecutor implements ThreadFactory, ShellFolder.Invoker { private static Thread comThread; private ComInvoker() { @@ -512,6 +516,7 @@ private ComInvoker() { Runtime.getRuntime().addShutdownHook(t); } + @Override public synchronized Thread newThread(final Runnable task) { final Runnable comRun = new Runnable() { public void run() { @@ -539,6 +544,7 @@ leads to memory consumption when listDrives() function is called return comThread; } + @Override public T invoke(Callable task) throws Exception { if (Thread.currentThread() == comThread) { // if it's already called from the COM diff --git a/src/java.desktop/windows/classes/sun/awt/windows/TranslucentWindowPainter.java b/src/java.desktop/windows/classes/sun/awt/windows/TranslucentWindowPainter.java index 6b9d54aaa28af..94a2c4df0a9a5 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/TranslucentWindowPainter.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/TranslucentWindowPainter.java @@ -355,7 +355,7 @@ public void run() { } } - private static class VIOptD3DWindowPainter extends VIOptWindowPainter { + private static final class VIOptD3DWindowPainter extends VIOptWindowPainter { protected VIOptD3DWindowPainter(WWindowPeer peer) { super(peer); @@ -370,7 +370,7 @@ protected boolean updateWindowAccel(long psdops, int w, int h) { } } - private static class VIOptWGLWindowPainter extends VIOptWindowPainter { + private static final class VIOptWGLWindowPainter extends VIOptWindowPainter { protected VIOptWGLWindowPainter(WWindowPeer peer) { super(peer); diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java index c07d116abfbcb..8b3218de6674d 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java @@ -789,6 +789,7 @@ public VolatileImage createVolatileImage(int width, int height) { // Object overrides + @Override public String toString() { return getClass().getName() + "[" + target + "]"; } diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WDataTransferer.java b/src/java.desktop/windows/classes/sun/awt/windows/WDataTransferer.java index 8aca12d268f05..068d577995f83 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WDataTransferer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WDataTransferer.java @@ -541,7 +541,7 @@ public static EHTMLReadMode getEHTMLReadMode (DataFlavor df) { * * on encode: static convertToHTMLFormat is responsible for HTML clipboard header creation */ -class HTMLCodec extends InputStream { +final class HTMLCodec extends InputStream { public static final String VERSION = "Version:"; public static final String START_HTML = "StartHTML:"; diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WDefaultFontCharset.java b/src/java.desktop/windows/classes/sun/awt/windows/WDefaultFontCharset.java index 7632e172b73c7..09c317c81f209 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WDefaultFontCharset.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WDefaultFontCharset.java @@ -46,7 +46,7 @@ public CharsetEncoder newEncoder() { return new Encoder(); } - private class Encoder extends AWTCharset.Encoder { + private final class Encoder extends AWTCharset.Encoder { @Override public boolean canEncode(char c){ return canConvert(c); diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WDesktopProperties.java b/src/java.desktop/windows/classes/sun/awt/windows/WDesktopProperties.java index d9b169160b4f2..6e3de090ee8f3 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WDesktopProperties.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WDesktopProperties.java @@ -198,7 +198,7 @@ private synchronized void setSoundProperty(String key, String winEventName) { */ private native void playWindowsSound(String winEventName); - class WinPlaySound implements Runnable { + final class WinPlaySound implements Runnable { String winEventName; WinPlaySound(String winEventName) { @@ -210,10 +210,12 @@ public void run() { WDesktopProperties.this.playWindowsSound(winEventName); } + @Override public String toString() { return "WinPlaySound("+winEventName+")"; } + @Override public boolean equals(Object o) { if (o == this) { return true; @@ -225,6 +227,7 @@ public boolean equals(Object o) { } } + @Override public int hashCode() { return winEventName.hashCode(); } diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WDragSourceContextPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WDragSourceContextPeer.java index f4ab5fe0a34e7..43a91c3c7abbd 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WDragSourceContextPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WDragSourceContextPeer.java @@ -54,9 +54,11 @@ */ final class WDragSourceContextPeer extends SunDragSourceContextPeer { + @Override public void startSecondaryEventLoop(){ WToolkit.startSecondaryEventLoop(); } + @Override public void quitSecondaryEventLoop(){ WToolkit.quitSecondaryEventLoop(); } @@ -168,6 +170,7 @@ native void doDragDrop( int imgWidth, int imgHight, int offsetX, int offsetY); + @Override protected native void setNativeCursor(long nativeCtxt, Cursor c, int cType); } diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WEmbeddedFrame.java b/src/java.desktop/windows/classes/sun/awt/windows/WEmbeddedFrame.java index e5db1d432cf6d..ad0745a273314 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WEmbeddedFrame.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WEmbeddedFrame.java @@ -36,7 +36,7 @@ import java.awt.peer.FramePeer; @SuppressWarnings("serial") // JDK-implementation class -public class WEmbeddedFrame extends EmbeddedFrame { +public final class WEmbeddedFrame extends EmbeddedFrame { static { initIDs(); @@ -79,6 +79,7 @@ public WEmbeddedFrame(long handle) { } } + @Override public void addNotify() { if (!isDisplayable()) { WToolkit toolkit = (WToolkit)Toolkit.getDefaultToolkit(); @@ -224,6 +225,7 @@ private native void printBand(long hdc, byte[] data, int offset, int sx, public void activateEmbeddingTopLevel() { } + @Override public void synthesizeWindowActivation(final boolean activate) { final FramePeer peer = AWTAccessor.getComponentAccessor().getPeer(this); if (!activate || EventQueue.isDispatchThread()) { @@ -241,7 +243,9 @@ public void run() { } } + @Override public void registerAccelerator(AWTKeyStroke stroke) {} + @Override public void unregisterAccelerator(AWTKeyStroke stroke) {} /** @@ -256,6 +260,7 @@ public void unregisterAccelerator(AWTKeyStroke stroke) {} * NOTE: This method may be called by privileged threads. * DO NOT INVOKE CLIENT CODE ON THIS THREAD! */ + @Override public void notifyModalBlocked(Dialog blocker, boolean blocked) { try { ComponentPeer thisPeer = (ComponentPeer)WToolkit.targetToPeer(this); diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java index 4d5219cf34e16..bab79c38ff4db 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java @@ -32,7 +32,7 @@ import sun.awt.EmbeddedFrame; import sun.awt.Win32GraphicsEnvironment; -public class WEmbeddedFramePeer extends WFramePeer { +public final class WEmbeddedFramePeer extends WFramePeer { public WEmbeddedFramePeer(EmbeddedFrame target) { super(target); diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WLabelPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WLabelPeer.java index 259329d4f6d33..c5267e52793c9 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WLabelPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WLabelPeer.java @@ -31,6 +31,7 @@ final class WLabelPeer extends WComponentPeer implements LabelPeer { // ComponentPeer overrides + @Override public Dimension getMinimumSize() { FontMetrics fm = getFontMetrics(((Label)target).getFont()); String label = ((Label)target).getText(); @@ -40,6 +41,7 @@ public Dimension getMinimumSize() { } native void lazyPaint(); + @Override synchronized void start() { super.start(); // if need then paint label @@ -47,11 +49,14 @@ synchronized void start() { } // LabelPeer implementation + @Override public boolean shouldClearRectBeforePaint() { return false; } + @Override public native void setText(String label); + @Override public native void setAlignment(int alignment); // Toolkit & peer internals @@ -60,8 +65,10 @@ public boolean shouldClearRectBeforePaint() { super(target); } + @Override native void create(WComponentPeer parent); + @Override void initialize() { Label l = (Label)target; diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WLightweightFramePeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WLightweightFramePeer.java index ff77a5c188c94..994b81e372eb4 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WLightweightFramePeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WLightweightFramePeer.java @@ -36,7 +36,7 @@ import sun.swing.JLightweightFrame; import sun.swing.SwingAccessor; -public class WLightweightFramePeer extends WFramePeer implements OverrideNativeWindowHandle { +public final class WLightweightFramePeer extends WFramePeer implements OverrideNativeWindowHandle { public WLightweightFramePeer(LightweightFrame target) { super(target); @@ -100,6 +100,7 @@ public void updateCursorImmediately() { SwingAccessor.getJLightweightFrameAccessor().updateCursor((JLightweightFrame)getLwTarget()); } + @Override public boolean isLightweightFramePeer() { return true; } diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WMenuItemPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WMenuItemPeer.java index 43d4d2b907a9b..f2961f79a0460 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WMenuItemPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WMenuItemPeer.java @@ -46,11 +46,13 @@ class WMenuItemPeer extends WObjectPeer implements MenuItemPeer { // MenuItemPeer implementation private synchronized native void _dispose(); + @Override protected void disposeImpl() { WToolkit.targetDisposedPeer(target, this); _dispose(); } + @Override public void setEnabled(boolean b) { enable(b); } @@ -69,6 +71,7 @@ private void readShortcutLabel() { } } + @Override public void setLabel(String label) { //Fix for 6288578: PIT. Windows: Shortcuts displayed for the menuitems in a popup menu readShortcutLabel(); @@ -165,6 +168,7 @@ static Font getDefaultFont() { private native void _setFont(Font f); + @Override public void setFont(final Font f) { _setFont(f); } diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WMouseInfoPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WMouseInfoPeer.java index e5bef4fe1b98b..4b785aaba6927 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WMouseInfoPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WMouseInfoPeer.java @@ -43,8 +43,10 @@ public final class WMouseInfoPeer implements MouseInfoPeer { WMouseInfoPeer() { } + @Override public native int fillPointWithCoords(Point point); + @Override public native boolean isWindowUnderMouse(Window w); } diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WPopupMenuPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WPopupMenuPeer.java index 69b6232567027..d89cbcfa53aaa 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WPopupMenuPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WPopupMenuPeer.java @@ -70,6 +70,7 @@ final class WPopupMenuPeer extends WMenuPeer implements PopupMenuPeer { private native void createMenu(WComponentPeer parent); + @Override @SuppressWarnings("deprecation") public void show(Event e) { Component origin = (Component)e.target; diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java b/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java index d7efc54ffd473..e50cfcff33b17 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java @@ -264,7 +264,7 @@ public final class WPrinterJob extends RasterPrinterJob /* The HandleRecord holds the native resources that need to be freed * when this WPrinterJob is GC'd. */ - static class HandleRecord implements DisposerRecord { + static final class HandleRecord implements DisposerRecord { /** * The Windows device context we will print into. * This variable is set after the Print dialog @@ -2269,7 +2269,7 @@ private void setPrinterNameAttrib(String printerName) { } @SuppressWarnings("serial") // JDK-implementation class -static class PrintToFileErrorDialog extends Dialog implements ActionListener { +static final class PrintToFileErrorDialog extends Dialog implements ActionListener { public PrintToFileErrorDialog(Frame parent, String title, String message, String buttonText) { super(parent, title, true); diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WScrollPanePeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WScrollPanePeer.java index e305654d91f8d..3a0d7bf3a71c1 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WScrollPanePeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WScrollPanePeer.java @@ -167,7 +167,7 @@ private void postScrollEvent(int orient, int type, * operation. */ @SuppressWarnings("serial") // JDK-implementation class - static class ScrollEvent extends PeerEvent { + static final class ScrollEvent extends PeerEvent { ScrollEvent(Object source, Runnable runnable) { super(source, runnable, 0L); } @@ -187,7 +187,7 @@ public PeerEvent coalesceEvents(PeerEvent newEvent) { /* * Runnable for the ScrollEvent that performs the adjustment. */ - class Adjustor implements Runnable { + final class Adjustor implements Runnable { int orient; // selects scrollbar int type; // adjustment type int pos; // new position (only used for absolute) diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WScrollbarPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WScrollbarPeer.java index 055f2523cea26..cfc227d29d6e4 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WScrollbarPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WScrollbarPeer.java @@ -35,6 +35,7 @@ final class WScrollbarPeer extends WComponentPeer implements ScrollbarPeer { static native int getScrollbarSize(int orientation); // ComponentPeer overrides + @Override public Dimension getMinimumSize() { if (((Scrollbar)target).getOrientation() == Scrollbar.VERTICAL) { return new Dimension(getScrollbarSize(Scrollbar.VERTICAL), 50); @@ -46,9 +47,12 @@ public Dimension getMinimumSize() { // ScrollbarPeer implementation + @Override public native void setValues(int value, int visible, int minimum, int maximum); + @Override public native void setLineIncrement(int l); + @Override public native void setPageIncrement(int l); @@ -58,8 +62,10 @@ public native void setValues(int value, int visible, super(target); } + @Override native void create(WComponentPeer parent); + @Override void initialize() { Scrollbar sb = (Scrollbar)target; setValues(sb.getValue(), sb.getVisibleAmount(), @@ -136,6 +142,7 @@ public void run() { }); } + @Override public boolean shouldClearRectBeforePaint() { return false; } diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java b/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java index e151a69a0f110..0fdc4c6005ba0 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java @@ -186,7 +186,7 @@ public static void loadLibraries() { } } - static class ToolkitDisposer implements sun.java2d.DisposerRecord { + static final class ToolkitDisposer implements sun.java2d.DisposerRecord { @Override public void dispose() { WToolkit.postDispose(); diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WTrayIconPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WTrayIconPeer.java index 90fbd880446f3..d6c311d3f48c7 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WTrayIconPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WTrayIconPeer.java @@ -199,7 +199,7 @@ native void setNativeIcon(int[] rData, byte[] andMask, int nScanStride, native void _displayMessage(String caption, String text, String messageType); - class IconObserver implements ImageObserver { + final class IconObserver implements ImageObserver { @Override public boolean imageUpdate(Image image, int flags, int x, int y, int width, int height) { if (image != ((TrayIcon)target).getImage() || // if the image has been changed diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java index 997db36beac06..0ba2217dde598 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java @@ -849,7 +849,7 @@ private static void initActiveWindowsTracking(Window w) { * it removes the list of the active windows from the disposed AppContext and * unregisters ActiveWindowListener listener. */ - private static class GuiDisposedListener implements PropertyChangeListener { + private static final class GuiDisposedListener implements PropertyChangeListener { @Override public void propertyChange(PropertyChangeEvent e) { boolean isDisposed = (Boolean)e.getNewValue(); @@ -875,7 +875,7 @@ public void propertyChange(PropertyChangeEvent e) { * window is always at the end of the list. The list is stored in AppContext. */ @SuppressWarnings("unchecked") - private static class ActiveWindowListener implements PropertyChangeListener { + private static final class ActiveWindowListener implements PropertyChangeListener { @Override public void propertyChange(PropertyChangeEvent e) { Window w = (Window)e.getNewValue(); diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WingDings.java b/src/java.desktop/windows/classes/sun/awt/windows/WingDings.java index 55c5236594c53..ae7573ac4e28a 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WingDings.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WingDings.java @@ -52,7 +52,7 @@ public boolean contains(Charset cs) { return cs instanceof WingDings; } - private static class Encoder extends CharsetEncoder { + private static final class Encoder extends CharsetEncoder { public Encoder(Charset cs) { super(cs, 1.0f, 1.0f); } diff --git a/src/java.desktop/windows/classes/sun/font/NativeFont.java b/src/java.desktop/windows/classes/sun/font/NativeFont.java index 7a5c29c7c73e0..9b0e6492d6738 100644 --- a/src/java.desktop/windows/classes/sun/font/NativeFont.java +++ b/src/java.desktop/windows/classes/sun/font/NativeFont.java @@ -37,7 +37,7 @@ * and the font is ignored. */ -public class NativeFont extends PhysicalFont { +public final class NativeFont extends PhysicalFont { /** * Verifies native font is accessible. @@ -53,6 +53,7 @@ static boolean hasExternalBitmaps(String platName) { return false; } + @Override public CharToGlyphMapper getMapper() { return null; } @@ -61,6 +62,7 @@ PhysicalFont getDelegateFont() { return null; } + @Override FontStrike createStrike(FontStrikeDesc desc) { return null; } @@ -69,16 +71,19 @@ public Rectangle2D getMaxCharBounds(FontRenderContext frc) { return null; } + @Override StrikeMetrics getFontMetrics(long pScalerContext) { return null; } + @Override public GeneralPath getGlyphOutline(long pScalerContext, int glyphCode, float x, float y) { return null; } + @Override public GeneralPath getGlyphVectorOutline(long pScalerContext, int[] glyphs, int numGlyphs, float x, float y) { @@ -86,20 +91,24 @@ public GeneralPath getGlyphVectorOutline(long pScalerContext, } + @Override long getGlyphImage(long pScalerContext, int glyphCode) { return 0L; } + @Override void getGlyphMetrics(long pScalerContext, int glyphCode, Point2D.Float metrics) { } + @Override float getGlyphAdvance(long pScalerContext, int glyphCode) { return 0f; } + @Override Rectangle2D.Float getGlyphOutlineBounds(long pScalerContext, int glyphCode) { return new Rectangle2D.Float(0f, 0f, 0f, 0f); diff --git a/src/java.desktop/windows/classes/sun/font/NativeStrike.java b/src/java.desktop/windows/classes/sun/font/NativeStrike.java index a28c47911ed47..7b2b947d722a7 100644 --- a/src/java.desktop/windows/classes/sun/font/NativeStrike.java +++ b/src/java.desktop/windows/classes/sun/font/NativeStrike.java @@ -48,9 +48,11 @@ public class NativeStrike extends PhysicalStrike { } + @Override void getGlyphImagePtrs(int[] glyphCodes, long[] images,int len) { } + @Override long getGlyphImagePtr(int glyphCode) { return 0L; } @@ -59,26 +61,32 @@ long getGlyphImagePtrNoCache(int glyphCode) { return 0L; } + @Override void getGlyphImageBounds(int glyphcode, Point2D.Float pt, Rectangle result) { } + @Override Point2D.Float getGlyphMetrics(int glyphCode) { return null; } + @Override float getGlyphAdvance(int glyphCode) { return 0f; } + @Override Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) { return null; } + @Override GeneralPath getGlyphOutline(int glyphCode, float x, float y) { return null; } + @Override GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) { return null; } diff --git a/src/java.desktop/windows/classes/sun/java2d/WindowsSurfaceManagerFactory.java b/src/java.desktop/windows/classes/sun/java2d/WindowsSurfaceManagerFactory.java index 4512492350d9a..4abb8c823f6e9 100644 --- a/src/java.desktop/windows/classes/sun/java2d/WindowsSurfaceManagerFactory.java +++ b/src/java.desktop/windows/classes/sun/java2d/WindowsSurfaceManagerFactory.java @@ -38,7 +38,7 @@ * The SurfaceManagerFactory that creates VolatileSurfaceManager * implementations for the Windows volatile images. */ -public class WindowsSurfaceManagerFactory extends SurfaceManagerFactory { +public final class WindowsSurfaceManagerFactory extends SurfaceManagerFactory { /** * Creates a new instance of a VolatileSurfaceManager given any @@ -49,6 +49,7 @@ public class WindowsSurfaceManagerFactory extends SurfaceManagerFactory { * For Windows platforms, this method returns a Windows-specific * VolatileSurfaceManager. */ + @Override public VolatileSurfaceManager createVolatileManager(SunVolatileImage vImg, Object context) { diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DBlitLoops.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DBlitLoops.java index 8f4da91eef26e..9aa9837b191d9 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DBlitLoops.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DBlitLoops.java @@ -358,7 +358,7 @@ static void IsoBlit(SurfaceData srcData, SurfaceData dstData, } } -class D3DSurfaceToSurfaceBlit extends Blit { +final class D3DSurfaceToSurfaceBlit extends Blit { D3DSurfaceToSurfaceBlit() { super(D3DSurfaceData.D3DSurface, @@ -366,6 +366,7 @@ class D3DSurfaceToSurfaceBlit extends Blit { D3DSurfaceData.D3DSurface); } + @Override public void Blit(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx, int sy, int dx, int dy, int w, int h) @@ -380,7 +381,7 @@ public void Blit(SurfaceData src, SurfaceData dst, } } -class D3DSurfaceToSurfaceScale extends ScaledBlit { +final class D3DSurfaceToSurfaceScale extends ScaledBlit { D3DSurfaceToSurfaceScale() { super(D3DSurfaceData.D3DSurface, @@ -388,6 +389,7 @@ class D3DSurfaceToSurfaceScale extends ScaledBlit { D3DSurfaceData.D3DSurface); } + @Override public void Scale(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx1, int sy1, @@ -405,7 +407,7 @@ public void Scale(SurfaceData src, SurfaceData dst, } } -class D3DSurfaceToSurfaceTransform extends TransformBlit { +final class D3DSurfaceToSurfaceTransform extends TransformBlit { D3DSurfaceToSurfaceTransform() { super(D3DSurfaceData.D3DSurface, @@ -413,6 +415,7 @@ class D3DSurfaceToSurfaceTransform extends TransformBlit { D3DSurfaceData.D3DSurface); } + @Override public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform at, int hint, @@ -428,7 +431,7 @@ public void Transform(SurfaceData src, SurfaceData dst, } } -class D3DRTTSurfaceToSurfaceBlit extends Blit { +final class D3DRTTSurfaceToSurfaceBlit extends Blit { D3DRTTSurfaceToSurfaceBlit() { super(D3DSurfaceData.D3DSurfaceRTT, @@ -436,6 +439,7 @@ class D3DRTTSurfaceToSurfaceBlit extends Blit { D3DSurfaceData.D3DSurface); } + @Override public void Blit(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx, int sy, int dx, int dy, int w, int h) @@ -450,7 +454,7 @@ public void Blit(SurfaceData src, SurfaceData dst, } } -class D3DRTTSurfaceToSurfaceScale extends ScaledBlit { +final class D3DRTTSurfaceToSurfaceScale extends ScaledBlit { D3DRTTSurfaceToSurfaceScale() { super(D3DSurfaceData.D3DSurfaceRTT, @@ -458,6 +462,7 @@ class D3DRTTSurfaceToSurfaceScale extends ScaledBlit { D3DSurfaceData.D3DSurface); } + @Override public void Scale(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx1, int sy1, @@ -475,7 +480,7 @@ public void Scale(SurfaceData src, SurfaceData dst, } } -class D3DRTTSurfaceToSurfaceTransform extends TransformBlit { +final class D3DRTTSurfaceToSurfaceTransform extends TransformBlit { D3DRTTSurfaceToSurfaceTransform() { super(D3DSurfaceData.D3DSurfaceRTT, @@ -483,6 +488,7 @@ class D3DRTTSurfaceToSurfaceTransform extends TransformBlit { D3DSurfaceData.D3DSurface); } + @Override public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform at, int hint, @@ -497,7 +503,7 @@ public void Transform(SurfaceData src, SurfaceData dst, } } -class D3DSurfaceToSwBlit extends Blit { +final class D3DSurfaceToSwBlit extends Blit { private int typeval; private WeakReference srcTmp; @@ -567,6 +573,7 @@ private synchronized void complexClipBlit(SurfaceData src, SurfaceData dst, } } + @Override public void Blit(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx, int sy, int dx, int dy, @@ -629,7 +636,7 @@ public void Blit(SurfaceData src, SurfaceData dst, } } -class D3DSwToSurfaceBlit extends Blit { +final class D3DSwToSurfaceBlit extends Blit { private int typeval; @@ -640,6 +647,7 @@ class D3DSwToSurfaceBlit extends Blit { this.typeval = typeval; } + @Override public void Blit(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx, int sy, int dx, int dy, int w, int h) @@ -653,7 +661,7 @@ public void Blit(SurfaceData src, SurfaceData dst, } } -class D3DSwToSurfaceScale extends ScaledBlit { +final class D3DSwToSurfaceScale extends ScaledBlit { private int typeval; @@ -664,6 +672,7 @@ class D3DSwToSurfaceScale extends ScaledBlit { this.typeval = typeval; } + @Override public void Scale(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx1, int sy1, @@ -680,7 +689,7 @@ public void Scale(SurfaceData src, SurfaceData dst, } } -class D3DSwToSurfaceTransform extends TransformBlit { +final class D3DSwToSurfaceTransform extends TransformBlit { private int typeval; @@ -691,6 +700,7 @@ class D3DSwToSurfaceTransform extends TransformBlit { this.typeval = typeval; } + @Override public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform at, int hint, @@ -704,7 +714,7 @@ public void Transform(SurfaceData src, SurfaceData dst, } } -class D3DSwToTextureBlit extends Blit { +final class D3DSwToTextureBlit extends Blit { private int typeval; @@ -715,6 +725,7 @@ class D3DSwToTextureBlit extends Blit { this.typeval = typeval; } + @Override public void Blit(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx, int sy, int dx, int dy, int w, int h) @@ -728,7 +739,7 @@ public void Blit(SurfaceData src, SurfaceData dst, } } -class D3DTextureToSurfaceBlit extends Blit { +final class D3DTextureToSurfaceBlit extends Blit { D3DTextureToSurfaceBlit() { super(D3DSurfaceData.D3DTexture, @@ -736,6 +747,7 @@ class D3DTextureToSurfaceBlit extends Blit { D3DSurfaceData.D3DSurface); } + @Override public void Blit(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx, int sy, int dx, int dy, int w, int h) @@ -750,7 +762,7 @@ public void Blit(SurfaceData src, SurfaceData dst, } } -class D3DTextureToSurfaceScale extends ScaledBlit { +final class D3DTextureToSurfaceScale extends ScaledBlit { D3DTextureToSurfaceScale() { super(D3DSurfaceData.D3DTexture, @@ -758,6 +770,7 @@ class D3DTextureToSurfaceScale extends ScaledBlit { D3DSurfaceData.D3DSurface); } + @Override public void Scale(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx1, int sy1, @@ -775,7 +788,7 @@ public void Scale(SurfaceData src, SurfaceData dst, } } -class D3DTextureToSurfaceTransform extends TransformBlit { +final class D3DTextureToSurfaceTransform extends TransformBlit { D3DTextureToSurfaceTransform() { super(D3DSurfaceData.D3DTexture, @@ -783,6 +796,7 @@ class D3DTextureToSurfaceTransform extends TransformBlit { D3DSurfaceData.D3DSurface); } + @Override public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform at, int hint, @@ -804,7 +818,7 @@ public void Transform(SurfaceData src, SurfaceData dst, * IntArgbPre->D3DSurface/Texture loop to get the intermediate * (premultiplied) surface down to D3D using simple blit. */ -class D3DGeneralBlit extends Blit { +final class D3DGeneralBlit extends Blit { private final Blit performop; private WeakReference srcTmp; @@ -817,6 +831,7 @@ class D3DGeneralBlit extends Blit { this.performop = performop; } + @Override public synchronized void Blit(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx, int sy, int dx, int dy, @@ -917,7 +932,7 @@ public synchronized void Transform(SurfaceData src, SurfaceData dst, * */ -class D3DSurfaceToGDIWindowSurfaceBlit extends Blit { +final class D3DSurfaceToGDIWindowSurfaceBlit extends Blit { D3DSurfaceToGDIWindowSurfaceBlit() { super(D3DSurfaceData.D3DSurface, @@ -935,7 +950,7 @@ public void Blit(SurfaceData src, SurfaceData dst, } -class D3DSurfaceToGDIWindowSurfaceScale extends ScaledBlit { +final class D3DSurfaceToGDIWindowSurfaceScale extends ScaledBlit { D3DSurfaceToGDIWindowSurfaceScale() { super(D3DSurfaceData.D3DSurface, @@ -955,7 +970,7 @@ public void Scale(SurfaceData src, SurfaceData dst, } } -class D3DSurfaceToGDIWindowSurfaceTransform extends TransformBlit { +final class D3DSurfaceToGDIWindowSurfaceTransform extends TransformBlit { D3DSurfaceToGDIWindowSurfaceTransform() { super(D3DSurfaceData.D3DSurface, diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DBufImgOps.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DBufImgOps.java index 890bb87d66b25..7ca0130391b2c 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DBufImgOps.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DBufImgOps.java @@ -37,7 +37,7 @@ import sun.java2d.pipe.BufferedBufImgOps; import static sun.java2d.d3d.D3DContext.D3DContextCaps.*; -class D3DBufImgOps extends BufferedBufImgOps { +final class D3DBufImgOps extends BufferedBufImgOps { /** * This method is called from D3DDrawImage.transformImage() only. It diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DContext.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DContext.java index 055e636bb6939..5d9b6c30b5bed 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DContext.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DContext.java @@ -106,7 +106,7 @@ D3DGraphicsDevice getDevice() { return device; } - static class D3DContextCaps extends ContextCapabilities { + static final class D3DContextCaps extends ContextCapabilities { /** * Indicates the presence of pixel shaders (v2.0 or greater). * This cap will only be set if the hardware supports the minimum number diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DDrawImage.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DDrawImage.java index f814dc2f6132e..e847c7ba7cd72 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DDrawImage.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DDrawImage.java @@ -37,7 +37,7 @@ import sun.java2d.loops.TransformBlit; import sun.java2d.pipe.DrawImage; -public class D3DDrawImage extends DrawImage { +public final class D3DDrawImage extends DrawImage { @Override protected void renderImageXform(SunGraphics2D sg, Image img, diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsConfig.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsConfig.java index 53d64017a3e4b..aab6b720d6a89 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsConfig.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsConfig.java @@ -223,7 +223,7 @@ public void flip(WComponentPeer peer, } } - private static class D3DBufferCaps extends BufferCapabilities { + private static final class D3DBufferCaps extends BufferCapabilities { public D3DBufferCaps() { // REMIND: should we indicate that the front-buffer // (the on-screen rendering) is not accelerated? @@ -244,7 +244,7 @@ public BufferCapabilities getBufferCapabilities() { return bufferCaps; } - private static class D3DImageCaps extends ImageCapabilities { + private static final class D3DImageCaps extends ImageCapabilities { private D3DImageCaps() { super(true); } diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java index e9f02a5d98ce6..1c838d0d32d6c 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java @@ -128,7 +128,7 @@ public void run() { return d3dCaps != null ? d3dCaps : new D3DContextCaps(CAPS_EMPTY, null); } - public final boolean isCapPresent(int cap) { + public boolean isCapPresent(int cap) { return ((d3dCaps.getCaps() & cap) != 0); } @@ -234,7 +234,7 @@ public void run() { * REMIND: we create an instance per each full-screen device while a single * instance would suffice (but requires more management). */ - private static class D3DFSWindowAdapter extends WindowAdapter { + private static final class D3DFSWindowAdapter extends WindowAdapter { @Override @SuppressWarnings("static") public void windowDeactivated(WindowEvent e) { diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DMaskBlit.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DMaskBlit.java index 835bcb733adaa..6ba766d2b1303 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DMaskBlit.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DMaskBlit.java @@ -36,7 +36,7 @@ import static sun.java2d.loops.CompositeType.*; import static sun.java2d.loops.SurfaceType.*; -class D3DMaskBlit extends BufferedMaskBlit { +final class D3DMaskBlit extends BufferedMaskBlit { static void register() { GraphicsPrimitive[] primitives = { diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DMaskFill.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DMaskFill.java index fb78616a98ff6..d00e3fe2ee132 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DMaskFill.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DMaskFill.java @@ -36,7 +36,7 @@ import static sun.java2d.loops.CompositeType.*; import static sun.java2d.loops.SurfaceType.*; -class D3DMaskFill extends BufferedMaskFill { +final class D3DMaskFill extends BufferedMaskFill { static void register() { GraphicsPrimitive[] primitives = { diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DPaints.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DPaints.java index 7d5bd4423eacf..74b7cfc69670a 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DPaints.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DPaints.java @@ -76,7 +76,7 @@ static boolean isValid(SunGraphics2D sg2d) { /************************* GradientPaint support ****************************/ - private static class Gradient extends D3DPaints { + private static final class Gradient extends D3DPaints { private Gradient() {} /** @@ -96,7 +96,7 @@ boolean isPaintValid(SunGraphics2D sg2d) { /************************** TexturePaint support ****************************/ - private static class Texture extends D3DPaints { + private static final class Texture extends D3DPaints { private Texture() {} /** @@ -201,7 +201,7 @@ boolean isPaintValid(SunGraphics2D sg2d) { /********************** LinearGradientPaint support *************************/ - private static class LinearGradient extends MultiGradient { + private static final class LinearGradient extends MultiGradient { private LinearGradient() {} @Override @@ -228,7 +228,7 @@ boolean isPaintValid(SunGraphics2D sg2d) { /********************** RadialGradientPaint support *************************/ - private static class RadialGradient extends MultiGradient { + private static final class RadialGradient extends MultiGradient { private RadialGradient() {} } } diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DRenderQueue.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DRenderQueue.java index d77e90456dfb6..be20e1c4e4c86 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DRenderQueue.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DRenderQueue.java @@ -33,7 +33,7 @@ /** * D3D-specific implementation of RenderQueue. */ -public class D3DRenderQueue extends RenderQueue { +public final class D3DRenderQueue extends RenderQueue { private static D3DRenderQueue theInstance; private static Thread rqThread; @@ -132,11 +132,13 @@ public static void disposeGraphicsConfig(long pConfigInfo) { } } + @Override public void flushNow() { // assert lock.isHeldByCurrentThread(); flushBuffer(null); } + @Override public void flushAndInvokeNow(Runnable r) { // assert lock.isHeldByCurrentThread(); flushBuffer(r); diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DRenderer.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DRenderer.java index fd63d758548a8..7361a09973b12 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DRenderer.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DRenderer.java @@ -87,6 +87,7 @@ void copyArea(SunGraphics2D sg2d, } } + @Override protected native void drawPoly(int[] xPoints, int[] yPoints, int nPoints, boolean isClosed, int transX, int transY); @@ -95,12 +96,13 @@ D3DRenderer traceWrap() { return new Tracer(this); } - private static class Tracer extends D3DRenderer { + private static final class Tracer extends D3DRenderer { private D3DRenderer d3dr; Tracer(D3DRenderer d3dr) { super(d3dr.rq); this.d3dr = d3dr; } + @Override public ParallelogramPipe getAAParallelogramPipe() { final ParallelogramPipe realpipe = d3dr.getAAParallelogramPipe(); return new ParallelogramPipe() { @@ -133,19 +135,23 @@ public void drawParallelogram(SunGraphics2D sg2d, }; } + @Override protected void validateContext(SunGraphics2D sg2d) { d3dr.validateContext(sg2d); } + @Override public void drawLine(SunGraphics2D sg2d, int x1, int y1, int x2, int y2) { GraphicsPrimitive.tracePrimitive("D3DDrawLine"); d3dr.drawLine(sg2d, x1, y1, x2, y2); } + @Override public void drawRect(SunGraphics2D sg2d, int x, int y, int w, int h) { GraphicsPrimitive.tracePrimitive("D3DDrawRect"); d3dr.drawRect(sg2d, x, y, w, h); } + @Override protected void drawPoly(SunGraphics2D sg2d, int[] xPoints, int[] yPoints, int nPoints, boolean isClosed) @@ -153,28 +159,33 @@ protected void drawPoly(SunGraphics2D sg2d, GraphicsPrimitive.tracePrimitive("D3DDrawPoly"); d3dr.drawPoly(sg2d, xPoints, yPoints, nPoints, isClosed); } + @Override public void fillRect(SunGraphics2D sg2d, int x, int y, int w, int h) { GraphicsPrimitive.tracePrimitive("D3DFillRect"); d3dr.fillRect(sg2d, x, y, w, h); } + @Override protected void drawPath(SunGraphics2D sg2d, Path2D.Float p2df, int transx, int transy) { GraphicsPrimitive.tracePrimitive("D3DDrawPath"); d3dr.drawPath(sg2d, p2df, transx, transy); } + @Override protected void fillPath(SunGraphics2D sg2d, Path2D.Float p2df, int transx, int transy) { GraphicsPrimitive.tracePrimitive("D3DFillPath"); d3dr.fillPath(sg2d, p2df, transx, transy); } + @Override protected void fillSpans(SunGraphics2D sg2d, SpanIterator si, int transx, int transy) { GraphicsPrimitive.tracePrimitive("D3DFillSpans"); d3dr.fillSpans(sg2d, si, transx, transy); } + @Override public void fillParallelogram(SunGraphics2D sg2d, double ux1, double uy1, double ux2, double uy2, @@ -187,6 +198,7 @@ public void fillParallelogram(SunGraphics2D sg2d, ux1, uy1, ux2, uy2, x, y, dx1, dy1, dx2, dy2); } + @Override public void drawParallelogram(SunGraphics2D sg2d, double ux1, double uy1, double ux2, double uy2, @@ -200,6 +212,7 @@ public void drawParallelogram(SunGraphics2D sg2d, ux1, uy1, ux2, uy2, x, y, dx1, dy1, dx2, dy2, lw1, lw2); } + @Override public void copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy) { diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java index a1afb5cd4c465..58dfd17dea713 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java @@ -58,7 +58,7 @@ * There are some restrictions to which windows we would use this for. * @see #createScreenSurface */ -public class D3DScreenUpdateManager extends ScreenUpdateManager +public final class D3DScreenUpdateManager extends ScreenUpdateManager implements Runnable { /** @@ -401,6 +401,7 @@ public void runUpdateNow() { } } + @Override public void run() { while (!done) { synchronized (runLock) { diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java index c8e082b59d6da..374fce63db047 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java @@ -441,6 +441,7 @@ public void run() { * Returns the D3DContext for the GraphicsConfig associated with this * surface. */ + @Override public final D3DContext getContext() { return graphicsDevice.getContext(); } @@ -448,6 +449,7 @@ public final D3DContext getContext() { /** * Returns one of the surface type constants defined above. */ + @Override public final int getType() { return type; } @@ -455,7 +457,7 @@ public final int getType() { private static native int dbGetPixelNative(long pData, int x, int y); private static native void dbSetPixelNative(long pData, int x, int y, int pixel); - static class D3DDataBufferNative extends DataBufferNative { + static final class D3DDataBufferNative extends DataBufferNative { int pixel; protected D3DDataBufferNative(SurfaceData sData, int type, int w, int h) @@ -463,6 +465,7 @@ protected D3DDataBufferNative(SurfaceData sData, super(sData, type, w, h); } + @Override protected int getElem(final int x, final int y, final SurfaceData sData) { @@ -486,6 +489,7 @@ public void run() { return retPixel; } + @Override protected void setElem(final int x, final int y, final int pixel, final SurfaceData sData) { @@ -508,6 +512,7 @@ public void run() { } } + @Override public synchronized Raster getRaster(int x, int y, int w, int h) { if (wrn == null) { DirectColorModel dcm = (DirectColorModel)getColorModel(); @@ -541,6 +546,7 @@ public synchronized Raster getRaster(int x, int y, int w, int h) { * - the source color is opaque * - and the destination is opaque */ + @Override public boolean canRenderLCDText(SunGraphics2D sg2d) { return graphicsDevice.isCapPresent(CAPS_LCD_SHADER) && @@ -564,6 +570,7 @@ void disableAccelerationForSurface() { } } + @Override public void validatePipe(SunGraphics2D sg2d) { TextPipe textpipe; boolean validated = false; @@ -803,10 +810,12 @@ public void run() { /** * Returns destination Image associated with this SurfaceData. */ + @Override public Object getDestination() { return offscreenImage; } + @Override public Rectangle getBounds() { if (type == FLIP_BACKBUFFER || type == WINDOW) { double scaleX = getDefaultScaleX(); @@ -821,6 +830,7 @@ public Rectangle getBounds() { } } + @Override public Rectangle getNativeBounds() { D3DRenderQueue rq = D3DRenderQueue.getInstance(); // need to lock to make sure nativeWidth and Height are consistent @@ -836,10 +846,12 @@ public Rectangle getNativeBounds() { } + @Override public GraphicsConfiguration getDeviceConfiguration() { return graphicsDevice.getDefaultConfiguration(); } + @Override public SurfaceData getReplacement() { return restoreContents(offscreenImage); } @@ -909,6 +921,7 @@ public void setSurfaceLost(boolean lost) { * such resource doesn't exist or can not be retrieved. * @see sun.java2d.pipe.hw.AccelSurface#getNativeResource */ + @Override public long getNativeResource(int resType) { return getNativeResourceNative(getNativeOps(), resType); } @@ -920,7 +933,7 @@ public long getNativeResource(int resType) { * * @see D3DScreenUpdateManager */ - public static class D3DWindowSurfaceData extends D3DSurfaceData { + public static final class D3DWindowSurfaceData extends D3DSurfaceData { StateTracker dirtyTracker; public D3DWindowSurfaceData(WComponentPeer peer, diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceDataProxy.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceDataProxy.java index 66e98882a19da..6ea095666b3e1 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceDataProxy.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceDataProxy.java @@ -38,7 +38,7 @@ * SurfaceData with a cached D3D Texture and the code to create * the accelerated surfaces. */ -public class D3DSurfaceDataProxy extends SurfaceDataProxy { +public final class D3DSurfaceDataProxy extends SurfaceDataProxy { public static SurfaceDataProxy createProxy(SurfaceData srcData, D3DGraphicsConfig dstConfig) diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DTextRenderer.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DTextRenderer.java index b892ed4b10c51..31b2cc207cd68 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DTextRenderer.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DTextRenderer.java @@ -59,10 +59,11 @@ D3DTextRenderer traceWrap() { return new Tracer(this); } - private static class Tracer extends D3DTextRenderer { + private static final class Tracer extends D3DTextRenderer { Tracer(D3DTextRenderer d3dtr) { super(d3dtr.rq); } + @Override protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) { GraphicsPrimitive.tracePrimitive("D3DDrawGlyphs"); super.drawGlyphList(sg2d, gl); diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DVolatileSurfaceManager.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DVolatileSurfaceManager.java index 4aac1c248a6a5..0fedb47836200 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DVolatileSurfaceManager.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DVolatileSurfaceManager.java @@ -48,7 +48,7 @@ import static sun.java2d.pipe.hw.AccelSurface.TEXTURE; import static sun.java2d.pipe.hw.AccelSurface.UNDEFINED; -public class D3DVolatileSurfaceManager +public final class D3DVolatileSurfaceManager extends VolatileSurfaceManager { private boolean accelerationEnabled; @@ -75,6 +75,7 @@ public D3DVolatileSurfaceManager(SunVolatileImage vImg, Object context) { gd.isCapPresent(CAPS_RT_TEXTURE_ALPHA))); } + @Override protected boolean isAccelerationEnabled() { return accelerationEnabled; } @@ -86,6 +87,7 @@ public void setAccelerationEnabled(boolean accelerationEnabled) { * Create a pbuffer-based SurfaceData object (or init the backbuffer * of an existing window if this is a double buffered GraphicsConfig). */ + @Override protected SurfaceData initAcceleratedSurface() { SurfaceData sData; Component comp = vImg.getComponent(); @@ -124,6 +126,7 @@ protected SurfaceData initAcceleratedSurface() { return sData; } + @Override protected boolean isConfigValid(GraphicsConfiguration gc) { return ((gc == null) || (gc == vImg.getGraphicsConfig())); } diff --git a/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java b/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java index 768f2df08add7..c6658bf291423 100644 --- a/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java +++ b/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java @@ -158,7 +158,7 @@ public void run() { * This is a small helper class that allows us to execute * getWGLConfigInfo() on the queue flushing thread. */ - private static class WGLGetConfigInfo implements Runnable { + private static final class WGLGetConfigInfo implements Runnable { private int screen; private int pixfmt; private long cfginfo; @@ -184,21 +184,21 @@ public static boolean isWGLAvailable() { * See OGLContext.java for a list of supported capabilities. */ @Override - public final boolean isCapPresent(int cap) { + public boolean isCapPresent(int cap) { return ((oglCaps.getCaps() & cap) != 0); } @Override - public final long getNativeConfigInfo() { + public long getNativeConfigInfo() { return pConfigInfo; } @Override - public final OGLContext getContext() { + public OGLContext getContext() { return context; } - private static class WGLGCDisposerRecord implements DisposerRecord { + private static final class WGLGCDisposerRecord implements DisposerRecord { private long pCfgInfo; public WGLGCDisposerRecord(long pCfgInfo) { this.pCfgInfo = pCfgInfo; @@ -374,7 +374,7 @@ public void flip(WComponentPeer peer, } } - private static class WGLBufferCaps extends BufferCapabilities { + private static final class WGLBufferCaps extends BufferCapabilities { public WGLBufferCaps(boolean dblBuf) { super(imageCaps, imageCaps, dblBuf ? FlipContents.UNDEFINED : null); @@ -390,7 +390,7 @@ public BufferCapabilities getBufferCapabilities() { return bufferCaps; } - private static class WGLImageCaps extends ImageCapabilities { + private static final class WGLImageCaps extends ImageCapabilities { private WGLImageCaps() { super(true); } diff --git a/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java b/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java index fa4cb6a3cc275..8f97980811f36 100644 --- a/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java +++ b/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java @@ -75,6 +75,7 @@ public double getDefaultScaleY() { return scaleY; } + @Override public GraphicsConfiguration getDeviceConfiguration() { return graphicsConfig; } @@ -151,7 +152,7 @@ public static WGLGraphicsConfig getGC(WComponentPeer peer) { } } - public static class WGLWindowSurfaceData extends WGLSurfaceData { + public static final class WGLWindowSurfaceData extends WGLSurfaceData { public WGLWindowSurfaceData(WComponentPeer peer, WGLGraphicsConfig gc) @@ -159,10 +160,12 @@ public WGLWindowSurfaceData(WComponentPeer peer, super(peer, gc, peer.getColorModel(), WINDOW); } + @Override public SurfaceData getReplacement() { return peer.getSurfaceData(); } + @Override public Rectangle getBounds() { Rectangle r = peer.getBounds(); r.x = r.y = 0; @@ -174,6 +177,7 @@ public Rectangle getBounds() { /** * Returns destination Component associated with this SurfaceData. */ + @Override public Object getDestination() { return peer.getTarget(); } @@ -188,7 +192,7 @@ public Object getDestination() { * belongs to is showed, it is first copied to the real private * FLIP_BACKBUFFER, which is then flipped. */ - public static class WGLVSyncOffScreenSurfaceData extends + public static final class WGLVSyncOffScreenSurfaceData extends WGLOffScreenSurfaceData { private WGLOffScreenSurfaceData flipSurface; @@ -235,10 +239,12 @@ public WGLOffScreenSurfaceData(WComponentPeer peer, initSurface(this.width, this.height); } + @Override public SurfaceData getReplacement() { return restoreContents(offscreenImage); } + @Override public Rectangle getBounds() { if (type == FLIP_BACKBUFFER) { Rectangle r = peer.getBounds(); @@ -254,6 +260,7 @@ public Rectangle getBounds() { /** * Returns destination Image associated with this SurfaceData. */ + @Override public Object getDestination() { return offscreenImage; } diff --git a/src/java.desktop/windows/classes/sun/java2d/opengl/WGLVolatileSurfaceManager.java b/src/java.desktop/windows/classes/sun/java2d/opengl/WGLVolatileSurfaceManager.java index 750bb94df0889..c90f8102e7ecd 100644 --- a/src/java.desktop/windows/classes/sun/java2d/opengl/WGLVolatileSurfaceManager.java +++ b/src/java.desktop/windows/classes/sun/java2d/opengl/WGLVolatileSurfaceManager.java @@ -43,7 +43,7 @@ import sun.java2d.pipe.hw.ExtendedBufferCapabilities; import static sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.*; -public class WGLVolatileSurfaceManager extends VolatileSurfaceManager { +public final class WGLVolatileSurfaceManager extends VolatileSurfaceManager { private final boolean accelerationEnabled; @@ -62,6 +62,7 @@ public WGLVolatileSurfaceManager(SunVolatileImage vImg, Object context) { && transparency != Transparency.BITMASK; } + @Override protected boolean isAccelerationEnabled() { return accelerationEnabled; } @@ -70,6 +71,7 @@ protected boolean isAccelerationEnabled() { * Create a FBO-based SurfaceData object (or init the backbuffer * of an existing window if this is a double buffered GraphicsConfig). */ + @Override protected SurfaceData initAcceleratedSurface() { SurfaceData sData; Component comp = vImg.getComponent(); diff --git a/src/java.desktop/windows/classes/sun/java2d/windows/GDIBlitLoops.java b/src/java.desktop/windows/classes/sun/java2d/windows/GDIBlitLoops.java index 3f1996309cd22..18d44ea6a498b 100644 --- a/src/java.desktop/windows/classes/sun/java2d/windows/GDIBlitLoops.java +++ b/src/java.desktop/windows/classes/sun/java2d/windows/GDIBlitLoops.java @@ -43,7 +43,7 @@ * that is faster than our current fallback (which creates * a temporary GDI DIB) */ -public class GDIBlitLoops extends Blit { +public final class GDIBlitLoops extends Blit { // Store these values to be passed to native code int rmask, gmask, bmask; @@ -134,6 +134,7 @@ public native void nativeBlit(SurfaceData src, SurfaceData dst, * Composite data because we only register these loops for * SrcNoEa composite operations. */ + @Override public void Blit(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx, int sy, int dx, int dy, int w, int h) diff --git a/src/java.desktop/windows/classes/sun/java2d/windows/GDIRenderer.java b/src/java.desktop/windows/classes/sun/java2d/windows/GDIRenderer.java index f08273c76fb19..9bb3ba38b20db 100644 --- a/src/java.desktop/windows/classes/sun/java2d/windows/GDIRenderer.java +++ b/src/java.desktop/windows/classes/sun/java2d/windows/GDIRenderer.java @@ -50,6 +50,7 @@ native void doDrawLine(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int x1, int y1, int x2, int y2); + @Override public void drawLine(SunGraphics2D sg2d, int x1, int y1, int x2, int y2) { @@ -68,6 +69,7 @@ native void doDrawRect(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int x, int y, int w, int h); + @Override public void drawRect(SunGraphics2D sg2d, int x, int y, int width, int height) { @@ -85,6 +87,7 @@ native void doDrawRoundRect(GDIWindowSurfaceData sData, int x, int y, int w, int h, int arcW, int arcH); + @Override public void drawRoundRect(SunGraphics2D sg2d, int x, int y, int width, int height, int arcWidth, int arcHeight) @@ -103,6 +106,7 @@ native void doDrawOval(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int x, int y, int w, int h); + @Override public void drawOval(SunGraphics2D sg2d, int x, int y, int width, int height) { @@ -120,6 +124,7 @@ native void doDrawArc(GDIWindowSurfaceData sData, int x, int y, int w, int h, int angleStart, int angleExtent); + @Override public void drawArc(SunGraphics2D sg2d, int x, int y, int width, int height, int startAngle, int arcAngle) @@ -140,6 +145,7 @@ native void doDrawPoly(GDIWindowSurfaceData sData, int[] xpoints, int[] ypoints, int npoints, boolean isclosed); + @Override public void drawPolyline(SunGraphics2D sg2d, int[] xpoints, int[] ypoints, int npoints) @@ -153,6 +159,7 @@ public void drawPolyline(SunGraphics2D sg2d, } } + @Override public void drawPolygon(SunGraphics2D sg2d, int[] xpoints, int[] ypoints, int npoints) @@ -170,6 +177,7 @@ native void doFillRect(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int x, int y, int w, int h); + @Override public void fillRect(SunGraphics2D sg2d, int x, int y, int width, int height) { @@ -187,6 +195,7 @@ native void doFillRoundRect(GDIWindowSurfaceData sData, int x, int y, int w, int h, int arcW, int arcH); + @Override public void fillRoundRect(SunGraphics2D sg2d, int x, int y, int width, int height, int arcWidth, int arcHeight) @@ -205,6 +214,7 @@ native void doFillOval(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int x, int y, int w, int h); + @Override public void fillOval(SunGraphics2D sg2d, int x, int y, int width, int height) { @@ -222,6 +232,7 @@ native void doFillArc(GDIWindowSurfaceData sData, int x, int y, int w, int h, int angleStart, int angleExtent); + @Override public void fillArc(SunGraphics2D sg2d, int x, int y, int width, int height, int startAngle, int arcAngle) @@ -242,6 +253,7 @@ native void doFillPoly(GDIWindowSurfaceData sData, int[] xpoints, int[] ypoints, int npoints); + @Override public void fillPolygon(SunGraphics2D sg2d, int[] xpoints, int[] ypoints, int npoints) @@ -303,6 +315,7 @@ public void doFillSpans(SunGraphics2D sg2d, SpanIterator si) { } } + @Override public void draw(SunGraphics2D sg2d, Shape s) { if (sg2d.strokeState == SunGraphics2D.STROKE_THIN) { doShape(sg2d, s, false); @@ -318,6 +331,7 @@ public void draw(SunGraphics2D sg2d, Shape s) { } } + @Override public void fill(SunGraphics2D sg2d, Shape s) { doShape(sg2d, s, true); } @@ -331,7 +345,8 @@ public GDIRenderer traceWrap() { return new Tracer(); } - public static class Tracer extends GDIRenderer { + public static final class Tracer extends GDIRenderer { + @Override void doDrawLine(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int x1, int y1, int x2, int y2) @@ -339,6 +354,7 @@ void doDrawLine(GDIWindowSurfaceData sData, GraphicsPrimitive.tracePrimitive("GDIDrawLine"); super.doDrawLine(sData, clip, comp, color, x1, y1, x2, y2); } + @Override void doDrawRect(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int x, int y, int w, int h) @@ -346,6 +362,7 @@ void doDrawRect(GDIWindowSurfaceData sData, GraphicsPrimitive.tracePrimitive("GDIDrawRect"); super.doDrawRect(sData, clip, comp, color, x, y, w, h); } + @Override void doDrawRoundRect(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int x, int y, int w, int h, @@ -355,6 +372,7 @@ void doDrawRoundRect(GDIWindowSurfaceData sData, super.doDrawRoundRect(sData, clip, comp, color, x, y, w, h, arcW, arcH); } + @Override void doDrawOval(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int x, int y, int w, int h) @@ -362,6 +380,7 @@ void doDrawOval(GDIWindowSurfaceData sData, GraphicsPrimitive.tracePrimitive("GDIDrawOval"); super.doDrawOval(sData, clip, comp, color, x, y, w, h); } + @Override void doDrawArc(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int x, int y, int w, int h, @@ -371,6 +390,7 @@ void doDrawArc(GDIWindowSurfaceData sData, super.doDrawArc(sData, clip, comp, color, x, y, w, h, angleStart, angleExtent); } + @Override void doDrawPoly(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int transx, int transy, @@ -381,6 +401,7 @@ void doDrawPoly(GDIWindowSurfaceData sData, super.doDrawPoly(sData, clip, comp, color, transx, transy, xpoints, ypoints, npoints, isclosed); } + @Override void doFillRect(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int x, int y, int w, int h) @@ -388,6 +409,7 @@ void doFillRect(GDIWindowSurfaceData sData, GraphicsPrimitive.tracePrimitive("GDIFillRect"); super.doFillRect(sData, clip, comp, color, x, y, w, h); } + @Override void doFillRoundRect(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int x, int y, int w, int h, @@ -397,6 +419,7 @@ void doFillRoundRect(GDIWindowSurfaceData sData, super.doFillRoundRect(sData, clip, comp, color, x, y, w, h, arcW, arcH); } + @Override void doFillOval(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int x, int y, int w, int h) @@ -404,6 +427,7 @@ void doFillOval(GDIWindowSurfaceData sData, GraphicsPrimitive.tracePrimitive("GDIFillOval"); super.doFillOval(sData, clip, comp, color, x, y, w, h); } + @Override void doFillArc(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int x, int y, int w, int h, @@ -413,6 +437,7 @@ void doFillArc(GDIWindowSurfaceData sData, super.doFillArc(sData, clip, comp, color, x, y, w, h, angleStart, angleExtent); } + @Override void doFillPoly(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int transx, int transy, @@ -423,6 +448,7 @@ void doFillPoly(GDIWindowSurfaceData sData, super.doFillPoly(sData, clip, comp, color, transx, transy, xpoints, ypoints, npoints); } + @Override void doShape(GDIWindowSurfaceData sData, Region clip, Composite comp, int color, int transX, int transY, @@ -434,6 +460,7 @@ void doShape(GDIWindowSurfaceData sData, super.doShape(sData, clip, comp, color, transX, transY, p2df, isfill); } + @Override public void devCopyArea(GDIWindowSurfaceData sData, int srcx, int srcy, int dx, int dy, diff --git a/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java b/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java index 52e0d47c55d14..38b57f77bce4c 100644 --- a/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java +++ b/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java @@ -51,7 +51,7 @@ import sun.java2d.loops.RenderLoops; import sun.java2d.loops.XORComposite; -public class GDIWindowSurfaceData extends SurfaceData { +public final class GDIWindowSurfaceData extends SurfaceData { private WComponentPeer peer; private Win32GraphicsConfig graphicsConfig; private RenderLoops solidloops; @@ -139,6 +139,7 @@ public SurfaceDataProxy makeProxyFor(SurfaceData srcData) { return SurfaceDataProxy.UNCACHED; } + @Override public Raster getRaster(int x, int y, int w, int h) { throw new InternalError("not implemented yet"); } @@ -155,6 +156,7 @@ public Raster getRaster(int x, int y, int w, int h) { } + @Override public void validatePipe(SunGraphics2D sg2d) { if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON && sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR && @@ -223,6 +225,7 @@ public void validatePipe(SunGraphics2D sg2d) { } } + @Override public RenderLoops getRenderLoops(SunGraphics2D sg2d) { if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR && sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY) @@ -232,6 +235,7 @@ public RenderLoops getRenderLoops(SunGraphics2D sg2d) { return super.getRenderLoops(sg2d); } + @Override public GraphicsConfiguration getDeviceConfiguration() { return graphicsConfig; } @@ -299,6 +303,7 @@ public SurfaceData getReplacement() { return mgr.getReplacementScreenSurface(peer, this); } + @Override public Rectangle getBounds() { Rectangle r = peer.getBounds(); r.x = r.y = 0; @@ -307,6 +312,7 @@ public Rectangle getBounds() { return r; } + @Override public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy) { diff --git a/src/java.desktop/windows/classes/sun/java2d/windows/WindowsFlags.java b/src/java.desktop/windows/classes/sun/java2d/windows/WindowsFlags.java index 7333eeda3dd92..b5b1e6376e960 100644 --- a/src/java.desktop/windows/classes/sun/java2d/windows/WindowsFlags.java +++ b/src/java.desktop/windows/classes/sun/java2d/windows/WindowsFlags.java @@ -28,7 +28,7 @@ import sun.awt.windows.WToolkit; import sun.java2d.opengl.WGLGraphicsConfig; -public class WindowsFlags { +public final class WindowsFlags { /** * Description of command-line flags. All flags with [true|false] diff --git a/src/java.desktop/windows/classes/sun/print/PlatformPrinterJobProxy.java b/src/java.desktop/windows/classes/sun/print/PlatformPrinterJobProxy.java index f9ac7621aa44c..677831a92450d 100644 --- a/src/java.desktop/windows/classes/sun/print/PlatformPrinterJobProxy.java +++ b/src/java.desktop/windows/classes/sun/print/PlatformPrinterJobProxy.java @@ -27,7 +27,7 @@ import java.awt.print.PrinterJob; -public class PlatformPrinterJobProxy { +public final class PlatformPrinterJobProxy { public static PrinterJob getPrinterJob() { return new sun.awt.windows.WPrinterJob(); diff --git a/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java b/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java index 4dbcf3a4701e8..7af6f1b61f878 100644 --- a/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java +++ b/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java @@ -43,7 +43,7 @@ import sun.awt.util.ThreadGroupUtils; -public class PrintServiceLookupProvider extends PrintServiceLookup { +public final class PrintServiceLookupProvider extends PrintServiceLookup { private PrintService defaultPrintService; private PrintService[] printServices; /* includes the default printer */ @@ -105,6 +105,7 @@ public PrintServiceLookupProvider() { * This isn't required by the API and there's a risk doing this will * lead people to assume its guaranteed. */ + @Override public synchronized PrintService[] getPrintServices() { if (printServices == null) { refreshServices(); @@ -199,6 +200,7 @@ boolean matchingService(PrintService service, return true; } + @Override public PrintService[] getPrintServices(DocFlavor flavor, AttributeSet attributes) { @@ -260,6 +262,7 @@ public PrintService[] getPrintServices(DocFlavor flavor, /* * return empty array as don't support multi docs */ + @Override public MultiDocPrintService[] getMultiDocPrintServices(DocFlavor[] flavors, AttributeSet attributes) { @@ -267,6 +270,7 @@ public PrintService[] getPrintServices(DocFlavor flavor, } + @Override public synchronized PrintService getDefaultPrintService() { // Windows does not have notification for a change in default diff --git a/src/java.desktop/windows/classes/sun/print/Win32MediaTray.java b/src/java.desktop/windows/classes/sun/print/Win32MediaTray.java index 43ce6a19d6a34..3cb8c858e3935 100644 --- a/src/java.desktop/windows/classes/sun/print/Win32MediaTray.java +++ b/src/java.desktop/windows/classes/sun/print/Win32MediaTray.java @@ -35,7 +35,7 @@ * It also implements driver-defined trays. **/ @SuppressWarnings("serial") // JDK implementation class -public class Win32MediaTray extends MediaTray { +public final class Win32MediaTray extends MediaTray { static final Win32MediaTray ENVELOPE_MANUAL = new Win32MediaTray(0, 6); //DMBIN_ENVMANUAL @@ -96,6 +96,7 @@ protected static int getTraySize() { return (myStringTable.length+winStringTable.size()); } + @Override protected String[] getStringTable() { ArrayList completeList = new ArrayList<>(); for (int i=0; i < myStringTable.length; i++) { @@ -106,6 +107,7 @@ protected String[] getStringTable() { return completeList.toArray(nameTable); } + @Override protected EnumSyntax[] getEnumValueTable() { ArrayList completeList = new ArrayList<>(); for (int i=0; i < myEnumValueTable.length; i++) { diff --git a/src/java.desktop/windows/classes/sun/print/Win32PrintJob.java b/src/java.desktop/windows/classes/sun/print/Win32PrintJob.java index f8ee2d3db0b21..cd4eec9926bc0 100644 --- a/src/java.desktop/windows/classes/sun/print/Win32PrintJob.java +++ b/src/java.desktop/windows/classes/sun/print/Win32PrintJob.java @@ -73,7 +73,7 @@ import java.awt.print.*; -public class Win32PrintJob implements CancelablePrintJob { +public final class Win32PrintJob implements CancelablePrintJob { private transient ArrayList jobListeners; private transient ArrayList attrListeners; @@ -113,10 +113,12 @@ public class Win32PrintJob implements CancelablePrintJob { this.service = service; } + @Override public PrintService getPrintService() { return service; } + @Override public PrintJobAttributeSet getAttributes() { synchronized (this) { if (jobAttrSet == null) { @@ -129,6 +131,7 @@ public PrintJobAttributeSet getAttributes() { } } + @Override public void addPrintJobListener(PrintJobListener listener) { synchronized (this) { if (listener == null) { @@ -141,6 +144,7 @@ public void addPrintJobListener(PrintJobListener listener) { } } + @Override public void removePrintJobListener(PrintJobListener listener) { synchronized (this) { if (listener == null || jobListeners == null ) { @@ -254,6 +258,7 @@ private void notifyEvent(int reason) { } } + @Override public void addPrintJobAttributeListener( PrintJobAttributeListener listener, PrintJobAttributeSet attributes) { @@ -273,6 +278,7 @@ public void addPrintJobAttributeListener( } } + @Override public void removePrintJobAttributeListener( PrintJobAttributeListener listener) { synchronized (this) { @@ -293,6 +299,7 @@ public void removePrintJobAttributeListener( } } + @Override public void print(Doc doc, PrintRequestAttributeSet attributes) throws PrintException { @@ -697,6 +704,7 @@ private native boolean startPrintRawData(String printerName, private native boolean endPrintRawData(); /* Cancel PrinterJob jobs that haven't yet completed. */ + @Override public void cancel() throws PrintException { synchronized (this) { if (!printing) { diff --git a/src/java.desktop/windows/classes/sun/print/Win32PrintService.java b/src/java.desktop/windows/classes/sun/print/Win32PrintService.java index 7d85755bf0cb9..3bca5b581bbc7 100644 --- a/src/java.desktop/windows/classes/sun/print/Win32PrintService.java +++ b/src/java.desktop/windows/classes/sun/print/Win32PrintService.java @@ -78,7 +78,7 @@ import javax.print.event.PrintServiceAttributeListener; import sun.awt.windows.WPrinterJob; -public class Win32PrintService implements PrintService, AttributeUpdater, +public final class Win32PrintService implements PrintService, AttributeUpdater, SunPrinterJobService { public static MediaSize[] predefMedia = Win32MediaSize.getPredefMedia(); @@ -242,6 +242,7 @@ public void invalidateService() { isInvalid = true; } + @Override public String getName() { return printer; } @@ -857,6 +858,7 @@ private boolean isSupportedResolution(PrinterResolution res) { return false; } + @Override public DocPrintJob createPrintJob() { return new Win32PrintJob(this); } @@ -868,6 +870,7 @@ private PrintServiceAttributeSet getDynamicAttributes() { return attrs; } + @Override public PrintServiceAttributeSet getUpdatedAttributes() { PrintServiceAttributeSet currSet = getDynamicAttributes(); if (lastSet == null) { @@ -896,6 +899,7 @@ public void wakeNotifier() { } } + @Override public void addPrintServiceAttributeListener(PrintServiceAttributeListener listener) { synchronized (this) { @@ -909,6 +913,7 @@ public void addPrintServiceAttributeListener(PrintServiceAttributeListener } } + @Override public void removePrintServiceAttributeListener( PrintServiceAttributeListener listener) { synchronized (this) { @@ -923,6 +928,7 @@ public void removePrintServiceAttributeListener( } } + @Override @SuppressWarnings("unchecked") public T getAttribute(Class category) @@ -955,6 +961,7 @@ public void removePrintServiceAttributeListener( } } + @Override public PrintServiceAttributeSet getAttributes() { PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet(); @@ -979,6 +986,7 @@ public PrintServiceAttributeSet getAttributes() { return AttributeSetUtilities.unmodifiableView(attrs); } + @Override public DocFlavor[] getSupportedDocFlavors() { int len = supportedFlavors.length; DocFlavor[] supportedDocFlavors; @@ -998,6 +1006,7 @@ public DocFlavor[] getSupportedDocFlavors() { return supportedDocFlavors; } + @Override public boolean isDocFlavorSupported(DocFlavor flavor) { /* To avoid a native query which may be time-consuming * do not invoke native unless postscript support is being queried. @@ -1017,6 +1026,7 @@ public boolean isDocFlavorSupported(DocFlavor flavor) { return false; } + @Override public Class[] getSupportedAttributeCategories() { ArrayList> categList = new ArrayList<>(otherAttrCats.length+3); for (int i=0; i < otherAttrCats.length; i++) { @@ -1049,6 +1059,7 @@ public Class[] getSupportedAttributeCategories() { return categList.toArray(new Class[categList.size()]); } + @Override public boolean isAttributeCategorySupported(Class category) { @@ -1072,6 +1083,7 @@ public Class[] getSupportedAttributeCategories() { return false; } + @Override public Object getDefaultAttributeValue(Class category) { @@ -1255,6 +1267,7 @@ private boolean isAutoSense(DocFlavor flavor) { } } + @Override public Object getSupportedAttributeValues(Class category, DocFlavor flavor, @@ -1457,6 +1470,7 @@ private boolean isAutoSense(DocFlavor flavor) { } } + @Override public boolean isAttributeValueSupported(Attribute attr, DocFlavor flavor, AttributeSet attributes) { @@ -1586,6 +1600,7 @@ else if (category == Chromaticity.class) { return true; } + @Override public AttributeSet getUnsupportedAttributes(DocFlavor flavor, AttributeSet attributes) { @@ -1622,7 +1637,7 @@ else if (!isAttributeValueSupported(attr, flavor, attributes)) { private Win32DocumentPropertiesUI docPropertiesUI = null; - private static class Win32DocumentPropertiesUI + private static final class Win32DocumentPropertiesUI extends DocumentPropertiesUI { Win32PrintService service; @@ -1631,6 +1646,7 @@ private Win32DocumentPropertiesUI(Win32PrintService s) { service = s; } + @Override public PrintRequestAttributeSet showDocumentProperties(PrinterJob job, Window owner, @@ -1649,7 +1665,7 @@ private synchronized DocumentPropertiesUI getDocumentPropertiesUI() { return new Win32DocumentPropertiesUI(this); } - private static class Win32ServiceUIFactory extends ServiceUIFactory { + private static final class Win32ServiceUIFactory extends ServiceUIFactory { Win32PrintService service; @@ -1657,6 +1673,7 @@ private static class Win32ServiceUIFactory extends ServiceUIFactory { service = s; } + @Override public Object getUI(int role, String ui) { if (role <= ServiceUIFactory.MAIN_UIROLE) { return null; @@ -1669,6 +1686,7 @@ public Object getUI(int role, String ui) { throw new IllegalArgumentException("Unsupported role"); } + @Override public String[] getUIClassNamesForRole(int role) { if (role <= ServiceUIFactory.MAIN_UIROLE) { @@ -1685,6 +1703,7 @@ public String[] getUIClassNamesForRole(int role) { private Win32ServiceUIFactory uiFactory = null; + @Override public synchronized ServiceUIFactory getServiceUIFactory() { if (uiFactory == null) { uiFactory = new Win32ServiceUIFactory(this); @@ -1692,20 +1711,24 @@ public synchronized ServiceUIFactory getServiceUIFactory() { return uiFactory; } + @Override public String toString() { return "Win32 Printer : " + getName(); } + @Override public boolean equals(Object obj) { return (obj == this || (obj instanceof Win32PrintService && ((Win32PrintService)obj).getName().equals(getName()))); } + @Override public int hashCode() { return this.getClass().hashCode()+getName().hashCode(); } + @Override public boolean usesClass(Class c) { return (c == sun.awt.windows.WPrinterJob.class); } @@ -1727,7 +1750,7 @@ private native float[] getMediaPrintableArea(String printerName, } @SuppressWarnings("serial") // JDK implementation class -class Win32MediaSize extends MediaSizeName { +final class Win32MediaSize extends MediaSizeName { private static ArrayList winStringTable = new ArrayList<>(); private static ArrayList winEnumTable = new ArrayList<>(); private static MediaSize[] predefMedia; @@ -1787,11 +1810,13 @@ int getDMPaper() { return dmPaperID; } + @Override protected String[] getStringTable() { String[] nameTable = new String[winStringTable.size()]; return winStringTable.toArray(nameTable); } + @Override protected EnumSyntax[] getEnumValueTable() { MediaSizeName[] enumTable = new MediaSizeName[winEnumTable.size()]; return winEnumTable.toArray(enumTable); diff --git a/src/java.desktop/windows/classes/sun/swing/plaf/windows/ClassicSortArrowIcon.java b/src/java.desktop/windows/classes/sun/swing/plaf/windows/ClassicSortArrowIcon.java index 6430a71f06ebc..f1180b3ae38a9 100644 --- a/src/java.desktop/windows/classes/sun/swing/plaf/windows/ClassicSortArrowIcon.java +++ b/src/java.desktop/windows/classes/sun/swing/plaf/windows/ClassicSortArrowIcon.java @@ -37,7 +37,7 @@ * */ @SuppressWarnings("serial") // JDK-implementation class -public class ClassicSortArrowIcon implements Icon, UIResource, Serializable{ +public final class ClassicSortArrowIcon implements Icon, UIResource, Serializable{ private static final int X_OFFSET = 9; private boolean ascending; @@ -45,6 +45,7 @@ public ClassicSortArrowIcon(boolean ascending) { this.ascending = ascending; } + @Override public void paintIcon(Component c, Graphics g, int x, int y) { x += X_OFFSET; if (ascending) { @@ -89,9 +90,11 @@ private void drawSide(Graphics g, int x, int y, int xIncrement) { g.fillRect(x, y, 1, 2); } + @Override public int getIconWidth() { return X_OFFSET + 8; } + @Override public int getIconHeight() { return 9; } From 1889dacb1981d3d15174bc5a201e683a6cdab725 Mon Sep 17 00:00:00 2001 From: Alisen Chung Date: Tue, 22 Apr 2025 16:01:34 +0000 Subject: [PATCH 0703/1101] 8353007: Open some JComboBox bugs 2 Reviewed-by: kizune, honkar --- .../jdk/javax/swing/JComboBox/bug4185024.java | 109 +++++++++++++++ .../jdk/javax/swing/JComboBox/bug4201964.java | 77 +++++++++++ .../jdk/javax/swing/JComboBox/bug4249732.java | 72 ++++++++++ .../jdk/javax/swing/JComboBox/bug4368848.java | 129 ++++++++++++++++++ 4 files changed, 387 insertions(+) create mode 100644 test/jdk/javax/swing/JComboBox/bug4185024.java create mode 100644 test/jdk/javax/swing/JComboBox/bug4201964.java create mode 100644 test/jdk/javax/swing/JComboBox/bug4249732.java create mode 100644 test/jdk/javax/swing/JComboBox/bug4368848.java diff --git a/test/jdk/javax/swing/JComboBox/bug4185024.java b/test/jdk/javax/swing/JComboBox/bug4185024.java new file mode 100644 index 0000000000000..da0360143d66e --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4185024.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.BorderLayout; +import java.awt.Point; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.JPanel; + +/* + * @test + * @bug 4185024 + * @summary Tests that Heavyweight combo boxes on JDesktop work correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4185024 + */ + +public class bug4185024 { + private static final String INSTRUCTIONS = """ + Click on the JComboBox button inside the JInternalFrame to bring up the menu. + Select one of the menu items and verify that the choice is highlighted correctly. + Click and drag the menu's scroll bar down and verify that it causes the menu to scroll down. + + Inside JInternalFrame: + This test is for the JComboBox in the JInternalFrame. + To test, please click on the combobox and check the following: + Does the selection in the popup list follow the mouse? + Does the popup list respond to clicking and dragging the scroll bar? + If so, press PASS, otherwise, press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4185024::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4185024"); + JPanel p = new JPanel(); + p.setLayout(new BorderLayout()); + JDesktopPane desktop = new JDesktopPane(); + p.add(desktop); + frame.add(p); + + JComboBox months = new JComboBox(); + months.addItem("January"); + months.addItem("February"); + months.addItem("March"); + months.addItem("April"); + months.addItem("May"); + months.addItem("June"); + months.addItem("July"); + months.addItem("August"); + months.addItem("September"); + months.addItem("October"); + months.addItem("November"); + months.addItem("December"); + months.getAccessibleContext().setAccessibleName("Months"); + months.getAccessibleContext().setAccessibleDescription("Choose a month of the year"); + + // Set this to true and the popup works correctly... + months.setLightWeightPopupEnabled(false); + + addFrame("Months", desktop, months); + + frame.setSize(300, 300); + return frame; + } + + private static void addFrame(String title, JDesktopPane desktop, JComponent component) { + JInternalFrame jf = new JInternalFrame(title); + Point newPos = new Point(20, 20); + jf.setResizable(true); + jf.add(component); + jf.setLocation(newPos); + desktop.add(jf); + + jf.pack(); + jf.show(); + } +} diff --git a/test/jdk/javax/swing/JComboBox/bug4201964.java b/test/jdk/javax/swing/JComboBox/bug4201964.java new file mode 100644 index 0000000000000..5c3a0f3019931 --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4201964.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.UIManager; + +/* + * @test + * @bug 4201964 + * @summary Tests that JComboBox's arrow button isn't drawn too wide in Windows Look&Feel + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4201964 + */ + +public class bug4201964 { + private static final String INSTRUCTIONS = """ + Does the arrow look too large? If not, it passes. + """; + + public static void main(String[] args) throws Exception { + try { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + } catch (Exception e) { + PassFailJFrame.forceFail("Couldn't load the Windows look and feel."); + } + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .rows(8) + .columns(30) + .testUI(bug4201964::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4201964"); + JPanel panel = new JPanel(); + JComboBox comboBox; + + comboBox = new JComboBox(new Object[]{ + "Coma Berenices", + "Triangulum", + "Camelopardis", + "Cassiopea"}); + + panel.add(comboBox); + + frame.add(panel); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/javax/swing/JComboBox/bug4249732.java b/test/jdk/javax/swing/JComboBox/bug4249732.java new file mode 100644 index 0000000000000..b8de7fa48b785 --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4249732.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.BorderLayout; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.UIManager; + +/* + * @test + * @bug 4249732 + * @requires (os.family == "windows") + * @summary Tests that Windows editable combo box selects text picked from its list + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4249732 + */ + +public class bug4249732 { + private static final String INSTRUCTIONS = """ + Click on combo box arrow button to open its dropdown list, and + select an item from there. The text in the combo box editor should + be selected, otherwise test fails. + """; + + public static void main(String[] args) throws Exception { + try { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + } catch (Exception e) { + PassFailJFrame.forceFail("Couldn't load the Windows look and feel."); + } + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .rows(8) + .columns(40) + .testUI(bug4249732::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4249732"); + + JComboBox cb = new JComboBox(new Object[]{"foo", "bar", "baz"}); + cb.setEditable(true); + + frame.add(cb, BorderLayout.NORTH); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/javax/swing/JComboBox/bug4368848.java b/test/jdk/javax/swing/JComboBox/bug4368848.java new file mode 100644 index 0000000000000..1673c458cac05 --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4368848.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.DefaultCellEditor; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; + +/* + * @test + * @bug 4368848 + * @summary Tests that mouse wheel events cancel popups + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4368848 + */ + +public class bug4368848 { + static final String[] names = {"First Name", "Last Name", "Veggy"}; + static Object[][] data = { + {"Mark", "Andrews", false}, + {"Tom", "Ball", false}, + {"Alan", "Chung", false}, + {"Jeff", "Dinkins", false}, + {"Amy", "Fowler", false}, + {"Brian", "Gerhold", false}, + {"James", "Gosling", false}, + {"David", "Karlton", false}, + {"Dave", "Kloba", false}, + {"Peter", "Korn", false}, + {"Phil", "Milne", false}, + {"Dave", "Moore", false}, + {"Hans", "Muller", false}, + {"Rick", "Levenson", false}, + {"Tim", "Prinzing", false}, + {"Chester", "Rose", false}, + {"Ray", "Ryan", false}, + {"Georges", "Saab", false}, + {"Willie", "Walker", false}, + {"Kathy", "Walrath", false}, + {"Arnaud", "Weber", false} + }; + + private static final String INSTRUCTIONS = """ + Click any cell in the 'Veggy' column, so that combo box appears. + Make sure mouse pointer is over the table, but _not_ over the combo + box. Try scrolling the table using the mouse wheel. The combo popup + should disappear. If it stays visible, test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4368848::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4368848"); + ExampleTableModel dataModel = new ExampleTableModel(); + + JComboBox _editor = new JComboBox(); + _editor.addItem(false); + _editor.addItem(true); + + JTable tableView = new JTable(dataModel); + tableView.setDefaultEditor(Boolean.class, new DefaultCellEditor(_editor)); + + frame.add(new JScrollPane(tableView)); + frame.setSize(200, 200); + return frame; + } + + static class ExampleTableModel extends AbstractTableModel { + // These methods always need to be implemented. + @Override + public int getColumnCount() { + return names.length; + } + + @Override + public int getRowCount() { + return data.length; + } + + public Object getValueAt(int row, int col) { + return data[row][col]; + } + + @Override + public boolean isCellEditable(int row, int col) { + return true; + } + + @Override + public String getColumnName(int column) { + return names[column]; + } + + @Override + public Class getColumnClass(int col) { + return getValueAt(0, col).getClass(); + } + } +} From 6a310613392b9d619ae1bbe3e663cb4a022165d9 Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Tue, 22 Apr 2025 16:11:55 +0000 Subject: [PATCH 0704/1101] 8354248: Open source several AWT GridBagLayout and List tests Reviewed-by: abhiscxk --- test/jdk/ProblemList.txt | 2 + .../awt/GridBagLayout/ComponentShortage.java | 99 +++++++++ .../awt/List/ListScrollbarCursorTest.java | 70 +++++++ test/jdk/java/awt/List/ListScrollbarTest.java | 197 ++++++++++++++++++ 4 files changed, 368 insertions(+) create mode 100644 test/jdk/java/awt/GridBagLayout/ComponentShortage.java create mode 100644 test/jdk/java/awt/List/ListScrollbarCursorTest.java create mode 100644 test/jdk/java/awt/List/ListScrollbarTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index fe0657ff1650d..56224181b0aa0 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -464,6 +464,7 @@ java/awt/TrayIcon/RightClickWhenBalloonDisplayed/RightClickWhenBalloonDisplayed. java/awt/PopupMenu/PopupMenuLocation.java 8259913,8315878 windows-all,macosx-aarch64 java/awt/GridLayout/ComponentPreferredSize/ComponentPreferredSize.java 8238720,8324782 windows-all,macosx-all java/awt/GridLayout/ChangeGridSize/ChangeGridSize.java 8238720,8324782 windows-all,macosx-all +java/awt/GridBagLayout/ComponentShortage.java 8355280 windows-all,linux-all java/awt/event/MouseEvent/FrameMouseEventAbsoluteCoordsTest/FrameMouseEventAbsoluteCoordsTest.java 8238720 windows-all # Several tests which fail sometimes on macos11 @@ -815,6 +816,7 @@ java/awt/PopupMenu/PopupHangTest.java 8340022 windows-all java/awt/Focus/MinimizeNonfocusableWindowTest.java 8024487 windows-all java/awt/Focus/InactiveFocusRace.java 8023263 linux-all java/awt/List/HandlingKeyEventIfMousePressedTest.java 6848358 macosx-all,windows-all +java/awt/List/ListScrollbarCursorTest.java 8066410 generic-all java/awt/Checkbox/CheckboxBoxSizeTest.java 8340870 windows-all java/awt/Checkbox/CheckboxIndicatorSizeTest.java 8340870 windows-all java/awt/Checkbox/CheckboxNullLabelTest.java 8340870 windows-all diff --git a/test/jdk/java/awt/GridBagLayout/ComponentShortage.java b/test/jdk/java/awt/GridBagLayout/ComponentShortage.java new file mode 100644 index 0000000000000..dd641bbf066c7 --- /dev/null +++ b/test/jdk/java/awt/GridBagLayout/ComponentShortage.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4238932 + * @summary JTextField in gridBagLayout does not properly set MinimumSize + * @key headful + * @run main ComponentShortage + */ + +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Robot; +import javax.swing.JFrame; +import javax.swing.JTextField; + +public class ComponentShortage { + static final int WIDTH_REDUCTION = 50; + static JFrame frame; + static JTextField jtf; + static volatile Dimension size; + static volatile Dimension fSize; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + try { + EventQueue.invokeAndWait(() -> { + frame = new JFrame(); + frame.setLayout(new GridBagLayout()); + GridBagConstraints gBC = new GridBagConstraints(); + + gBC.gridx = 1; + gBC.gridy = 0; + gBC.gridwidth = 1; + gBC.gridheight = 1; + gBC.weightx = 1.0; + gBC.weighty = 0.0; + gBC.fill = GridBagConstraints.NONE; + gBC.anchor = GridBagConstraints.NORTHWEST; + jtf = new JTextField(16); + frame.add(jtf, gBC); + frame.pack(); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + size = jtf.getSize(); + }); + System.out.println("TextField size before Frame's width reduction : " + size); + + EventQueue.invokeAndWait(() -> { + frame.setSize(frame.getSize().width - WIDTH_REDUCTION, frame.getSize().height); + }); + frame.repaint(); + + EventQueue.invokeAndWait(() -> { + size = jtf.getSize(); + fSize = frame.getSize(); + }); + System.out.println("TextField size after Frame's width reduction : " + size); + + if (size.width < fSize.width - WIDTH_REDUCTION) { + throw new RuntimeException("Width of JTextField is too small to be visible."); + } + System.out.println("Test passed."); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } +} diff --git a/test/jdk/java/awt/List/ListScrollbarCursorTest.java b/test/jdk/java/awt/List/ListScrollbarCursorTest.java new file mode 100644 index 0000000000000..fc832029b134a --- /dev/null +++ b/test/jdk/java/awt/List/ListScrollbarCursorTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4290684 + * @summary Tests that cursor on the scrollbar of the list is set to default. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ListScrollbarCursorTest + */ + +import java.awt.Cursor; +import java.awt.Frame; +import java.awt.List; +import java.awt.Panel; + +public class ListScrollbarCursorTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. You see the list in the middle of the panel. + This list has two scrollbars. + 2. The cursor should have a shape of hand over the main area + and a shape of arrow over scrollbars. + 3. Move the mouse cursor to either horizontal or vertical scrollbar. + 4. Press PASS if you see the default arrow cursor else press FAIL. + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(ListScrollbarCursorTest::initialize) + .build() + .awaitAndCheck(); + } + + static Frame initialize() { + Frame frame = new Frame("List Scrollbar Cursor Test"); + Panel panel = new Panel(); + List list = new List(3); + list.add("List item with a very long name" + + "(just to make the horizontal scrollbar visible)"); + list.add("Item 2"); + list.add("Item 3"); + list.setCursor(new Cursor(Cursor.HAND_CURSOR)); + panel.add(list); + frame.add(panel); + frame.setSize(200, 200); + return frame; + } +} diff --git a/test/jdk/java/awt/List/ListScrollbarTest.java b/test/jdk/java/awt/List/ListScrollbarTest.java new file mode 100644 index 0000000000000..b676303b927ab --- /dev/null +++ b/test/jdk/java/awt/List/ListScrollbarTest.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4096445 + * @summary Test to verify List Scollbar appears/disappears automatically + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ListScrollbarTest + */ + +import java.awt.Button; +import java.awt.Component; +import java.awt.Event; +import java.awt.Frame; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.List; + +public class ListScrollbarTest extends Frame { + static final int ITEMS = 10; + List ltList; + List rtList; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. There are two lists added to the Frame separated by + a column of buttons + 2. Double click on any item(s) on the left list, you would see + a '*' added at the end of the item + 3. Keep double clicking on the same item till the length of the + item exceeds the width of the list + 4. Now, if you don't get the horizontal scrollbar on + the left list click FAIL. + 5. If you get horizontal scrollbar, select the item + (that you double clicked) and press the '>' button + to move the item to the right list. + 6. If horizontal scroll bar appears on the right list + as well as disappears from the left list [only if both + happen] proceed with step 8 else click FAIL + 7. Now move the same item to the left list, by pressing + '<' button + 8. If the horizontal scrollbar appears on the left list + and disappears from the right list[only if both happen] + click PASS else click FAIL. + """; + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(ListScrollbarTest::new) + .build() + .awaitAndCheck(); + } + + public ListScrollbarTest() { + super("List scroll bar test"); + GridBagLayout gbl = new GridBagLayout(); + ltList = new List(ITEMS, true); + rtList = new List(0, true); + setLayout(gbl); + add(ltList, 0, 0, 1, 5, 1.0, 1.0); + add(rtList, 2, 0, 1, 5, 1.0, 1.0); + add(new Button(">"), 1, 0, 1, 1, 0, 1.0); + add(new Button(">>"), 1, 1, 1, 1, 0, 1.0); + add(new Button("<"), 1, 2, 1, 1, 0, 1.0); + add(new Button("<<"), 1, 3, 1, 1, 0, 1.0); + add(new Button("!"), 1, 4, 1, 1, 0, 1.0); + + for (int i = 0; i < ITEMS; i++) { + ltList.addItem("item " + i); + } + setSize(220, 250); + } + + void add(Component comp, int x, int y, int w, int h, double weightx, double weighty) { + GridBagLayout gbl = (GridBagLayout) getLayout(); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + c.gridx = x; + c.gridy = y; + c.gridwidth = w; + c.gridheight = h; + c.weightx = weightx; + c.weighty = weighty; + add(comp); + gbl.setConstraints(comp, c); + } + + void reverseSelections(List l) { + for (int i = 0; i < l.countItems(); i++) { + if (l.isSelected(i)) { + l.deselect(i); + } else { + l.select(i); + } + } + } + + void deselectAll(List l) { + for (int i = 0; i < l.countItems(); i++) { + l.deselect(i); + } + } + + void replaceItem(List l, String item) { + for (int i = 0; i < l.countItems(); i++) { + if (l.getItem(i).equals(item)) { + l.replaceItem(item + "*", i); + } + } + } + + void move(List l1, List l2, boolean all) { + + // if all the items are to be moved + if (all) { + for (int i = 0; i < l1.countItems(); i++) { + l2.addItem(l1.getItem(i)); + } + l1.delItems(0, l1.countItems() - 1); + } else { // else move the selected items + String[] items = l1.getSelectedItems(); + int[] itemIndexes = l1.getSelectedIndexes(); + + deselectAll(l2); + for (int i = 0; i < items.length; i++) { + l2.addItem(items[i]); + l2.select(l2.countItems() - 1); + if (i == 0) { + l2.makeVisible(l2.countItems() - 1); + } + } + for (int i = itemIndexes.length - 1; i >= 0; i--) { + l1.delItem(itemIndexes[i]); + } + } + } + + @Override + public boolean action(Event evt, Object arg) { + if (">".equals(arg)) { + move(ltList, rtList, false); + } else if (">>".equals(arg)) { + move(ltList, rtList, true); + } else if ("<".equals(arg)) { + move(rtList, ltList, false); + } else if ("<<".equals(arg)) { + move(rtList, ltList, true); + } else if ("!".equals(arg)) { + if (ltList.getSelectedItems().length > 0) { + reverseSelections(ltList); + } else if (rtList.getSelectedItems().length > 0) { + reverseSelections(rtList); + } + } else if (evt.target == rtList || evt.target == ltList) { + replaceItem((List) evt.target, (String) arg); + } else { + return false; + } + return true; + } + + @Override + public boolean handleEvent(Event evt) { + if (evt.id == Event.LIST_SELECT + || evt.id == Event.LIST_DESELECT) { + if (evt.target == ltList) { + deselectAll(rtList); + } else if (evt.target == rtList) { + deselectAll(ltList); + } + return true; + } + return super.handleEvent(evt); + } +} From d783a940988677dc91975f884adeaf9f047f7e07 Mon Sep 17 00:00:00 2001 From: Boris Ulasevich Date: Tue, 22 Apr 2025 16:46:44 +0000 Subject: [PATCH 0705/1101] 8332368: ubsan aarch64: immediate_aarch64.cpp:298:31: runtime error: shift exponent 32 is too large for 32-bit type 'int' Reviewed-by: adinn --- src/hotspot/share/adlc/output_h.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/adlc/output_h.cpp b/src/hotspot/share/adlc/output_h.cpp index a4ab29008f0af..dd149064a5a8f 100644 --- a/src/hotspot/share/adlc/output_h.cpp +++ b/src/hotspot/share/adlc/output_h.cpp @@ -870,7 +870,8 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " void step(uint cycles) {\n"); fprintf(fp_hpp, " _used = 0;\n"); - fprintf(fp_hpp, " _mask <<= cycles;\n"); + fprintf(fp_hpp, " uint max_shift = 8 * sizeof(_mask) - 1;\n"); + fprintf(fp_hpp, " _mask <<= (cycles < max_shift) ? cycles : max_shift;\n"); fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " friend class Pipeline_Use;\n"); fprintf(fp_hpp, "};\n\n"); From 594b26516e5c01d7daa331db59bdbe8ab7dc0a6d Mon Sep 17 00:00:00 2001 From: Jamil Nimeh Date: Tue, 22 Apr 2025 16:49:29 +0000 Subject: [PATCH 0706/1101] 8350126: Regression ~3% on Crypto-ChaCha20Poly1305.encrypt for MacOSX aarch64 Reviewed-by: aph --- .../cpu/aarch64/macroAssembler_aarch64.hpp | 16 +- .../aarch64/macroAssembler_aarch64_chacha.cpp | 149 +++++-- .../cpu/aarch64/stubGenerator_aarch64.cpp | 408 +++++++++--------- 3 files changed, 315 insertions(+), 258 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 11d1985e50bf4..af09f97e93854 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2024, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1611,11 +1611,15 @@ class MacroAssembler: public Assembler { void aes_round(FloatRegister input, FloatRegister subkey); // ChaCha20 functions support block - void cc20_quarter_round(FloatRegister aVec, FloatRegister bVec, - FloatRegister cVec, FloatRegister dVec, FloatRegister scratch, - FloatRegister tbl); - void cc20_shift_lane_org(FloatRegister bVec, FloatRegister cVec, - FloatRegister dVec, bool colToDiag); + void cc20_qr_add4(FloatRegister (&addFirst)[4], + FloatRegister (&addSecond)[4]); + void cc20_qr_xor4(FloatRegister (&firstElem)[4], + FloatRegister (&secondElem)[4], FloatRegister (&result)[4]); + void cc20_qr_lrot4(FloatRegister (&sourceReg)[4], + FloatRegister (&destReg)[4], int bits, FloatRegister table); + void cc20_set_qr_registers(FloatRegister (&vectorSet)[4], + const FloatRegister (&stateVectors)[16], int idx1, int idx2, + int idx3, int idx4); // Place an ISB after code may have been modified due to a safepoint. void safepoint_isb(); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64_chacha.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64_chacha.cpp index 1f7bb8f46f64f..083e81af5d969 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64_chacha.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64_chacha.cpp @@ -28,60 +28,119 @@ #include "runtime/stubRoutines.hpp" /** - * Perform the quarter round calculations on values contained within - * four SIMD registers. + * Perform the vectorized add for a group of 4 quarter round operations. + * In the ChaCha20 quarter round, there are two add ops: a += b and c += d. + * Each parameter is a set of 4 registers representing the 4 registers + * for the each addend in the add operation for each of the quarter rounds. + * (e.g. for "a" it would consist of v0/v1/v2/v3). The result of the add + * is placed into the vectors in the "addFirst" array. * - * @param aVec the SIMD register containing only the "a" values - * @param bVec the SIMD register containing only the "b" values - * @param cVec the SIMD register containing only the "c" values - * @param dVec the SIMD register containing only the "d" values - * @param scratch scratch SIMD register used for 12 and 7 bit left rotations - * @param table the SIMD register used as a table for 8 bit left rotations + * @param addFirst array of SIMD registers representing the first addend. + * @param addSecond array of SIMD registers representing the second addend. */ -void MacroAssembler::cc20_quarter_round(FloatRegister aVec, FloatRegister bVec, - FloatRegister cVec, FloatRegister dVec, FloatRegister scratch, - FloatRegister table) { +void MacroAssembler::cc20_qr_add4(FloatRegister (&addFirst)[4], + FloatRegister (&addSecond)[4]) { + for (int i = 0; i < 4; i++) { + addv(addFirst[i], T4S, addFirst[i], addSecond[i]); + } +} + + +/** + * Perform the vectorized XOR for a group of 4 quarter round operations. + * In the ChaCha20 quarter round, there are two XOR ops: d ^= a and b ^= c + * Each parameter is a set of 4 registers representing the 4 registers + * for the each element in the xor operation for each of the quarter rounds. + * (e.g. for "a" it would consist of v0/v1/v2/v3) + * Note: because the b ^= c ops precede a non-byte-aligned left-rotation, + * there is a third parameter which can take a set of scratch registers + * for the result, which facilitates doing the subsequent operations for + * the left rotation. + * + * @param firstElem array of SIMD registers representing the first element. + * @param secondElem array of SIMD registers representing the second element. + * @param result array of SIMD registers representing the destination. + * May be the same as firstElem or secondElem, or a separate array. + */ +void MacroAssembler::cc20_qr_xor4(FloatRegister (&firstElem)[4], + FloatRegister (&secondElem)[4], FloatRegister (&result)[4]) { + for (int i = 0; i < 4; i++) { + eor(result[i], T16B, firstElem[i], secondElem[i]); + } +} + +/** + * Perform the vectorized left-rotation on 32-bit lanes for a group of + * 4 quarter round operations. + * Each parameter is a set of 4 registers representing the 4 registers + * for the each element in the source and destination for each of the quarter + * rounds (e.g. for "d" it would consist of v12/v13/v14/v15 on columns and + * v15/v12/v13/v14 on diagonal alignments). + * + * @param sourceReg array of SIMD registers representing the source + * @param destReg array of SIMD registers representing the destination + * @param bits the distance of the rotation in bits, must be 16/12/8/7 per + * the ChaCha20 specification. + */ +void MacroAssembler::cc20_qr_lrot4(FloatRegister (&sourceReg)[4], + FloatRegister (&destReg)[4], int bits, FloatRegister table) { + switch (bits) { + case 16: // reg <<<= 16, in-place swap of half-words + for (int i = 0; i < 4; i++) { + rev32(destReg[i], T8H, sourceReg[i]); + } + break; - // a += b, d ^= a, d <<<= 16 - addv(aVec, T4S, aVec, bVec); - eor(dVec, T16B, dVec, aVec); - rev32(dVec, T8H, dVec); + case 7: // reg <<<= (12 || 7) + case 12: // r-shift src -> dest, l-shift src & ins to dest + for (int i = 0; i < 4; i++) { + ushr(destReg[i], T4S, sourceReg[i], 32 - bits); + } - // c += d, b ^= c, b <<<= 12 - addv(cVec, T4S, cVec, dVec); - eor(scratch, T16B, bVec, cVec); - ushr(bVec, T4S, scratch, 20); - sli(bVec, T4S, scratch, 12); + for (int i = 0; i < 4; i++) { + sli(destReg[i], T4S, sourceReg[i], bits); + } + break; - // a += b, d ^= a, d <<<= 8 - addv(aVec, T4S, aVec, bVec); - eor(dVec, T16B, dVec, aVec); - tbl(dVec, T16B, dVec, 1, table); + case 8: // reg <<<= 8, simulate left rotation with table reorg + for (int i = 0; i < 4; i++) { + tbl(destReg[i], T16B, sourceReg[i], 1, table); + } + break; - // c += d, b ^= c, b <<<= 7 - addv(cVec, T4S, cVec, dVec); - eor(scratch, T16B, bVec, cVec); - ushr(bVec, T4S, scratch, 25); - sli(bVec, T4S, scratch, 7); + default: + // The caller shouldn't be sending bit rotation values outside + // of the 16/12/8/7 as defined in the specification. + ShouldNotReachHere(); + } } /** - * Shift the b, c, and d vectors between columnar and diagonal representations. - * Note that the "a" vector does not shift. + * Set the FloatRegisters for a 4-vector register set. These will be used + * during various quarter round transformations (adds, xors and left-rotations). + * This method itself does not result in the output of any assembly + * instructions. It just organizes the vectors so they can be in columnar or + * diagonal alignments. * - * @param bVec the SIMD register containing only the "b" values - * @param cVec the SIMD register containing only the "c" values - * @param dVec the SIMD register containing only the "d" values - * @param colToDiag true if moving columnar to diagonal, false if - * moving diagonal back to columnar. + * @param vectorSet a 4-vector array to be altered into a new alignment + * @param stateVectors the 16-vector array that represents the current + * working state. The indices of this array match up with the + * organization of the ChaCha20 state per RFC 7539 (e.g. stateVectors[12] + * would contain the vector that holds the 32-bit counter, etc.) + * @param idx1 the index of the stateVectors array to be assigned to the + * first vectorSet element. + * @param idx2 the index of the stateVectors array to be assigned to the + * second vectorSet element. + * @param idx3 the index of the stateVectors array to be assigned to the + * third vectorSet element. + * @param idx4 the index of the stateVectors array to be assigned to the + * fourth vectorSet element. */ -void MacroAssembler::cc20_shift_lane_org(FloatRegister bVec, FloatRegister cVec, - FloatRegister dVec, bool colToDiag) { - int bShift = colToDiag ? 4 : 12; - int cShift = 8; - int dShift = colToDiag ? 12 : 4; - - ext(bVec, T16B, bVec, bVec, bShift); - ext(cVec, T16B, cVec, cVec, cShift); - ext(dVec, T16B, dVec, dVec, dShift); +void MacroAssembler::cc20_set_qr_registers(FloatRegister (&vectorSet)[4], + const FloatRegister (&stateVectors)[16], int idx1, int idx2, + int idx3, int idx4) { + vectorSet[0] = stateVectors[idx1]; + vectorSet[1] = stateVectors[idx2]; + vectorSet[2] = stateVectors[idx3]; + vectorSet[3] = stateVectors[idx4]; } diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 467505ed33784..a6cc757f6a0f8 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -4405,89 +4405,44 @@ class StubGenerator: public StubCodeGenerator { return start; } - /** - * Arguments: - * - * Inputs: - * c_rarg0 - int crc - * c_rarg1 - byte* buf - * c_rarg2 - int length - * - * Output: - * rax - int crc result - */ - address generate_updateBytesCRC32() { - assert(UseCRC32Intrinsics, "what are we doing here?"); - - __ align(CodeEntryAlignment); - StubGenStubId stub_id = StubGenStubId::updateBytesCRC32_id; - StubCodeMark mark(this, stub_id); - - address start = __ pc(); - - const Register crc = c_rarg0; // crc - const Register buf = c_rarg1; // source java byte array address - const Register len = c_rarg2; // length - const Register table0 = c_rarg3; // crc_table address - const Register table1 = c_rarg4; - const Register table2 = c_rarg5; - const Register table3 = c_rarg6; - const Register tmp3 = c_rarg7; - - BLOCK_COMMENT("Entry:"); - __ enter(); // required for proper stackwalking of RuntimeStub frame - - __ kernel_crc32(crc, buf, len, - table0, table1, table2, table3, rscratch1, rscratch2, tmp3); - - __ leave(); // required for proper stackwalking of RuntimeStub frame - __ ret(lr); - - return start; - } - - // ChaCha20 block function. This version parallelizes 4 quarter - // round operations at a time. It uses 16 SIMD registers to - // produce 4 blocks of key stream. + // ChaCha20 block function. This version parallelizes the 32-bit + // state elements on each of 16 vectors, producing 4 blocks of + // keystream at a time. // // state (int[16]) = c_rarg0 // keystream (byte[256]) = c_rarg1 - // return - number of bytes of keystream (always 256) + // return - number of bytes of produced keystream (always 256) // - // In this approach, we load the 512-bit start state sequentially into - // 4 128-bit vectors. We then make 4 4-vector copies of that starting - // state, with each successive set of 4 vectors having a +1 added into - // the first 32-bit lane of the 4th vector in that group (the counter). - // By doing this, we can perform the block function on 4 512-bit blocks - // within one run of this intrinsic. - // The alignment of the data across the 4-vector group is such that at - // the start it is already aligned for the first round of each two-round - // loop iteration. In other words, the corresponding lanes of each vector - // will contain the values needed for that quarter round operation (e.g. - // elements 0/4/8/12, 1/5/9/13, 2/6/10/14, etc.). - // In between each full round, a lane shift must occur. Within a loop - // iteration, between the first and second rounds, the 2nd, 3rd, and 4th - // vectors are rotated left 32, 64 and 96 bits, respectively. The result - // is effectively a diagonal orientation in columnar form. After the - // second full round, those registers are left-rotated again, this time - // 96, 64, and 32 bits - returning the vectors to their columnar organization. - // After all 10 iterations, the original state is added to each 4-vector - // working state along with the add mask, and the 4 vector groups are - // sequentially written to the memory dedicated for the output key stream. - // - // For a more detailed explanation, see Goll and Gueron, "Vectorization of - // ChaCha Stream Cipher", 2014 11th Int. Conf. on Information Technology: - // New Generations, Las Vegas, NV, USA, April 2014, DOI: 10.1109/ITNG.2014.33 - address generate_chacha20Block_qrpar() { - Label L_Q_twoRounds, L_Q_cc20_const; + // This implementation takes each 32-bit integer from the state + // array and broadcasts it across all 4 32-bit lanes of a vector register + // (e.g. state[0] is replicated on all 4 lanes of v4, state[1] to all 4 lanes + // of v5, etc.). Once all 16 elements have been broadcast onto 16 vectors, + // the quarter round schedule is implemented as outlined in RFC 7539 section + // 2.3. However, instead of sequentially processing the 3 quarter round + // operations represented by one QUARTERROUND function, we instead stack all + // the adds, xors and left-rotations from the first 4 quarter rounds together + // and then do the same for the second set of 4 quarter rounds. This removes + // some latency that would otherwise be incurred by waiting for an add to + // complete before performing an xor (which depends on the result of the + // add), etc. An adjustment happens between the first and second groups of 4 + // quarter rounds, but this is done only in the inputs to the macro functions + // that generate the assembly instructions - these adjustments themselves are + // not part of the resulting assembly. + // The 4 registers v0-v3 are used during the quarter round operations as + // scratch registers. Once the 20 rounds are complete, these 4 scratch + // registers become the vectors involved in adding the start state back onto + // the post-QR working state. After the adds are complete, each of the 16 + // vectors write their first lane back to the keystream buffer, followed + // by the second lane from all vectors and so on. + address generate_chacha20Block_blockpar() { + Label L_twoRounds, L_cc20_const; // The constant data is broken into two 128-bit segments to be loaded - // onto SIMD registers. The first 128 bits are a counter add overlay - // that adds +1/+0/+0/+0 to the vectors holding replicated state[12]. + // onto FloatRegisters. The first 128 bits are a counter add overlay + // that adds +0/+1/+2/+3 to the vector holding replicated state[12]. // The second 128-bits is a table constant used for 8-bit left rotations. - // on 32-bit lanes within a SIMD register. - __ BIND(L_Q_cc20_const); - __ emit_int64(0x0000000000000001UL); - __ emit_int64(0x0000000000000000UL); + __ BIND(L_cc20_const); + __ emit_int64(0x0000000100000000UL); + __ emit_int64(0x0000000300000002UL); __ emit_int64(0x0605040702010003UL); __ emit_int64(0x0E0D0C0F0A09080BUL); @@ -4497,144 +4452,142 @@ class StubGenerator: public StubCodeGenerator { address start = __ pc(); __ enter(); + int i, j; const Register state = c_rarg0; const Register keystream = c_rarg1; const Register loopCtr = r10; const Register tmpAddr = r11; + const FloatRegister ctrAddOverlay = v28; + const FloatRegister lrot8Tbl = v29; + + // Organize SIMD registers in an array that facilitates + // putting repetitive opcodes into loop structures. It is + // important that each grouping of 4 registers is monotonically + // increasing to support the requirements of multi-register + // instructions (e.g. ld4r, st4, etc.) + const FloatRegister workSt[16] = { + v4, v5, v6, v7, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27 + }; - const FloatRegister aState = v0; - const FloatRegister bState = v1; - const FloatRegister cState = v2; - const FloatRegister dState = v3; - const FloatRegister a1Vec = v4; - const FloatRegister b1Vec = v5; - const FloatRegister c1Vec = v6; - const FloatRegister d1Vec = v7; - // Skip the callee-saved registers v8 - v15 - const FloatRegister a2Vec = v16; - const FloatRegister b2Vec = v17; - const FloatRegister c2Vec = v18; - const FloatRegister d2Vec = v19; - const FloatRegister a3Vec = v20; - const FloatRegister b3Vec = v21; - const FloatRegister c3Vec = v22; - const FloatRegister d3Vec = v23; - const FloatRegister a4Vec = v24; - const FloatRegister b4Vec = v25; - const FloatRegister c4Vec = v26; - const FloatRegister d4Vec = v27; - const FloatRegister scratch = v28; - const FloatRegister addMask = v29; - const FloatRegister lrot8Tbl = v30; - - // Load the initial state in the first 4 quadword registers, - // then copy the initial state into the next 4 quadword registers - // that will be used for the working state. - __ ld1(aState, bState, cState, dState, __ T16B, Address(state)); - - // Load the index register for 2 constant 128-bit data fields. - // The first represents the +1/+0/+0/+0 add mask. The second is - // the 8-bit left rotation. - __ adr(tmpAddr, L_Q_cc20_const); - __ ldpq(addMask, lrot8Tbl, Address(tmpAddr)); - - __ mov(a1Vec, __ T16B, aState); - __ mov(b1Vec, __ T16B, bState); - __ mov(c1Vec, __ T16B, cState); - __ mov(d1Vec, __ T16B, dState); - - __ mov(a2Vec, __ T16B, aState); - __ mov(b2Vec, __ T16B, bState); - __ mov(c2Vec, __ T16B, cState); - __ addv(d2Vec, __ T4S, d1Vec, addMask); - - __ mov(a3Vec, __ T16B, aState); - __ mov(b3Vec, __ T16B, bState); - __ mov(c3Vec, __ T16B, cState); - __ addv(d3Vec, __ T4S, d2Vec, addMask); - - __ mov(a4Vec, __ T16B, aState); - __ mov(b4Vec, __ T16B, bState); - __ mov(c4Vec, __ T16B, cState); - __ addv(d4Vec, __ T4S, d3Vec, addMask); - - // Set up the 10 iteration loop + // Pull in constant data. The first 16 bytes are the add overlay + // which is applied to the vector holding the counter (state[12]). + // The second 16 bytes is the index register for the 8-bit left + // rotation tbl instruction. + __ adr(tmpAddr, L_cc20_const); + __ ldpq(ctrAddOverlay, lrot8Tbl, Address(tmpAddr)); + + // Load from memory and interlace across 16 SIMD registers, + // With each word from memory being broadcast to all lanes of + // each successive SIMD register. + // Addr(0) -> All lanes in workSt[i] + // Addr(4) -> All lanes workSt[i + 1], etc. + __ mov(tmpAddr, state); + for (i = 0; i < 16; i += 4) { + __ ld4r(workSt[i], workSt[i + 1], workSt[i + 2], workSt[i + 3], __ T4S, + __ post(tmpAddr, 16)); + } + __ addv(workSt[12], __ T4S, workSt[12], ctrAddOverlay); // Add ctr overlay + + // Before entering the loop, create 5 4-register arrays. These + // will hold the 4 registers that represent the a/b/c/d fields + // in the quarter round operation. For instance the "b" field + // for the first 4 quarter round operations is the set of v16/v17/v18/v19, + // but in the second 4 quarter rounds it gets adjusted to v17/v18/v19/v16 + // since it is part of a diagonal organization. The aSet and scratch + // register sets are defined at declaration time because they do not change + // organization at any point during the 20-round processing. + FloatRegister aSet[4] = { v4, v5, v6, v7 }; + FloatRegister bSet[4]; + FloatRegister cSet[4]; + FloatRegister dSet[4]; + FloatRegister scratch[4] = { v0, v1, v2, v3 }; + + // Set up the 10 iteration loop and perform all 8 quarter round ops __ mov(loopCtr, 10); - __ BIND(L_Q_twoRounds); - - // The first set of operations on the vectors covers the first 4 quarter - // round operations: - // Qround(state, 0, 4, 8,12) - // Qround(state, 1, 5, 9,13) - // Qround(state, 2, 6,10,14) - // Qround(state, 3, 7,11,15) - __ cc20_quarter_round(a1Vec, b1Vec, c1Vec, d1Vec, scratch, lrot8Tbl); - __ cc20_quarter_round(a2Vec, b2Vec, c2Vec, d2Vec, scratch, lrot8Tbl); - __ cc20_quarter_round(a3Vec, b3Vec, c3Vec, d3Vec, scratch, lrot8Tbl); - __ cc20_quarter_round(a4Vec, b4Vec, c4Vec, d4Vec, scratch, lrot8Tbl); - - // Shuffle the b1Vec/c1Vec/d1Vec to reorganize the state vectors to - // diagonals. The a1Vec does not need to change orientation. - __ cc20_shift_lane_org(b1Vec, c1Vec, d1Vec, true); - __ cc20_shift_lane_org(b2Vec, c2Vec, d2Vec, true); - __ cc20_shift_lane_org(b3Vec, c3Vec, d3Vec, true); - __ cc20_shift_lane_org(b4Vec, c4Vec, d4Vec, true); - - // The second set of operations on the vectors covers the second 4 quarter - // round operations, now acting on the diagonals: - // Qround(state, 0, 5,10,15) - // Qround(state, 1, 6,11,12) - // Qround(state, 2, 7, 8,13) - // Qround(state, 3, 4, 9,14) - __ cc20_quarter_round(a1Vec, b1Vec, c1Vec, d1Vec, scratch, lrot8Tbl); - __ cc20_quarter_round(a2Vec, b2Vec, c2Vec, d2Vec, scratch, lrot8Tbl); - __ cc20_quarter_round(a3Vec, b3Vec, c3Vec, d3Vec, scratch, lrot8Tbl); - __ cc20_quarter_round(a4Vec, b4Vec, c4Vec, d4Vec, scratch, lrot8Tbl); - - // Before we start the next iteration, we need to perform shuffles - // on the b/c/d vectors to move them back to columnar organizations - // from their current diagonal orientation. - __ cc20_shift_lane_org(b1Vec, c1Vec, d1Vec, false); - __ cc20_shift_lane_org(b2Vec, c2Vec, d2Vec, false); - __ cc20_shift_lane_org(b3Vec, c3Vec, d3Vec, false); - __ cc20_shift_lane_org(b4Vec, c4Vec, d4Vec, false); + __ BIND(L_twoRounds); + + // Set to columnar organization and do the following 4 quarter-rounds: + // QUARTERROUND(0, 4, 8, 12) + // QUARTERROUND(1, 5, 9, 13) + // QUARTERROUND(2, 6, 10, 14) + // QUARTERROUND(3, 7, 11, 15) + __ cc20_set_qr_registers(bSet, workSt, 4, 5, 6, 7); + __ cc20_set_qr_registers(cSet, workSt, 8, 9, 10, 11); + __ cc20_set_qr_registers(dSet, workSt, 12, 13, 14, 15); + + __ cc20_qr_add4(aSet, bSet); // a += b + __ cc20_qr_xor4(dSet, aSet, dSet); // d ^= a + __ cc20_qr_lrot4(dSet, dSet, 16, lrot8Tbl); // d <<<= 16 + + __ cc20_qr_add4(cSet, dSet); // c += d + __ cc20_qr_xor4(bSet, cSet, scratch); // b ^= c (scratch) + __ cc20_qr_lrot4(scratch, bSet, 12, lrot8Tbl); // b <<<= 12 + + __ cc20_qr_add4(aSet, bSet); // a += b + __ cc20_qr_xor4(dSet, aSet, dSet); // d ^= a + __ cc20_qr_lrot4(dSet, dSet, 8, lrot8Tbl); // d <<<= 8 + + __ cc20_qr_add4(cSet, dSet); // c += d + __ cc20_qr_xor4(bSet, cSet, scratch); // b ^= c (scratch) + __ cc20_qr_lrot4(scratch, bSet, 7, lrot8Tbl); // b <<<= 12 + + // Set to diagonal organization and do the next 4 quarter-rounds: + // QUARTERROUND(0, 5, 10, 15) + // QUARTERROUND(1, 6, 11, 12) + // QUARTERROUND(2, 7, 8, 13) + // QUARTERROUND(3, 4, 9, 14) + __ cc20_set_qr_registers(bSet, workSt, 5, 6, 7, 4); + __ cc20_set_qr_registers(cSet, workSt, 10, 11, 8, 9); + __ cc20_set_qr_registers(dSet, workSt, 15, 12, 13, 14); + + __ cc20_qr_add4(aSet, bSet); // a += b + __ cc20_qr_xor4(dSet, aSet, dSet); // d ^= a + __ cc20_qr_lrot4(dSet, dSet, 16, lrot8Tbl); // d <<<= 16 + + __ cc20_qr_add4(cSet, dSet); // c += d + __ cc20_qr_xor4(bSet, cSet, scratch); // b ^= c (scratch) + __ cc20_qr_lrot4(scratch, bSet, 12, lrot8Tbl); // b <<<= 12 + + __ cc20_qr_add4(aSet, bSet); // a += b + __ cc20_qr_xor4(dSet, aSet, dSet); // d ^= a + __ cc20_qr_lrot4(dSet, dSet, 8, lrot8Tbl); // d <<<= 8 + + __ cc20_qr_add4(cSet, dSet); // c += d + __ cc20_qr_xor4(bSet, cSet, scratch); // b ^= c (scratch) + __ cc20_qr_lrot4(scratch, bSet, 7, lrot8Tbl); // b <<<= 12 // Decrement and iterate __ sub(loopCtr, loopCtr, 1); - __ cbnz(loopCtr, L_Q_twoRounds); - - // Once the counter reaches zero, we fall out of the loop - // and need to add the initial state back into the working state - // represented by the a/b/c/d1Vec registers. This is destructive - // on the dState register but we no longer will need it. - __ addv(a1Vec, __ T4S, a1Vec, aState); - __ addv(b1Vec, __ T4S, b1Vec, bState); - __ addv(c1Vec, __ T4S, c1Vec, cState); - __ addv(d1Vec, __ T4S, d1Vec, dState); - - __ addv(a2Vec, __ T4S, a2Vec, aState); - __ addv(b2Vec, __ T4S, b2Vec, bState); - __ addv(c2Vec, __ T4S, c2Vec, cState); - __ addv(dState, __ T4S, dState, addMask); - __ addv(d2Vec, __ T4S, d2Vec, dState); - - __ addv(a3Vec, __ T4S, a3Vec, aState); - __ addv(b3Vec, __ T4S, b3Vec, bState); - __ addv(c3Vec, __ T4S, c3Vec, cState); - __ addv(dState, __ T4S, dState, addMask); - __ addv(d3Vec, __ T4S, d3Vec, dState); - - __ addv(a4Vec, __ T4S, a4Vec, aState); - __ addv(b4Vec, __ T4S, b4Vec, bState); - __ addv(c4Vec, __ T4S, c4Vec, cState); - __ addv(dState, __ T4S, dState, addMask); - __ addv(d4Vec, __ T4S, d4Vec, dState); - - // Write the final state back to the result buffer - __ st1(a1Vec, b1Vec, c1Vec, d1Vec, __ T16B, __ post(keystream, 64)); - __ st1(a2Vec, b2Vec, c2Vec, d2Vec, __ T16B, __ post(keystream, 64)); - __ st1(a3Vec, b3Vec, c3Vec, d3Vec, __ T16B, __ post(keystream, 64)); - __ st1(a4Vec, b4Vec, c4Vec, d4Vec, __ T16B, __ post(keystream, 64)); + __ cbnz(loopCtr, L_twoRounds); + + __ mov(tmpAddr, state); + + // Add the starting state back to the post-loop keystream + // state. We read/interlace the state array from memory into + // 4 registers similar to what we did in the beginning. Then + // add the counter overlay onto workSt[12] at the end. + for (i = 0; i < 16; i += 4) { + __ ld4r(v0, v1, v2, v3, __ T4S, __ post(tmpAddr, 16)); + __ addv(workSt[i], __ T4S, workSt[i], v0); + __ addv(workSt[i + 1], __ T4S, workSt[i + 1], v1); + __ addv(workSt[i + 2], __ T4S, workSt[i + 2], v2); + __ addv(workSt[i + 3], __ T4S, workSt[i + 3], v3); + } + __ addv(workSt[12], __ T4S, workSt[12], ctrAddOverlay); // Add ctr overlay + + // Write working state into the keystream buffer. This is accomplished + // by taking the lane "i" from each of the four vectors and writing + // it to consecutive 4-byte offsets, then post-incrementing by 16 and + // repeating with the next 4 vectors until all 16 vectors have been used. + // Then move to the next lane and repeat the process until all lanes have + // been written. + for (i = 0; i < 4; i++) { + for (j = 0; j < 16; j += 4) { + __ st4(workSt[j], workSt[j + 1], workSt[j + 2], workSt[j + 3], __ S, i, + __ post(keystream, 16)); + } + } __ mov(r0, 256); // Return length of output keystream __ leave(); @@ -7008,6 +6961,47 @@ class StubGenerator: public StubCodeGenerator { return start; } + /** + * Arguments: + * + * Inputs: + * c_rarg0 - int crc + * c_rarg1 - byte* buf + * c_rarg2 - int length + * + * Output: + * rax - int crc result + */ + address generate_updateBytesCRC32() { + assert(UseCRC32Intrinsics, "what are we doing here?"); + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = StubGenStubId::updateBytesCRC32_id; + StubCodeMark mark(this, stub_id); + + address start = __ pc(); + + const Register crc = c_rarg0; // crc + const Register buf = c_rarg1; // source java byte array address + const Register len = c_rarg2; // length + const Register table0 = c_rarg3; // crc_table address + const Register table1 = c_rarg4; + const Register table2 = c_rarg5; + const Register table3 = c_rarg6; + const Register tmp3 = c_rarg7; + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + + __ kernel_crc32(crc, buf, len, + table0, table1, table2, table3, rscratch1, rscratch2, tmp3); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(lr); + + return start; + } + /** * Arguments: * @@ -11403,7 +11397,7 @@ class StubGenerator: public StubCodeGenerator { #endif // COMPILER2 if (UseChaCha20Intrinsics) { - StubRoutines::_chacha20Block = generate_chacha20Block_qrpar(); + StubRoutines::_chacha20Block = generate_chacha20Block_blockpar(); } if (UseKyberIntrinsics) { From e020752ea4a6f74c321bc83597fadac51332e188 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 22 Apr 2025 16:55:11 +0000 Subject: [PATCH 0707/1101] 8354484: SIGSEGV when supertype of an AOT-cached class is excluded Reviewed-by: ccheung, shade --- src/hotspot/share/cds/aotArtifactFinder.cpp | 29 +++++++++++++++++++-- src/hotspot/share/cds/aotArtifactFinder.hpp | 1 + 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/cds/aotArtifactFinder.cpp b/src/hotspot/share/cds/aotArtifactFinder.cpp index 95d242c2089cd..65eb06ca7f093 100644 --- a/src/hotspot/share/cds/aotArtifactFinder.cpp +++ b/src/hotspot/share/cds/aotArtifactFinder.cpp @@ -207,11 +207,36 @@ void AOTArtifactFinder::add_aot_inited_class(InstanceKlass* ik) { } } +void AOTArtifactFinder::append_to_all_cached_classes(Klass* k) { + precond(!SystemDictionaryShared::should_be_excluded(k)); + _all_cached_classes->append(k); +} + void AOTArtifactFinder::add_cached_instance_class(InstanceKlass* ik) { + if (CDSConfig::is_dumping_dynamic_archive() && ik->is_shared()) { + // This class is already included in the base archive. No need to cache + // it again in the dynamic archive. + return; + } + bool created; _seen_classes->put_if_absent(ik, &created); if (created) { - _all_cached_classes->append(ik); + append_to_all_cached_classes(ik); + + // All super types must be added. + InstanceKlass* s = ik->java_super(); + if (s != nullptr) { + add_cached_instance_class(s); + } + + Array* interfaces = ik->local_interfaces(); + int len = interfaces->length(); + for (int i = 0; i < len; i++) { + InstanceKlass* intf = interfaces->at(i); + add_cached_instance_class(intf); + } + if (CDSConfig::is_dumping_final_static_archive() && ik->is_shared_unregistered_class()) { // The following are not appliable to unregistered classes return; @@ -229,7 +254,7 @@ void AOTArtifactFinder::add_cached_type_array_class(TypeArrayKlass* tak) { bool created; _seen_classes->put_if_absent(tak, &created); if (created) { - _all_cached_classes->append(tak); + append_to_all_cached_classes(tak); scan_oops_in_array_class(tak); } } diff --git a/src/hotspot/share/cds/aotArtifactFinder.hpp b/src/hotspot/share/cds/aotArtifactFinder.hpp index d890d874af9ef..5d293f20af073 100644 --- a/src/hotspot/share/cds/aotArtifactFinder.hpp +++ b/src/hotspot/share/cds/aotArtifactFinder.hpp @@ -79,6 +79,7 @@ class AOTArtifactFinder : AllStatic { static void scan_oops_in_array_class(ArrayKlass* ak); static void add_cached_type_array_class(TypeArrayKlass* tak); static void add_cached_instance_class(InstanceKlass* ik); + static void append_to_all_cached_classes(Klass* k); public: static void initialize(); static void find_artifacts(); From f98af0ad617a445362859e58af48258bfd5bed03 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Tue, 22 Apr 2025 17:31:31 +0000 Subject: [PATCH 0708/1101] 8354701: Open source few JToolTip tests Reviewed-by: honkar --- .../jdk/javax/swing/JToolTip/TooltipTest.java | 90 +++++++++++++++++++ test/jdk/javax/swing/JToolTip/bug4225314.java | 72 +++++++++++++++ test/jdk/javax/swing/JToolTip/bug4255441.java | 64 +++++++++++++ 3 files changed, 226 insertions(+) create mode 100644 test/jdk/javax/swing/JToolTip/TooltipTest.java create mode 100644 test/jdk/javax/swing/JToolTip/bug4225314.java create mode 100644 test/jdk/javax/swing/JToolTip/bug4255441.java diff --git a/test/jdk/javax/swing/JToolTip/TooltipTest.java b/test/jdk/javax/swing/JToolTip/TooltipTest.java new file mode 100644 index 0000000000000..c081730a8d7b5 --- /dev/null +++ b/test/jdk/javax/swing/JToolTip/TooltipTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4207474 4218495 4375928 + * @summary Tests various tooltip issues: HTML tooltips, long tooltip text + * and mnemonic keys displayed in tooltips + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TooltipTest + */ + +import java.awt.FlowLayout; +import java.awt.event.KeyEvent; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.UIManager; + +public class TooltipTest { + private static final String INSTRUCTIONS = """ + 1. Move the mouse over the button labeled "Red tip" and let it stay + still in order to test HTML in JToolTip. If the tooltip has some + text which is red then test passes, otherwise it fails (bug 4207474). + + 2. Move the mouse over the button labeled "Long tip". + If the last letter of the tooltip appears clipped, + then the test fails. If you can see the entire last character, + then the test passes (bug 4218495). + + 3. Verify that "M" is underlined on the button labeled "Mnemonic" + Move the mouse pointer over the button labeled "Mnemonic" and look + at tooltip when it appears. It should read "hint". + If the above is true test passes else test fails (bug 4375928). + """; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + + PassFailJFrame.builder() + .title("TooltipTest Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(TooltipTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JComponent createTestUI() { + JPanel panel = new JPanel(); + panel.setLayout(new FlowLayout()); + + JButton b = new JButton("Red tip"); + b.setToolTipText("

Here is some " + + "red text.
"); + panel.add(b); + + b = new JButton("Long tip"); + b.setToolTipText("Is the last letter clipped?"); + panel.add(b); + + b = new JButton("Mnemonic"); + b.setMnemonic(KeyEvent.VK_M); + b.setToolTipText("hint"); + panel.add(b); + + return panel; + } +} diff --git a/test/jdk/javax/swing/JToolTip/bug4225314.java b/test/jdk/javax/swing/JToolTip/bug4225314.java new file mode 100644 index 0000000000000..d36bd461272a4 --- /dev/null +++ b/test/jdk/javax/swing/JToolTip/bug4225314.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4225314 + * @summary Tests that tooltip is painted properly when it has thick border + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4225314 + */ + +import java.awt.Color; +import java.awt.FlowLayout; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JToolTip; +import javax.swing.border.LineBorder; + +public class bug4225314 { + private static final String INSTRUCTIONS = """ + The word "Tooltip" in both tooltips should not be clipped by the + black border and be fully visible for this test to pass. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4225314 Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4225314::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JComponent createTestUI() { + JToolTip tt1 = new JToolTip(); + tt1.setTipText("Tooltip"); + tt1.setBorder(new LineBorder(Color.BLACK, 10)); + + JToolTip tt2 = new JToolTip(); + tt2.setTipText("Tooltip"); + tt2.setBorder(new LineBorder(Color.BLACK, 10)); + + JPanel panel = new JPanel(); + panel.setLayout(new FlowLayout()); + panel.add(tt1); + panel.add(tt2); + + return panel; + } +} diff --git a/test/jdk/javax/swing/JToolTip/bug4255441.java b/test/jdk/javax/swing/JToolTip/bug4255441.java new file mode 100644 index 0000000000000..4a90c97550256 --- /dev/null +++ b/test/jdk/javax/swing/JToolTip/bug4255441.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4255441 + * @summary Tests that tooltip appears inside AWT Frame + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4255441 + */ + +import java.awt.FlowLayout; +import java.awt.Frame; +import javax.swing.JButton; + +public class bug4255441 { + private static final String INSTRUCTIONS = """ + Move mouse pointer inside the button. + If a tooltip with "Tooltip text" appears, the test passes. + """; + + private static Frame createTestUI() { + Frame fr = new Frame("bug4255441"); + fr.setLayout(new FlowLayout()); + + JButton bt = new JButton("Button"); + bt.setToolTipText("Tooltip text"); + fr.add(bt); + + fr.setSize(200, 200); + return fr; + } + + public static void main(String[] argv) throws Exception { + PassFailJFrame.builder() + .title("bug4255441 Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4255441::createTestUI) + .build() + .awaitAndCheck(); + } +} From 486a66469bc0c814d07e03ce0e7231b408a4d579 Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Tue, 22 Apr 2025 17:49:52 +0000 Subject: [PATCH 0709/1101] 8353486: Open source Swing Tests - Set 4 Reviewed-by: azvegint, dnguyen, tr --- .../javax/swing/JFileChooser/bug4464774.java | 62 +++++++++ .../javax/swing/JFileChooser/bug4522756.java | 64 +++++++++ .../javax/swing/JFileChooser/bug4759934.java | 124 ++++++++++++++++++ .../javax/swing/JFileChooser/bug4943900.java | 118 +++++++++++++++++ .../javax/swing/JOptionPane/bug4194862.java | 94 +++++++++++++ 5 files changed, 462 insertions(+) create mode 100644 test/jdk/javax/swing/JFileChooser/bug4464774.java create mode 100644 test/jdk/javax/swing/JFileChooser/bug4522756.java create mode 100644 test/jdk/javax/swing/JFileChooser/bug4759934.java create mode 100644 test/jdk/javax/swing/JFileChooser/bug4943900.java create mode 100644 test/jdk/javax/swing/JOptionPane/bug4194862.java diff --git a/test/jdk/javax/swing/JFileChooser/bug4464774.java b/test/jdk/javax/swing/JFileChooser/bug4464774.java new file mode 100644 index 0000000000000..368063e46cd8d --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/bug4464774.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4464774 + * @requires (os.family == "windows") + * @summary JFileChooser: selection of left-side folder buttons shown incorrectly + in Windows L&F + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4464774 + */ + +import javax.swing.JFileChooser; +import javax.swing.UIManager; + +public class bug4464774 { + private static final String INSTRUCTIONS = """ + Click any button from the buttons to the left + ("Documents", "Desktop", "My Computer" etc.) in FileChooser dialog. + When the button is toggled, it should be lowered and + should NOT have focus painted inside it (black dotted frame). + + If the above is true, press PASS else FAIL. + """; + + public static void main(String[] argv) throws Exception { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(65) + .rows(10) + .testUI(() -> { + JFileChooser jfc = new JFileChooser(); + jfc.setControlButtonsAreShown(false); + return jfc; + }) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/javax/swing/JFileChooser/bug4522756.java b/test/jdk/javax/swing/JFileChooser/bug4522756.java new file mode 100644 index 0000000000000..87c430cfb1d67 --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/bug4522756.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4522756 + * @requires (os.family == "windows") + * @summary Verifies that the Desktop icon is not missing when + JFileChooser is opened for the first time. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4522756 + */ + +import javax.swing.JFileChooser; +import javax.swing.UIManager; + +public class bug4522756 { + private static final String INSTRUCTIONS = """ + Verify the following: + + 1. If Desktop icon image is present on the Desktop button + on the left panel of JFileChooser. + 2. Press Desktop button. Check that you actually + go up to the desktop. + + If the above is true, press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .rows(12) + .testUI(() -> { + JFileChooser jfc = new JFileChooser(); + jfc.setControlButtonsAreShown(false); + return jfc; + }) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/javax/swing/JFileChooser/bug4759934.java b/test/jdk/javax/swing/JFileChooser/bug4759934.java new file mode 100644 index 0000000000000..08ccdebfb2be0 --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/bug4759934.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @key headful + * @bug 4759934 + * @summary windows activation problem + * @library /javax/swing/regtesthelpers + * @build Util + * @run main bug4759934 + */ + +import java.awt.Dialog; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +public class bug4759934 { + private static JFrame fr; + private static Dialog dlg; + private static JFileChooser jfc; + + private static JButton frameBtn; + private static JButton dialogBtn; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(50); + + SwingUtilities.invokeAndWait(bug4759934::createTestUI); + robot.waitForIdle(); + robot.delay(1000); + + Point frameBtnLoc = Util.getCenterPoint(frameBtn); + robot.mouseMove(frameBtnLoc.x, frameBtnLoc.y); + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); + robot.delay(500); + + Point dlgBtnLoc = Util.getCenterPoint(dialogBtn); + robot.mouseMove(dlgBtnLoc.x , dlgBtnLoc.y); + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); + robot.delay(500); + + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.delay(500); + + SwingUtilities.invokeAndWait(() -> { + if (frameBtn.hasFocus() && !dialogBtn.hasFocus()) { + throw new RuntimeException("Test failed! Focus was passed back" + + " to Frame instead of Dialog"); + } + }); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (dlg != null) { + dlg.dispose(); + } + if (fr != null) { + fr.dispose(); + } + }); + } + } + + private static void createTestUI() { + fr = new JFrame("bug4759934 - JFrame"); + + frameBtn = new JButton("Show Dialog"); + frameBtn.addActionListener(e -> createDialog()); + fr.add(frameBtn); + + fr.setSize(300, 200); + fr.setLocationRelativeTo(null); + fr.setVisible(true); + } + + private static void createDialog() { + dlg = new JDialog(fr, "bug4759934 - JDialog"); + + dialogBtn = new JButton("Show FileChooser"); + dlg.add(dialogBtn); + + dialogBtn.addActionListener(e -> { + jfc = new JFileChooser(); + jfc.showOpenDialog(dlg); + }); + + dlg.setSize(300, 200); + dlg.setLocation(fr.getX() + fr.getWidth() + 10, fr.getY()); + dlg.setVisible(true); + } +} diff --git a/test/jdk/javax/swing/JFileChooser/bug4943900.java b/test/jdk/javax/swing/JFileChooser/bug4943900.java new file mode 100644 index 0000000000000..0cea17e764ccc --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/bug4943900.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4943900 + * @summary Tests that FileFilter combo box is shown in FileChooser + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4943900 + */ + +import java.io.File; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.UIManager; +import javax.swing.filechooser.FileFilter; + +public class bug4943900 { + private static final String INSTRUCTIONS = """ + +
    +
  1. When the test runs, a JFileChooser will be displayed. +
  2. Ensure that there is a filter combo box with these two items: +
      +
    • Text Files (*.txt) + — [must be selected when the dialog opens] +
    • All Files +
    +
  3. Leave the Text files item selected and check that the + filter works: only *.txt files can appear in the file list. + You can navigate directories in the file chooser and find one + that contains some *.txt files to ensure they are shown in + the file list. On macOS when the text filter is applied verify + that the non-text files are greyed out. +
  4. Try switching the filters and ensure that the file list + is updated properly. +
  5. If the FileFilter works correctly, + press Pass else press Fail. +
+ + """; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + + PassFailJFrame.builder() + .title("bug4943900 Test Instructions") + .instructions(INSTRUCTIONS) + .rows(14) + .columns(50) + .testUI(bug4943900::createAndShowUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createAndShowUI() { + JFileChooser fc = new JFileChooser(); + fc.setControlButtonsAreShown(false); + TextFileFilter filter = new TextFileFilter(); + fc.setFileFilter(filter); + + JFrame frame = new JFrame("bug4943900 - JFileChooser"); + frame.add(fc); + frame.pack(); + return frame; + } + + private static final class TextFileFilter extends FileFilter { + @Override + public boolean accept(File f) { + if (f != null) { + if (f.isDirectory()) { + return true; + } + String extension = getExtension(f); + return extension != null && extension.equals("txt"); + } + return false; + } + + @Override + public String getDescription() { + return "Text Files (*.txt)"; + } + + private static String getExtension(File f) { + if (f != null) { + String filename = f.getName(); + int i = filename.lastIndexOf('.'); + if (i > 0 && i < filename.length() - 1) { + return filename.substring(i + 1).toLowerCase(); + } + } + return null; + } + } +} diff --git a/test/jdk/javax/swing/JOptionPane/bug4194862.java b/test/jdk/javax/swing/JOptionPane/bug4194862.java new file mode 100644 index 0000000000000..2a2822ebf1d38 --- /dev/null +++ b/test/jdk/javax/swing/JOptionPane/bug4194862.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4194862 + * @summary Tests that internal frame-based dialogs are centered relative + to their parents + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4194862 + */ + +import javax.swing.JButton; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.JOptionPane; + +public class bug4194862 { + private static final String INSTRUCTIONS = """ + In the internal frame titled "Main", + click the "Show JOptionPane Dialog" button. + A dialog will appear. It should be centered with + respect to the JInternalFrame - "Main". + + If the above is true then click on JOptionPane's "YES" button + to PASS else click JOptionPane's "NO" button to FAIL the test. + """; + + public static void main(String[] args) throws Exception{ + PassFailJFrame.builder() + .title("Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4194862::createAndShowUI) + .screenCapture() + .build() + .awaitAndCheck(); + } + + private static JFrame createAndShowUI() { + JFrame frame = new JFrame("bug4194862 - JInternalFrame JOptionPane"); + JDesktopPane desktop = new JDesktopPane(); + frame.add(desktop); + JInternalFrame jInternalFrame = new JInternalFrame("Main", true); + desktop.add(jInternalFrame); + jInternalFrame.setBounds(5, 30, 390, 240); + jInternalFrame.setVisible(true); + + JButton b = new JButton("Show JOptionPane Dialog"); + b.addActionListener(e -> { + int retVal = JOptionPane.showInternalConfirmDialog( + jInternalFrame, "Am I centered?", + "bug4194862 JOptionPane", JOptionPane.YES_NO_OPTION); + switch (retVal) { + case JOptionPane.YES_OPTION -> PassFailJFrame.forcePass(); + case JOptionPane.NO_OPTION -> + PassFailJFrame.forceFail("JOptionPane isn't centered" + + " within JInternalFrame \"Main\""); + } + }); + jInternalFrame.add(b); + + for (int i = 0; i < 4; i++) { + JInternalFrame f = new JInternalFrame("JIF: "+ i); + f.setBounds(i * 50, i * 33, 120, 120); + f.setVisible(true); + desktop.add(f); + } + frame.setSize(450, 400); + return frame; + } +} From d61765f64d6361b6e71c6f783c8c5a127b1ac745 Mon Sep 17 00:00:00 2001 From: Alisen Chung Date: Tue, 22 Apr 2025 17:56:04 +0000 Subject: [PATCH 0710/1101] 8353488: Open some JComboBox bugs 3 Reviewed-by: kizune --- .../jdk/javax/swing/JComboBox/bug4135833.java | 62 ++++++++++++ .../jdk/javax/swing/JComboBox/bug4171819.java | 89 +++++++++++++++++ .../jdk/javax/swing/JComboBox/bug4248128.java | 80 ++++++++++++++++ .../jdk/javax/swing/JComboBox/bug4436376.java | 95 +++++++++++++++++++ 4 files changed, 326 insertions(+) create mode 100644 test/jdk/javax/swing/JComboBox/bug4135833.java create mode 100644 test/jdk/javax/swing/JComboBox/bug4171819.java create mode 100644 test/jdk/javax/swing/JComboBox/bug4248128.java create mode 100644 test/jdk/javax/swing/JComboBox/bug4436376.java diff --git a/test/jdk/javax/swing/JComboBox/bug4135833.java b/test/jdk/javax/swing/JComboBox/bug4135833.java new file mode 100644 index 0000000000000..3b2888c862d01 --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4135833.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JPanel; + +/* + * @test + * @bug 4135833 + * @summary Tests that JComboBox draws correctly if the first item in list is an empty string + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4135833 + */ + +public class bug4135833 { + private static final String INSTRUCTIONS = """ + Press the combo box. If the popup is readable and appears to be sized properly, + then it passes. The First item is blank intentionally. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4135833::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4135833"); + JPanel panel = new JPanel(); + JComboBox comboBox = new JComboBox(new Object[]{"", "Bob", "Hank", "Joe", "Fred"}); + panel.add(comboBox); + frame.add(panel); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/javax/swing/JComboBox/bug4171819.java b/test/jdk/javax/swing/JComboBox/bug4171819.java new file mode 100644 index 0000000000000..108512edf7e88 --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4171819.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.UIManager; + +/* + * @test + * @bug 4171819 + * @summary Tests that JComboBox uses a lower bevel border in windows + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4171819 + */ + +public class bug4171819 { + static boolean lafOk = true; + + private static final String INSTRUCTIONS = """ + This test is for Windows L&F only. If you see + "No Windows L&F installed" label just press "Pass". + + Look at the combo box. If the border around it looks like it's + lowered rather than raised, it passes the test. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4171819::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + try { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + System.out.println("succeeded"); + } catch (Exception e) { + System.err.println("Couldn't load the Windows Look and Feel"); + lafOk = false; + } + + JFrame frame = new JFrame("bug4171819"); + JPanel panel = new JPanel(); + JComboBox comboBox; + + if (lafOk) { + comboBox = new JComboBox(new Object[]{ + "Coma Berenices", + "Triangulum", + "Camelopardis", + "Cassiopea"}); + panel.add(comboBox); + } else { + JLabel label = new JLabel("No Windows L&F installed"); + panel.add(label); + } + frame.add(panel); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/javax/swing/JComboBox/bug4248128.java b/test/jdk/javax/swing/JComboBox/bug4248128.java new file mode 100644 index 0000000000000..311cae4b61a33 --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4248128.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +import java.awt.Robot; +import java.awt.event.KeyEvent; +import javax.swing.BoxLayout; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4248128 7148092 + * @summary Tests that alt+down arrow pulls down JComboBox popup + * @key headful + * @run main bug4248128 + */ + +public class bug4248128 { + static JFrame frame; + static volatile JComboBox combo; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(250); + SwingUtilities.invokeAndWait(() -> createTestUI()); + robot.waitForIdle(); + + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_ALT); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(() -> { + if (!combo.isPopupVisible()) { + throw new RuntimeException("Popup did not appear."); + } + }); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static void createTestUI() { + frame = new JFrame("4248128 Test"); + Object[] fruits = {"Banana", "Pear", "Apple"}; + combo = new JComboBox(fruits); + frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.X_AXIS)); + frame.add(combo); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } +} diff --git a/test/jdk/javax/swing/JComboBox/bug4436376.java b/test/jdk/javax/swing/JComboBox/bug4436376.java new file mode 100644 index 0000000000000..064efe8c9586d --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/bug4436376.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.FlowLayout; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.KeyEvent; +import java.awt.event.InputEvent; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4436376 + * @key headful + * @summary Tests that ComboBox items can't be deselected with Ctrl+click + * @run main bug4436376 + */ + +public class bug4436376 { + static JFrame frame; + static volatile Point p; + static volatile JComboBox combo; + + final static int SELECTED_INDEX = 2; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(250); + SwingUtilities.invokeAndWait(() -> createTestUI()); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(() -> p = combo.getLocationOnScreen()); + robot.waitForIdle(); + + robot.mouseMove(p.x + 10, p.y + 10); + robot.waitForIdle(); + + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(() -> { + if (combo.getSelectedIndex() != SELECTED_INDEX) { + throw new RuntimeException("Failed: selected index has been changed"); + } + }); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static void createTestUI() { + frame = new JFrame("bug4436376"); + String[] items = new String[]{"One", "Two", "Three", "Four"}; + combo = new JComboBox(items); + combo.setSelectedIndex(SELECTED_INDEX); + + frame.setLayout(new FlowLayout()); + frame.add(combo); + frame.setLocationRelativeTo(null); + frame.pack(); + frame.setVisible(true); + } +} From 239760ac09c78a9c989df54f6526b67448540eda Mon Sep 17 00:00:00 2001 From: Eric Caspole Date: Tue, 22 Apr 2025 19:59:41 +0000 Subject: [PATCH 0711/1101] 8355233: Add a DMB related benchmark Reviewed-by: kvn --- .../openjdk/bench/vm/compiler/DMBCheck.java | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 test/micro/org/openjdk/bench/vm/compiler/DMBCheck.java diff --git a/test/micro/org/openjdk/bench/vm/compiler/DMBCheck.java b/test/micro/org/openjdk/bench/vm/compiler/DMBCheck.java new file mode 100644 index 0000000000000..0552e52fb0267 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/DMBCheck.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.vm.compiler; + +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.CompilerControl; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Group; +import org.openjdk.jmh.annotations.GroupThreads; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@BenchmarkMode(Mode.Throughput) +@State(Scope.Benchmark) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 8, time = 4) +@Measurement(iterations = 6, time = 3) +public class DMBCheck { + + // The allocations of DoubleDMB$A and DoubleDMB$C + // will cause aarch64 dmb barrier instructions. + // The different latency of the dmb ish/ishst/ishld modes + // may make a noticeable difference in the benchmark results. + // These modes may be set by cpu defaults or XX options. + + class A { + + final String b = new String("Hi there"); + } + + class C { + + private A a; + + public A getA() { + if (a == null) { + a = new A(); + } + return a; + } + } + + static C c = null; + + @Setup + public void setup() { + c = new C(); + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + void action(Blackhole b) throws Exception { + c = new C(); + + if (c.getA().b == null) { + throw new Exception("a should not be null"); + } + b.consume(c); + } + + @Benchmark + @Fork(value = 1, jvmArgs = { + "-XX:+UnlockDiagnosticVMOptions", "-XX:+AlwaysMergeDMB", "-XX:+IgnoreUnrecognizedVMOptions"}) + public void plusAlwaysMergeDMB(Blackhole b) throws Exception { + + action(b); + } + + @Benchmark + @Fork(value = 1, jvmArgs = { + "-XX:+UnlockDiagnosticVMOptions", "-XX:-AlwaysMergeDMB", "-XX:+IgnoreUnrecognizedVMOptions"}) + public void minusAlwaysMergeDMB(Blackhole b) throws Exception { + + action(b); + } + +} From 1b8f760d1b60e63c1391dcad42753a7ebb3f80ec Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Tue, 22 Apr 2025 20:17:01 +0000 Subject: [PATCH 0712/1101] 8354928: Clean up and open source some miscellaneous AWT tests Reviewed-by: prr, dnguyen --- .../event/InputEvent/InputEventTimeTest.java | 115 +++++++++++++ .../event/MouseWheelEvent/HWWheelScroll.java | 160 ++++++++++++++++++ .../MouseWheelEvent/WheelEventCoord.java | 95 +++++++++++ .../MouseWheelEvent/WheelScrollEnabled.java | 129 ++++++++++++++ 4 files changed, 499 insertions(+) create mode 100644 test/jdk/java/awt/event/InputEvent/InputEventTimeTest.java create mode 100644 test/jdk/java/awt/event/MouseWheelEvent/HWWheelScroll.java create mode 100644 test/jdk/java/awt/event/MouseWheelEvent/WheelEventCoord.java create mode 100644 test/jdk/java/awt/event/MouseWheelEvent/WheelScrollEnabled.java diff --git a/test/jdk/java/awt/event/InputEvent/InputEventTimeTest.java b/test/jdk/java/awt/event/InputEvent/InputEventTimeTest.java new file mode 100644 index 0000000000000..38339f8e87703 --- /dev/null +++ b/test/jdk/java/awt/event/InputEvent/InputEventTimeTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4176525 + * @summary InputEvent.getWhen() returns the wrong event time. + * @key headful + * @run main InputEventTimeTest + */ + +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.lang.reflect.InvocationTargetException; +import java.util.Date; + +public class InputEventTimeTest extends Frame { + public void initUI() { + setTitle("Input Event Time Test"); + enableEvents(AWTEvent.MOUSE_EVENT_MASK); + enableEvents(AWTEvent.KEY_EVENT_MASK); + setSize(200, 200); + setLocationRelativeTo(null); + setVisible(true); + } + + public void center(Point point) { + Point loc = getLocationOnScreen(); + Dimension size = getSize(); + point.setLocation(loc.x + (size.width / 2), loc.y + (size.height / 2)); + } + + public void processEvent(AWTEvent e) { + long currentTime; + long eventTime; + long difference; + + if (!(e instanceof InputEvent)) { + return; + } + + currentTime = (new Date()).getTime(); + eventTime = ((InputEvent) e).getWhen(); + difference = currentTime - eventTime; + + if ((difference > 5000) || (difference < -5000)) { + throw new RuntimeException("The difference between current time" + + " and event creation time is " + difference + "ms"); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + InputEventTimeTest test = new InputEventTimeTest(); + try { + EventQueue.invokeAndWait(test::initUI); + Robot robot = new Robot(); + robot.setAutoDelay(50); + robot.waitForIdle(); + robot.delay(1000); + Point center = new Point(); + EventQueue.invokeAndWait(() -> test.center(center)); + robot.mouseMove(center.x, center.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.mousePress(InputEvent.BUTTON2_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON2_DOWN_MASK); + robot.waitForIdle(); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + for (int i = 0; i < 6; i++) { + robot.keyPress(KeyEvent.VK_A + i); + robot.keyRelease(KeyEvent.VK_A + i); + robot.waitForIdle(); + } + for (int i = 0; i < 150; i += 5) { + robot.mouseMove(center.x - i, center.y - i); + } + for (int i = 150; i > 0; i -= 5) { + robot.mouseMove(center.x - i, center.y - i); + } + } finally { + EventQueue.invokeAndWait(test::dispose); + } + } +} diff --git a/test/jdk/java/awt/event/MouseWheelEvent/HWWheelScroll.java b/test/jdk/java/awt/event/MouseWheelEvent/HWWheelScroll.java new file mode 100644 index 0000000000000..2851ff668fe6e --- /dev/null +++ b/test/jdk/java/awt/event/MouseWheelEvent/HWWheelScroll.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4425654 + * @summary Test wheel scrolling of heavyweight components + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual HWWheelScroll + */ + +import java.awt.Choice; +import java.awt.FileDialog; +import java.awt.Frame; +import java.awt.List; +import java.awt.TextArea; +import java.awt.Window; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; + +public class HWWheelScroll { + public static final int TEXT_TALL = 0; + public static final int TEXT_WIDE = 1; + public static final int TEXT_SMALL = 2; + public static final int TEXT_BIG = 3; + static String INSTRUCTIONS = """ + Test for mouse wheel scrolling of heavyweight components with built-in + scrollbars or similar functionality that is controlled by guestures + such as Apple Magic Mouse or trackpad scrolling guesture. + Several windows containing either a TextArea, List, Choice, or a + FileDialog will appear. For each window, use the mouse wheel to + scroll its content, and then minimize it or move away + and continue with the next window. + Do not close any of the opened windows except the FileDialog. + For the FileDialog, first change to a directory with enough items that a + scrollbar appears. + Some of the other windows don't have enough text to warrant scrollbars, + but should be tested anyway to make sure no crash or hang occurs. + If all scrollbars scroll correctly, press "Pass", otherwise press "Fail". + """; + + public static ArrayList initUI() { + ArrayList retValue = new ArrayList<>(); + retValue.add(makeTextFrame(TextArea.SCROLLBARS_BOTH, TEXT_BIG)); + retValue.add(makeTextFrame(TextArea.SCROLLBARS_BOTH, TEXT_TALL)); + retValue.add(makeTextFrame(TextArea.SCROLLBARS_BOTH, TEXT_SMALL)); + retValue.add(makeTextFrame(TextArea.SCROLLBARS_BOTH, TEXT_WIDE)); + retValue.add(makeTextFrame(TextArea.SCROLLBARS_VERTICAL_ONLY, TEXT_TALL)); + retValue.add(makeTextFrame(TextArea.SCROLLBARS_VERTICAL_ONLY, TEXT_SMALL)); + retValue.add(makeTextFrame(TextArea.SCROLLBARS_HORIZONTAL_ONLY, TEXT_SMALL)); + retValue.add(makeTextFrame(TextArea.SCROLLBARS_HORIZONTAL_ONLY, TEXT_WIDE)); + retValue.add(makeListFrame(TEXT_TALL)); + retValue.add(makeListFrame(TEXT_WIDE)); + retValue.add(makeListFrame(TEXT_SMALL)); + Frame f = new Frame("File Dialog Owner"); + f.setSize(150, 150); + f.setLocationRelativeTo(null); + FileDialog fd = new FileDialog(f, "FileDialog"); + fd.setDirectory("."); + retValue.add(fd); + retValue.add(f); + Frame choiceFrame = new Frame("Choice"); + Choice c = new Choice(); + for (int i = 0; i < 50; i++) { + c.add(i + " choice item"); + } + choiceFrame.add(c); + choiceFrame.setSize(150, 150); + choiceFrame.setLocationRelativeTo(null); + retValue.add(choiceFrame); + return retValue; + } + + public static Frame makeTextFrame(int policy, int textShape) { + Frame f = new Frame("TextArea"); + f.add(makeTextArea(policy, textShape)); + f.setSize(150, 150); + f.setLocationRelativeTo(null); + return f; + } + + public static Frame makeListFrame(int textShape) { + Frame f = new Frame("List"); + f.add(makeList(textShape)); + f.setSize(150, 150); + f.setLocationRelativeTo(null); + return f; + } + + public static TextArea makeTextArea(int policy, int textShape) { + TextArea ta = new TextArea("", 0, 0, policy); + if (textShape == TEXT_TALL) { + for (int i = 0; i < 50 ; i++) { + ta.append(i + "\n"); + } + } else if (textShape == TEXT_WIDE) { + for (int i = 0; i < 2; i++) { + ta.append(i + "very, very, very, very, very, very, very, long line of text number\n"); + } + } else if (textShape == TEXT_SMALL) { + ta.append("text"); + } else if (textShape == TEXT_BIG) { + for (int i = 0; i < 50 ; i++) { + ta.append(i + "very, very, very, very, very, very, very, long line of text number\n"); + } + } + return ta; + } + + public static List makeList(int textShape) { + java.awt.List l = new java.awt.List(); + if (textShape == TEXT_TALL) { + for (int i = 0; i < 50 ; i++) { + l.add(" " + i + " "); + } + } else if (textShape == TEXT_WIDE) { + for (int i = 0; i < 2 ; i++) { + l.add(i + "very, very, very, very, very, very, very, long line of text number"); + } + } else if (textShape == TEXT_SMALL) { + l.add("text"); + } else if (textShape == TEXT_BIG) { + for (int i = 0; i < 50 ; i++) { + l.add(i + "very, very, very, very, very, very, very, long line of text number"); + } + } + return l; + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .logArea(10) + .testUI(HWWheelScroll::initUI) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/event/MouseWheelEvent/WheelEventCoord.java b/test/jdk/java/awt/event/MouseWheelEvent/WheelEventCoord.java new file mode 100644 index 0000000000000..418151d3798f4 --- /dev/null +++ b/test/jdk/java/awt/event/MouseWheelEvent/WheelEventCoord.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4492456 + * @summary MouseWheelEvent coordinates are wrong + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual WheelEventCoord + */ + +import java.awt.Button; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.GridLayout; +import java.lang.reflect.InvocationTargetException; + +public class WheelEventCoord extends Frame { + static String INSTRUCTIONS = """ + This test requires mouse with scrolling wheel or device, + that has capability to simulate scrolling wheel with gestures + such as Apple mouse or a trackpad with gesture control. + If you do not have such device press "Pass". + Move mouse to the top of the button named "Button 1". + While constantly turning mouse wheel up and down slowly move + mouse cursor until it reaches bottom of the button named "Button 3". + While doing so look at the log area. + If despite the wheel direction y coordinate is steadily increases + as you move the mouse down press "Pass". + If y coordinate decreases when cursor is moving down or suddenly jumps + by more than 50 points when crossing to another button press "Fail". + """; + + public WheelEventCoord() { + super("Wheel Event Coordinates"); + setLayout(new GridLayout(3, 1)); + + add(new BigButton("Button 1")); + add(new BigButton("Button 2")); + add(new BigButton("Button 3")); + + addMouseWheelListener(e -> PassFailJFrame.log("Mouse y coordinate = " + e.getY())); + pack(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Wheel Event Coordinates Instructions") + .instructions(INSTRUCTIONS) + .logArea(10) + .testUI(WheelEventCoord::new) + .build() + .awaitAndCheck(); + } +} + +class BigButton extends Button { + public BigButton(String label) { + super(label); + } + + public Dimension getPreferredSize() { + return new Dimension(300, 100); + } + + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + public Dimension getMaximumSize() { + return getPreferredSize(); + } +} diff --git a/test/jdk/java/awt/event/MouseWheelEvent/WheelScrollEnabled.java b/test/jdk/java/awt/event/MouseWheelEvent/WheelScrollEnabled.java new file mode 100644 index 0000000000000..cbdd7676e94ad --- /dev/null +++ b/test/jdk/java/awt/event/MouseWheelEvent/WheelScrollEnabled.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4372477 + * @summary Test disabling of wheel scrolling + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual WheelScrollEnabled + */ + +import java.awt.BorderLayout; +import java.awt.Checkbox; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.Panel; +import java.awt.ScrollPane; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.lang.reflect.InvocationTargetException; + +public class WheelScrollEnabled extends Frame { + static String INSTRUCTIONS = """ + This test requires mouse with a scrolling wheel or + device that is able to simulate scrolling using gestures. + If you do not have such device press "Pass" to skip testing. + You should see a ScrollPane with some labels in it and two checkboxes. + For each of the four combinations of the two checkboxes, + move the cursor over the ScrollPane and rotate the mouse wheel. + When (and ONLY when) the 'WheelListener added' checkbox is checked, + scrolling the mouse wheel should produce a text message in the log area. + When (and ONLY when) the 'Wheel scrolling enabled' checkbox is checked, + the ScrollPane should scroll when mouse wheel is scrolled on top of it. + If all four checkbox combinations work properly press "Pass", + otherwise press "Fail". + """; + MouseWheelListener mwl; + Checkbox cb; + Checkbox cb2; + ScrollPane sp; + + public WheelScrollEnabled() { + setLayout(new BorderLayout()); + Panel pnl = new Panel(); + pnl.setLayout(new GridLayout(10, 10)); + for (int i = 0; i < 100; i++) { + pnl.add(new Label("Label " + i)); + } + sp = new ScrollPane(); + sp.add(pnl); + sp.setWheelScrollingEnabled(false); + mwl = new MouseWheelListener() { + int i; + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + PassFailJFrame.log("mouseWheelMoved " + i++); + } + }; + sp.addMouseWheelListener(mwl); + add(sp, BorderLayout.CENTER); + + Panel pl2 = new Panel(); + ItemListener il = new ControlListener(); + + cb = new Checkbox("WheelListener added", true); + cb.addItemListener(il); + pl2.add(cb); + + cb2 = new Checkbox("Wheel scrolling enabled", false); + cb2.addItemListener(il); + pl2.add(cb2); + + add(pl2, BorderLayout.SOUTH); + setSize(400, 200); + } + + class ControlListener implements ItemListener { + public void itemStateChanged(ItemEvent e) { + if (e.getSource() == cb) { + boolean state = cb.getState(); + if (state) { + sp.addMouseWheelListener(mwl); + } + else { + sp.removeMouseWheelListener(mwl); + } + } + if (e.getSource() == cb2) { + sp.setWheelScrollingEnabled(cb2.getState()); + } + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Wheel Scroll Enabled Instructions") + .instructions(INSTRUCTIONS) + .logArea(10) + .testUI(WheelScrollEnabled::new) + .build() + .awaitAndCheck(); + } +} + From cc9148ddef95c6ca27ff9fee4c17fb0d4ba7f88e Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Tue, 22 Apr 2025 20:27:17 +0000 Subject: [PATCH 0713/1101] 8354695: Open source several swing tests batch7 Reviewed-by: kizune, achung --- .../jdk/javax/swing/JRootPane/bug4403624.java | 106 +++ .../HorizScrollers.java | 234 ++++++ .../RTLScrollers.java | 684 ++++++++++++++++++ .../javax/swing/JScrollPane/bug4166037.java | 167 +++++ .../javax/swing/JScrollPane/bug4237517.java | 69 ++ .../javax/swing/JScrollPane/bug4237560.java | 77 ++ .../javax/swing/JScrollPane/bug4244899.java | 99 +++ 7 files changed, 1436 insertions(+) create mode 100644 test/jdk/javax/swing/JRootPane/bug4403624.java create mode 100644 test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/HorizScrollers.java create mode 100644 test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/RTLScrollers.java create mode 100644 test/jdk/javax/swing/JScrollPane/bug4166037.java create mode 100644 test/jdk/javax/swing/JScrollPane/bug4237517.java create mode 100644 test/jdk/javax/swing/JScrollPane/bug4237560.java create mode 100644 test/jdk/javax/swing/JScrollPane/bug4244899.java diff --git a/test/jdk/javax/swing/JRootPane/bug4403624.java b/test/jdk/javax/swing/JRootPane/bug4403624.java new file mode 100644 index 0000000000000..1c3ba3ddd2a8e --- /dev/null +++ b/test/jdk/javax/swing/JRootPane/bug4403624.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4403624 + * @summary Tests JRootPane layout with invisible menubar + * @key headful + * @run main bug4403624 + */ + +import java.awt.Color; +import java.awt.Container; +import java.awt.FlowLayout; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.SwingUtilities; + +public class bug4403624 { + private static JFrame f; + private static Container c; + private static JButton b; + private static volatile Point p; + private static volatile int bWidth; + private static volatile int bHeight; + private static final int OFFSET = 2; + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("bug4403624 Test"); + JMenuBar mbar; + mbar = new JMenuBar(); + mbar.add(new JMenu("Menu")); + f.setJMenuBar(mbar); + b = new JButton("Hide Menu"); + b.addActionListener(e -> mbar.setVisible(false)); + c = f.getContentPane(); + c.setLayout(new FlowLayout()); + c.setBackground(Color.GREEN); + c.add(b); + f.pack(); + f.setLocationRelativeTo(null); + f.setAlwaysOnTop(true); + f.setVisible(true); + }); + + Robot r = new Robot(); + r.setAutoDelay(200); + r.waitForIdle(); + r.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + p = b.getLocationOnScreen(); + bWidth = b.getWidth(); + bHeight = b.getHeight(); + }); + + r.mouseMove(p.x + (bWidth / 2), p.y + (bHeight / 2)); + r.mousePress(InputEvent.BUTTON1_DOWN_MASK); + r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + SwingUtilities.invokeAndWait(() -> p = c.getLocationOnScreen()); + + Color c = r.getPixelColor(p.x + OFFSET, p.y + OFFSET); + + if (c.getGreen() < 240 && c.getBlue() > 10 && c.getRed() > 10) { + System.out.println("EXPECTED: " + Color.GREEN); + System.out.println("ACTUAL: " + c); + throw new RuntimeException("Failure to hide menu bar."); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } +} diff --git a/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/HorizScrollers.java b/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/HorizScrollers.java new file mode 100644 index 0000000000000..b584fd66da3f6 --- /dev/null +++ b/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/HorizScrollers.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5078454 + * @summary Test horizontal wheel scroll behavior of (including RTL) + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual HorizScrollers + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; + +public class HorizScrollers { + private static final String INSTRUCTIONS = """ + This is a semi-automatic test with three phases. + For each phase, you will need to change the mouse setting, as + directed by a dialog. Once the correct setting is confirmed, + the next test phase will run automatically. + DO NOT TOUCH ANYTHING DURING TESTING! + + The test will automatically FAIL during testing if something + fails. Otherwise, the test will automatically PASS after the + third testing phase. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("HorizScrollers Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testTimeOut(10) + .splitUIRight(ConfigPanel::new) + .logArea(6) + .build() + .awaitAndCheck(); + } + + private static final int[] SCROLLAMTS = {1, 30, 3}; + private static final String[] CONFIG_MSGS = { + "Set the scrolling speed to the slowest value (1 line).", + "Set the scrolling speed to the fastest value (30 lines).", + "Set the scrolling speed to two ticks above the slowest value (3 lines)." + }; + + private static int current = 0; + private static final String MW_TEXT = "Rotate the mouse wheel here"; + private static final String CONFIG_INSTRUCTION_TEMPLATE = """ + Configure Mouse Wheel for Phase %d + + Open the Mouse Control Panel and go to the 'Wheel' tab. + If 'Wheel' tab is not available just press Pass. + + %s + + Test the setting on the area below. + Once the mouse is setup correctly, the area will turn green. + When you're ready for the next part of the test to run, press GO! + """; + + static class ConfigPanel extends JPanel + implements ActionListener, MouseWheelListener { + JTextArea msg; + JButton goBtn; + JLabel mwArea; + int scrollAmount; + + private final Color defaultBg; + + ConfigPanel() { + this.scrollAmount = SCROLLAMTS[current]; + Container content = this; + content.setLayout(new BorderLayout()); + msg = new JTextArea(); + msg.setMargin(new Insets(5, 5, 5, 5)); + msg.setEditable(false); + msg.setLineWrap(true); + msg.setWrapStyleWord(true); + content.add(msg, BorderLayout.NORTH); + + mwArea = new JLabel(MW_TEXT, SwingConstants.CENTER); + mwArea.setPreferredSize(new Dimension(200, 250)); + mwArea.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + mwArea.setOpaque(true); + mwArea.addMouseWheelListener(this); + content.add(mwArea, BorderLayout.CENTER); + + defaultBg = mwArea.getBackground(); + setPhase(current); + + goBtn = new JButton("GO!"); + goBtn.setEnabled(false); + goBtn.addActionListener(this); + JPanel flowPanel = new JPanel(); + flowPanel.setLayout(new FlowLayout()); + flowPanel.add(goBtn); + content.add(flowPanel, BorderLayout.SOUTH); + + setPreferredSize(new Dimension(600, 400)); + } + + public void setPhase(int phase) { + if (phase < 3) { + setVisible(true); + PassFailJFrame.log("Phase %d scroll speed %d" + .formatted(phase + 1, SCROLLAMTS[phase])); + PassFailJFrame.log(CONFIG_MSGS[phase]); + + scrollAmount = SCROLLAMTS[phase]; + msg.setText(CONFIG_INSTRUCTION_TEMPLATE + .formatted(phase + 1, CONFIG_MSGS[phase])); + mwArea.setBackground(defaultBg); + mwArea.setText(MW_TEXT); + } else { + // all cases passed + showFinalReminderIfNeeded(false); + } + } + + private void showFinalReminderIfNeeded(boolean isFailure) { + if (scrollAmount != 3) { + JOptionPane.showMessageDialog( + ConfigPanel.this.getTopLevelAncestor(), + ("Test %s. please make sure you have restored " + + "the original speed value blah blah") + .formatted(isFailure + ? "failed" + : "passed"), + isFailure + ? "Failure" + : "Success", + isFailure + ? JOptionPane.WARNING_MESSAGE + : JOptionPane.INFORMATION_MESSAGE + ); + } + + if (isFailure) { + PassFailJFrame.forceFail(); + } else { + PassFailJFrame.forcePass(); + } + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == goBtn) { + goBtn.setEnabled(false); + + new Thread(() -> { // new thread to avoid running robot on EDT + boolean passed; + try { + passed = RTLScrollers.runTest(SCROLLAMTS[current]); + } catch (Exception ex) { + PassFailJFrame.log("Failure: " + ex); + SwingUtilities.invokeLater(() -> + showFinalReminderIfNeeded(true)); + return; + } + + PassFailJFrame.log("Phase %d passed: %b\n" + .formatted(current + 1, passed)); + if (passed) { + SwingUtilities.invokeLater(() -> { + goBtn.setEnabled(true); + setPhase(++current); + }); + } else { + SwingUtilities.invokeLater(() -> + showFinalReminderIfNeeded(true)); + } + }).start(); + } + } + + public void mouseWheelMoved(MouseWheelEvent e) { + int eventScrollAmt = e.getScrollAmount(); + if (eventScrollAmt == scrollAmount) { + mwArea.setBackground(Color.GREEN); + mwArea.setText("Mouse wheel configured - press Go"); + goBtn.setEnabled(true); + goBtn.requestFocusInWindow(); + PassFailJFrame.log("Proceed to the test with go button"); + return; + } + if (eventScrollAmt < scrollAmount) { + mwArea.setText("Increase the scroll speed. (Want:" + + scrollAmount + " Got:" + eventScrollAmt + ")"); + } else { + mwArea.setText("Decrease the scroll speed. (Want:" + + scrollAmount + " Got:" + eventScrollAmt + ")"); + } + } + } +} \ No newline at end of file diff --git a/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/RTLScrollers.java b/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/RTLScrollers.java new file mode 100644 index 0000000000000..24e8df6fad8e1 --- /dev/null +++ b/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/RTLScrollers.java @@ -0,0 +1,684 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// A few Swing components which use the mouse wheel to scroll + +import java.awt.AWTException; +import java.awt.Color; +import java.awt.ComponentOrientation; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.awt.image.BufferedImage; +import java.lang.reflect.InvocationTargetException; + +import javax.swing.DefaultListModel; +import javax.swing.ImageIcon; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTextArea; +import javax.swing.ListModel; +import javax.swing.ScrollPaneConstants; +import javax.swing.SwingUtilities; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumn; +import javax.swing.table.TableModel; + +public class RTLScrollers extends JDialog + implements MouseWheelListener, ActionListener { + private static final int ROWS = 5; + private static final int COLUMNS = 150; + private static final int WINWIDTH = 1000; + + static RTLScrollers rtl; + static volatile RTLScrollers f; + static volatile boolean retVal; + static volatile JScrollPane jsp; + static volatile JScrollBar hsb; + static volatile JScrollBar sb; + static volatile Point loc; + static volatile Dimension size; + TestList list; + JScrollPane listScroller; + JTextArea text; + JScrollPane textScroller; + TestTable table; + JScrollPane tableScroller; + JCheckBoxMenuItem rightToLeft; + ImageIcon photoIcon; + int scrollAmount; + + private static Robot robot; + private static BufferedImage logo = genIcon(166, 39, Color.PINK); + private static BufferedImage photo = genIcon(59, 80, Color.MAGENTA); + private static BufferedImage photo2 = genIcon(80, 53, Color.ORANGE); + + private static BufferedImage genIcon(int width, int height, Color color) { + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics g = image.getGraphics(); + g.setColor(color); + g.fillRect(0, 0, width, height); + + return image; + } + + public RTLScrollers() { + this(0); + } + + public RTLScrollers(int scrollAmount) { + super(new JFrame(), "RTLScrollers", false); + + this.scrollAmount = scrollAmount; + Container content = getContentPane(); + content.setLayout(new GridBagLayout()); + + DefaultListModel listModel = new DefaultListModel<>(); + + photoIcon = new ImageIcon(photo); + for (int i = 0; i < COLUMNS / 4 ; i++) { + for (int j = 0; j < ROWS; j++) { + listModel.addElement(new ImageIcon(logo)); + } + for (int j = 0; j < ROWS; j++) { + listModel.addElement(photoIcon); + } + for (int j = 0; j < ROWS; j++) { + listModel.addElement(new ImageIcon(photo2)); + } + for (int j = 0; j < ROWS; j++) { + listModel.addElement("Text Item " + ((1 + i) * 3)); + } + } + + list = new TestList(listModel); + list.setVisibleRowCount(ROWS); + list.setLayoutOrientation(JList.VERTICAL_WRAP); + listScroller = new JScrollPane(list); + listScroller.addMouseWheelListener(this); + + text = new JTextArea(); + for (int j = 0; j < ROWS ; j++) { + for (int i = 0; i < COLUMNS ; i++) { + text.append(i + " some text, some more text, a really long line of text "); + } + text.append("\n"); + } + + textScroller = new JScrollPane(text); + textScroller.addMouseWheelListener(this); + + DefaultTableModel model = new DefaultTableModel(ROWS, COLUMNS); + table = new TestTable(model); + table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + for (int i = 0; i < COLUMNS; i++) { + for (int j = 0; j < ROWS; j++) { + table.setValueAt(j + ", " + i, j, i); + } + + TableColumn column = table.getColumnModel().getColumn(i); + + if (i % 4 == 0) { + column.setMinWidth(0); + column.setPreferredWidth(0); + column.setMaxWidth(0); + } + else if ((i + 1) % 4 == 0) { + column.setMinWidth(95); + column.setPreferredWidth(95); + column.setMaxWidth(95); + } + else if ((i + 2) % 4 == 0) { + column.setMinWidth(26); + column.setPreferredWidth(26); + column.setMaxWidth(26); + } + else { + column.setMinWidth(50); + column.setPreferredWidth(50); + column.setMaxWidth(50); + } + } + tableScroller = new JScrollPane(table); + tableScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); + tableScroller.addMouseWheelListener(this); + + GridBagConstraints tableGBC = new GridBagConstraints(0, + 0, + 1, + 1, + 1.0, + 0.3, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + new Insets(0,0,0,0), + 0, + 0); + content.add(tableScroller, tableGBC); + GridBagConstraints textGBC = new GridBagConstraints(0, + 1, + 1, + 1, + 1.0, + 0.3, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + new Insets(0,0,0,0), + 0, + 0); + content.add(textScroller, textGBC); + + GridBagConstraints listGBC = new GridBagConstraints(0, + 2, + 1, + 5, + 1.0, + 1.2, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + new Insets(0,0,0,0), + 0, + 0); + + content.add(listScroller, listGBC); + + rightToLeft = new JCheckBoxMenuItem("Right-To-Left", false); + rightToLeft.addActionListener(this); + JMenu menu = new JMenu("Component Orientation"); + menu.add(rightToLeft); + + JMenuItem close = new JMenuItem("Close"); + close.addActionListener(e -> RTLScrollers.this.setVisible(false)); + menu.add(close); + + JMenuBar mb = new JMenuBar(); + mb.add(menu); + setJMenuBar(mb); + setBounds(0, 0, WINWIDTH, 760); + setLocationRelativeTo(null); + } + + public void actionPerformed(ActionEvent e) { + if (rightToLeft.getState()) { + applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); + } + else { + applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + } + } + public void mouseWheelMoved(MouseWheelEvent e) { + System.out.println("Rotation: " + e.getWheelRotation()); + } + + public static boolean runTest(int scrollAmount) + throws InterruptedException, InvocationTargetException { + System.out.println("RTLS.runTest()"); + if (robot == null) { + try { + robot = new Robot(); + robot.setAutoDelay(150); + robot.setAutoWaitForIdle(true); + } + catch (AWTException e) { + e.printStackTrace(); + return false; + } + } + + SwingUtilities.invokeAndWait(() -> { + rtl = new RTLScrollers(scrollAmount); + rtl.setVisible(true); + }); + robot.delay(100); + + SwingUtilities.invokeAndWait(() -> { + try { + retVal = rtl.runTests(scrollAmount); + } catch (Exception e) { + e.printStackTrace(); + } finally { + rtl.setVisible(false); + rtl.dispose(); + } + }); + + robot.delay(100); + System.out.println("RTLS.runTest(): " + retVal); + return retVal; + } + + private boolean runTests(int scrollAmount) + throws InterruptedException, InvocationTargetException { + if (robot == null) { + try { + robot = new Robot(); + robot.setAutoDelay(150); + robot.setAutoWaitForIdle(true); + } + catch (AWTException e) { + e.printStackTrace(); + return false; + } + } + + // + // run robot tests + // + robot.delay(500); + + System.out.println("Testing Table"); + testComp(table, scrollAmount); + + System.out.println("Testing List"); + testComp(list, scrollAmount); + + SwingUtilities.invokeAndWait(() -> { + applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); + }); + robot.delay(100); + + System.out.println("Testing RTL Table"); + testComp(table, scrollAmount); + + System.out.println("Testing RTL List"); + testComp(list, scrollAmount); + + return true; + } + + public boolean testComp(TestTools comp, int scrollAmount) + throws InterruptedException, InvocationTargetException { + // Make sure we start from the beginning + SwingUtilities.invokeAndWait(() -> { + jsp = (JScrollPane)((JComponent)comp).getParent().getParent(); + hsb = jsp.getHorizontalScrollBar(); + hsb.setValue(hsb.getMinimum()); + + loc = jsp.getLocationOnScreen(); + size = jsp.getSize(); + }); + int midx = loc.x + size.width / 2; + int midy = loc.y + size.height / 2; + int maxIdx = 0; + robot.mouseMove(midx, midy); + + // Don't bother for max scroll w/ RTL JList, because the block increment is broken + if (scrollAmount != 30 || !(comp instanceof TestList) + || getComponentOrientation().isLeftToRight()) { + scrollToMiddle(jsp, robot); + + // check that we're lined up + comp.checkTopCellIsLinedUp(); + + int startVal = hsb.getValue(); + int leadingCell = comp.getLeadingCell().y; + System.out.println("leadingCell is " + leadingCell); + + // become unaligned + int width = comp.getLeadingCellWidth(); + int midVal = startVal + width / 2; + System.out.println("becoming unaligned: startVal is " + + startVal + ", midVal is " + midVal); + SwingUtilities.invokeAndWait(() -> hsb.setValue(midVal)); + + // + // Check partial inc up + // + robot.mouseWheel(-1); + + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, -scrollAmount + 1); + } + comp.checkTopCellIsLinedUp(); + + // + // Check partial inc down + // + SwingUtilities.invokeAndWait(() -> hsb.setValue(midVal)); + robot.delay(100); + robot.mouseWheel(1); + + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, scrollAmount); + } + comp.checkTopCellIsLinedUp(); + + // + // Check full inc down (3 times) + // + SwingUtilities.invokeAndWait(() -> hsb.setValue(startVal)); + leadingCell = comp.getLeadingCell().y; + + // Once... + robot.mouseWheel(1); + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, scrollAmount); + } + comp.checkTopCellIsLinedUp(); + + // Twice... + robot.mouseWheel(1); + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, (2 * scrollAmount)); + } + + comp.checkTopCellIsLinedUp(); + + // Thrice... + robot.mouseWheel(1); + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, (3 * scrollAmount)); + + } + comp.checkTopCellIsLinedUp(); + + // + // Check full inc up (3 times) + // + leadingCell = comp.getLeadingCell().y; + + // Once... + robot.mouseWheel(-1); + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, -scrollAmount); + } + comp.checkTopCellIsLinedUp(); + + // Twice... + robot.mouseWheel(-1); + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, -(2 * scrollAmount)); + } + comp.checkTopCellIsLinedUp(); + + // Thrice... + robot.mouseWheel(-1); + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, -(3 * scrollAmount)); + } + comp.checkTopCellIsLinedUp(); + } + + // + // Test acceleration for max scrolling + // (this part should still work for RTL JList) + if (scrollAmount == 30) { + SwingUtilities.invokeAndWait(() -> { + hsb.setValue(hsb.getMinimum()); + }); + robot.delay(100); + robot.mouseWheel(2); + robot.mouseWheel(2); + robot.mouseWheel(2); + if (hsb.getValue() < hsb.getMaximum() - hsb.getVisibleAmount()) { + throw new RuntimeException("Wheel acceleration for max " + + "scrolling doesn't work: hsb value (" + hsb.getValue() + + " < hsb max (" + hsb.getMaximum() + + ") - hsb vis (" + hsb.getVisibleAmount() + ")"); + } + robot.delay(100); + robot.mouseWheel(-2); + robot.mouseWheel(-2); + robot.mouseWheel(-2); + if (hsb.getValue() > hsb.getMinimum()) { + throw new RuntimeException("Wheel acceleration for max " + + "scrolling doesn't work: hsb value (" + + hsb.getValue() + " > hsb min (" + hsb.getMinimum() + ")"); + } + } + + return true; + } + + class TestTable extends JTable implements TestTools { + final int[] MAXVALS = {23, 67, 67, 89, 111, 89, 66, 45}; //Lookup table + public TestTable(TableModel model) { + super(model); + } + + public void checkTopCellIsLinedUp() { + boolean isLeftToRight = getComponentOrientation().isLeftToRight(); + Point leading = getLeadingCell(); + Rectangle visRect = getVisibleRect(); + Rectangle cellRect = getCellRect(leading.x, leading.y, true); + + if (isLeftToRight) { + if (cellRect.x != visRect.x) { + throw new RuntimeException("leading cell is not aligned!"); + } + } + else { + if (cellRect.x + cellRect.width != visRect.x + visRect.width) { + throw new RuntimeException("leading cell is not aligned!"); + } + } + } + + public void checkTopCellIs(int col) { + Point cell = getLeadingCell(); + if (cell.y != col) { + throw new RuntimeException("leading cell (" + cell.y + + ") is not " + col); + } + } + + /* + * Account for 0-width cells + * + * shift is a non-0 number of visible cells to shift. The shift is + * augmented for zero-width cells, and the new sum is passed into + * checkTopCellIs(). + */ + public void checkTopCellIs(int col, int shift) { + if (shift == 0) { + checkTopCellIs(col); + return; + } + + int row = getLeadingCell().x; + int newShift = 0; + int foundCells = 0; + int direction = shift > 0 ? 1 : -1; + int index = col; + Rectangle cellRect; + + while (foundCells < Math.abs(shift)) { + index += direction; + cellRect = getCellRect(row, index, true); + if (cellRect.width > 0) { + foundCells++; + } + newShift++; + } + + checkTopCellIs(col + (direction*newShift)); + } + + public void checkTopCellIsMax(int idx) { + checkTopCellIs(MAXVALS[idx]); + } + + public int getLeadingCellWidth() { + Point leading = getLeadingCell(); + Rectangle cellRect = getCellRect(leading.x, leading.y, true); + return cellRect.width; + } + + public Point getLeadingCell() { + boolean isLeftToRight = getComponentOrientation().isLeftToRight(); + Rectangle visRect = getVisibleRect(); + int row = rowAtPoint(visRect.getLocation()); + int column; + if (isLeftToRight) { + column = columnAtPoint(visRect.getLocation()); + } + else { + column = columnAtPoint(new Point(visRect.x + visRect.width - 1, visRect.y)); + } + return new Point(row, column); + } + } + + class TestList extends JList implements TestTools { + final int[] MAXVALS = {5, 16, 15, 20, 25, 20, 15, 10 }; + public TestList(ListModel model) { + super(model); + } + + // Note - implemented in terms of columns + public Point getLeadingCell() { + System.out.println("TL.gLC(): first vis index is " + + getFirstVisibleIndex()); + return new Point(getFirstVisibleIndex() / ROWS, + getFirstVisibleIndex() / ROWS); + } + public void checkTopCellIsLinedUp() { + boolean isLeftToRight = getComponentOrientation().isLeftToRight(); + int visIdx = getFirstVisibleIndex(); + Rectangle cellRect = getCellBounds(visIdx, visIdx); + Rectangle visRect = getVisibleRect(); + if (isLeftToRight) { + if (cellRect.x != visRect.x) { + throw new RuntimeException("leading cell is not aligned!"); + } + } + else { + if (cellRect.x + cellRect.width != visRect.x + visRect.width) { + throw new RuntimeException("leading cell is not aligned!"); + } + } + } + public void checkTopCellIs(int col) { + int firstVis = getLeadingCell().y; + if (firstVis != col) { + throw new RuntimeException("leading cell (" + + firstVis + ") is not " + col); + } + } + public void checkTopCellIs(int idx, int shift) { + checkTopCellIs(idx + shift); + + } + public void checkTopCellIsMax(int idx) { + checkTopCellIs(MAXVALS[idx]); + } + public int getLeadingCellWidth() { + int visIdx = getFirstVisibleIndex(); + Rectangle cellRect = getCellBounds(visIdx, visIdx); + System.out.println("TL.gLCW(): leading cell width is " + cellRect.width); + return cellRect.width; + } + } + + private interface TestTools { + /** + * Throws a runtime exception if the top cell isn't lined up + */ + void checkTopCellIsLinedUp(); + void checkTopCellIs(int col); + void checkTopCellIs(int col, int shift); + int getLeadingCellWidth(); + Point getLeadingCell(); + + void checkTopCellIsMax(int idx); + } + + public void scrollToMiddle(JScrollPane jsp, Robot robot) + throws InterruptedException, InvocationTargetException { + SwingUtilities.invokeAndWait(() -> { + sb = jsp.getHorizontalScrollBar(); + loc = sb.getLocationOnScreen(); + size = sb.getSize(); + }); + robot.setAutoDelay(250); + + robot.mouseMove(loc.x + size.width / 2, + loc.y + size.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + SwingUtilities.invokeAndWait(() -> { + if (jsp == listScroller) { + int idx = list.getFirstVisibleIndex(); + list.ensureIndexIsVisible(idx); + } + }); + } + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(() -> f = new RTLScrollers()); + } finally { + SwingUtilities.invokeAndWait(() -> { + f.setVisible(true); + f.dispose(); + }); + } + } +} diff --git a/test/jdk/javax/swing/JScrollPane/bug4166037.java b/test/jdk/javax/swing/JScrollPane/bug4166037.java new file mode 100644 index 0000000000000..e2ce75867a70c --- /dev/null +++ b/test/jdk/javax/swing/JScrollPane/bug4166037.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4166037 + * @summary Tests if changes to JScrollPane propagate to ScrollPaneLayout + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4166037 + */ + +import java.awt.Color; + +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.ScrollPaneLayout; + +public class bug4166037 { + static final String INSTRUCTIONS = """ + Press button "Never". Scroll bars should disappear. + Press button "Always". Scroll bars should appear. + Press button "Colhead". Label ColumnHeader should + get replaced with yellow rectangles. + Press button "Corner". You should see 4 green + rectangles in the corners of the scroll pane. + Press button "Rowhead". Label RowHeader should get + replaced with yellow rectangles. + Press button "Viewport". Viewport (the rest of the + area except scrollbars) should get replaced with yellow + rectangles. + If the behavior is as described, the test PASSES. + Otherwise, this test FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4166037 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4166037::createUI) + .logArea() + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("JScrollPane in JScrollLayout Test"); + JScrollPane scroll = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + JPanel p = new JPanel(); + scroll.setSize(200, 200); + f.add(scroll); + f.setLayout(new BoxLayout(f.getContentPane(), BoxLayout.Y_AXIS)); + JButton bn = new JButton("Never"); + bn.addActionListener(e -> { + PassFailJFrame.log("pane before: " + + scroll.getVerticalScrollBarPolicy() + + scroll.getHorizontalScrollBarPolicy()); + PassFailJFrame.log("layout before: " + + ((ScrollPaneLayout) scroll.getLayout()).getVerticalScrollBarPolicy() + + ((ScrollPaneLayout) scroll.getLayout()).getHorizontalScrollBarPolicy()); + scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); + scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + PassFailJFrame.log("pane after: " + + scroll.getVerticalScrollBarPolicy() + + scroll.getHorizontalScrollBarPolicy()); + PassFailJFrame.log("layout after: " + + ((ScrollPaneLayout) scroll.getLayout()).getVerticalScrollBarPolicy() + + ((ScrollPaneLayout) scroll.getLayout()).getHorizontalScrollBarPolicy()); + }); + JButton ba = new JButton("Always"); + ba.addActionListener(e -> { + PassFailJFrame.log("pane before: " + + scroll.getVerticalScrollBarPolicy() + + scroll.getHorizontalScrollBarPolicy()); + PassFailJFrame.log("layout before: " + + ((ScrollPaneLayout) scroll.getLayout()).getVerticalScrollBarPolicy() + + ((ScrollPaneLayout) scroll.getLayout()).getHorizontalScrollBarPolicy()); + scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + PassFailJFrame.log("pane after: " + + scroll.getVerticalScrollBarPolicy() + + scroll.getHorizontalScrollBarPolicy()); + PassFailJFrame.log("layout after: " + + ((ScrollPaneLayout) scroll.getLayout()).getVerticalScrollBarPolicy() + + ((ScrollPaneLayout) scroll.getLayout()).getHorizontalScrollBarPolicy()); + }); + JLabel ch = new JLabel("ColumnHeader"); + scroll.setColumnHeaderView(ch); + JButton b1 = new JButton("Colhead"); + b1.addActionListener(e -> { + JPanel filler = new JPanel(); + filler.setSize(150, 150); + filler.setBackground(Color.yellow); + scroll.getColumnHeader().add(filler); + }); + JButton b2 = new JButton("Corners"); + b2.addActionListener(e -> { + JPanel filler1 = new JPanel(); + filler1.setSize(150, 150); + filler1.setBackground(Color.green); + scroll.setCorner(JScrollPane.LOWER_RIGHT_CORNER, filler1); + JPanel filler2 = new JPanel(); + filler2.setSize(150, 150); + filler2.setBackground(Color.green); + scroll.setCorner(JScrollPane.LOWER_LEFT_CORNER, filler2); + JPanel filler3 = new JPanel(); + filler3.setSize(150, 150); + filler3.setBackground(Color.green); + scroll.setCorner(JScrollPane.UPPER_RIGHT_CORNER, filler3); + JPanel filler4 = new JPanel(); + filler4.setSize(150, 150); + filler4.setBackground(Color.green); + scroll.setCorner(JScrollPane.UPPER_LEFT_CORNER, filler4); + }); + JLabel rh = new JLabel("RowHeader"); + scroll.setRowHeaderView(rh); + JButton b3 = new JButton("Rowhead"); + b3.addActionListener(e -> { + JPanel filler = new JPanel(); + filler.setSize(150, 150); + filler.setBackground(Color.yellow); + scroll.getRowHeader().add(filler); + }); + JButton b4 = new JButton("Viewport"); + b4.addActionListener(e -> { + JPanel filler = new JPanel(); + filler.setSize(150, 150); + filler.setBackground(Color.yellow); + scroll.getViewport().add(filler); + }); + + p.add(bn); + p.add(ba); + p.add(b1); + p.add(b2); + p.add(b3); + p.add(b4); + f.add(p); + f.setSize(300, 300); + return f; + } +} diff --git a/test/jdk/javax/swing/JScrollPane/bug4237517.java b/test/jdk/javax/swing/JScrollPane/bug4237517.java new file mode 100644 index 0000000000000..4e1d135619986 --- /dev/null +++ b/test/jdk/javax/swing/JScrollPane/bug4237517.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4237517 + * @summary Tests that scrolling with blit draws the right thing + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4237517 + */ + +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JScrollPane; + +public class bug4237517 { + static final String INSTRUCTIONS = """ + Select the first item in the list and hit PageDown + key two times. If the list is redrawn correctly, + i.e. if the digits go in order, then the test PASSES. + Otherwise, the test FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4237517 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4237517::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("Scrolling Window Blit Test"); + String[] data = new String[100]; + + for (int counter = 0; counter < data.length; counter++) { + data[counter] = Integer.toString(counter); + } + JList list = new JList(data); + JScrollPane sp = new JScrollPane(list); + sp.getViewport().putClientProperty("EnableWindowBlit", Boolean.TRUE); + f.add(sp); + f.setSize(200, 200); + return f; + } +} diff --git a/test/jdk/javax/swing/JScrollPane/bug4237560.java b/test/jdk/javax/swing/JScrollPane/bug4237560.java new file mode 100644 index 0000000000000..4f8f27683e542 --- /dev/null +++ b/test/jdk/javax/swing/JScrollPane/bug4237560.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4237560 + * @summary Tests that JScrollPane do not distort TAB order in an HTML page + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4237560 + */ + +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.JScrollPane; + +public class bug4237560 { + static final String INSTRUCTIONS = """ + A JEditorPane contains 10 input fields and is inserted into + JScrollPane. Click text field #8 so that it is selected. Press + TAB three times (even if text field #9 and #10 are not visible in + the ScrollPane). If this gives focus to the first text field (#1) + the test PASSES, else it FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4237560 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4237560::createUI) + .build() + .awaitAndCheck(); + } + + private static final String TEXT = "
\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "
"; + + private static JFrame createUI() { + JFrame frame = new JFrame("JScrollPane HTML TAB Test"); + JEditorPane viewer = new JEditorPane("text/html", TEXT); + viewer.setEditable(false); + frame.add(new JScrollPane(viewer)); + frame.setSize(300, 300); + return frame; + } +} diff --git a/test/jdk/javax/swing/JScrollPane/bug4244899.java b/test/jdk/javax/swing/JScrollPane/bug4244899.java new file mode 100644 index 0000000000000..4cb5367f4f543 --- /dev/null +++ b/test/jdk/javax/swing/JScrollPane/bug4244899.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4244899 + * @summary Tests whether scrolling with blit has artifacts + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4244899 + */ + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; + +public class bug4244899 { + static final String INSTRUCTIONS = """ + Widen the first column of the table, so that + you get a horizontal scrollbar. Click in the + scrollbar (not on the thumb, but in the track). + If you notice some artifacts/flashing at + the bottom of the frame, the test FAILS. + Otherwise, the test PASSES. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4244899 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4244899::createUI) + .build() + .awaitAndCheck(); + } + + static class TestModel extends AbstractTableModel { + private final int rows = 20; + private final int cols = 5; + + private Integer[][] data; + + public TestModel() { + data = new Integer[rows][]; + int realCount = 0; + for (int counter = 0; counter < rows; counter++) { + data[counter] = new Integer[cols]; + for (int y = 0; y < cols; y++) { + data[counter][y] = Integer.valueOf(realCount); + realCount = (realCount + 1) % 23; + } + } + } + + public int getRowCount() { + return data.length; + } + + public int getColumnCount() { + return data[0].length; + } + + public Object getValueAt(int row, int column) { + return data[row][column]; + } + } + + static JFrame createUI() { + JFrame f = new JFrame("Scrolling Blit Artifact Test"); + JTable table = new JTable(new TestModel()); + JScrollPane sp = new JScrollPane(table); + sp.getViewport().putClientProperty("EnableWindowBlit", Boolean.TRUE); + table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + f.add(sp); + f.setSize(400, 400); + return f; + } +} From b7e8952ad6def4ebae8c8c3c04cf6793f472b029 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Tue, 22 Apr 2025 23:21:26 +0000 Subject: [PATCH 0714/1101] 8355071: Fix nsk/jdi test to not require lookup of main thread in order to set the breakpoint used for communication Reviewed-by: lmesnik, amenkov --- .../BooleanType/_itself_/booleantype001.java | 11 +---- .../addInstanceFilter/instancefilter002.java | 12 +----- .../addInstanceFilter/instancefilter003.java | 12 +----- .../addThreadFilter/threadfilter002.java | 12 +----- .../addThreadFilter/threadfilter003.java | 12 +----- .../location/location001.java | 13 +----- .../jdi/ByteType/_itself_/bytetype001.java | 11 +---- .../jdi/CharType/_itself_/chartype001.java | 11 +---- .../definedClasses/definedclasses001.java | 11 +---- .../visibleClasses/visibleclasses001.java | 11 +---- .../addClassExclusionFilter/filter003.java | 15 ++----- .../addClassFilter_rt/filter_rt002.java | 12 +----- .../addClassFilter_s/filter_s002.java | 13 +----- .../DoubleType/_itself_/doubletype001.java | 11 +---- .../nsk/jdi/Event/request/request001.java | 13 +----- .../EventIterator/nextEvent/nextevent001.java | 13 +----- .../nsk/jdi/EventQueue/remove/remove004.java | 15 +------ .../jdi/EventQueue/remove_l/remove_l004.java | 15 +------ .../addCountFilter/addcountfilter001.java | 12 +----- .../jdi/EventRequest/disable/disable002.java | 12 +----- .../jdi/EventRequest/enable/enable001.java | 12 +----- .../jdi/EventRequest/enable/enable002.java | 12 +----- .../getProperty/getproperty001.java | 12 +----- .../EventRequest/isEnabled/isenabled001.java | 12 +----- .../putProperty/putproperty001.java | 12 +----- .../setEnabled/setenabled001.java | 12 +----- .../setEnabled/setenabled002.java | 12 +----- .../setEnabled/setenabled003.java | 12 +----- .../setSuspendPolicy/setsuspendpolicy001.java | 12 +----- .../suspendPolicy/suspendpolicy001.java | 12 +----- .../accwtchpreq002.java | 12 +----- .../breakpointRequests/breakpreq002.java | 12 +----- .../classPrepareRequests/clsprepreq002.java | 12 +----- .../classUnloadRequests/clsunlreq002.java | 12 +----- .../craccwtchpreq003.java | 12 +----- .../crbreakpreq003.java | 12 +----- .../createClassPrepareRequest/cpreg001.java | 12 +----- .../createClassUnloadRequest/cureg001.java | 12 +----- .../createExceptionRequest/crexreq009.java | 12 +----- .../createExceptionRequest/crexreq010.java | 12 +----- .../createMethodEntryRequest/menreg001.java | 12 +----- .../createMethodExitRequest/mexreg001.java | 12 +----- .../crmodwtchpreq003.java | 12 +----- .../createStepRequest/crstepreq002.java | 12 +----- .../createStepRequest/crstepreq003.java | 10 +---- .../createStepRequest/crstepreq004.java | 6 +-- .../createThreadDeathRequest/tdreg001.java | 12 +----- .../createThreadStartRequest/tsreg001.java | 12 +----- .../createVMDeathRequest/vmdreg001.java | 12 +----- .../deleteAllBreakpoints/delallbreakp002.java | 12 +----- .../deleteEventRequest/delevtreq002.java | 12 +----- .../deleteEventRequests/delevtreqs002.java | 12 +----- .../exceptionRequests/excreq002.java | 12 +----- .../methodEntryRequests/methentreq002.java | 12 +----- .../methodExitRequests/methexitreq002.java | 12 +----- .../modwtchpreq002.java | 12 +----- .../stepRequests/stepreq002.java | 12 +----- .../threadDeathRequests/thrdeathreq002.java | 12 +----- .../threadStartRequests/thrstartreq002.java | 12 +----- .../vmDeathRequests/vmdeathreq001.java | 12 +----- .../eventIterator/eventiterator001.java | 13 +----- .../eventIterator/eventiterator002.java | 14 ++----- .../eventIterator/eventiterator003.java | 11 +---- .../eventIterator/eventiterator004.java | 13 +----- .../nsk/jdi/EventSet/resume/resume002.java | 13 ++---- .../nsk/jdi/EventSet/resume/resume003.java | 12 ++---- .../nsk/jdi/EventSet/resume/resume004.java | 12 ++---- .../nsk/jdi/EventSet/resume/resume005.java | 12 ++---- .../nsk/jdi/EventSet/resume/resume006.java | 12 ++---- .../nsk/jdi/EventSet/resume/resume007.java | 12 ++---- .../nsk/jdi/EventSet/resume/resume010.java | 12 ++---- .../nsk/jdi/EventSet/resume/resume011.java | 12 ++---- .../nsk/jdi/EventSet/resume/resume012.java | 12 ++---- .../nsk/jdi/EventSet/resume/resume013.java | 12 ++---- .../suspendPolicy/suspendpolicy001.java | 12 ++---- .../suspendPolicy/suspendpolicy002.java | 12 ++---- .../suspendPolicy/suspendpolicy003.java | 12 ++---- .../suspendPolicy/suspendpolicy004.java | 12 ++---- .../suspendPolicy/suspendpolicy005.java | 12 ++---- .../suspendPolicy/suspendpolicy006.java | 12 ++---- .../suspendPolicy/suspendpolicy007.java | 12 ++---- .../suspendPolicy/suspendpolicy008.java | 12 ++---- .../suspendPolicy/suspendpolicy009.java | 12 ++---- .../suspendPolicy/suspendpolicy010.java | 12 ++---- .../suspendPolicy/suspendpolicy011.java | 12 ++---- .../suspendPolicy/suspendpolicy012.java | 12 ++---- .../suspendPolicy/suspendpolicy013.java | 12 ++---- .../suspendPolicy/suspendpolicy014.java | 12 ++---- .../suspendPolicy/suspendpolicy015.java | 12 ++---- .../suspendPolicy/suspendpolicy016.java | 12 ++---- .../suspendPolicy/suspendpolicy017.java | 12 ++---- .../addClassExclusionFilter/filter002.java | 12 +----- .../addClassFilter_rt/filter_rt002.java | 12 +----- .../addClassFilter_s/filter_s002.java | 12 +----- .../addInstanceFilter/instancefilter002.java | 12 +----- .../addInstanceFilter/instancefilter003.java | 12 +----- .../addThreadFilter/threadfilter002.java | 12 +----- .../addThreadFilter/threadfilter003.java | 12 +----- .../exception/exception001.java | 12 +----- .../notifyCaught/notifycaught001.java | 12 +----- .../notifyUncaught/notifyuncaught001.java | 12 +----- .../jdi/FloatType/_itself_/floattype001.java | 11 +---- .../IntegerType/_itself_/integertype001.java | 11 +---- .../jdi/LocatableEvent/thread/thread001.java | 11 +---- .../jdi/LongType/_itself_/longtype001.java | 11 +---- .../jdi/Method/isObsolete/isobsolete001.java | 17 +++----- .../jdi/Method/isObsolete/isobsolete002.java | 17 +++----- .../addClassExclusionFilter/filter002.java | 12 +----- .../addClassFilter_rt/filter_rt002.java | 12 +----- .../addClassFilter_s/filter_s002.java | 12 +----- .../addInstanceFilter/instancefilter002.java | 12 +----- .../addInstanceFilter/instancefilter003.java | 12 +----- .../addThreadFilter/threadfilter002.java | 12 +----- .../addThreadFilter/threadfilter003.java | 12 +----- .../addClassExclusionFilter/filter002.java | 12 +----- .../addClassFilter_rt/filter_rt002.java | 12 +----- .../addClassFilter_s/filter_s002.java | 12 +----- .../addInstanceFilter/instancefilter002.java | 12 +----- .../addInstanceFilter/instancefilter003.java | 12 +----- .../addThreadFilter/threadfilter002.java | 12 +----- .../addThreadFilter/threadfilter003.java | 12 +----- .../_itself_/mwevent001.java | 12 +----- .../disablecollection002.java | 11 +---- .../classPath/classpath001.java | 15 +------ .../_itself_/primitivetype001.java | 11 +---- .../classLoader/classloader001.java | 15 +------ .../ReferenceType/getValue/getvalue001.java | 15 +------ .../ReferenceType/getValue/getvalue002.java | 15 +------ .../ReferenceType/getValue/getvalue003.java | 15 +------ .../ReferenceType/getValues/getvalues001.java | 15 +------ .../jdi/ReferenceType/isFinal/isfinal001.java | 15 +------ .../ReferenceType/isStatic/isstatic001.java | 11 +---- .../ReferenceType/isStatic/isstatic002.java | 11 +---- .../nestedTypes/nestedtypes001.java | 15 +------ .../nestedTypes/nestedtypes002.java | 15 +------ .../jdi/ShortType/_itself_/shorttype001.java | 11 +---- .../addClassExclusionFilter/filter002.java | 16 ++----- .../addClassFilter_rt/filter_rt002.java | 12 +----- .../addClassFilter_s/filter_s002.java | 12 +----- .../addInstanceFilter/instancefilter002.java | 12 +----- .../addInstanceFilter/instancefilter003.java | 12 +----- .../nsk/jdi/StepRequest/depth/depth001.java | 12 +----- .../nsk/jdi/StepRequest/depth/depth002.java | 12 +----- .../nsk/jdi/StepRequest/depth/depth003.java | 12 +----- .../nsk/jdi/StepRequest/size/size001.java | 12 +----- .../nsk/jdi/StepRequest/size/size002.java | 12 +----- .../nsk/jdi/StepRequest/thread/thread001.java | 12 +----- .../addThreadFilter/addthreadfilter001.java | 13 +----- .../addThreadFilter/addthreadfilter002.java | 14 ++----- .../addThreadFilter/addthreadfilter003.java | 11 +---- .../addThreadFilter/addthreadfilter005.java | 12 +----- .../popFrames/popframes001.java | 15 +------ .../popFrames/popframes002.java | 14 +------ .../popFrames/popframes003.java | 19 ++------- .../popFrames/popframes004.java | 12 +----- .../popFrames/popframes005.java | 12 +----- .../addThreadFilter/addthreadfilter001.java | 13 +----- .../addThreadFilter/addthreadfilter003.java | 11 +---- .../addThreadFilter/addthreadfilter005.java | 12 +----- .../jdi/VMDeathEvent/_itself_/vmdeath002.java | 11 +---- .../jdi/VMDeathEvent/_itself_/vmdeath003.java | 11 +---- .../allClasses/allclasses001.java | 15 +------ .../canAddMethod/canaddmethod001.java | 15 +------ .../canPopFrames/canpopframes001.java | 15 +------ .../canredefineclasses001.java | 15 +------ .../canreqvmdev001.java | 15 +------ .../curc001.java | 15 +------ .../canusefilters001.java | 15 +------ .../canwatchaccess001.java | 15 +------ .../canwatchmod001.java | 15 +------ .../redefineClasses/redefineclasses001.java | 25 ++++------- .../jdi/VoidType/_itself_/voidtype001.java | 11 +---- .../addClassExclusionFilter/filter003.java | 12 +----- .../addClassExclusionFilter/filter004.java | 12 +----- .../addClassFilter_rt/filter_rt003.java | 12 +----- .../addClassFilter_rt/filter_rt004.java | 12 +----- .../addClassFilter_s/filter_s003.java | 12 +----- .../addClassFilter_s/filter_s004.java | 12 +----- .../addInstanceFilter/instancefilter003.java | 12 +----- .../addInstanceFilter/instancefilter004.java | 12 +----- .../addInstanceFilter/instancefilter005.java | 12 +----- .../addInstanceFilter/instancefilter006.java | 12 +----- .../addThreadFilter/addthreadfilter003.java | 12 +----- .../addThreadFilter/addthreadfilter004.java | 12 +----- .../addThreadFilter/addthreadfilter005.java | 12 +----- .../addThreadFilter/addthreadfilter006.java | 12 +----- .../jdi/WatchpointRequest/field/field001.java | 13 +----- .../jdi/WatchpointRequest/field/field002.java | 12 +----- .../vmTestbase/nsk/share/jdi/JDIBase.java | 42 ++++++++++++++++++- 189 files changed, 462 insertions(+), 1923 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/BooleanType/_itself_/booleantype001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/BooleanType/_itself_/booleantype001.java index 92bb93ad15ce9..49c0b778c767c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/BooleanType/_itself_/booleantype001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/BooleanType/_itself_/booleantype001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -244,14 +244,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addInstanceFilter/instancefilter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addInstanceFilter/instancefilter002.java index e37ee7eacbe8d..31dd671817739 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addInstanceFilter/instancefilter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addInstanceFilter/instancefilter002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -257,15 +257,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addInstanceFilter/instancefilter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addInstanceFilter/instancefilter003.java index 612792a417b35..5562d2c4239b3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addInstanceFilter/instancefilter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addInstanceFilter/instancefilter003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -245,15 +245,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addThreadFilter/threadfilter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addThreadFilter/threadfilter002.java index 6d39e3d31c1ad..b76ccc799f27e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addThreadFilter/threadfilter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addThreadFilter/threadfilter002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -252,15 +252,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addThreadFilter/threadfilter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addThreadFilter/threadfilter003.java index 421ffc2618501..ff18b6b6cf5f0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addThreadFilter/threadfilter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/addThreadFilter/threadfilter003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -252,15 +252,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/location/location001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/location/location001.java index f2d2de7321050..325159b6eb5a2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/location/location001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/BreakpointRequest/location/location001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -250,16 +250,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ByteType/_itself_/bytetype001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ByteType/_itself_/bytetype001.java index 4c56c75ad133e..36666e3b08eb1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ByteType/_itself_/bytetype001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ByteType/_itself_/bytetype001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,14 +238,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/CharType/_itself_/chartype001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/CharType/_itself_/chartype001.java index 66579c598b775..3b0d71619aea1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/CharType/_itself_/chartype001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/CharType/_itself_/chartype001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,14 +238,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassLoaderReference/definedClasses/definedclasses001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassLoaderReference/definedClasses/definedclasses001.java index 59fc1a0ab1101..c7b9cb9285854 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassLoaderReference/definedClasses/definedclasses001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassLoaderReference/definedClasses/definedclasses001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -241,14 +241,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassLoaderReference/visibleClasses/visibleclasses001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassLoaderReference/visibleClasses/visibleclasses001.java index 63b6fec010c5a..1d561c27b95cb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassLoaderReference/visibleClasses/visibleclasses001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassLoaderReference/visibleClasses/visibleclasses001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -255,14 +255,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassExclusionFilter/filter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassExclusionFilter/filter003.java index cabaf723c146c..c0bfe91a7505f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassExclusionFilter/filter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassExclusionFilter/filter003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -244,18 +244,9 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; + setupBreakpointForCommunication(debuggeeClass); - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); - - //------------------------------------------------------ testing section + //------------------------------------------------------ testing section log1(" TESTING BEGINS"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_rt/filter_rt002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_rt/filter_rt002.java index dfaaa17697757..9be0d89a4b93a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_rt/filter_rt002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_rt/filter_rt002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -248,15 +248,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_s/filter_s002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_s/filter_s002.java index c175dff4e2f83..1cc0dff5c997d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_s/filter_s002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_s/filter_s002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -250,16 +250,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/DoubleType/_itself_/doubletype001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/DoubleType/_itself_/doubletype001.java index c7aa128fa9411..99ddbbdcbcc26 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/DoubleType/_itself_/doubletype001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/DoubleType/_itself_/doubletype001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,14 +238,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Event/request/request001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Event/request/request001.java index c6d7b7292e76c..970aedb047dfc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Event/request/request001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Event/request/request001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -308,16 +308,7 @@ private void testRun() log2("......setting up ClassPrepareEvent"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventIterator/nextEvent/nextevent001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventIterator/nextEvent/nextevent001.java index 11b6e4824fc84..a60184507716e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventIterator/nextEvent/nextevent001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventIterator/nextEvent/nextevent001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -306,16 +306,7 @@ private void testRun() log2("......setting up ClassPrepareEvent"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventQueue/remove/remove004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventQueue/remove/remove004.java index a5d74ff3d951c..f6cf40dad38e2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventQueue/remove/remove004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventQueue/remove/remove004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -243,18 +243,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventQueue/remove_l/remove_l004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventQueue/remove_l/remove_l004.java index 056030aab3d10..9a84dd3f0fea9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventQueue/remove_l/remove_l004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventQueue/remove_l/remove_l004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,18 +238,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/addCountFilter/addcountfilter001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/addCountFilter/addcountfilter001.java index 41411b88ac9ea..f4e41409cae58 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/addCountFilter/addcountfilter001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/addCountFilter/addcountfilter001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -248,15 +248,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/disable/disable002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/disable/disable002.java index 2bf6c911e6d51..b46bf2ee1a2fa 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/disable/disable002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/disable/disable002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -244,15 +244,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/enable/enable001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/enable/enable001.java index 109ab14880605..615cf46c7461d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/enable/enable001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/enable/enable001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -244,15 +244,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/enable/enable002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/enable/enable002.java index f4f9a14ac1d97..767f069438fe1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/enable/enable002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/enable/enable002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,15 +246,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/getProperty/getproperty001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/getProperty/getproperty001.java index 886993a4bb013..b4b9f0edcbcdc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/getProperty/getproperty001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/getProperty/getproperty001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,15 +246,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/isEnabled/isenabled001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/isEnabled/isenabled001.java index 3ef5500e4aba5..d91db9a5a6ac1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/isEnabled/isenabled001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/isEnabled/isenabled001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -245,15 +245,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/putProperty/putproperty001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/putProperty/putproperty001.java index fcedeca850bfd..479c40904e732 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/putProperty/putproperty001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/putProperty/putproperty001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,15 +246,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setEnabled/setenabled001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setEnabled/setenabled001.java index 1d7c80dfa344d..57ed8454edadd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setEnabled/setenabled001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setEnabled/setenabled001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -243,15 +243,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setEnabled/setenabled002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setEnabled/setenabled002.java index c7bcfaa47b72b..25b665dbed922 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setEnabled/setenabled002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setEnabled/setenabled002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -247,15 +247,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setEnabled/setenabled003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setEnabled/setenabled003.java index 8e129027b516b..7ebe5b99a1f55 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setEnabled/setenabled003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setEnabled/setenabled003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,15 +246,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setSuspendPolicy/setsuspendpolicy001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setSuspendPolicy/setsuspendpolicy001.java index e1b315519fd94..04995ea0b13a3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setSuspendPolicy/setsuspendpolicy001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/setSuspendPolicy/setsuspendpolicy001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -248,15 +248,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/suspendPolicy/suspendpolicy001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/suspendPolicy/suspendpolicy001.java index 7f927de157787..b11a291b2f588 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/suspendPolicy/suspendpolicy001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/suspendPolicy/suspendpolicy001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -244,15 +244,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/accessWatchpointRequests/accwtchpreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/accessWatchpointRequests/accwtchpreq002.java index f27f6a12e312e..c7b1af9d79b1d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/accessWatchpointRequests/accwtchpreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/accessWatchpointRequests/accwtchpreq002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -245,15 +245,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/breakpointRequests/breakpreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/breakpointRequests/breakpreq002.java index 4046560e44437..699793453824f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/breakpointRequests/breakpreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/breakpointRequests/breakpreq002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -240,15 +240,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/classPrepareRequests/clsprepreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/classPrepareRequests/clsprepreq002.java index c9719ba3a5434..b2905b6527e7f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/classPrepareRequests/clsprepreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/classPrepareRequests/clsprepreq002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -241,15 +241,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/classUnloadRequests/clsunlreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/classUnloadRequests/clsunlreq002.java index b6bc52f154e30..c185b8b398e3b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/classUnloadRequests/clsunlreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/classUnloadRequests/clsunlreq002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -241,15 +241,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createAccessWatchpointRequest/craccwtchpreq003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createAccessWatchpointRequest/craccwtchpreq003.java index 2be4f8afc9d26..9326ce5c7d942 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createAccessWatchpointRequest/craccwtchpreq003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createAccessWatchpointRequest/craccwtchpreq003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -244,15 +244,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createBreakpointRequest/crbreakpreq003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createBreakpointRequest/crbreakpreq003.java index 610a691b269e1..b4af90a642c26 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createBreakpointRequest/crbreakpreq003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createBreakpointRequest/crbreakpreq003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -241,15 +241,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createClassPrepareRequest/cpreg001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createClassPrepareRequest/cpreg001.java index dd0848af06c9b..62761b58d33dd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createClassPrepareRequest/cpreg001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createClassPrepareRequest/cpreg001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -240,15 +240,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createClassUnloadRequest/cureg001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createClassUnloadRequest/cureg001.java index bba4427d531be..4cedae783cf18 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createClassUnloadRequest/cureg001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createClassUnloadRequest/cureg001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -239,15 +239,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createExceptionRequest/crexreq009.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createExceptionRequest/crexreq009.java index 4ba4bba13a352..fa92b0e5b9680 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createExceptionRequest/crexreq009.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createExceptionRequest/crexreq009.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -242,15 +242,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createExceptionRequest/crexreq010.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createExceptionRequest/crexreq010.java index 6d466265ddf2b..28a787d957f2a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createExceptionRequest/crexreq010.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createExceptionRequest/crexreq010.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -243,15 +243,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createMethodEntryRequest/menreg001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createMethodEntryRequest/menreg001.java index e744ec1e8f802..7bfeb11932aa6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createMethodEntryRequest/menreg001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createMethodEntryRequest/menreg001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -239,15 +239,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createMethodExitRequest/mexreg001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createMethodExitRequest/mexreg001.java index 9d107ee60b0a4..94b97da9c0e7e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createMethodExitRequest/mexreg001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createMethodExitRequest/mexreg001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,15 +238,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createModificationWatchpointRequest/crmodwtchpreq003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createModificationWatchpointRequest/crmodwtchpreq003.java index 2419863358026..6059dead1314d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createModificationWatchpointRequest/crmodwtchpreq003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createModificationWatchpointRequest/crmodwtchpreq003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -243,15 +243,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createStepRequest/crstepreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createStepRequest/crstepreq002.java index da62eaea14644..a5dd9023dfd6d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createStepRequest/crstepreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createStepRequest/crstepreq002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -243,15 +243,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createStepRequest/crstepreq003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createStepRequest/crstepreq003.java index 129d9470730a7..d712fb34c42a4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createStepRequest/crstepreq003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createStepRequest/crstepreq003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -157,14 +157,6 @@ private int runThis(String argv[], PrintStream out) { //--------------------------------------------------------- mutable common methods private void execTest() { - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); -/* - BreakpointRequest bpRequest = setBreakpoint( mainThread, - debuggeeClass, - "methodForCommunication", - 2, - "breakpointForCommunication"); -*/ BreakpointRequest bpRequest = setBreakpoint( null, debuggeeClass, "breakInThread", diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createStepRequest/crstepreq004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createStepRequest/crstepreq004.java index 24305ec29f262..1ab0ce68af8ad 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createStepRequest/crstepreq004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createStepRequest/crstepreq004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -158,9 +158,7 @@ private int runThis(String argv[], PrintStream out) { //--------------------------------------------------------- mutable common methods private void execTest() { - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = setBreakpoint( mainThread, + BreakpointRequest bpRequest = setBreakpoint( null, debuggeeClass, "methodForCommunication", lineForBreakInThread, diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createThreadDeathRequest/tdreg001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createThreadDeathRequest/tdreg001.java index 5c650112f5615..e2045f9a94dd2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createThreadDeathRequest/tdreg001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createThreadDeathRequest/tdreg001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -239,15 +239,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createThreadStartRequest/tsreg001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createThreadStartRequest/tsreg001.java index 8b594d43285eb..ed81b00561e9a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createThreadStartRequest/tsreg001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createThreadStartRequest/tsreg001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,15 +238,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createVMDeathRequest/vmdreg001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createVMDeathRequest/vmdreg001.java index dcc5c1b680cef..29f1cacf7e796 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createVMDeathRequest/vmdreg001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/createVMDeathRequest/vmdreg001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -241,15 +241,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/deleteAllBreakpoints/delallbreakp002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/deleteAllBreakpoints/delallbreakp002.java index 072277425ccdf..9ed87be5e1127 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/deleteAllBreakpoints/delallbreakp002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/deleteAllBreakpoints/delallbreakp002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -240,15 +240,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/deleteEventRequest/delevtreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/deleteEventRequest/delevtreq002.java index 9cfafaea23ec0..5b5481af06320 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/deleteEventRequest/delevtreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/deleteEventRequest/delevtreq002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,15 +246,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/deleteEventRequests/delevtreqs002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/deleteEventRequests/delevtreqs002.java index 8a53a91e8e192..03e5e38a3ecb3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/deleteEventRequests/delevtreqs002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/deleteEventRequests/delevtreqs002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -244,15 +244,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/exceptionRequests/excreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/exceptionRequests/excreq002.java index 7c59958fb89d2..78219909d0350 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/exceptionRequests/excreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/exceptionRequests/excreq002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -242,15 +242,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodEntryRequests/methentreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodEntryRequests/methentreq002.java index 2b37b6e47fa54..95a9b36d826ff 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodEntryRequests/methentreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodEntryRequests/methentreq002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -241,15 +241,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodExitRequests/methexitreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodExitRequests/methexitreq002.java index e63a1cd4349a8..f975441a9ba0d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodExitRequests/methexitreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodExitRequests/methexitreq002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -240,15 +240,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/modificationWatchpointRequests/modwtchpreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/modificationWatchpointRequests/modwtchpreq002.java index fe60b2c39636c..8a9d5fcbd3496 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/modificationWatchpointRequests/modwtchpreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/modificationWatchpointRequests/modwtchpreq002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -247,15 +247,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/stepRequests/stepreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/stepRequests/stepreq002.java index b43549953896e..e1f2677c4297c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/stepRequests/stepreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/stepRequests/stepreq002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -241,15 +241,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/threadDeathRequests/thrdeathreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/threadDeathRequests/thrdeathreq002.java index ab46a848c8e29..9e1b9d8edec05 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/threadDeathRequests/thrdeathreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/threadDeathRequests/thrdeathreq002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -241,15 +241,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/threadStartRequests/thrstartreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/threadStartRequests/thrstartreq002.java index f7607b22e086e..d192c61470d39 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/threadStartRequests/thrstartreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/threadStartRequests/thrstartreq002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,15 +246,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/vmDeathRequests/vmdeathreq001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/vmDeathRequests/vmdeathreq001.java index 7f839dcc192ba..3f740b2f30e57 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/vmDeathRequests/vmdeathreq001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/vmDeathRequests/vmdeathreq001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -241,15 +241,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator001.java index f16ab02ddfec2..e56fb00108d2b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -266,16 +266,7 @@ private void testRun() cpRequest.disable(); debuggeeClass = event.referenceType(); - - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); - + setupBreakpointForCommunication(debuggeeClass); } else if (property.equals("TestClassPrepareRequest")) { nn2++; if (nn2 > 1) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator002.java index e0a32aa0aa2fb..0d374f39e3769 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -255,16 +255,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section @@ -286,6 +277,7 @@ private void testRun() vm.resume(); breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator003.java index 323dea95fe7ca..35a9eedfd4d50 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -251,14 +251,7 @@ private void testRun() throws JDITestRuntimeException, Exception { log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - bpRequest = settingBreakpoint(mainThread, debuggeeClass, bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator004.java index 084db7b66766f..20686736deb02 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/eventIterator/eventiterator004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -276,16 +276,7 @@ private void testRun() log2("......setting up ClassPrepareEvent"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume002.java index 09bcb91cbdd04..b391036fa2622 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -260,14 +260,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -287,10 +280,10 @@ private void testRun() ReferenceType testClassReference = null; - for (int i = 0; ; i++) { breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume003.java index 3ea05a0c7d912..0e13529f5e160 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -260,14 +260,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -291,6 +284,7 @@ private void testRun() for (int i = 0; ; i++) { breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume004.java index 413309e92ad7e..398e6f074a0ae 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -253,14 +253,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -285,6 +278,7 @@ private void testRun() for (int i = 0; ; i++) { breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume005.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume005.java index 13e0344dd3fcd..7074828dc8d7d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -253,14 +253,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -285,6 +278,7 @@ private void testRun() for (int i = 0; ; i++) { breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume006.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume006.java index ef87bba8a0d00..492afad89ca95 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -253,14 +253,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -282,6 +275,7 @@ private void testRun() for (int i = 0; ; i++) { breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume007.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume007.java index 235fe36c35c0e..8052c19395472 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume007.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume007.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -253,14 +253,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -282,6 +275,7 @@ private void testRun() for (int i = 0; ; i++) { breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume010.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume010.java index d49e0c516a33d..443b7e942866b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume010.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume010.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -253,14 +253,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -281,6 +274,7 @@ private void testRun() for (int i = 0; ; i++) { breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume011.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume011.java index fb9c1e6fde424..0eb923321bd99 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume011.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume011.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -254,14 +254,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -280,6 +273,7 @@ private void testRun() breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ variable part diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume012.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume012.java index 3d153675ee8c2..32f30882efb7d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume012.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume012.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -255,14 +255,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -281,6 +274,7 @@ private void testRun() breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ variable part diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume013.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume013.java index d1fc3cb68bbf5..6019903d6b888 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume013.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume013.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -255,14 +255,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -280,6 +273,7 @@ private void testRun() breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ variable part diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy001.java index dd51b0d03903d..d145bf46136d6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -257,14 +257,8 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy002.java index 01be6ad55c45a..93f0a5ca62781 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -258,14 +258,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -300,6 +293,7 @@ private void testRun() breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy003.java index 522d6019f2565..5c0052e84f9f9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -265,14 +265,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -308,6 +301,7 @@ private void testRun() breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy004.java index cddb7ace5b05f..d6b6a76be192d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -259,14 +259,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -303,6 +296,7 @@ private void testRun() breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy005.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy005.java index 9d0c7604aba8d..cfdb651348276 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -259,14 +259,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -303,6 +296,7 @@ private void testRun() breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy006.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy006.java index 068dd94eeadf7..660f4bbbc36a6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -258,14 +258,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -301,6 +294,7 @@ private void testRun() breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy007.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy007.java index 4601a0039fad6..71abca720e11f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy007.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy007.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -258,14 +258,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -300,6 +293,7 @@ private void testRun() breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy008.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy008.java index d507d8c6a384d..f0838067241d5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy008.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy008.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -258,14 +258,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -295,6 +288,7 @@ private void testRun() for (int i = 0; ; i++) { breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy009.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy009.java index ca284271be868..21bffce5cf371 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy009.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy009.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -258,14 +258,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -295,6 +288,7 @@ private void testRun() for (int i = 0; ; i++) { breakpointForCommunication(debuggeeName); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy010.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy010.java index ec0155762777f..7bd3b660b93d7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy010.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy010.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -257,14 +257,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -294,6 +287,7 @@ private void testRun() for (int i = 0; ; i++) { breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy011.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy011.java index 03d7677c0fb14..47025717ed7f2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy011.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy011.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -266,14 +266,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -300,6 +293,7 @@ private void testRun() int policy = 0; breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ variable part diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy012.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy012.java index bb5488d9eb6ad..420b2fe6c87ce 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy012.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy012.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -265,14 +265,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -299,6 +292,7 @@ private void testRun() int policy = 0; breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ variable part diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy013.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy013.java index d78655d1b2a00..db3a15f3571bf 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy013.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy013.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -266,14 +266,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -300,6 +293,7 @@ private void testRun() int policy = 0; breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ variable part diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy014.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy014.java index 511dc1ddcc1ed..d1258b93b0dd2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy014.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy014.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -267,14 +267,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -301,6 +294,7 @@ private void testRun() int policy = 0; breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ variable part diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy015.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy015.java index a3961c1d0053b..a14f2485129d4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy015.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy015.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -267,14 +267,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -301,6 +294,7 @@ private void testRun() int policy = 0; breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ variable part diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy016.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy016.java index 0b6257f34eff4..3c270b547fbbb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy016.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy016.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -265,14 +265,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -299,6 +292,7 @@ private void testRun() int policy = 0; breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ variable part diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy017.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy017.java index c7589574ee558..171db5a9bb606 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy017.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/suspendPolicy/suspendpolicy017.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -267,14 +267,7 @@ private void testRun() log2("......setting up ClassPrepareEvent for breakpointForCommunication"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); @@ -301,6 +294,7 @@ private void testRun() int policy = 0; breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ variable part diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addClassExclusionFilter/filter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addClassExclusionFilter/filter002.java index d0dac294c8bea..9402145c3a0d4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addClassExclusionFilter/filter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addClassExclusionFilter/filter002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,15 +249,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addClassFilter_rt/filter_rt002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addClassFilter_rt/filter_rt002.java index c3a39e40d0b7b..ea0e2d3689184 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addClassFilter_rt/filter_rt002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addClassFilter_rt/filter_rt002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -250,15 +250,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addClassFilter_s/filter_s002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addClassFilter_s/filter_s002.java index 8fa62d0edfc1b..c5cad69c37d62 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addClassFilter_s/filter_s002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addClassFilter_s/filter_s002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -250,15 +250,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addInstanceFilter/instancefilter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addInstanceFilter/instancefilter002.java index 6f62f5b08d556..c39f6c8c15d7c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addInstanceFilter/instancefilter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addInstanceFilter/instancefilter002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -257,15 +257,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addInstanceFilter/instancefilter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addInstanceFilter/instancefilter003.java index f1e9f6607ff9f..80f8c4024e2cd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addInstanceFilter/instancefilter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addInstanceFilter/instancefilter003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -245,15 +245,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addThreadFilter/threadfilter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addThreadFilter/threadfilter002.java index d641750204ceb..bb20c736a0664 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addThreadFilter/threadfilter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addThreadFilter/threadfilter002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -252,15 +252,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addThreadFilter/threadfilter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addThreadFilter/threadfilter003.java index 467a66f52fcbe..0d6f85304c892 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addThreadFilter/threadfilter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/addThreadFilter/threadfilter003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -252,15 +252,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/exception/exception001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/exception/exception001.java index 4c0d1824812b3..ef0bf98418290 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/exception/exception001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/exception/exception001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -244,15 +244,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); vm.resume(); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/notifyCaught/notifycaught001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/notifyCaught/notifycaught001.java index ad7478765861e..fd3410f5d4c07 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/notifyCaught/notifycaught001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/notifyCaught/notifycaught001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -242,15 +242,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/notifyUncaught/notifyuncaught001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/notifyUncaught/notifyuncaught001.java index 883e020caa6f1..557f60138ba70 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/notifyUncaught/notifyuncaught001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ExceptionRequest/notifyUncaught/notifyuncaught001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -242,15 +242,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/FloatType/_itself_/floattype001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/FloatType/_itself_/floattype001.java index 156d4b471ba0e..5a051ad546fc1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/FloatType/_itself_/floattype001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/FloatType/_itself_/floattype001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,14 +238,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/IntegerType/_itself_/integertype001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/IntegerType/_itself_/integertype001.java index 206882b2768d1..e40dbb1b7849c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/IntegerType/_itself_/integertype001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/IntegerType/_itself_/integertype001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,14 +238,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/LocatableEvent/thread/thread001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/LocatableEvent/thread/thread001.java index 543123066cf45..f2031008b2fe2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/LocatableEvent/thread/thread001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/LocatableEvent/thread/thread001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -253,14 +253,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/LongType/_itself_/longtype001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/LongType/_itself_/longtype001.java index 05d5baf3a66e0..a483e04e5d915 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/LongType/_itself_/longtype001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/LongType/_itself_/longtype001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,14 +238,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Method/isObsolete/isobsolete001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Method/isObsolete/isobsolete001.java index 02ce3f5e02078..6ccbbca659cae 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Method/isObsolete/isobsolete001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Method/isObsolete/isobsolete001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -261,16 +261,7 @@ private void testRun() return; } - - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByName("main"); - - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section @@ -288,6 +279,7 @@ private void testRun() vm.resume(); breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); @@ -315,7 +307,8 @@ private void testRun() log2(" : isObsolete() == false for m2 method before redefineClasses() invocation "); // Create breakpoint request to have isobsolete002b.m2 on the top of the stack. - bpRequest = debuggee.makeBreakpoint(redefClass, methodName, brkpLineNumber); + BreakpointRequest bpRequest = + debuggee.makeBreakpoint(redefClass, methodName, brkpLineNumber); bpRequest.addThreadFilter(mainThread); bpRequest.setSuspendPolicy( EventRequest.SUSPEND_EVENT_THREAD); bpRequest.putProperty("number", "one"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Method/isObsolete/isobsolete002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Method/isObsolete/isobsolete002.java index 1693a63843ee9..35f59f55524d0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Method/isObsolete/isobsolete002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Method/isObsolete/isobsolete002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -259,16 +259,7 @@ private void testRun() return; } - - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - ThreadReference mainThread = debuggee.threadByName("main"); - - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section @@ -284,6 +275,7 @@ private void testRun() vm.resume(); breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); @@ -315,7 +307,8 @@ private void testRun() log2(" : isObsolete() == false for m2 method before redefineClasses() invocation"); // Create breakpoint request to have isobsolete002b.m2 on the top of the stack. - bpRequest = debuggee.makeBreakpoint(redefClass, methodName, brkpLineNumber); + BreakpointRequest bpRequest = + debuggee.makeBreakpoint(redefClass, methodName, brkpLineNumber); bpRequest.addThreadFilter(mainThread); bpRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); bpRequest.putProperty("number", "one"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassExclusionFilter/filter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassExclusionFilter/filter002.java index 5fef3066c4458..6e293a98670e3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassExclusionFilter/filter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassExclusionFilter/filter002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,15 +249,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassFilter_rt/filter_rt002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassFilter_rt/filter_rt002.java index 1d83e104b72e1..b34e5c577dba1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassFilter_rt/filter_rt002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassFilter_rt/filter_rt002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -250,15 +250,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassFilter_s/filter_s002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassFilter_s/filter_s002.java index 7cb4c40ee473b..215639d825f7e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassFilter_s/filter_s002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassFilter_s/filter_s002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,15 +249,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addInstanceFilter/instancefilter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addInstanceFilter/instancefilter002.java index 3f013618ac918..02cdff05b4ebf 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addInstanceFilter/instancefilter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addInstanceFilter/instancefilter002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -257,15 +257,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addInstanceFilter/instancefilter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addInstanceFilter/instancefilter003.java index 67009ca963dbe..a6386045f2058 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addInstanceFilter/instancefilter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addInstanceFilter/instancefilter003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -248,15 +248,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addThreadFilter/threadfilter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addThreadFilter/threadfilter002.java index b889d75510b58..a5a2b16318ec0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addThreadFilter/threadfilter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addThreadFilter/threadfilter002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -252,15 +252,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addThreadFilter/threadfilter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addThreadFilter/threadfilter003.java index 161190a7abddf..da83ab4ece450 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addThreadFilter/threadfilter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addThreadFilter/threadfilter003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -252,15 +252,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassExclusionFilter/filter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassExclusionFilter/filter002.java index 75f7ad3a523a5..3fd039e10d1f1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassExclusionFilter/filter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassExclusionFilter/filter002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,15 +249,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassFilter_rt/filter_rt002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassFilter_rt/filter_rt002.java index 374ebace2ff7f..4dedd0debb019 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassFilter_rt/filter_rt002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassFilter_rt/filter_rt002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,15 +249,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassFilter_s/filter_s002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassFilter_s/filter_s002.java index 3d243865d1a63..917bc96c467ee 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassFilter_s/filter_s002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassFilter_s/filter_s002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,15 +249,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addInstanceFilter/instancefilter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addInstanceFilter/instancefilter002.java index 25ccf74fe0db0..a00e92c32e9c9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addInstanceFilter/instancefilter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addInstanceFilter/instancefilter002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -257,15 +257,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addInstanceFilter/instancefilter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addInstanceFilter/instancefilter003.java index 33d8d26129108..c5414ae5ae139 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addInstanceFilter/instancefilter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addInstanceFilter/instancefilter003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,15 +246,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addThreadFilter/threadfilter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addThreadFilter/threadfilter002.java index b87bfba5fa64d..8d2dab19a4500 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addThreadFilter/threadfilter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addThreadFilter/threadfilter002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -251,15 +251,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addThreadFilter/threadfilter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addThreadFilter/threadfilter003.java index b09d7f46f9e17..0067f7dde1982 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addThreadFilter/threadfilter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addThreadFilter/threadfilter003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -251,15 +251,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ModificationWatchpointEvent/_itself_/mwevent001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ModificationWatchpointEvent/_itself_/mwevent001.java index 42a1e08eb3b92..ef10699b5fe2b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ModificationWatchpointEvent/_itself_/mwevent001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ModificationWatchpointEvent/_itself_/mwevent001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -252,15 +252,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/disableCollection/disablecollection002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/disableCollection/disablecollection002.java index 89dcfde4d9957..b7ea4154fec2c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/disableCollection/disablecollection002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/disableCollection/disablecollection002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -261,14 +261,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PathSearchingVirtualMachine/classPath/classpath001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PathSearchingVirtualMachine/classPath/classpath001.java index 97908175e7b3a..f67e21a7cdd7c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PathSearchingVirtualMachine/classPath/classpath001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PathSearchingVirtualMachine/classPath/classpath001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -244,18 +244,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PrimitiveType/_itself_/primitivetype001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PrimitiveType/_itself_/primitivetype001.java index a3c32fb0d2780..bb3d23352a105 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/PrimitiveType/_itself_/primitivetype001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/PrimitiveType/_itself_/primitivetype001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -237,14 +237,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classLoader/classloader001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classLoader/classloader001.java index 644e60f484403..1040f7eba695c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classLoader/classloader001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/classLoader/classloader001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -230,18 +230,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValue/getvalue001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValue/getvalue001.java index bcd64b0b46029..ad2be88a6dbf0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValue/getvalue001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValue/getvalue001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -231,18 +231,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValue/getvalue002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValue/getvalue002.java index 5d7439b2f8c3b..8c9aae8802bcf 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValue/getvalue002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValue/getvalue002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -230,18 +230,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValue/getvalue003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValue/getvalue003.java index b81bfd78729d7..46411cb9d747f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValue/getvalue003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValue/getvalue003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -230,18 +230,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValues/getvalues001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValues/getvalues001.java index b14d687b411b8..4e7fb04fe0d38 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValues/getvalues001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/getValues/getvalues001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -234,18 +234,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isFinal/isfinal001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isFinal/isfinal001.java index 885e1ec17a453..88d0d5d81387f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isFinal/isfinal001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isFinal/isfinal001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -218,18 +218,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isStatic/isstatic001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isStatic/isstatic001.java index e6e901f31e5ab..d72a6480dbf8d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isStatic/isstatic001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isStatic/isstatic001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,14 +246,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isStatic/isstatic002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isStatic/isstatic002.java index d07705fe4c6bd..b3cf2483d80a8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isStatic/isstatic002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/isStatic/isstatic002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,14 +246,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/nestedTypes/nestedtypes001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/nestedTypes/nestedtypes001.java index 69d2a8ed24b3f..7369b6638760d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/nestedTypes/nestedtypes001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/nestedTypes/nestedtypes001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -224,18 +224,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/nestedTypes/nestedtypes002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/nestedTypes/nestedtypes002.java index 344e1fd199a7c..dce3f638f28b7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/nestedTypes/nestedtypes002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/nestedTypes/nestedtypes002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -225,18 +225,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch (Exception e) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ShortType/_itself_/shorttype001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ShortType/_itself_/shorttype001.java index fea3e5c78b4fb..54e297f27e8c8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ShortType/_itself_/shorttype001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ShortType/_itself_/shorttype001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,14 +238,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addClassExclusionFilter/filter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addClassExclusionFilter/filter002.java index e53f12004cf00..d64fa09323cca 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addClassExclusionFilter/filter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addClassExclusionFilter/filter002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -248,15 +248,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section @@ -271,6 +263,7 @@ private void testRun() vm.resume(); breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); @@ -287,8 +280,7 @@ private void testRun() switch (i) { case 0: - ThreadReference thread1 = debuggee.threadByNameOrThrow("main"); - eventRequest1 = setting23StepRequest(thread1, testedClassName1, + eventRequest1 = setting23StepRequest(mainThread, testedClassName1, EventRequest.SUSPEND_NONE, property1); eventRequest1.enable(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addClassFilter_rt/filter_rt002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addClassFilter_rt/filter_rt002.java index e12e48e9ebf33..23be3eab4c95a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addClassFilter_rt/filter_rt002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addClassFilter_rt/filter_rt002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -250,15 +250,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addClassFilter_s/filter_s002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addClassFilter_s/filter_s002.java index db080ef80edeb..d4ff86268dafe 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addClassFilter_s/filter_s002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addClassFilter_s/filter_s002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -250,15 +250,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addInstanceFilter/instancefilter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addInstanceFilter/instancefilter002.java index e75a998a07c9b..19ddd27942569 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addInstanceFilter/instancefilter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addInstanceFilter/instancefilter002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -257,15 +257,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addInstanceFilter/instancefilter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addInstanceFilter/instancefilter003.java index f4fa3e1bf68f2..1f8236db782b2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addInstanceFilter/instancefilter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/addInstanceFilter/instancefilter003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,15 +246,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/depth/depth001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/depth/depth001.java index 99d24970e6d27..de63a0af86bf9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/depth/depth001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/depth/depth001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,15 +246,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/depth/depth002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/depth/depth002.java index 09b0fa297b4ab..5cd109f6fa3fe 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/depth/depth002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/depth/depth002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,15 +246,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/depth/depth003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/depth/depth003.java index ef3668a66e8f9..03b8f415b5620 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/depth/depth003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/depth/depth003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,15 +246,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/size/size001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/size/size001.java index 33b2c02e8eb83..db59bf6e4982a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/size/size001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/size/size001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,15 +246,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/size/size002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/size/size002.java index 5a0df35456938..09b0c53ea8cb1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/size/size002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/size/size002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,15 +246,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/thread/thread001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/thread/thread001.java index 8bb9711d37baa..a8d3769c6c2fb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/thread/thread001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepRequest/thread/thread001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -248,15 +248,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter001.java index 542a5280d4b4d..020c04c05d580 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -243,16 +243,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter002.java index 4d572e1d12cf5..961a38a63938c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -240,16 +240,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section @@ -259,6 +250,7 @@ private void testRun() vm.resume(); breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter003.java index 70d9e87fee47b..3a5770ff03c02 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -254,14 +254,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter005.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter005.java index 30fac8e0aaa00..d07758242ec28 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -254,15 +254,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes001.java index 69c30d0aa2405..3091f51097703 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -260,18 +260,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes002.java index 2e5b28c2dfc3a..c47358e96f82f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,7 +111,6 @@ public static int run (String argv[], PrintStream out) { //====================================================== test program - BreakpointRequest bpRequest; BreakpointRequest breakpointRequest2; BreakpointRequest breakpointRequest3; @@ -259,16 +258,7 @@ private void testRun() return; } - - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - log2("......setting BreakpointRequest (bpRequest) in main thread"); - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - log2("bpRequest.enable();"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes003.java index 27866885bdbc6..84ee5996a778a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -110,7 +110,6 @@ public static int run (String argv[], PrintStream out) { //====================================================== test program - BreakpointRequest bpRequest; MethodEntryRequest meRequest; BreakpointRequest bpRequest2; @@ -260,18 +259,7 @@ private void testRun() return; } - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference threadMainRef = debuggee.threadByNameOrThrow("main"); - try { - bpRequest = settingBreakpoint(threadMainRef, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section @@ -284,9 +272,10 @@ private void testRun() vm.resume(); breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() log2("......setting MethodEntryRequest (meRequest) in ForCommunication.methodForCommunication"); - meRequest = settingMethodEntryRequest(threadMainRef, + meRequest = settingMethodEntryRequest(mainThread, debuggeeName + "$ForCommunication", "zero"); log2("meRequest.enable();"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes004.java index 5e06aec181075..eb46fac37dac2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -258,15 +258,7 @@ private void testRun() return; } - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - log2("......setting BreakpointRequest (bpRequest) in main thread"); - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - log2("bpRequest.enable();"); - bpRequest.enable(); + bpRequest = setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes005.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes005.java index 7618a200e28bb..ec499eba24d6c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -262,15 +262,7 @@ private void testRun() return; } - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - log2("......setting BreakpointRequest (bpRequest) in main thread"); - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - log2("bpRequest.enable();"); - bpRequest.enable(); + bpRequest = setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter001.java index ace63e511aa8c..b9a15b2c37796 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -243,16 +243,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter003.java index 21cf8a9d1640d..cacda11b6c4d5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -254,14 +254,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter005.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter005.java index 8dad0781d1630..255984d7a01bb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -248,15 +248,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VMDeathEvent/_itself_/vmdeath002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VMDeathEvent/_itself_/vmdeath002.java index 1fa254e7d4a49..1280453231548 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VMDeathEvent/_itself_/vmdeath002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VMDeathEvent/_itself_/vmdeath002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -237,14 +237,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VMDeathEvent/_itself_/vmdeath003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VMDeathEvent/_itself_/vmdeath003.java index 8070d8143c19d..26b4693d69620 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VMDeathEvent/_itself_/vmdeath003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VMDeathEvent/_itself_/vmdeath003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -242,14 +242,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/allClasses/allclasses001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/allClasses/allclasses001.java index 44477e156f921..e5981bf0b3471 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/allClasses/allclasses001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/allClasses/allclasses001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -236,18 +236,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canAddMethod/canaddmethod001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canAddMethod/canaddmethod001.java index f0eea0731c048..d31f547f80d16 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canAddMethod/canaddmethod001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canAddMethod/canaddmethod001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -225,18 +225,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canPopFrames/canpopframes001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canPopFrames/canpopframes001.java index 03f38b66f1f05..31e29c10240cc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canPopFrames/canpopframes001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canPopFrames/canpopframes001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -225,18 +225,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canRedefineClasses/canredefineclasses001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canRedefineClasses/canredefineclasses001.java index 88e54ac79a4fb..b1023026c47a2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canRedefineClasses/canredefineclasses001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canRedefineClasses/canredefineclasses001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -225,18 +225,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canRequestVMDeathEvent/canreqvmdev001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canRequestVMDeathEvent/canreqvmdev001.java index 8d057c809cb2c..aa43d39b559c6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canRequestVMDeathEvent/canreqvmdev001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canRequestVMDeathEvent/canreqvmdev001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -225,18 +225,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canUnrestrictedlyRedefineClasses/curc001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canUnrestrictedlyRedefineClasses/curc001.java index 62d44d8c7bb4e..b95f5a19a3180 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canUnrestrictedlyRedefineClasses/curc001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canUnrestrictedlyRedefineClasses/curc001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -225,18 +225,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canUseInstanceFilters/canusefilters001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canUseInstanceFilters/canusefilters001.java index c03cef0d05c72..ad337dd54f5df 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canUseInstanceFilters/canusefilters001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canUseInstanceFilters/canusefilters001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -225,18 +225,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canWatchFieldAccess/canwatchaccess001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canWatchFieldAccess/canwatchaccess001.java index 466c2c6ed789e..6b0d64d978183 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canWatchFieldAccess/canwatchaccess001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canWatchFieldAccess/canwatchaccess001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -236,18 +236,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canWatchFieldModification/canwatchmod001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canWatchFieldModification/canwatchmod001.java index b64d346994dd2..07410545e9fe1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canWatchFieldModification/canwatchmod001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/canWatchFieldModification/canwatchmod001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -237,18 +237,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - try { - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - } catch ( Exception e ) { - throw e; - } - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/redefineClasses/redefineclasses001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/redefineClasses/redefineclasses001.java index 5db62c170de0b..aab5c173f304a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/redefineClasses/redefineclasses001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VirtualMachine/redefineClasses/redefineclasses001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -264,15 +264,7 @@ private void testRun() return; } - - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section @@ -293,6 +285,7 @@ private void testRun() vm.resume(); breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); @@ -310,9 +303,9 @@ private void testRun() case 0: List classes = vm.classesByName(bpClassName); bpClass = (ReferenceType) classes.get(0); - bpRequest2 = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - bpClass, - bpMethodName, bpLineName, "one"); + bpRequest2 = settingBreakpoint(mainThread, + bpClass, + bpMethodName, bpLineName, "one"); bpRequest2.enable(); vm.resume(); @@ -335,9 +328,9 @@ private void testRun() case 1: - bpRequest3 = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - bpClass, - bpMethodName, bpLineName, "one"); + bpRequest3 = settingBreakpoint(mainThread, + bpClass, + bpMethodName, bpLineName, "one"); bpRequest3.enable(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VoidType/_itself_/voidtype001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VoidType/_itself_/voidtype001.java index f3e0c7f583da8..90da9975df489 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/VoidType/_itself_/voidtype001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/VoidType/_itself_/voidtype001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -237,14 +237,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - bpRequest = settingBreakpoint(debuggee.threadByNameOrThrow("main"), - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassExclusionFilter/filter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassExclusionFilter/filter003.java index 7b77beedc1a9c..d7a182cba7915 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassExclusionFilter/filter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassExclusionFilter/filter003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -250,15 +250,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassExclusionFilter/filter004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassExclusionFilter/filter004.java index 6be78f1d59662..0b8d7135cfb62 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassExclusionFilter/filter004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassExclusionFilter/filter004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -250,15 +250,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_rt/filter_rt003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_rt/filter_rt003.java index 1fd6ae0ffde19..0d2176b091007 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_rt/filter_rt003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_rt/filter_rt003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -250,15 +250,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_rt/filter_rt004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_rt/filter_rt004.java index 1e37d5cac4103..0bd09aca33926 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_rt/filter_rt004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_rt/filter_rt004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -250,15 +250,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_s/filter_s003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_s/filter_s003.java index 92234071cc6c3..d2ea9213899bb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_s/filter_s003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_s/filter_s003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -250,15 +250,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_s/filter_s004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_s/filter_s004.java index 21030c2bf402b..3790d2e7dcc0e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_s/filter_s004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addClassFilter_s/filter_s004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -250,15 +250,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter003.java index 1d71e9990d364..5b3184ded80f3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -258,15 +258,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter004.java index 12a0fdac2c8d9..dd02ed1c67f0d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -258,15 +258,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter005.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter005.java index 005367911afd8..9e690424420d5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -247,15 +247,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter006.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter006.java index e479bb104eb88..21756dfd59c4c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addInstanceFilter/instancefilter006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -247,15 +247,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter003.java index 344d0e364280c..75f4e45345d0e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -261,15 +261,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter004.java index c875dcaa03409..b4c7b60971beb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -261,15 +261,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter005.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter005.java index e5bc8a555edef..9e371abf8ee84 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -261,15 +261,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter006.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter006.java index 3ee70ff8202ee..8f24855f9af6e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/addThreadFilter/addthreadfilter006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -262,15 +262,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/field/field001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/field/field001.java index 36af014db0bdb..0b6d1b67a42f3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/field/field001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/field/field001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -248,16 +248,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); - + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section log1(" TESTING BEGINS"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/field/field002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/field/field002.java index 3fbbeb5915b0b..314b0b32cc7aa 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/field/field002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/WatchpointRequest/field/field002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,15 +249,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java index bc722844afdea..ac99b1216510e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,12 +89,33 @@ public final void log3(String message) { protected Location breakpLocation = null; protected BreakpointEvent bpEvent; + protected final BreakpointRequest settingBreakpoint( + ReferenceType testedClass, + String methodName, + String bpLine, + String property) + throws JDITestRuntimeException { + return settingBreakpoint_private(null, testedClass, methodName, bpLine, property); + } + protected final BreakpointRequest settingBreakpoint(ThreadReference thread, ReferenceType testedClass, String methodName, String bpLine, String property) throws JDITestRuntimeException { + if (thread == null) { + log3("ERROR: TEST_ERROR_IN_settingBreakpoint(): thread is null"); + } + return settingBreakpoint_private(thread, testedClass, methodName, bpLine, property); + } + + private final BreakpointRequest settingBreakpoint_private(ThreadReference thread, + ReferenceType testedClass, + String methodName, + String bpLine, + String property) + throws JDITestRuntimeException { log2("......setting up a breakpoint:"); log2(" thread: " + thread + "; class: " + testedClass + @@ -119,11 +140,14 @@ protected final BreakpointRequest settingBreakpoint(ThreadReference thread, try { breakpRequest = eventRManager.createBreakpointRequest(lineLocation); breakpRequest.putProperty("number", property); - breakpRequest.addThreadFilter(thread); + if (thread != null) { + breakpRequest.addThreadFilter(thread); + } breakpRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); } catch (Exception e1) { log3("ERROR: inner Exception within settingBreakpoint() : " + e1); breakpRequest = null; + e1.printStackTrace(logHandler.getOutStream()); } } } catch (Exception e2) { @@ -188,6 +212,19 @@ protected void getEventSetForThreadStartDeath(String threadName) throws JDITestR eventIterator = eventSet.eventIterator(); } + // Sets up the standard breakpoint for communication. The breakpoint is set on + // methodForCommunication() using the line number stored in the "lineForComm" + // local variable. The breakpoint is enabled. + protected BreakpointRequest setupBreakpointForCommunication(ReferenceType debuggeeClass) { + String bPointMethod = "methodForCommunication"; + String lineForComm = "lineForComm"; + + BreakpointRequest bpRequest = + settingBreakpoint(debuggeeClass, bPointMethod, lineForComm, "zero"); + bpRequest.enable(); + return bpRequest; + } + protected void breakpointForCommunication() throws JDITestRuntimeException { log2("breakpointForCommunication"); @@ -219,6 +256,7 @@ protected void breakpointForCommunication(String debuggeeName) throws JDITestRun Event event = eventIterator.nextEvent(); if (event instanceof BreakpointEvent) { + bpEvent = (BreakpointEvent) event; return; } if (EventFilters.filtered(event, debuggeeName)) { From 53924882326d3756a4ec52f37a59c8a81059a069 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Wed, 23 Apr 2025 00:13:09 +0000 Subject: [PATCH 0715/1101] 8355332: Fix failing semi-manual test EDT issue Reviewed-by: azvegint --- .../HorizScrollers.java | 7 +++--- .../RTLScrollers.java | 24 ++++++++----------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/HorizScrollers.java b/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/HorizScrollers.java index b584fd66da3f6..61124ea1e9736 100644 --- a/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/HorizScrollers.java +++ b/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/HorizScrollers.java @@ -161,8 +161,9 @@ private void showFinalReminderIfNeeded(boolean isFailure) { if (scrollAmount != 3) { JOptionPane.showMessageDialog( ConfigPanel.this.getTopLevelAncestor(), - ("Test %s. please make sure you have restored " + - "the original speed value blah blah") + ("Test %s. Please make sure you have restored " + + "the original scrolling speed in the " + + "Mouse settings.") .formatted(isFailure ? "failed" : "passed"), @@ -231,4 +232,4 @@ public void mouseWheelMoved(MouseWheelEvent e) { } } } -} \ No newline at end of file +} diff --git a/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/RTLScrollers.java b/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/RTLScrollers.java index 24e8df6fad8e1..da395282bf5b0 100644 --- a/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/RTLScrollers.java +++ b/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/RTLScrollers.java @@ -265,22 +265,21 @@ public static boolean runTest(int scrollAmount) } } + robot.delay(1000); SwingUtilities.invokeAndWait(() -> { rtl = new RTLScrollers(scrollAmount); rtl.setVisible(true); }); robot.delay(100); - SwingUtilities.invokeAndWait(() -> { - try { - retVal = rtl.runTests(scrollAmount); - } catch (Exception e) { - e.printStackTrace(); - } finally { + try { + retVal = rtl.runTests(scrollAmount); + } finally { + SwingUtilities.invokeAndWait(() -> { rtl.setVisible(false); rtl.dispose(); - } - }); + }); + } robot.delay(100); System.out.println("RTLS.runTest(): " + retVal); @@ -312,9 +311,8 @@ private boolean runTests(int scrollAmount) System.out.println("Testing List"); testComp(list, scrollAmount); - SwingUtilities.invokeAndWait(() -> { - applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); - }); + SwingUtilities.invokeAndWait(() -> + applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT)); robot.delay(100); System.out.println("Testing RTL Table"); @@ -467,9 +465,7 @@ public boolean testComp(TestTools comp, int scrollAmount) // Test acceleration for max scrolling // (this part should still work for RTL JList) if (scrollAmount == 30) { - SwingUtilities.invokeAndWait(() -> { - hsb.setValue(hsb.getMinimum()); - }); + SwingUtilities.invokeAndWait(() -> hsb.setValue(hsb.getMinimum())); robot.delay(100); robot.mouseWheel(2); robot.mouseWheel(2); From 4c373703d9ed63dfc85df7cdcc04ecad5b02ade0 Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Wed, 23 Apr 2025 02:04:46 +0000 Subject: [PATCH 0716/1101] 8354668: Missing REX2 prefix accounting in ZGC barriers leads to incorrect encoding Reviewed-by: aboldtch, sviswanathan --- .../cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp | 14 +++++++------- .../cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp | 2 +- src/hotspot/cpu/x86/gc/z/z_x86_64.ad | 4 ++-- src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp index 9cdf0b229c0a4..0891d303563d7 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp @@ -391,8 +391,8 @@ void ZBarrierSetAssembler::store_barrier_fast(MacroAssembler* masm, if (rnew_zaddress != noreg) { // noreg means null; no need to color __ movptr(rnew_zpointer, rnew_zaddress); - __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeShl); __ shlq(rnew_zpointer, barrier_Relocation::unpatched); + __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodAfterShX); __ orq_imm32(rnew_zpointer, barrier_Relocation::unpatched); __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatStoreGoodAfterOr); } @@ -969,13 +969,13 @@ void ZBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, #define __ ce->masm()-> static void z_uncolor(LIR_Assembler* ce, LIR_Opr ref) { - __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeShl); __ shrq(ref->as_register(), barrier_Relocation::unpatched); + __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodAfterShX); } static void z_color(LIR_Assembler* ce, LIR_Opr ref) { - __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeShl); __ shlq(ref->as_register(), barrier_Relocation::unpatched); + __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodAfterShX); __ orq_imm32(ref->as_register(), barrier_Relocation::unpatched); __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatStoreGoodAfterOr); } @@ -1278,8 +1278,8 @@ void ZBarrierSetAssembler::generate_c2_store_barrier_stub(MacroAssembler* masm, static int patch_barrier_relocation_offset(int format) { switch (format) { - case ZBarrierRelocationFormatLoadGoodBeforeShl: - return 3; + case ZBarrierRelocationFormatLoadGoodAfterShX: + return -1; case ZBarrierRelocationFormatStoreGoodAfterCmp: return -2; @@ -1300,7 +1300,7 @@ static int patch_barrier_relocation_offset(int format) { static uint16_t patch_barrier_relocation_value(int format) { switch (format) { - case ZBarrierRelocationFormatLoadGoodBeforeShl: + case ZBarrierRelocationFormatLoadGoodAfterShX: return (uint16_t)ZPointerLoadShift; case ZBarrierRelocationFormatMarkBadAfterTest: @@ -1327,7 +1327,7 @@ void ZBarrierSetAssembler::patch_barrier_relocation(address addr, int format) { const int offset = patch_barrier_relocation_offset(format); const uint16_t value = patch_barrier_relocation_value(format); uint8_t* const patch_addr = (uint8_t*)addr + offset; - if (format == ZBarrierRelocationFormatLoadGoodBeforeShl) { + if (format == ZBarrierRelocationFormatLoadGoodAfterShX) { *patch_addr = (uint8_t)value; } else { *(uint16_t*)patch_addr = value; diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp index 8bb653ec5fbaf..6976452bd6381 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp @@ -49,7 +49,7 @@ class ZLoadBarrierStubC2; class ZStoreBarrierStubC2; #endif // COMPILER2 -const int ZBarrierRelocationFormatLoadGoodBeforeShl = 0; +const int ZBarrierRelocationFormatLoadGoodAfterShX = 0; const int ZBarrierRelocationFormatLoadBadAfterTest = 1; const int ZBarrierRelocationFormatMarkBadAfterTest = 2; const int ZBarrierRelocationFormatStoreGoodAfterCmp = 3; diff --git a/src/hotspot/cpu/x86/gc/z/z_x86_64.ad b/src/hotspot/cpu/x86/gc/z/z_x86_64.ad index 045aa5d538193..e2484a71e7dd3 100644 --- a/src/hotspot/cpu/x86/gc/z/z_x86_64.ad +++ b/src/hotspot/cpu/x86/gc/z/z_x86_64.ad @@ -35,15 +35,15 @@ source %{ #include "gc/z/zBarrierSetAssembler.hpp" static void z_color(MacroAssembler* masm, const MachNode* node, Register ref) { - __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeShl); __ shlq(ref, barrier_Relocation::unpatched); + __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodAfterShX); __ orq_imm32(ref, barrier_Relocation::unpatched); __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatStoreGoodAfterOr); } static void z_uncolor(MacroAssembler* masm, const MachNode* node, Register ref) { - __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeShl); __ shrq(ref, barrier_Relocation::unpatched); + __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodAfterShX); } static void z_keep_alive_load_barrier(MacroAssembler* masm, const MachNode* node, Address ref_addr, Register ref) { diff --git a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp index 9e6a4789dc2cd..7e239a6898354 100644 --- a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp +++ b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp @@ -221,7 +221,7 @@ bool CodeInstaller::pd_relocate(address pc, jint mark) { return true; #if INCLUDE_ZGC case Z_BARRIER_RELOCATION_FORMAT_LOAD_GOOD_BEFORE_SHL: - _instructions->relocate(pc, barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeShl); + _instructions->relocate(pc, barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodAfterShX); return true; case Z_BARRIER_RELOCATION_FORMAT_LOAD_BAD_AFTER_TEST: _instructions->relocate(pc, barrier_Relocation::spec(), ZBarrierRelocationFormatLoadBadAfterTest); From a8c6ff161c2c4f1dcf0f8588c9d007994c84e703 Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Wed, 23 Apr 2025 02:10:25 +0000 Subject: [PATCH 0717/1101] 8355239: RISC-V: Do not support subword scatter store Reviewed-by: mli, fjiang --- src/hotspot/cpu/riscv/riscv_v.ad | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 7c1ca4f8960ab..6fea439954c81 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -89,6 +89,8 @@ source %{ return UseZvbb; case Op_LoadVectorGather: case Op_LoadVectorGatherMasked: + case Op_StoreVectorScatter: + case Op_StoreVectorScatterMasked: if (is_subword_type(bt)) { return false; } From bc518a6cbb9fadc47b00239b4d721c1c62dc5dad Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Wed, 23 Apr 2025 02:32:36 +0000 Subject: [PATCH 0718/1101] 8355240: Remove unused Import in StringUTF16 Reviewed-by: rgiulietti --- src/java.base/share/classes/java/lang/StringUTF16.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 99226ac1012ba..a07c022040f7b 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,6 @@ import jdk.internal.vm.annotation.IntrinsicCandidate; import static java.lang.String.UTF16; -import static java.lang.String.LATIN1; final class StringUTF16 { From 8c89fb95351ea0bc5ffdd920c18f9e820231f233 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 23 Apr 2025 03:40:26 +0000 Subject: [PATCH 0719/1101] 8355179: Reinstate javax/swing/JScrollBar/4865918/bug4865918.java headful and macos run Reviewed-by: abhiscxk, serb --- .../swing/JScrollBar/4865918/bug4865918.java | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/test/jdk/javax/swing/JScrollBar/4865918/bug4865918.java b/test/jdk/javax/swing/JScrollBar/4865918/bug4865918.java index 96b1034c943de..d68f1bff5971e 100644 --- a/test/jdk/javax/swing/JScrollBar/4865918/bug4865918.java +++ b/test/jdk/javax/swing/JScrollBar/4865918/bug4865918.java @@ -24,14 +24,16 @@ /* * @test * @bug 4865918 - * @requires (os.family != "mac") + * @key headful * @summary REGRESSION:JCK1.4a-runtime api/javax_swing/interactive/JScrollBarTests.html#JScrollBar * @run main bug4865918 */ import java.awt.Dimension; +import java.awt.Robot; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import javax.swing.JFrame; import javax.swing.JScrollBar; import javax.swing.SwingUtilities; import java.util.concurrent.CountDownLatch; @@ -41,24 +43,33 @@ public class bug4865918 { + private static JFrame frame; private static TestScrollBar sbar; private static final CountDownLatch mousePressLatch = new CountDownLatch(1); public static void main(String[] argv) throws Exception { - String osName = System.getProperty("os.name"); - if (osName.toLowerCase().contains("os x")) { - System.out.println("This test is not for MacOS, considered passed."); - return; - } - SwingUtilities.invokeAndWait(() -> setupTest()); + try { + Robot robot = new Robot(); + SwingUtilities.invokeAndWait(() -> createAndShowGUI()); - SwingUtilities.invokeAndWait(() -> sbar.pressMouse()); - if (!mousePressLatch.await(2, TimeUnit.SECONDS)) { - throw new RuntimeException("Timed out waiting for mouse press"); - } + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> sbar.pressMouse()); + if (!mousePressLatch.await(2, TimeUnit.SECONDS)) { + throw new RuntimeException("Timed out waiting for mouse press"); + } - if (getValue() != 9) { - throw new RuntimeException("The scrollbar block increment is incorrect"); + if (getValue() != 9) { + throw new RuntimeException("The scrollbar block increment " + + getValue() + " is incorrect"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); } } @@ -73,8 +84,8 @@ private static int getValue() throws Exception { return result[0]; } - private static void setupTest() { - + private static void createAndShowGUI() { + frame = new JFrame("bug4865918"); sbar = new TestScrollBar(JScrollBar.HORIZONTAL, -1, 10, -100, 100); sbar.setPreferredSize(new Dimension(200, 20)); sbar.setBlockIncrement(10); @@ -83,7 +94,11 @@ public void mousePressed(MouseEvent e) { mousePressLatch.countDown(); } }); - + frame.getContentPane().add(sbar); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + frame.toFront(); } static class TestScrollBar extends JScrollBar { From 9a2b425b13cc468d8627c1548d1d39015ce17af1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Wed, 23 Apr 2025 05:17:41 +0000 Subject: [PATCH 0720/1101] 8354920: SA core file support on Linux only prints error messages when debug logging is enabled Reviewed-by: cjplummer, kevinw --- .../linux/native/libsaproc/libproc_impl.c | 4 +- .../linux/native/libsaproc/ps_core.c | 89 ++++++++++++------- .../linux/native/libsaproc/ps_proc.c | 34 +++++-- .../macosx/native/libsaproc/libproc_impl.c | 4 +- .../macosx/native/libsaproc/ps_core.c | 43 +++++---- .../share/native/libsaproc/ps_core_common.c | 2 + 6 files changed, 114 insertions(+), 62 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 977347048a3a4..74563aa0d6c3d 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -349,7 +349,7 @@ const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* p thread_info* add_thread_info(struct ps_prochandle* ph, lwpid_t lwp_id) { thread_info* newthr; if ( (newthr = (thread_info*) calloc(1, sizeof(thread_info))) == NULL) { - print_debug("can't allocate memory for thread_info\n"); + print_error("can't allocate memory for thread_info\n"); return NULL; } diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c index b1b69c81e2e0c..808ef42e06906 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ #include #include #include +#include #include "libproc_impl.h" #include "ps_core_common.h" #include "proc_service.h" @@ -67,7 +68,7 @@ static bool sort_map_array(struct ps_prochandle* ph) { // allocate map_array map_info** array; if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) { - print_debug("can't allocate memory for map array\n"); + print_error("can't allocate memory for map array\n"); return false; } @@ -189,8 +190,10 @@ static bool core_handle_prstatus(struct ps_prochandle* ph, const char* buf, size prstatus_t* prstat = (prstatus_t*) buf; thread_info* newthr; print_debug("got integer regset for lwp %d\n", prstat->pr_pid); - if((newthr = add_thread_info(ph, prstat->pr_pid)) == NULL) + if((newthr = add_thread_info(ph, prstat->pr_pid)) == NULL) { + print_error("failed to add thread info\n"); return false; + } // copy regs memcpy(&newthr->regs, prstat->pr_reg, sizeof(struct user_regs_struct)); @@ -256,20 +259,20 @@ static bool core_handle_note(struct ps_prochandle* ph, ELF_PHDR* note_phdr) { // we are interested in just prstatus entries. we will ignore the rest. // Advance the seek pointer to the start of the PT_NOTE data if (lseek(ph->core->core_fd, note_phdr->p_offset, SEEK_SET) == (off_t)-1) { - print_debug("failed to lseek to PT_NOTE data\n"); + print_error("failed to lseek to PT_NOTE data\n"); return false; } // Now process the PT_NOTE structures. Each one is preceded by // an Elf{32/64}_Nhdr structure describing its type and size. if ( (buf = (char*) malloc(size)) == NULL) { - print_debug("can't allocate memory for reading core notes\n"); + print_error("can't allocate memory for reading core notes\n"); goto err; } // read notes into buffer if (read(ph->core->core_fd, buf, size) != size) { - print_debug("failed to read notes, core file must have been truncated\n"); + print_error("failed to read notes, core file must have been truncated\n"); goto err; } @@ -282,6 +285,7 @@ static bool core_handle_note(struct ps_prochandle* ph, ELF_PHDR* note_phdr) { if (notep->n_type == NT_PRSTATUS) { if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) { + print_error("failed to handle NT_PRSTATUS note\n"); return false; } } else if (notep->n_type == NT_AUXV) { @@ -314,8 +318,10 @@ static bool read_core_segments(struct ps_prochandle* ph, ELF_EHDR* core_ehdr) { ELF_PHDR* phbuf = NULL; ELF_PHDR* core_php = NULL; - if ((phbuf = read_program_header_table(ph->core->core_fd, core_ehdr)) == NULL) + if ((phbuf = read_program_header_table(ph->core->core_fd, core_ehdr)) == NULL) { + print_error("failed to read program header table\n"); return false; + } /* * Now iterate through the program headers in the core file. @@ -344,6 +350,7 @@ static bool read_core_segments(struct ps_prochandle* ph, ELF_EHDR* core_ehdr) { switch (core_php->p_type) { case PT_NOTE: if (core_handle_note(ph, core_php) != true) { + print_error("failed to read note segment\n"); goto err; } break; @@ -351,7 +358,10 @@ static bool read_core_segments(struct ps_prochandle* ph, ELF_EHDR* core_ehdr) { case PT_LOAD: { if (core_php->p_filesz != 0) { if (add_map_info(ph, ph->core->core_fd, core_php->p_offset, - core_php->p_vaddr, core_php->p_filesz, core_php->p_flags) == NULL) goto err; + core_php->p_vaddr, core_php->p_filesz, core_php->p_flags) == NULL) { + print_error("failed to add map info\n"); + goto err; + } } break; } @@ -376,6 +386,7 @@ static bool read_lib_segments(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* li int page_size = sysconf(_SC_PAGE_SIZE); if ((phbuf = read_program_header_table(lib_fd, lib_ehdr)) == NULL) { + print_error("failed to read program header table\n"); return false; } @@ -391,6 +402,7 @@ static bool read_lib_segments(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* li if (existing_map == NULL){ if (add_map_info(ph, lib_fd, lib_php->p_offset, target_vaddr, lib_php->p_memsz, lib_php->p_flags) == NULL) { + print_error("failed to add map info\n"); goto err; } } else if (lib_php->p_flags != existing_map->flags) { @@ -412,7 +424,7 @@ static bool read_lib_segments(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* li (existing_map->fd != lib_fd) && (ROUNDUP(existing_map->memsz, page_size) != ROUNDUP(lib_php->p_memsz, page_size))) { - print_debug("address conflict @ 0x%lx (existing map size = %ld, size = %ld, flags = %d)\n", + print_error("address conflict @ 0x%lx (existing map size = %ld, size = %ld, flags = %d)\n", target_vaddr, existing_map->memsz, lib_php->p_memsz, lib_php->p_flags); goto err; } @@ -442,12 +454,12 @@ static bool read_interp_segments(struct ps_prochandle* ph) { ELF_EHDR interp_ehdr; if (read_elf_header(ph->core->interp_fd, &interp_ehdr) != true) { - print_debug("interpreter is not a valid ELF file\n"); + print_error("interpreter is not a valid ELF file\n"); return false; } if (read_lib_segments(ph, ph->core->interp_fd, &interp_ehdr, ph->core->ld_base_addr) != true) { - print_debug("can't read segments of interpreter\n"); + print_error("can't read segments of interpreter\n"); return false; } @@ -463,6 +475,7 @@ static uintptr_t read_exec_segments(struct ps_prochandle* ph, ELF_EHDR* exec_ehd uintptr_t result = 0L; if ((phbuf = read_program_header_table(ph->core->exec_fd, exec_ehdr)) == NULL) { + print_error("failed to read program header table\n"); return 0L; } @@ -473,7 +486,10 @@ static uintptr_t read_exec_segments(struct ps_prochandle* ph, ELF_EHDR* exec_ehd case PT_LOAD: { // add only non-writable segments of non-zero filesz if (!(exec_php->p_flags & PF_W) && exec_php->p_filesz != 0) { - if (add_map_info(ph, ph->core->exec_fd, exec_php->p_offset, exec_php->p_vaddr, exec_php->p_filesz, exec_php->p_flags) == NULL) goto err; + if (add_map_info(ph, ph->core->exec_fd, exec_php->p_offset, exec_php->p_vaddr, exec_php->p_filesz, exec_php->p_flags) == NULL) { + print_error("failed to add map info\n"); + goto err; + } } break; } @@ -484,18 +500,19 @@ static uintptr_t read_exec_segments(struct ps_prochandle* ph, ELF_EHDR* exec_ehd // BUF_SIZE is PATH_MAX + NAME_MAX + 1. if (exec_php->p_filesz > BUF_SIZE) { + print_error("Invalid ELF interpreter info\n"); goto err; } if (pread(ph->core->exec_fd, interp_name, exec_php->p_filesz, exec_php->p_offset) != exec_php->p_filesz) { - print_debug("Unable to read in the ELF interpreter\n"); + print_error("Unable to read in the ELF interpreter\n"); goto err; } interp_name[exec_php->p_filesz] = '\0'; print_debug("ELF interpreter %s\n", interp_name); // read interpreter segments as well if ((ph->core->interp_fd = pathmap_open(interp_name)) < 0) { - print_debug("can't open runtime loader\n"); + print_error("can't open runtime loader\n"); goto err; } break; @@ -555,7 +572,7 @@ static uintptr_t calc_prelinked_load_address(struct ps_prochandle* ph, int lib_f phbuf = read_program_header_table(lib_fd, elf_ehdr); if (phbuf == NULL) { - print_debug("can't read program header of shared object\n"); + print_error("can't read program header of shared object\n"); return INVALID_LOAD_ADDRESS; } @@ -571,7 +588,7 @@ static uintptr_t calc_prelinked_load_address(struct ps_prochandle* ph, int lib_f if (ps_pdread(ph, (psaddr_t)link_map_addr + LINK_MAP_LD_OFFSET, &lib_ld, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read address of dynamic section in shared object\n"); + print_error("can't read address of dynamic section in shared object\n"); return INVALID_LOAD_ADDRESS; } @@ -607,7 +624,7 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) { dyn.d_tag = DT_NULL; while (dyn.d_tag != DT_DEBUG) { if (ps_pdread(ph, (psaddr_t) addr, &dyn, sizeof(ELF_DYN)) != PS_OK) { - print_debug("can't read debug info from _DYNAMIC\n"); + print_error("can't read debug info from _DYNAMIC\n"); return false; } addr += sizeof(ELF_DYN); @@ -618,14 +635,14 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) { // at debug_base we have struct r_debug. This has first link map in r_map field if (ps_pdread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET, &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read first link map address\n"); + print_error("can't read first link map address\n"); return false; } // read ld_base address from struct r_debug if (ps_pdread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read ld base address\n"); + print_error("can't read ld base address\n"); return false; } ph->core->ld_base_addr = ld_base_addr; @@ -634,11 +651,13 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) { // now read segments from interp (i.e ld.so or ld-linux.so or ld-elf.so) if (read_interp_segments(ph) != true) { + print_error("failed to read interp segments\n"); return false; } // after adding interpreter (ld.so) mappings sort again if (sort_map_array(ph) != true) { + print_error("failed to sort segment map array\n"); return false; } @@ -654,14 +673,14 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) { if (ps_pdread(ph, (psaddr_t) link_map_addr + LINK_MAP_ADDR_OFFSET, &lib_base_diff, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read shared object base address diff\n"); + print_error("can't read shared object base address diff\n"); return false; } // read address of the name if (ps_pdread(ph, (psaddr_t) link_map_addr + LINK_MAP_NAME_OFFSET, &lib_name_addr, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read address of shared object name\n"); + print_error("can't read address of shared object name\n"); return false; } @@ -687,6 +706,7 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) { lib_base_diff = calc_prelinked_load_address(ph, lib_fd, &elf_ehdr, link_map_addr); if (lib_base_diff == INVALID_LOAD_ADDRESS) { close(lib_fd); + print_error("failed to calculate load address\n"); return false; } } @@ -696,15 +716,17 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) { lib_name, lib_base, lib_base_diff); // while adding library mappings we need to use "base difference". if (! read_lib_segments(ph, lib_fd, &elf_ehdr, lib_base_diff)) { - print_debug("can't read shared object's segments\n"); + print_error("can't read shared object's segments\n"); close(lib_fd); return false; } add_lib_info_fd(ph, lib_name, lib_fd, lib_base); // Map info is added for the library (lib_name) so // we need to re-sort it before calling the p_pdread. - if (sort_map_array(ph) != true) + if (sort_map_array(ph) != true) { + print_error("failed to sort segment map array\n"); return false; + } } else { print_debug("can't read ELF header for shared object %s\n", lib_name); close(lib_fd); @@ -716,7 +738,7 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) { // read next link_map address if (ps_pdread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET, &link_map_addr, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read next link in link_map\n"); + print_error("can't read next link in link_map\n"); return false; } } @@ -732,13 +754,13 @@ Pgrab_core(const char* exec_file, const char* core_file) { struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); if (ph == NULL) { - print_debug("can't allocate ps_prochandle\n"); + print_error("can't allocate ps_prochandle\n"); return NULL; } if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { free(ph); - print_debug("can't allocate ps_prochandle\n"); + print_error("can't allocate ps_prochandle\n"); return NULL; } @@ -750,39 +772,42 @@ Pgrab_core(const char* exec_file, const char* core_file) { // open the core file if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) { - print_debug("can't open core file\n"); + print_error("can't open core file: %s\n", strerror(errno)); goto err; } // read core file ELF header if (read_elf_header(ph->core->core_fd, &core_ehdr) != true || core_ehdr.e_type != ET_CORE) { - print_debug("core file is not a valid ELF ET_CORE file\n"); + print_error("core file is not a valid ELF ET_CORE file\n"); goto err; } if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { - print_debug("can't open executable file\n"); + print_error("can't open executable file: %s\n", strerror(errno)); goto err; } if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || ((exec_ehdr.e_type != ET_EXEC) && (exec_ehdr.e_type != ET_DYN))) { - print_debug("executable file is not a valid ELF file\n"); + print_error("executable file is not a valid ELF file\n"); goto err; } // process core file segments if (read_core_segments(ph, &core_ehdr) != true) { + print_error("failed to read core segments\n"); goto err; } // process exec file segments uintptr_t exec_base_addr = read_exec_segments(ph, &exec_ehdr); if (exec_base_addr == 0L) { + print_error("failed to read exec segments\n"); goto err; } print_debug("exec_base_addr = 0x%lx\n", exec_base_addr); if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd, exec_base_addr) == NULL) { + print_error("failed to add lib info\n"); goto err; } @@ -790,19 +815,23 @@ Pgrab_core(const char* exec_file, const char* core_file) { // here because read_shared_lib_info needs to read from debuggee // address space if (sort_map_array(ph) != true) { + print_error("failed to sort segment map array\n"); goto err; } if (read_shared_lib_info(ph) != true) { + print_error("failed to read libraries\n"); goto err; } // sort again because we have added more mappings from shared objects if (sort_map_array(ph) != true) { + print_error("failed to sort segment map array\n"); goto err; } if (init_classsharing_workaround(ph) != true) { + print_error("failed to workaround class sharing\n"); goto err; } diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c index de81e962d8a24..fdaa30c3f5d05 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -349,7 +349,7 @@ static bool read_lib_info(struct ps_prochandle* ph) { snprintf(fname, sizeof(fname), "/proc/%d/maps", ph->pid); fp = fopen(fname, "r"); if (fp == NULL) { - print_debug("can't open /proc/%d/maps file\n", ph->pid); + print_error("can't open /proc/%d/maps file\n", ph->pid); return false; } @@ -447,13 +447,14 @@ Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) { if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) { snprintf(err_buf, err_buf_len, "can't allocate memory for ps_prochandle"); - print_debug("%s\n", err_buf); + print_error("%s\n", err_buf); return NULL; } if ((attach_status = ptrace_attach(pid, err_buf, err_buf_len)) != ATTACH_SUCCESS) { if (attach_status == ATTACH_THREAD_DEAD) { - print_error("The process with pid %d does not exist.\n", pid); + snprintf(err_buf, err_buf_len, "The process with pid %d does not exist.", pid); + print_error("%s\n", err_buf); } free(ph); return NULL; @@ -461,7 +462,12 @@ Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) { // initialize ps_prochandle ph->pid = pid; - add_thread_info(ph, ph->pid); + if (add_thread_info(ph, ph->pid) == NULL) { + snprintf(err_buf, err_buf_len, "failed to add thread info"); + print_error("%s\n", err_buf); + free(ph); + return NULL; + } // initialize vtable ph->ops = &process_ops; @@ -469,7 +475,10 @@ Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) { // read library info and symbol tables, must do this before attaching threads, // as the symbols in the pthread library will be used to figure out // the list of threads within the same process. - read_lib_info(ph); + if (read_lib_info(ph) == false) { + snprintf(err_buf, err_buf_len, "failed to read lib info"); + goto err; + } /* * Read thread info. @@ -491,7 +500,10 @@ Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) { continue; } if (!process_doesnt_exist(lwp_id)) { - add_thread_info(ph, lwp_id); + if (add_thread_info(ph, lwp_id) == NULL) { + snprintf(err_buf, err_buf_len, "failed to add thread info"); + goto err; + } } } closedir(dirp); @@ -510,11 +522,15 @@ Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) { delete_thread_info(ph, current_thr); } else { - Prelease(ph); - return NULL; + snprintf(err_buf, err_buf_len, "Failed to attach to the thread with lwp_id %d.", current_thr->lwp_id); + goto err; } // ATTACH_THREAD_DEAD } // !ATTACH_SUCCESS } } return ph; +err: + print_error("%s\n", err_buf); + Prelease(ph); + return NULL; } diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c b/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c index ff48c402f8d20..8bcd09d40ced5 100644 --- a/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c +++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -323,7 +323,7 @@ const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* p sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) { sa_thread_info* newthr; if ( (newthr = (sa_thread_info*) calloc(1, sizeof(sa_thread_info))) == NULL) { - print_debug("can't allocate memory for thread_info\n"); + print_error("can't allocate memory for thread_info\n"); return NULL; } diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c b/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c index e07b3a8fd9776..149997dc4bb1b 100644 --- a/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c +++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -74,7 +74,7 @@ static bool sort_map_array(struct ps_prochandle* ph) { // allocate map_array map_info** array; if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) { - print_debug("can't allocate memory for map array\n"); + print_error("can't allocate memory for map array\n"); return false; } @@ -280,6 +280,7 @@ static bool read_core_segments(struct ps_prochandle* ph) { lseek(fd, offset, SEEK_SET); if(read(fd, (void *)&fhead, sizeof(mach_header_64)) != sizeof(mach_header_64)) { + print_error("Failed to read program header table\n"); goto err; } print_debug("total commands: %d\n", fhead.ncmds); @@ -287,6 +288,7 @@ static bool read_core_segments(struct ps_prochandle* ph) { for (i = 0; i < fhead.ncmds; i++) { lseek(fd, offset, SEEK_SET); if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) { + print_error("Failed to read command\n"); goto err; } offset += lcmd.cmdsize; // next command position @@ -294,14 +296,14 @@ static bool read_core_segments(struct ps_prochandle* ph) { if (lcmd.cmd == LC_SEGMENT_64) { lseek(fd, -sizeof(load_command), SEEK_CUR); if (read(fd, (void *)&segcmd, sizeof(segment_command_64)) != sizeof(segment_command_64)) { - print_debug("failed to read LC_SEGMENT_64 i = %d!\n", i); + print_error("failed to read LC_SEGMENT_64 i = %d!\n", i); goto err; } // The base of the library is offset by a random amount which ends up as a load command with a // filesize of 0. This must be ignored otherwise the base address of the library is wrong. if (segcmd.filesize != 0) { if (add_map_info(ph, fd, segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize, segcmd.flags) == NULL) { - print_debug("Failed to add map_info at i = %d\n", i); + print_error("Failed to add map_info at i = %d\n", i); goto err; } } @@ -318,7 +320,7 @@ static bool read_core_segments(struct ps_prochandle* ph) { uint32_t size = sizeof(load_command); while (size < lcmd.cmdsize) { if (read(fd, (void *)&fc, sizeof(thread_fc)) != sizeof(thread_fc)) { - printf("Reading flavor, count failed.\n"); + print_error("Reading flavor, count failed.\n"); goto err; } size += sizeof(thread_fc); @@ -326,14 +328,14 @@ static bool read_core_segments(struct ps_prochandle* ph) { if (fc.flavor == x86_THREAD_STATE) { x86_thread_state_t thrstate; if (read(fd, (void *)&thrstate, sizeof(x86_thread_state_t)) != sizeof(x86_thread_state_t)) { - printf("Reading flavor, count failed.\n"); + print_error("Reading flavor, count failed.\n"); goto err; } size += sizeof(x86_thread_state_t); // create thread info list, update lwp_id later sa_thread_info* newthr = add_thread_info(ph, (pthread_t) -1, (lwpid_t) num_threads++); if (newthr == NULL) { - printf("create thread_info failed\n"); + print_error("create thread_info failed\n"); goto err; } @@ -370,14 +372,14 @@ static bool read_core_segments(struct ps_prochandle* ph) { } else if (fc.flavor == x86_FLOAT_STATE) { x86_float_state_t flstate; if (read(fd, (void *)&flstate, sizeof(x86_float_state_t)) != sizeof(x86_float_state_t)) { - print_debug("Reading flavor, count failed.\n"); + print_error("Reading flavor, count failed.\n"); goto err; } size += sizeof(x86_float_state_t); } else if (fc.flavor == x86_EXCEPTION_STATE) { x86_exception_state_t excpstate; if (read(fd, (void *)&excpstate, sizeof(x86_exception_state_t)) != sizeof(x86_exception_state_t)) { - printf("Reading flavor, count failed.\n"); + print_error("Reading flavor, count failed.\n"); goto err; } size += sizeof(x86_exception_state_t); @@ -387,14 +389,14 @@ static bool read_core_segments(struct ps_prochandle* ph) { if (fc.flavor == ARM_THREAD_STATE64) { arm_thread_state64_t thrstate; if (read(fd, (void *)&thrstate, sizeof(arm_thread_state64_t)) != sizeof(arm_thread_state64_t)) { - printf("Reading flavor, count failed.\n"); + print_error("Reading flavor, count failed.\n"); goto err; } size += sizeof(arm_thread_state64_t); // create thread info list, update lwp_id later sa_thread_info* newthr = add_thread_info(ph, (pthread_t) -1, (lwpid_t) num_threads++); if (newthr == NULL) { - printf("create thread_info failed\n"); + print_error("create thread_info failed\n"); goto err; } @@ -443,21 +445,21 @@ static bool read_core_segments(struct ps_prochandle* ph) { } else if (fc.flavor == ARM_NEON_STATE64) { arm_neon_state64_t flstate; if (read(fd, (void *)&flstate, sizeof(arm_neon_state64_t)) != sizeof(arm_neon_state64_t)) { - printf("Reading flavor, count failed.\n"); + print_error("Reading flavor, count failed.\n"); goto err; } size += sizeof(arm_neon_state64_t); } else if (fc.flavor == ARM_EXCEPTION_STATE64) { arm_exception_state64_t excpstate; if (read(fd, (void *)&excpstate, sizeof(arm_exception_state64_t)) != sizeof(arm_exception_state64_t)) { - printf("Reading flavor, count failed.\n"); + print_error("Reading flavor, count failed.\n"); goto err; } size += sizeof(arm_exception_state64_t); } else if (fc.flavor == ARM_DEBUG_STATE64) { arm_debug_state64_t dbgstate; if (read(fd, (void *)&dbgstate, sizeof(arm_debug_state64_t)) != sizeof(arm_debug_state64_t)) { - printf("Reading flavor, count failed.\n"); + print_error("Reading flavor, count failed.\n"); goto err; } size += sizeof(arm_debug_state64_t); @@ -631,6 +633,7 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) { lseek(fd, -sizeof(uint32_t), SEEK_CUR); // This is the beginning of the mach-o file in the segment. if (read(fd, (void *)&header, sizeof(mach_header_64)) != sizeof(mach_header_64)) { + print_error("Failed to file header\n"); goto err; } fpos = ltell(fd); @@ -641,6 +644,7 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) { // LC_ID_DYLIB is the file itself for a .dylib lseek(fd, fpos, SEEK_SET); if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) { + print_error("Failed to read command\n"); return false; // error } fpos += lcmd.cmdsize; // next command position @@ -652,6 +656,7 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) { if (lcmd.cmd == LC_ID_DYLIB) { lseek(fd, -sizeof(load_command), SEEK_CUR); if (read(fd, (void *)&dylibcmd, sizeof(dylib_command)) != sizeof(dylib_command)) { + print_error("Failed to read command\n"); return false; } /**** name stored at dylib_command.dylib.name.offset, is a C string */ @@ -710,13 +715,13 @@ struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) { struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); if (ph == NULL) { - print_debug("can't allocate ps_prochandle\n"); + print_error("can't allocate ps_prochandle\n"); return NULL; } if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { free(ph); - print_debug("can't allocate ps_prochandle\n"); + print_error("can't allocate ps_prochandle\n"); return NULL; } @@ -738,12 +743,12 @@ struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) { // read core file header if (read_macho64_header(ph->core->core_fd, &core_header) != true || core_header.filetype != MH_CORE) { - print_debug("core file is not a valid Mach-O file\n"); + print_error("core file is not a valid Mach-O file\n"); goto err; } if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { - print_error("can't open executable file\n"); + print_error("can't open executable file: %s\n", strerror(errno)); goto err; } @@ -779,7 +784,7 @@ struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) { } if (init_classsharing_workaround(ph) != true) { - print_error("failed to workaround classshareing\n"); + print_error("failed to workaround class sharing\n"); goto err; } diff --git a/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c b/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c index 3c244aab0f379..40757a346fe2c 100644 --- a/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c +++ b/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c @@ -141,6 +141,7 @@ map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset, uintptr_t vaddr, size_t memsz, uint32_t flags) { map_info* map; if ((map = allocate_init_map(fd, offset, vaddr, memsz, flags)) == NULL) { + print_error("failed to allocate map\n"); return NULL; } @@ -158,6 +159,7 @@ static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset map_info* map; if ((map = allocate_init_map(ph->core->classes_jsa_fd, offset, vaddr, memsz, MAP_R_FLAG)) == NULL) { + print_debug("failed to allocate class share map\n"); return NULL; } From 27faf45422082009f23463984b8a6e43c15e9e71 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Wed, 23 Apr 2025 06:22:30 +0000 Subject: [PATCH 0721/1101] 8354826: Make ResolverConfigurationImpl.lock field final Reviewed-by: dfuchs, jpai --- .../unix/classes/sun/net/dns/ResolverConfigurationImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java b/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java index a466331de9339..2f633ad711d98 100644 --- a/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java +++ b/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ public final class ResolverConfigurationImpl extends ResolverConfiguration { // Lock helds whilst loading configuration or checking - private static Object lock = new Object(); + private static final Object lock = new Object(); // Time of last refresh. private static long lastRefresh = -1; From 263983d0fb9ca567b03d2be4c82cf9fe3d0e6f61 Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Wed, 23 Apr 2025 08:04:57 +0000 Subject: [PATCH 0722/1101] 8298733: Reconsider monitors_on_stack assert Reviewed-by: pchilanomate, coleenp --- .../share/runtime/continuationFreezeThaw.cpp | 59 +++++++++++++------ src/hotspot/share/runtime/stackWatermark.hpp | 3 +- 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 12a75c6c62e76..d20cfde09cab0 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -565,10 +565,50 @@ void FreezeBase::copy_to_chunk(intptr_t* from, intptr_t* to, int size) { #endif } +static void assert_frames_in_continuation_are_safe(JavaThread* thread) { +#ifdef ASSERT + StackWatermark* watermark = StackWatermarkSet::get(thread, StackWatermarkKind::gc); + if (watermark == nullptr) { + return; + } + ContinuationEntry* ce = thread->last_continuation(); + RegisterMap map(thread, + RegisterMap::UpdateMap::include, + RegisterMap::ProcessFrames::skip, + RegisterMap::WalkContinuation::skip); + map.set_include_argument_oops(false); + for (frame f = thread->last_frame(); Continuation::is_frame_in_continuation(ce, f); f = f.sender(&map)) { + watermark->assert_is_frame_safe(f); + } +#endif // ASSERT +} + +#ifdef ASSERT +static bool monitors_on_stack(JavaThread* thread) { + assert_frames_in_continuation_are_safe(thread); + ContinuationEntry* ce = thread->last_continuation(); + RegisterMap map(thread, + RegisterMap::UpdateMap::include, + RegisterMap::ProcessFrames::skip, + RegisterMap::WalkContinuation::skip); + map.set_include_argument_oops(false); + for (frame f = thread->last_frame(); Continuation::is_frame_in_continuation(ce, f); f = f.sender(&map)) { + if ((f.is_interpreted_frame() && ContinuationHelper::InterpretedFrame::is_owning_locks(f)) || + (f.is_compiled_frame() && ContinuationHelper::CompiledFrame::is_owning_locks(map.thread(), &map, f)) || + (f.is_native_frame() && ContinuationHelper::NativeFrame::is_owning_locks(map.thread(), f))) { + return true; + } + } + return false; +} +#endif // ASSERT + // Called _after_ the last possible safepoint during the freeze operation (chunk allocation) void FreezeBase::unwind_frames() { ContinuationEntry* entry = _cont.entry(); entry->flush_stack_processing(_thread); + assert_frames_in_continuation_are_safe(_thread); + assert(LockingMode != LM_LEGACY || !monitors_on_stack(_thread), "unexpected monitors on stack"); set_anchor_to_entry(_thread, entry); } @@ -1621,23 +1661,6 @@ static void jvmti_mount_end(JavaThread* current, ContinuationWrapper& cont, fram #endif // INCLUDE_JVMTI #ifdef ASSERT -static bool monitors_on_stack(JavaThread* thread) { - ContinuationEntry* ce = thread->last_continuation(); - RegisterMap map(thread, - RegisterMap::UpdateMap::include, - RegisterMap::ProcessFrames::include, - RegisterMap::WalkContinuation::skip); - map.set_include_argument_oops(false); - for (frame f = thread->last_frame(); Continuation::is_frame_in_continuation(ce, f); f = f.sender(&map)) { - if ((f.is_interpreted_frame() && ContinuationHelper::InterpretedFrame::is_owning_locks(f)) || - (f.is_compiled_frame() && ContinuationHelper::CompiledFrame::is_owning_locks(map.thread(), &map, f)) || - (f.is_native_frame() && ContinuationHelper::NativeFrame::is_owning_locks(map.thread(), f))) { - return true; - } - } - return false; -} - // There are no interpreted frames if we're not called from the interpreter and we haven't ancountered an i2c // adapter or called Deoptimization::unpack_frames. As for native frames, upcalls from JNI also go through the // interpreter (see JavaCalls::call_helper), while the UpcallLinker explicitly sets cont_fastpath. @@ -1714,8 +1737,6 @@ static inline freeze_result freeze_internal(JavaThread* current, intptr_t* const assert(entry->is_virtual_thread() == (entry->scope(current) == java_lang_VirtualThread::vthread_scope()), ""); - assert(LockingMode != LM_LEGACY || (monitors_on_stack(current) == ((current->held_monitor_count() - current->jni_monitor_count()) > 0)), - "Held monitor count and locks on stack invariant: " INT64_FORMAT " JNI: " INT64_FORMAT, (int64_t)current->held_monitor_count(), (int64_t)current->jni_monitor_count()); assert(LockingMode == LM_LEGACY || (current->held_monitor_count() == 0 && current->jni_monitor_count() == 0), "Held monitor count should only be used for LM_LEGACY: " INT64_FORMAT " JNI: " INT64_FORMAT, (int64_t)current->held_monitor_count(), (int64_t)current->jni_monitor_count()); diff --git a/src/hotspot/share/runtime/stackWatermark.hpp b/src/hotspot/share/runtime/stackWatermark.hpp index 8d51f694a1d71..4f1c65c903c8a 100644 --- a/src/hotspot/share/runtime/stackWatermark.hpp +++ b/src/hotspot/share/runtime/stackWatermark.hpp @@ -102,7 +102,6 @@ class StackWatermark : public CHeapObj { void yield_processing(); static bool has_barrier(const frame& f); void ensure_safe(const frame& f); - void assert_is_frame_safe(const frame& f) NOT_DEBUG_RETURN; bool is_frame_safe(const frame& f); // API for consumers of the stack watermark barrier. @@ -151,6 +150,8 @@ class StackWatermark : public CHeapObj { void on_safepoint(); void start_processing(); void finish_processing(void* context); + + void assert_is_frame_safe(const frame& f) NOT_DEBUG_RETURN; }; #endif // SHARE_RUNTIME_STACKWATERMARK_HPP From c2e90bcc8026fb2047b42deae6cdad738d6d01b8 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Wed, 23 Apr 2025 08:21:07 +0000 Subject: [PATCH 0723/1101] 8355363: [BACKOUT] 8354668: Missing REX2 prefix accounting in ZGC barriers leads to incorrect encoding Reviewed-by: chagedorn --- .../cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp | 14 +++++++------- .../cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp | 2 +- src/hotspot/cpu/x86/gc/z/z_x86_64.ad | 4 ++-- src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp index 0891d303563d7..9cdf0b229c0a4 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp @@ -391,8 +391,8 @@ void ZBarrierSetAssembler::store_barrier_fast(MacroAssembler* masm, if (rnew_zaddress != noreg) { // noreg means null; no need to color __ movptr(rnew_zpointer, rnew_zaddress); + __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeShl); __ shlq(rnew_zpointer, barrier_Relocation::unpatched); - __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodAfterShX); __ orq_imm32(rnew_zpointer, barrier_Relocation::unpatched); __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatStoreGoodAfterOr); } @@ -969,13 +969,13 @@ void ZBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, #define __ ce->masm()-> static void z_uncolor(LIR_Assembler* ce, LIR_Opr ref) { + __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeShl); __ shrq(ref->as_register(), barrier_Relocation::unpatched); - __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodAfterShX); } static void z_color(LIR_Assembler* ce, LIR_Opr ref) { + __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeShl); __ shlq(ref->as_register(), barrier_Relocation::unpatched); - __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodAfterShX); __ orq_imm32(ref->as_register(), barrier_Relocation::unpatched); __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatStoreGoodAfterOr); } @@ -1278,8 +1278,8 @@ void ZBarrierSetAssembler::generate_c2_store_barrier_stub(MacroAssembler* masm, static int patch_barrier_relocation_offset(int format) { switch (format) { - case ZBarrierRelocationFormatLoadGoodAfterShX: - return -1; + case ZBarrierRelocationFormatLoadGoodBeforeShl: + return 3; case ZBarrierRelocationFormatStoreGoodAfterCmp: return -2; @@ -1300,7 +1300,7 @@ static int patch_barrier_relocation_offset(int format) { static uint16_t patch_barrier_relocation_value(int format) { switch (format) { - case ZBarrierRelocationFormatLoadGoodAfterShX: + case ZBarrierRelocationFormatLoadGoodBeforeShl: return (uint16_t)ZPointerLoadShift; case ZBarrierRelocationFormatMarkBadAfterTest: @@ -1327,7 +1327,7 @@ void ZBarrierSetAssembler::patch_barrier_relocation(address addr, int format) { const int offset = patch_barrier_relocation_offset(format); const uint16_t value = patch_barrier_relocation_value(format); uint8_t* const patch_addr = (uint8_t*)addr + offset; - if (format == ZBarrierRelocationFormatLoadGoodAfterShX) { + if (format == ZBarrierRelocationFormatLoadGoodBeforeShl) { *patch_addr = (uint8_t)value; } else { *(uint16_t*)patch_addr = value; diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp index 6976452bd6381..8bb653ec5fbaf 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp @@ -49,7 +49,7 @@ class ZLoadBarrierStubC2; class ZStoreBarrierStubC2; #endif // COMPILER2 -const int ZBarrierRelocationFormatLoadGoodAfterShX = 0; +const int ZBarrierRelocationFormatLoadGoodBeforeShl = 0; const int ZBarrierRelocationFormatLoadBadAfterTest = 1; const int ZBarrierRelocationFormatMarkBadAfterTest = 2; const int ZBarrierRelocationFormatStoreGoodAfterCmp = 3; diff --git a/src/hotspot/cpu/x86/gc/z/z_x86_64.ad b/src/hotspot/cpu/x86/gc/z/z_x86_64.ad index e2484a71e7dd3..045aa5d538193 100644 --- a/src/hotspot/cpu/x86/gc/z/z_x86_64.ad +++ b/src/hotspot/cpu/x86/gc/z/z_x86_64.ad @@ -35,15 +35,15 @@ source %{ #include "gc/z/zBarrierSetAssembler.hpp" static void z_color(MacroAssembler* masm, const MachNode* node, Register ref) { + __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeShl); __ shlq(ref, barrier_Relocation::unpatched); - __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodAfterShX); __ orq_imm32(ref, barrier_Relocation::unpatched); __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatStoreGoodAfterOr); } static void z_uncolor(MacroAssembler* masm, const MachNode* node, Register ref) { + __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeShl); __ shrq(ref, barrier_Relocation::unpatched); - __ relocate(barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodAfterShX); } static void z_keep_alive_load_barrier(MacroAssembler* masm, const MachNode* node, Address ref_addr, Register ref) { diff --git a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp index 7e239a6898354..9e6a4789dc2cd 100644 --- a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp +++ b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp @@ -221,7 +221,7 @@ bool CodeInstaller::pd_relocate(address pc, jint mark) { return true; #if INCLUDE_ZGC case Z_BARRIER_RELOCATION_FORMAT_LOAD_GOOD_BEFORE_SHL: - _instructions->relocate(pc, barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodAfterShX); + _instructions->relocate(pc, barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeShl); return true; case Z_BARRIER_RELOCATION_FORMAT_LOAD_BAD_AFTER_TEST: _instructions->relocate(pc, barrier_Relocation::spec(), ZBarrierRelocationFormatLoadBadAfterTest); From e76f20301c3dcd65610e982fc98b7a08ebf0c8f1 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Wed, 23 Apr 2025 10:13:26 +0000 Subject: [PATCH 0724/1101] 8354309: Sort GC includes Reviewed-by: eosterlund, iwalulya, kbarrett --- .../c1/shenandoahBarrierSetC1_aarch64.cpp | 2 +- .../shenandoahBarrierSetAssembler_aarch64.cpp | 6 ++--- .../cpu/aarch64/gc/z/zAddress_aarch64.cpp | 2 +- .../arm/gc/g1/g1BarrierSetAssembler_arm.cpp | 1 - .../arm/gc/shared/barrierSetNMethod_arm.cpp | 2 +- .../ppc/gc/shared/barrierSetNMethod_ppc.cpp | 2 +- .../c1/shenandoahBarrierSetC1_ppc.cpp | 2 +- .../shenandoahBarrierSetAssembler_ppc.cpp | 6 ++--- src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp | 2 +- .../gc/shared/barrierSetNMethod_riscv.cpp | 2 +- .../c1/shenandoahBarrierSetC1_riscv.cpp | 2 +- .../shenandoahBarrierSetAssembler_riscv.cpp | 6 ++--- src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp | 2 +- .../s390/gc/g1/g1BarrierSetAssembler_s390.cpp | 4 +-- .../c1/shenandoahBarrierSetC1_x86.cpp | 2 +- .../shenandoahBarrierSetAssembler_x86.cpp | 4 +-- .../os/windows/gc/z/zSyscall_windows.hpp | 1 - .../gc/epsilon/epsilonMonitoringSupport.cpp | 2 +- src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp | 2 +- src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp | 2 +- src/hotspot/share/gc/g1/g1AllocRegion.cpp | 2 +- src/hotspot/share/gc/g1/g1Allocator.cpp | 2 +- .../gc/g1/g1AnalyticsSequences.inline.hpp | 1 + src/hotspot/share/gc/g1/g1BarrierSet.hpp | 2 +- .../share/gc/g1/g1BlockOffsetTable.inline.hpp | 3 ++- src/hotspot/share/gc/g1/g1CardSet.inline.hpp | 1 + .../gc/g1/g1CardSetContainers.inline.hpp | 1 + .../share/gc/g1/g1CardSetMemory.inline.hpp | 1 + src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 6 ++--- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 2 +- .../share/gc/g1/g1CollectionSet.inline.hpp | 1 + src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 2 +- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 2 +- ...ConcurrentMarkObjArrayProcessor.inline.hpp | 2 +- .../gc/g1/g1ConcurrentRebuildAndScrub.cpp | 3 +-- .../share/gc/g1/g1ConcurrentRefine.cpp | 1 + src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp | 2 +- src/hotspot/share/gc/g1/g1EdenRegions.hpp | 2 +- .../gc/g1/g1EvacFailureRegions.inline.hpp | 3 ++- src/hotspot/share/gc/g1/g1EvacStats.cpp | 2 +- src/hotspot/share/gc/g1/g1EvacStats.hpp | 2 +- src/hotspot/share/gc/g1/g1FullCollector.cpp | 2 +- src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp | 4 +-- .../share/gc/g1/g1HeapRegionManager.cpp | 2 +- src/hotspot/share/gc/g1/g1InitLogger.cpp | 2 +- .../share/gc/g1/g1MonitoringSupport.cpp | 2 +- .../share/gc/g1/g1MonitoringSupport.hpp | 2 +- .../share/gc/g1/g1MonotonicArena.inline.hpp | 1 + .../gc/g1/g1MonotonicArenaFreeMemoryTask.cpp | 2 +- src/hotspot/share/gc/g1/g1NMethodClosure.cpp | 2 +- .../share/gc/g1/g1OopClosures.inline.hpp | 2 +- .../share/gc/g1/g1ParScanThreadState.hpp | 2 +- src/hotspot/share/gc/g1/g1Policy.cpp | 7 +++--- src/hotspot/share/gc/g1/g1Policy.hpp | 2 +- src/hotspot/share/gc/g1/g1RemSet.cpp | 4 +-- src/hotspot/share/gc/g1/g1ServiceThread.cpp | 2 +- src/hotspot/share/gc/g1/g1SurvivorRegions.cpp | 2 +- src/hotspot/share/gc/g1/g1Trace.cpp | 2 +- src/hotspot/share/gc/g1/g1VMOperations.cpp | 2 +- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 6 ++--- .../share/gc/g1/g1YoungGCPreEvacuateTasks.cpp | 2 +- .../share/gc/parallel/parallelInitLogger.cpp | 2 +- .../gc/parallel/psAdaptiveSizePolicy.cpp | 2 +- src/hotspot/share/gc/parallel/psCardTable.cpp | 2 +- .../share/gc/parallel/psCompactionManager.cpp | 2 +- .../share/gc/parallel/psCompactionManager.hpp | 2 +- src/hotspot/share/gc/parallel/psScavenge.cpp | 6 ++--- src/hotspot/share/gc/parallel/psScavenge.hpp | 2 +- .../share/gc/parallel/psVMOperations.cpp | 2 +- .../share/gc/serial/serialArguments.cpp | 4 +-- src/hotspot/share/gc/serial/serialFullGC.cpp | 4 +-- .../gc/serial/tenuredGeneration.inline.hpp | 1 + src/hotspot/share/gc/shared/ageTable.cpp | 2 +- .../gc/shared/barrierSetConfig.inline.hpp | 2 +- .../share/gc/shared/barrierSetNMethod.cpp | 2 +- src/hotspot/share/gc/shared/bufferNode.cpp | 2 +- .../share/gc/shared/c1/barrierSetC1.hpp | 2 +- .../share/gc/shared/c2/barrierSetC2.cpp | 2 +- .../gc/shared/c2/cardTableBarrierSetC2.cpp | 2 +- .../share/gc/shared/c2/modRefBarrierSetC2.cpp | 2 +- src/hotspot/share/gc/shared/cardTable.cpp | 2 +- src/hotspot/share/gc/shared/collectedHeap.cpp | 6 ++--- src/hotspot/share/gc/shared/gcHeapSummary.hpp | 2 +- src/hotspot/share/gc/shared/gcInitLogger.cpp | 2 +- src/hotspot/share/gc/shared/gcLocker.cpp | 4 +-- src/hotspot/share/gc/shared/gcLogPrecious.hpp | 2 +- .../share/gc/shared/gcOverheadChecker.hpp | 4 +-- .../share/gc/shared/gcPolicyCounters.cpp | 2 +- src/hotspot/share/gc/shared/gcTimer.cpp | 2 +- src/hotspot/share/gc/shared/gcTraceTime.cpp | 2 +- .../share/gc/shared/gcVMOperations.cpp | 2 +- .../share/gc/shared/locationPrinter.cpp | 2 +- src/hotspot/share/gc/shared/memAllocator.cpp | 2 +- .../share/gc/shared/parallelCleaning.cpp | 3 +-- .../share/gc/shared/partialArrayState.cpp | 1 + .../shared/partialArrayTaskStepper.inline.hpp | 3 ++- .../shared/referenceProcessorPhaseTimes.cpp | 2 +- src/hotspot/share/gc/shared/satbMarkQueue.cpp | 2 +- .../gc/shared/stringdedup/stringDedup.cpp | 2 +- .../shared/stringdedup/stringDedupTable.cpp | 4 +-- .../shared/stringdedup/stringDedupTable.hpp | 2 +- .../share/gc/shared/taskTerminator.cpp | 2 +- src/hotspot/share/gc/shared/taskqueue.cpp | 2 +- .../shared/threadLocalAllocBuffer.inline.hpp | 2 +- src/hotspot/share/gc/shared/weakProcessor.cpp | 2 +- .../shenandoah/c1/shenandoahBarrierSetC1.cpp | 2 +- .../shenandoah/c2/shenandoahBarrierSetC2.cpp | 6 ++--- .../gc/shenandoah/c2/shenandoahSupport.cpp | 2 +- .../shenandoahAdaptiveHeuristics.cpp | 2 +- .../shenandoahAdaptiveHeuristics.hpp | 2 +- .../shenandoahCompactHeuristics.cpp | 2 +- .../shenandoahGenerationalHeuristics.cpp | 3 +-- .../heuristics/shenandoahGlobalHeuristics.cpp | 3 +-- .../heuristics/shenandoahHeuristics.cpp | 2 +- .../heuristics/shenandoahYoungHeuristics.cpp | 1 - .../mode/shenandoahGenerationalMode.cpp | 2 +- .../shenandoah/mode/shenandoahPassiveMode.cpp | 2 +- .../gc/shenandoah/shenandoahBarrierSet.cpp | 2 +- .../shenandoahBarrierSet.inline.hpp | 2 +- .../shenandoah/shenandoahClosures.inline.hpp | 4 +-- .../gc/shenandoah/shenandoahCodeRoots.hpp | 2 +- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 6 ++--- .../shenandoah/shenandoahConcurrentMark.cpp | 4 +-- .../gc/shenandoah/shenandoahControlThread.cpp | 6 ++--- .../gc/shenandoah/shenandoahControlThread.hpp | 4 +-- .../gc/shenandoah/shenandoahController.cpp | 3 +-- .../gc/shenandoah/shenandoahController.hpp | 2 +- .../gc/shenandoah/shenandoahDegeneratedGC.cpp | 4 +-- .../gc/shenandoah/shenandoahEvacTracker.cpp | 4 +-- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 2 +- .../share/gc/shenandoah/shenandoahFreeSet.hpp | 2 +- .../share/gc/shenandoah/shenandoahFullGC.cpp | 13 +++++----- .../share/gc/shenandoah/shenandoahGC.hpp | 2 +- .../gc/shenandoah/shenandoahGeneration.cpp | 5 ++-- .../gc/shenandoah/shenandoahGeneration.hpp | 2 +- .../shenandoah/shenandoahGenerationSizer.cpp | 2 +- .../shenandoahGenerationalControlThread.cpp | 8 +++--- .../shenandoahGenerationalEvacuationTask.cpp | 2 +- .../shenandoahGenerationalFullGC.cpp | 4 +-- .../shenandoah/shenandoahGenerationalHeap.cpp | 2 +- .../shenandoah/shenandoahGlobalGeneration.cpp | 2 +- .../shenandoah/shenandoahGlobalGeneration.hpp | 2 +- .../share/gc/shenandoah/shenandoahHeap.cpp | 25 ++++++++----------- .../share/gc/shenandoah/shenandoahHeap.hpp | 8 +++--- .../gc/shenandoah/shenandoahHeap.inline.hpp | 14 +++++------ .../gc/shenandoah/shenandoahHeapRegion.cpp | 6 ++--- .../shenandoahHeapRegion.inline.hpp | 3 ++- .../shenandoahHeapRegionCounters.cpp | 2 +- .../shenandoahHeapRegionCounters.hpp | 2 +- .../gc/shenandoah/shenandoahHeapRegionSet.cpp | 2 +- .../gc/shenandoah/shenandoahHeapRegionSet.hpp | 2 +- .../gc/shenandoah/shenandoahInitLogger.cpp | 4 +-- .../share/gc/shenandoah/shenandoahLock.cpp | 3 +-- .../share/gc/shenandoah/shenandoahMark.hpp | 2 +- .../gc/shenandoah/shenandoahMarkBitMap.cpp | 2 +- .../shenandoah/shenandoahMarkingContext.cpp | 1 - .../shenandoahMarkingContext.inline.hpp | 1 + .../gc/shenandoah/shenandoahMemoryPool.cpp | 2 +- .../share/gc/shenandoah/shenandoahMetrics.cpp | 4 +-- .../gc/shenandoah/shenandoahMmuTracker.cpp | 2 +- .../shenandoahMonitoringSupport.cpp | 2 +- .../share/gc/shenandoah/shenandoahOldGC.cpp | 2 +- .../gc/shenandoah/shenandoahOldGeneration.cpp | 2 +- .../gc/shenandoah/shenandoahPhaseTimings.cpp | 4 +-- .../gc/shenandoah/shenandoahPhaseTimings.hpp | 4 +-- .../shenandoahReferenceProcessor.cpp | 4 +-- .../gc/shenandoah/shenandoahRootProcessor.cpp | 2 +- .../shenandoahRootProcessor.inline.hpp | 2 +- .../gc/shenandoah/shenandoahRootVerifier.cpp | 6 ++--- .../share/gc/shenandoah/shenandoahRuntime.cpp | 2 +- .../shenandoahScanRemembered.inline.hpp | 11 ++++---- .../gc/shenandoah/shenandoahSimpleBitMap.hpp | 4 +-- .../shenandoahStringDedup.inline.hpp | 3 ++- .../gc/shenandoah/shenandoahTaskqueue.hpp | 2 +- .../shenandoah/shenandoahThreadLocalData.hpp | 8 +++--- .../share/gc/shenandoah/shenandoahUnload.cpp | 4 +-- .../share/gc/shenandoah/shenandoahUtils.cpp | 2 +- .../share/gc/shenandoah/shenandoahUtils.hpp | 2 +- .../gc/shenandoah/shenandoahVerifier.cpp | 2 +- .../gc/shenandoah/shenandoahWorkGroup.cpp | 3 +-- .../shenandoah/shenandoahYoungGeneration.cpp | 2 +- .../shenandoah/shenandoahYoungGeneration.hpp | 2 +- .../gc/shenandoah/vmStructs_shenandoah.hpp | 2 +- src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp | 2 +- src/hotspot/share/gc/z/zHeapIterator.hpp | 2 +- src/hotspot/share/gc/z/zMarkContext.hpp | 2 +- src/hotspot/share/gc/z/zMarkingSMR.hpp | 2 +- src/hotspot/share/gc/z/zNMT.cpp | 2 +- src/hotspot/share/gc/z/zNMT.hpp | 2 +- src/hotspot/share/gc/z/zNMethod.cpp | 2 +- src/hotspot/share/gc/z/zNMethodTable.cpp | 2 +- src/hotspot/share/gc/z/zObjArrayAllocator.cpp | 2 +- src/hotspot/share/gc/z/zRuntimeWorkers.cpp | 2 +- src/hotspot/share/gc/z/zStat.cpp | 2 +- .../share/gc/z/zUncoloredRoot.inline.hpp | 2 +- src/hotspot/share/gc/z/zVerify.cpp | 2 +- .../gc/z/zVirtualMemoryManager.inline.hpp | 2 +- 197 files changed, 281 insertions(+), 284 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp index e33ef47cf3c38..e4db8a9ab1f82 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp @@ -27,9 +27,9 @@ #include "c1/c1_MacroAssembler.hpp" #include "compiler/compilerDefinitions.inline.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" -#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #define __ masm->masm()-> diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp index ac22b43faaf02..a2b3f44c68b72 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp @@ -23,6 +23,8 @@ * */ +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" #include "gc/shenandoah/shenandoahForwarding.hpp" @@ -30,10 +32,8 @@ #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahRuntime.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" -#include "interpreter/interpreter.hpp" #include "interpreter/interp_masm.hpp" +#include "interpreter/interpreter.hpp" #include "runtime/javaThread.hpp" #include "runtime/sharedRuntime.hpp" #ifdef COMPILER1 diff --git a/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp index 20e37528c047c..7008615ed438a 100644 --- a/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp @@ -21,8 +21,8 @@ * questions. */ -#include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcLogPrecious.hpp" #include "gc/z/zAddress.hpp" #include "gc/z/zBarrierSetAssembler.hpp" #include "gc/z/zGlobals.hpp" diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp index 466dcc8fe66c1..049477cda7658 100644 --- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp @@ -26,7 +26,6 @@ #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1BarrierSetAssembler.hpp" #include "gc/g1/g1BarrierSetRuntime.hpp" -#include "gc/g1/g1ThreadLocalData.hpp" #include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1HeapRegion.hpp" #include "gc/g1/g1ThreadLocalData.hpp" diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp b/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp index 224a499ff5420..c6cc0ce406e19 100644 --- a/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp +++ b/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp @@ -29,8 +29,8 @@ #include "memory/resourceArea.hpp" #include "runtime/frame.inline.hpp" #include "runtime/javaThread.hpp" -#include "runtime/sharedRuntime.hpp" #include "runtime/registerMap.hpp" +#include "runtime/sharedRuntime.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp index 19084ed27c7c0..1b44a169e678f 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp @@ -23,8 +23,8 @@ */ #include "code/codeBlob.hpp" -#include "code/nmethod.hpp" #include "code/nativeInst.hpp" +#include "code/nmethod.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "gc/shared/barrierSetNMethod.hpp" diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp index 48422bc66212e..5b24259103f53 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp @@ -26,9 +26,9 @@ #include "asm/macroAssembler.inline.hpp" #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" +#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" -#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #define __ masm->masm()-> diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp index 842201e158489..ec5b98bd4c516 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp @@ -24,8 +24,10 @@ */ #include "asm/macroAssembler.inline.hpp" -#include "gc/shared/gcArguments.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcArguments.hpp" +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" #include "gc/shenandoah/shenandoahForwarding.hpp" @@ -34,8 +36,6 @@ #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahRuntime.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "interpreter/interpreter.hpp" #include "macroAssembler_ppc.hpp" #include "runtime/javaThread.hpp" diff --git a/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp b/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp index 2e3eed8ec60d9..f3a7a948f7021 100644 --- a/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp @@ -21,8 +21,8 @@ * questions. */ -#include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcLogPrecious.hpp" #include "gc/z/zAddress.inline.hpp" #include "gc/z/zGlobals.hpp" #include "runtime/globals.hpp" diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp index 39da77181c674..f24e4f789bc50 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp @@ -31,8 +31,8 @@ #include "memory/resourceArea.hpp" #include "runtime/frame.inline.hpp" #include "runtime/javaThread.hpp" -#include "runtime/sharedRuntime.hpp" #include "runtime/registerMap.hpp" +#include "runtime/sharedRuntime.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" #if INCLUDE_JVMCI diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp index 2a96bd32cf8d7..11c4e5dc81b6c 100644 --- a/src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp @@ -26,9 +26,9 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" -#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #define __ masm->masm()-> diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp index 3021351cca84f..4c1056e75a551 100644 --- a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp @@ -23,6 +23,8 @@ * */ +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" #include "gc/shenandoah/shenandoahForwarding.hpp" @@ -30,10 +32,8 @@ #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahRuntime.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" -#include "interpreter/interpreter.hpp" #include "interpreter/interp_masm.hpp" +#include "interpreter/interpreter.hpp" #include "runtime/javaThread.hpp" #include "runtime/sharedRuntime.hpp" #ifdef COMPILER1 diff --git a/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp b/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp index 1f2f0146f04a2..5f783e6fb8ba5 100644 --- a/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp @@ -22,8 +22,8 @@ * questions. */ -#include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcLogPrecious.hpp" #include "gc/z/zAddress.hpp" #include "gc/z/zBarrierSetAssembler.hpp" #include "gc/z/zGlobals.hpp" diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp index 2054c3db36c50..dea3317270e71 100644 --- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp @@ -24,16 +24,16 @@ */ #include "asm/macroAssembler.inline.hpp" -#include "registerSaver_s390.hpp" -#include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1BarrierSetAssembler.hpp" #include "gc/g1/g1BarrierSetRuntime.hpp" +#include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1DirtyCardQueue.hpp" #include "gc/g1/g1HeapRegion.hpp" #include "gc/g1/g1SATBMarkQueueSet.hpp" #include "gc/g1/g1ThreadLocalData.hpp" #include "interpreter/interp_masm.hpp" +#include "registerSaver_s390.hpp" #include "runtime/jniHandles.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/macros.hpp" diff --git a/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp index 298e5640b27d1..66fb4cbb8c78d 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp @@ -26,9 +26,9 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" -#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #define __ masm->masm()-> diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp index 45e4c46161ff1..deb8111adade8 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp @@ -23,6 +23,8 @@ * */ +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" #include "gc/shenandoah/shenandoahForwarding.hpp" @@ -30,8 +32,6 @@ #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahRuntime.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "interpreter/interpreter.hpp" #include "runtime/javaThread.hpp" #include "runtime/sharedRuntime.hpp" diff --git a/src/hotspot/os/windows/gc/z/zSyscall_windows.hpp b/src/hotspot/os/windows/gc/z/zSyscall_windows.hpp index d6174de7d884c..3d20fa5a9245a 100644 --- a/src/hotspot/os/windows/gc/z/zSyscall_windows.hpp +++ b/src/hotspot/os/windows/gc/z/zSyscall_windows.hpp @@ -27,7 +27,6 @@ #include "utilities/globalDefinitions.hpp" #include -#include class ZSyscall { private: diff --git a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp index 540ede9dd83ac..a2ae6f8a14a9d 100644 --- a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp @@ -22,8 +22,8 @@ * */ -#include "gc/epsilon/epsilonMonitoringSupport.hpp" #include "gc/epsilon/epsilonHeap.hpp" +#include "gc/epsilon/epsilonMonitoringSupport.hpp" #include "gc/shared/generationCounters.hpp" #include "memory/allocation.hpp" #include "memory/metaspaceCounters.hpp" diff --git a/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp b/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp index a0eb218dd6caa..c4791311e9b21 100644 --- a/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp +++ b/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp @@ -22,8 +22,8 @@ * */ -#include "c1/c1_LIRGenerator.hpp" #include "c1/c1_CodeStubs.hpp" +#include "c1/c1_LIRGenerator.hpp" #include "gc/g1/c1/g1BarrierSetC1.hpp" #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1BarrierSetAssembler.hpp" diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp index 57e481668f8d8..bca2255479b58 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp @@ -29,8 +29,8 @@ #include "gc/g1/g1BarrierSetAssembler.hpp" #include "gc/g1/g1BarrierSetRuntime.hpp" #include "gc/g1/g1CardTable.hpp" -#include "gc/g1/g1ThreadLocalData.hpp" #include "gc/g1/g1HeapRegion.hpp" +#include "gc/g1/g1ThreadLocalData.hpp" #include "opto/arraycopynode.hpp" #include "opto/block.hpp" #include "opto/compile.hpp" diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.cpp b/src/hotspot/share/gc/g1/g1AllocRegion.cpp index 29907cbc05157..7e748cf7e9f0b 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.cpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.cpp @@ -23,8 +23,8 @@ */ #include "gc/g1/g1AllocRegion.inline.hpp" -#include "gc/g1/g1EvacStats.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1EvacStats.inline.hpp" #include "gc/shared/tlab_globals.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" diff --git a/src/hotspot/share/gc/g1/g1Allocator.cpp b/src/hotspot/share/gc/g1/g1Allocator.cpp index 49a4958f7186b..c44234fa11cb8 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.cpp +++ b/src/hotspot/share/gc/g1/g1Allocator.cpp @@ -24,9 +24,9 @@ #include "gc/g1/g1Allocator.inline.hpp" #include "gc/g1/g1AllocRegion.inline.hpp" +#include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1EvacInfo.hpp" #include "gc/g1/g1EvacStats.inline.hpp" -#include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" #include "gc/g1/g1HeapRegionPrinter.hpp" #include "gc/g1/g1HeapRegionSet.inline.hpp" diff --git a/src/hotspot/share/gc/g1/g1AnalyticsSequences.inline.hpp b/src/hotspot/share/gc/g1/g1AnalyticsSequences.inline.hpp index cd59cac80b423..9fae49320bc94 100644 --- a/src/hotspot/share/gc/g1/g1AnalyticsSequences.inline.hpp +++ b/src/hotspot/share/gc/g1/g1AnalyticsSequences.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_G1_G1ANALYTICSSEQUENCES_INLINE_HPP #include "gc/g1/g1AnalyticsSequences.hpp" + #include "gc/g1/g1Predictions.hpp" bool G1PhaseDependentSeq::enough_samples_to_use_mixed_seq() const { diff --git a/src/hotspot/share/gc/g1/g1BarrierSet.hpp b/src/hotspot/share/gc/g1/g1BarrierSet.hpp index 3212aec278010..8c2605b974677 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSet.hpp +++ b/src/hotspot/share/gc/g1/g1BarrierSet.hpp @@ -27,9 +27,9 @@ #include "gc/g1/g1DirtyCardQueue.hpp" #include "gc/g1/g1SATBMarkQueueSet.hpp" +#include "gc/shared/bufferNode.hpp" #include "gc/shared/cardTable.hpp" #include "gc/shared/cardTableBarrierSet.hpp" -#include "gc/shared/bufferNode.hpp" class G1CardTable; diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp index 7e6b0e56d9346..e35ae08dfada2 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp @@ -26,11 +26,12 @@ #define SHARE_GC_G1_G1BLOCKOFFSETTABLE_INLINE_HPP #include "gc/g1/g1BlockOffsetTable.hpp" + #include "gc/g1/g1HeapRegion.hpp" #include "gc/shared/cardTable.hpp" #include "gc/shared/memset_with_concurrent_readers.hpp" -#include "runtime/atomic.hpp" #include "oops/oop.inline.hpp" +#include "runtime/atomic.hpp" inline HeapWord* G1BlockOffsetTable::block_start_reaching_into_card(const void* addr) const { assert(_reserved.contains(addr), "invalid address"); diff --git a/src/hotspot/share/gc/g1/g1CardSet.inline.hpp b/src/hotspot/share/gc/g1/g1CardSet.inline.hpp index 7d753f00bfba6..4909e922c6bdc 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardSet.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_G1_G1CARDSET_INLINE_HPP #include "gc/g1/g1CardSet.hpp" + #include "gc/g1/g1CardSetContainers.inline.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "logging/log.hpp" diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp index 61707dcf012d5..0efc44dea12fe 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_G1_G1CARDSETCONTAINERS_INLINE_HPP #include "gc/g1/g1CardSetContainers.hpp" + #include "gc/g1/g1GCPhaseTimes.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/checkedCast.hpp" diff --git a/src/hotspot/share/gc/g1/g1CardSetMemory.inline.hpp b/src/hotspot/share/gc/g1/g1CardSetMemory.inline.hpp index 8c0fab3fd1160..7bb618e79b463 100644 --- a/src/hotspot/share/gc/g1/g1CardSetMemory.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetMemory.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_G1_G1CARDSETMEMORY_INLINE_HPP #include "gc/g1/g1CardSetMemory.hpp" + #include "gc/g1/g1CardSetContainers.inline.hpp" #include "gc/g1/g1MonotonicArena.inline.hpp" #include "utilities/globalCounter.inline.hpp" diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 31f0cc12aa5ee..8b36bf124f2db 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -35,16 +35,16 @@ #include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1CollectionSetCandidates.hpp" #include "gc/g1/g1CollectorState.hpp" +#include "gc/g1/g1ConcurrentMarkThread.inline.hpp" #include "gc/g1/g1ConcurrentRefine.hpp" #include "gc/g1/g1ConcurrentRefineThread.hpp" -#include "gc/g1/g1ConcurrentMarkThread.inline.hpp" #include "gc/g1/g1DirtyCardQueue.hpp" #include "gc/g1/g1EvacStats.inline.hpp" #include "gc/g1/g1FullCollector.hpp" #include "gc/g1/g1GCCounters.hpp" #include "gc/g1/g1GCParPhaseTimesTracker.hpp" -#include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1GCPauseType.hpp" +#include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" #include "gc/g1/g1HeapRegionPrinter.hpp" #include "gc/g1/g1HeapRegionRemSet.inline.hpp" @@ -91,8 +91,8 @@ #include "gc/shared/taskqueue.inline.hpp" #include "gc/shared/taskTerminator.hpp" #include "gc/shared/tlab_globals.hpp" -#include "gc/shared/workerPolicy.hpp" #include "gc/shared/weakProcessor.inline.hpp" +#include "gc/shared/workerPolicy.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/heapInspection.hpp" diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 8d449ceedc6d1..0f583e8dcbf3e 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -27,8 +27,8 @@ #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1BiasedArray.hpp" -#include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1CardSet.hpp" +#include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1ConcurrentMark.hpp" diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp index f295eff3edd2b..717f6860eb697 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_G1_G1COLLECTIONSET_INLINE_HPP #include "gc/g1/g1CollectionSet.hpp" + #include "gc/g1/g1HeapRegionRemSet.hpp" template diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 0b8e66f904343..ef62587d86814 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -52,8 +52,8 @@ #include "gc/shared/referencePolicy.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/suspendibleThreadSet.hpp" -#include "gc/shared/taskTerminator.hpp" #include "gc/shared/taskqueue.inline.hpp" +#include "gc/shared/taskTerminator.hpp" #include "gc/shared/weakProcessor.inline.hpp" #include "gc/shared/workerPolicy.hpp" #include "jvm.h" diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index d54f9bc96f1d9..2fb9732b88ecf 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -31,8 +31,8 @@ #include "gc/g1/g1HeapVerifier.hpp" #include "gc/g1/g1RegionMarkStatsCache.hpp" #include "gc/shared/gcCause.hpp" -#include "gc/shared/taskTerminator.hpp" #include "gc/shared/taskqueue.hpp" +#include "gc/shared/taskTerminator.hpp" #include "gc/shared/verifyOption.hpp" #include "gc/shared/workerThread.hpp" #include "gc/shared/workerUtils.hpp" diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp index d51c5c740824c..bc2fd565aab8c 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp @@ -27,9 +27,9 @@ #include "gc/g1/g1ConcurrentMarkObjArrayProcessor.hpp" +#include "gc/shared/gc_globals.hpp" #include "oops/oop.inline.hpp" #include "oops/oopsHierarchy.hpp" -#include "gc/shared/gc_globals.hpp" inline bool G1CMObjArrayProcessor::should_be_sliced(oop obj) { return obj->is_objArray() && ((objArrayOop)obj)->size() >= 2 * ObjArrayMarkingStride; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp index 993df8b47ce3d..0633e18411dfb 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp @@ -23,10 +23,9 @@ */ -#include "gc/g1/g1ConcurrentRebuildAndScrub.hpp" - #include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" +#include "gc/g1/g1ConcurrentRebuildAndScrub.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" #include "gc/g1/g1HeapRegionManager.inline.hpp" #include "gc/shared/gc_globals.hpp" diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp index ce4738d784edc..dc88f09f9809b 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp @@ -38,6 +38,7 @@ #include "runtime/mutexLocker.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" + #include G1ConcurrentRefineThread* G1ConcurrentRefineThreadControl::create_refinement_thread(uint worker_id, bool initializing) { diff --git a/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp b/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp index ce2f88c9b48ec..6beb536df87c3 100644 --- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp +++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_GC_G1_G1DIRTYCARDQUEUE_HPP #define SHARE_GC_G1_G1DIRTYCARDQUEUE_HPP -#include "gc/g1/g1FreeIdSet.hpp" #include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1ConcurrentRefineStats.hpp" +#include "gc/g1/g1FreeIdSet.hpp" #include "gc/shared/bufferNode.hpp" #include "gc/shared/bufferNodeList.hpp" #include "gc/shared/ptrQueue.hpp" diff --git a/src/hotspot/share/gc/g1/g1EdenRegions.hpp b/src/hotspot/share/gc/g1/g1EdenRegions.hpp index 81d02381c9b67..a6e005ff2dc10 100644 --- a/src/hotspot/share/gc/g1/g1EdenRegions.hpp +++ b/src/hotspot/share/gc/g1/g1EdenRegions.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_GC_G1_G1EDENREGIONS_HPP #define SHARE_GC_G1_G1EDENREGIONS_HPP -#include "gc/g1/g1RegionsOnNodes.hpp" #include "gc/g1/g1HeapRegion.hpp" +#include "gc/g1/g1RegionsOnNodes.hpp" #include "runtime/globals.hpp" #include "utilities/debug.hpp" diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp index 0d4f5091d9eae..6d5084a144720 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp @@ -25,8 +25,9 @@ #ifndef SHARE_GC_G1_G1EVACFAILUREREGIONS_INLINE_HPP #define SHARE_GC_G1_G1EVACFAILUREREGIONS_INLINE_HPP -#include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1EvacFailureRegions.hpp" + +#include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "runtime/atomic.hpp" diff --git a/src/hotspot/share/gc/g1/g1EvacStats.cpp b/src/hotspot/share/gc/g1/g1EvacStats.cpp index b0e5f7b6864f2..049175a4eccd6 100644 --- a/src/hotspot/share/gc/g1/g1EvacStats.cpp +++ b/src/hotspot/share/gc/g1/g1EvacStats.cpp @@ -23,8 +23,8 @@ */ #include "gc/g1/g1EvacStats.hpp" -#include "gc/shared/gcId.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcId.hpp" #include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "runtime/globals.hpp" diff --git a/src/hotspot/share/gc/g1/g1EvacStats.hpp b/src/hotspot/share/gc/g1/g1EvacStats.hpp index 8b7360f55e3f8..4227cbab93692 100644 --- a/src/hotspot/share/gc/g1/g1EvacStats.hpp +++ b/src/hotspot/share/gc/g1/g1EvacStats.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_GC_G1_G1EVACSTATS_HPP #define SHARE_GC_G1_G1EVACSTATS_HPP -#include "gc/shared/plab.hpp" #include "gc/shared/gcUtil.hpp" +#include "gc/shared/plab.hpp" // Records various memory allocation statistics gathered during evacuation. All sizes // are in HeapWords. diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index e9d6d23149fda..a1e1d152fd8d1 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -35,9 +35,9 @@ #include "gc/g1/g1OopClosures.hpp" #include "gc/g1/g1Policy.hpp" #include "gc/g1/g1RegionMarkStatsCache.inline.hpp" +#include "gc/shared/classUnloadingContext.hpp" #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/preservedMarks.inline.hpp" -#include "gc/shared/classUnloadingContext.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/verifyOption.hpp" #include "gc/shared/weakProcessor.inline.hpp" diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp index ebe77b2551dad..5b0d5ca8eb971 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp @@ -31,11 +31,11 @@ #include "gc/shared/oopStorageSet.hpp" #include "gc/shared/tlab_globals.hpp" #include "gc/shared/workerDataArray.inline.hpp" -#include "memory/resourceArea.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" -#include "runtime/timer.hpp" +#include "memory/resourceArea.hpp" #include "runtime/os.hpp" +#include "runtime/timer.hpp" #include "utilities/enumIterator.hpp" #include "utilities/macros.hpp" diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp index 016b2046265d8..0098839c1a4c0 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp @@ -24,8 +24,8 @@ #include "gc/g1/g1Arguments.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" -#include "gc/g1/g1ConcurrentRefine.hpp" #include "gc/g1/g1CommittedRegionMap.inline.hpp" +#include "gc/g1/g1ConcurrentRefine.hpp" #include "gc/g1/g1HeapRegion.hpp" #include "gc/g1/g1HeapRegionManager.inline.hpp" #include "gc/g1/g1HeapRegionPrinter.hpp" diff --git a/src/hotspot/share/gc/g1/g1InitLogger.cpp b/src/hotspot/share/gc/g1/g1InitLogger.cpp index 1e09eed904315..1838b55e4d3ed 100644 --- a/src/hotspot/share/gc/g1/g1InitLogger.cpp +++ b/src/hotspot/share/gc/g1/g1InitLogger.cpp @@ -23,8 +23,8 @@ */ #include "gc/g1/g1InitLogger.hpp" -#include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcLogPrecious.hpp" #include "runtime/globals.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp b/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp index 03bd1840206f7..6d1ffdb7c005a 100644 --- a/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp +++ b/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp @@ -23,9 +23,9 @@ */ #include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1MemoryPool.hpp" #include "gc/g1/g1MonitoringSupport.hpp" #include "gc/g1/g1Policy.hpp" -#include "gc/g1/g1MemoryPool.hpp" #include "gc/shared/hSpaceCounters.hpp" #include "memory/metaspaceCounters.hpp" #include "runtime/mutexLocker.hpp" diff --git a/src/hotspot/share/gc/g1/g1MonitoringSupport.hpp b/src/hotspot/share/gc/g1/g1MonitoringSupport.hpp index f22581ad9b152..62c502d497cad 100644 --- a/src/hotspot/share/gc/g1/g1MonitoringSupport.hpp +++ b/src/hotspot/share/gc/g1/g1MonitoringSupport.hpp @@ -27,9 +27,9 @@ #include "gc/shared/collectorCounters.hpp" #include "gc/shared/generationCounters.hpp" +#include "runtime/mutex.hpp" #include "services/memoryManager.hpp" #include "services/memoryService.hpp" -#include "runtime/mutex.hpp" class CollectorCounters; class G1CollectedHeap; diff --git a/src/hotspot/share/gc/g1/g1MonotonicArena.inline.hpp b/src/hotspot/share/gc/g1/g1MonotonicArena.inline.hpp index f01248424a026..4ded4bcccae4d 100644 --- a/src/hotspot/share/gc/g1/g1MonotonicArena.inline.hpp +++ b/src/hotspot/share/gc/g1/g1MonotonicArena.inline.hpp @@ -27,6 +27,7 @@ #define SHARE_GC_G1_G1MONOTONICARENA_INLINE_HPP #include "gc/g1/g1MonotonicArena.hpp" + #include "runtime/atomic.hpp" #include "utilities/globalCounter.inline.hpp" diff --git a/src/hotspot/share/gc/g1/g1MonotonicArenaFreeMemoryTask.cpp b/src/hotspot/share/gc/g1/g1MonotonicArenaFreeMemoryTask.cpp index cc857a5396907..40c199dee49b7 100644 --- a/src/hotspot/share/gc/g1/g1MonotonicArenaFreeMemoryTask.cpp +++ b/src/hotspot/share/gc/g1/g1MonotonicArenaFreeMemoryTask.cpp @@ -28,8 +28,8 @@ #include "gc/g1/g1HeapRegionRemSet.hpp" #include "gc/g1/g1MonotonicArenaFreeMemoryTask.hpp" #include "gc/g1/g1MonotonicArenaFreePool.hpp" -#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/suspendibleThreadSet.hpp" #include "runtime/os.hpp" diff --git a/src/hotspot/share/gc/g1/g1NMethodClosure.cpp b/src/hotspot/share/gc/g1/g1NMethodClosure.cpp index 8dc817f145224..d74aa5eae1d01 100644 --- a/src/hotspot/share/gc/g1/g1NMethodClosure.cpp +++ b/src/hotspot/share/gc/g1/g1NMethodClosure.cpp @@ -23,11 +23,11 @@ */ #include "code/nmethod.hpp" -#include "gc/g1/g1NMethodClosure.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1HeapRegion.hpp" #include "gc/g1/g1HeapRegionRemSet.inline.hpp" +#include "gc/g1/g1NMethodClosure.hpp" #include "gc/shared/barrierSetNMethod.hpp" #include "oops/access.inline.hpp" #include "oops/compressedOops.inline.hpp" diff --git a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp index 5ab1f58bce11a..8d84f144f0245 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp @@ -38,8 +38,8 @@ #include "memory/iterator.inline.hpp" #include "oops/access.inline.hpp" #include "oops/compressedOops.inline.hpp" -#include "oops/oopsHierarchy.hpp" #include "oops/oop.inline.hpp" +#include "oops/oopsHierarchy.hpp" #include "runtime/prefetch.inline.hpp" #include "utilities/align.hpp" diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp index 94ca0878df8e5..4d569622238e5 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp @@ -26,8 +26,8 @@ #define SHARE_GC_G1_G1PARSCANTHREADSTATE_HPP #include "gc/g1/g1CollectedHeap.hpp" -#include "gc/g1/g1RedirtyCardsQueue.hpp" #include "gc/g1/g1OopClosures.hpp" +#include "gc/g1/g1RedirtyCardsQueue.hpp" #include "gc/g1/g1YoungGCAllocationFailureInjector.hpp" #include "gc/shared/ageTable.hpp" #include "gc/shared/copyFailedInfo.hpp" diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index deb67656a417c..6488bf44e41e7 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -28,20 +28,21 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1CollectionSetCandidates.inline.hpp" +#include "gc/g1/g1CollectionSetChooser.hpp" #include "gc/g1/g1ConcurrentMark.hpp" #include "gc/g1/g1ConcurrentMarkThread.inline.hpp" #include "gc/g1/g1ConcurrentRefine.hpp" #include "gc/g1/g1ConcurrentRefineStats.hpp" -#include "gc/g1/g1CollectionSetChooser.hpp" +#include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" #include "gc/g1/g1HeapRegionRemSet.inline.hpp" #include "gc/g1/g1IHOPControl.hpp" -#include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1Policy.hpp" #include "gc/g1/g1SurvivorRegions.hpp" #include "gc/g1/g1YoungGenSizer.hpp" #include "gc/shared/concurrentGCBreakpoints.hpp" #include "gc/shared/gcPolicyCounters.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "logging/log.hpp" #include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" @@ -49,8 +50,6 @@ #include "utilities/growableArray.hpp" #include "utilities/pair.hpp" -#include "gc/shared/gcTraceTime.inline.hpp" - G1Policy::G1Policy(STWGCTimer* gc_timer) : _predictor((100 - G1ConfidencePercent) / 100.0), _analytics(new G1Analytics(&_predictor)), diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index fb24b5ab72bbc..37d66ee6535bf 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -31,8 +31,8 @@ #include "gc/g1/g1HeapRegionAttr.hpp" #include "gc/g1/g1MMUTracker.hpp" #include "gc/g1/g1OldGenAllocationTracker.hpp" -#include "gc/g1/g1RemSetTrackingPolicy.hpp" #include "gc/g1/g1Predictions.hpp" +#include "gc/g1/g1RemSetTrackingPolicy.hpp" #include "gc/g1/g1YoungGenSizer.hpp" #include "gc/shared/gcCause.hpp" #include "runtime/atomic.hpp" diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index a25fce2d006c9..c4f84b02d0182 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -40,12 +40,12 @@ #include "gc/g1/g1HeapRegionRemSet.inline.hpp" #include "gc/g1/g1OopClosures.inline.hpp" #include "gc/g1/g1Policy.hpp" -#include "gc/g1/g1RootClosures.hpp" #include "gc/g1/g1RemSet.hpp" +#include "gc/g1/g1RootClosures.hpp" #include "gc/shared/bufferNode.hpp" #include "gc/shared/bufferNodeList.hpp" -#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "jfr/jfrEvents.hpp" #include "memory/iterator.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/gc/g1/g1ServiceThread.cpp b/src/hotspot/share/gc/g1/g1ServiceThread.cpp index 5f664cfba3a21..22675ec2a64e1 100644 --- a/src/hotspot/share/gc/g1/g1ServiceThread.cpp +++ b/src/hotspot/share/gc/g1/g1ServiceThread.cpp @@ -26,8 +26,8 @@ #include "logging/log.hpp" #include "runtime/cpuTimeCounters.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/timer.hpp" #include "runtime/os.hpp" +#include "runtime/timer.hpp" G1SentinelTask::G1SentinelTask() : G1ServiceTask("Sentinel Task") { set_time(max_jlong); diff --git a/src/hotspot/share/gc/g1/g1SurvivorRegions.cpp b/src/hotspot/share/gc/g1/g1SurvivorRegions.cpp index dd3323f4079e2..edd4f35d5ed55 100644 --- a/src/hotspot/share/gc/g1/g1SurvivorRegions.cpp +++ b/src/hotspot/share/gc/g1/g1SurvivorRegions.cpp @@ -24,8 +24,8 @@ #include "gc/g1/g1HeapRegion.hpp" #include "gc/g1/g1SurvivorRegions.hpp" -#include "utilities/growableArray.hpp" #include "utilities/debug.hpp" +#include "utilities/growableArray.hpp" G1SurvivorRegions::G1SurvivorRegions() : _regions(new (mtGC) GrowableArray(8, mtGC)), diff --git a/src/hotspot/share/gc/g1/g1Trace.cpp b/src/hotspot/share/gc/g1/g1Trace.cpp index 3cc8a8a28e176..6c9a87e4d98c9 100644 --- a/src/hotspot/share/gc/g1/g1Trace.cpp +++ b/src/hotspot/share/gc/g1/g1Trace.cpp @@ -23,9 +23,9 @@ */ #include "gc/g1/g1EvacInfo.hpp" +#include "gc/g1/g1GCPauseType.hpp" #include "gc/g1/g1HeapRegionTraceType.hpp" #include "gc/g1/g1Trace.hpp" -#include "gc/g1/g1GCPauseType.hpp" #include "gc/shared/gcHeapSummary.hpp" #include "jfr/jfrEvents.hpp" #if INCLUDE_JFR diff --git a/src/hotspot/share/gc/g1/g1VMOperations.cpp b/src/hotspot/share/gc/g1/g1VMOperations.cpp index 9552bd6d41812..260817f7a578f 100644 --- a/src/hotspot/share/gc/g1/g1VMOperations.cpp +++ b/src/hotspot/share/gc/g1/g1VMOperations.cpp @@ -25,8 +25,8 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentMarkThread.inline.hpp" #include "gc/g1/g1Policy.hpp" -#include "gc/g1/g1VMOperations.hpp" #include "gc/g1/g1Trace.hpp" +#include "gc/g1/g1VMOperations.hpp" #include "gc/shared/concurrentGCBreakpoints.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcId.hpp" diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index 44803564de1bc..69586b4ebf25f 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -32,9 +32,9 @@ #include "gc/g1/g1CollectionSetCandidates.inline.hpp" #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1ConcurrentMark.hpp" -#include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1EvacFailureRegions.inline.hpp" #include "gc/g1/g1EvacInfo.hpp" +#include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1HeapRegionPrinter.hpp" #include "gc/g1/g1MonitoringSupport.hpp" #include "gc/g1/g1ParScanThreadState.inline.hpp" @@ -49,9 +49,9 @@ #include "gc/g1/g1YoungGCPostEvacuateTasks.hpp" #include "gc/g1/g1YoungGCPreEvacuateTasks.hpp" #include "gc/shared/concurrentGCBreakpoints.hpp" -#include "gc/shared/gcTraceTime.inline.hpp" -#include "gc/shared/gcTimer.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcTimer.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/weakProcessor.inline.hpp" #include "gc/shared/workerPolicy.hpp" diff --git a/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp index 63e7797981210..839b70d93afcd 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp @@ -25,9 +25,9 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentRefineStats.hpp" #include "gc/g1/g1DirtyCardQueue.hpp" -#include "gc/g1/g1YoungGCPreEvacuateTasks.hpp" #include "gc/g1/g1RegionPinCache.inline.hpp" #include "gc/g1/g1ThreadLocalData.hpp" +#include "gc/g1/g1YoungGCPreEvacuateTasks.hpp" #include "gc/shared/barrierSet.inline.hpp" #include "gc/shared/threadLocalAllocBuffer.inline.hpp" #include "memory/allocation.inline.hpp" diff --git a/src/hotspot/share/gc/parallel/parallelInitLogger.cpp b/src/hotspot/share/gc/parallel/parallelInitLogger.cpp index b28f0385c516f..1d9c9f840ba17 100644 --- a/src/hotspot/share/gc/parallel/parallelInitLogger.cpp +++ b/src/hotspot/share/gc/parallel/parallelInitLogger.cpp @@ -23,8 +23,8 @@ */ #include "gc/parallel/parallelInitLogger.hpp" -#include "gc/shared/genArguments.hpp" #include "gc/shared/gcLogPrecious.hpp" +#include "gc/shared/genArguments.hpp" void ParallelInitLogger::print_heap() { log_info_p(gc, init)("Alignments:" diff --git a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp index 3bb0c0bf1192a..b4f860e053f8e 100644 --- a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp +++ b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp @@ -27,8 +27,8 @@ #include "gc/parallel/psGCAdaptivePolicyCounters.hpp" #include "gc/parallel/psScavenge.hpp" #include "gc/shared/gcCause.hpp" -#include "gc/shared/gcUtil.hpp" #include "gc/shared/gcPolicyCounters.hpp" +#include "gc/shared/gcUtil.hpp" #include "logging/log.hpp" #include "runtime/timer.hpp" #include "utilities/align.hpp" diff --git a/src/hotspot/share/gc/parallel/psCardTable.cpp b/src/hotspot/share/gc/parallel/psCardTable.cpp index f8841b9a164f5..22a38d816f639 100644 --- a/src/hotspot/share/gc/parallel/psCardTable.cpp +++ b/src/hotspot/share/gc/parallel/psCardTable.cpp @@ -32,8 +32,8 @@ #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/prefetch.inline.hpp" -#include "utilities/spinYield.hpp" #include "utilities/align.hpp" +#include "utilities/spinYield.hpp" // Checks an individual oop for missing precise marks. Mark // may be either dirty or newgen. diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.cpp b/src/hotspot/share/gc/parallel/psCompactionManager.cpp index f00e18c3297b9..ba9362778212f 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.cpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.cpp @@ -23,8 +23,8 @@ */ #include "gc/parallel/objectStartArray.hpp" -#include "gc/parallel/parMarkBitMap.inline.hpp" #include "gc/parallel/parallelScavengeHeap.hpp" +#include "gc/parallel/parMarkBitMap.inline.hpp" #include "gc/parallel/psCompactionManager.inline.hpp" #include "gc/parallel/psOldGen.hpp" #include "gc/parallel/psParallelCompact.inline.hpp" diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.hpp index 739d2cb1cc7e2..b013238a9f8cd 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.hpp @@ -28,8 +28,8 @@ #include "classfile/classLoaderData.hpp" #include "gc/parallel/psParallelCompact.hpp" #include "gc/shared/partialArraySplitter.hpp" -#include "gc/shared/partialArrayTaskStats.hpp" #include "gc/shared/partialArrayState.hpp" +#include "gc/shared/partialArrayTaskStats.hpp" #include "gc/shared/preservedMarks.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/taskqueue.hpp" diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index be31da5b05d3c..661bc3da3e111 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -44,8 +44,8 @@ #include "gc/shared/gcVMOperations.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "gc/shared/oopStorage.inline.hpp" -#include "gc/shared/oopStorageSetParState.inline.hpp" #include "gc/shared/oopStorageParState.inline.hpp" +#include "gc/shared/oopStorageSetParState.inline.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/referenceProcessorPhaseTimes.hpp" @@ -57,18 +57,18 @@ #include "gc/shared/workerPolicy.hpp" #include "gc/shared/workerThread.hpp" #include "gc/shared/workerUtils.hpp" +#include "logging/log.hpp" #include "memory/iterator.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" -#include "logging/log.hpp" #include "oops/access.inline.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/threadCritical.hpp" #include "runtime/threads.hpp" -#include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" +#include "runtime/vmThread.hpp" #include "services/memoryService.hpp" #include "utilities/stack.inline.hpp" diff --git a/src/hotspot/share/gc/parallel/psScavenge.hpp b/src/hotspot/share/gc/parallel/psScavenge.hpp index 55abdfd3cf38e..8da555a8bb408 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.hpp +++ b/src/hotspot/share/gc/parallel/psScavenge.hpp @@ -28,8 +28,8 @@ #include "gc/parallel/psCardTable.hpp" #include "gc/parallel/psVirtualspace.hpp" #include "gc/shared/collectorCounters.hpp" -#include "gc/shared/referenceProcessor.hpp" #include "gc/shared/gcTrace.hpp" +#include "gc/shared/referenceProcessor.hpp" #include "memory/allStatic.hpp" #include "oops/oop.hpp" #include "utilities/stack.hpp" diff --git a/src/hotspot/share/gc/parallel/psVMOperations.cpp b/src/hotspot/share/gc/parallel/psVMOperations.cpp index 4873853a3ddfd..dc96d9506e278 100644 --- a/src/hotspot/share/gc/parallel/psVMOperations.cpp +++ b/src/hotspot/share/gc/parallel/psVMOperations.cpp @@ -22,8 +22,8 @@ * */ -#include "gc/parallel/psParallelCompact.inline.hpp" #include "gc/parallel/parallelScavengeHeap.inline.hpp" +#include "gc/parallel/psParallelCompact.inline.hpp" #include "gc/parallel/psScavenge.hpp" #include "gc/parallel/psVMOperations.hpp" #include "gc/shared/gcLocker.hpp" diff --git a/src/hotspot/share/gc/serial/serialArguments.cpp b/src/hotspot/share/gc/serial/serialArguments.cpp index 9b55e0cd9f69b..aed1c2353b4d8 100644 --- a/src/hotspot/share/gc/serial/serialArguments.cpp +++ b/src/hotspot/share/gc/serial/serialArguments.cpp @@ -22,10 +22,10 @@ * */ -#include "gc/shared/fullGCForwarding.hpp" -#include "gc/shared/gcArguments.hpp" #include "gc/serial/serialArguments.hpp" #include "gc/serial/serialHeap.hpp" +#include "gc/shared/fullGCForwarding.hpp" +#include "gc/shared/gcArguments.hpp" void SerialArguments::initialize() { GCArguments::initialize(); diff --git a/src/hotspot/share/gc/serial/serialFullGC.cpp b/src/hotspot/share/gc/serial/serialFullGC.cpp index 9d0dc1932fcbc..1546870454754 100644 --- a/src/hotspot/share/gc/serial/serialFullGC.cpp +++ b/src/hotspot/share/gc/serial/serialFullGC.cpp @@ -22,8 +22,8 @@ * */ -#include "classfile/classLoaderDataGraph.hpp" #include "classfile/classLoaderData.inline.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" @@ -43,11 +43,11 @@ #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" #include "gc/shared/fullGCForwarding.inline.hpp" +#include "gc/shared/gc_globals.hpp" #include "gc/shared/gcHeapSummary.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/gcTraceTime.inline.hpp" -#include "gc/shared/gc_globals.hpp" #include "gc/shared/modRefBarrierSet.hpp" #include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/referencePolicy.hpp" diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp index c6a6a0ae71634..d88b256629953 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_SERIAL_TENUREDGENERATION_INLINE_HPP #include "gc/serial/tenuredGeneration.hpp" + #include "gc/shared/space.hpp" inline size_t TenuredGeneration::capacity() const { diff --git a/src/hotspot/share/gc/shared/ageTable.cpp b/src/hotspot/share/gc/shared/ageTable.cpp index f5b62466556ed..2ed6ea967db4c 100644 --- a/src/hotspot/share/gc/shared/ageTable.cpp +++ b/src/hotspot/share/gc/shared/ageTable.cpp @@ -28,11 +28,11 @@ #include "gc/shared/gc_globals.hpp" #include "jvm.h" #include "logging/log.hpp" +#include "logging/logStream.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/perfData.hpp" #include "utilities/copy.hpp" -#include "logging/logStream.hpp" /* Copyright (c) 1992, 2025, Oracle and/or its affiliates, and Stanford University. See the LICENSE file for license information. */ diff --git a/src/hotspot/share/gc/shared/barrierSetConfig.inline.hpp b/src/hotspot/share/gc/shared/barrierSetConfig.inline.hpp index 38c568889d1bf..f637c227ee1d9 100644 --- a/src/hotspot/share/gc/shared/barrierSetConfig.inline.hpp +++ b/src/hotspot/share/gc/shared/barrierSetConfig.inline.hpp @@ -27,8 +27,8 @@ #include "gc/shared/barrierSetConfig.hpp" -#include "gc/shared/modRefBarrierSet.inline.hpp" #include "gc/shared/cardTableBarrierSet.inline.hpp" +#include "gc/shared/modRefBarrierSet.inline.hpp" #if INCLUDE_EPSILONGC #include "gc/epsilon/epsilonBarrierSet.hpp" diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp index c5d8a7e54015f..41eb0a24b625a 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp @@ -35,8 +35,8 @@ #include "oops/method.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/javaThread.hpp" -#include "runtime/threadWXSetters.inline.hpp" #include "runtime/threads.hpp" +#include "runtime/threadWXSetters.inline.hpp" #include "utilities/debug.hpp" #if INCLUDE_JVMCI #include "jvmci/jvmciRuntime.hpp" diff --git a/src/hotspot/share/gc/shared/bufferNode.cpp b/src/hotspot/share/gc/shared/bufferNode.cpp index e27b1279c7904..b064f9c7efedb 100644 --- a/src/hotspot/share/gc/shared/bufferNode.cpp +++ b/src/hotspot/share/gc/shared/bufferNode.cpp @@ -23,8 +23,8 @@ */ #include "gc/shared/bufferNode.hpp" -#include "utilities/debug.hpp" #include "memory/allocation.inline.hpp" +#include "utilities/debug.hpp" #include diff --git a/src/hotspot/share/gc/shared/c1/barrierSetC1.hpp b/src/hotspot/share/gc/shared/c1/barrierSetC1.hpp index 3d0621cdc7a67..e618a81b26be9 100644 --- a/src/hotspot/share/gc/shared/c1/barrierSetC1.hpp +++ b/src/hotspot/share/gc/shared/c1/barrierSetC1.hpp @@ -26,9 +26,9 @@ #define SHARE_GC_SHARED_C1_BARRIERSETC1_HPP #include "c1/c1_Decorators.hpp" -#include "c1/c1_LIRGenerator.hpp" #include "c1/c1_Instruction.hpp" #include "c1/c1_LIR.hpp" +#include "c1/c1_LIRGenerator.hpp" #include "memory/allocation.hpp" class LIRGenerator; diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp index 92154e7a46e96..f0ed9687f112d 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp @@ -24,8 +24,8 @@ #include "code/vmreg.inline.hpp" #include "gc/shared/barrierSet.hpp" -#include "gc/shared/tlab_globals.hpp" #include "gc/shared/c2/barrierSetC2.hpp" +#include "gc/shared/tlab_globals.hpp" #include "opto/arraycopynode.hpp" #include "opto/block.hpp" #include "opto/convertnode.hpp" diff --git a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp index 7df210d9fb622..536cd6da1ef8c 100644 --- a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp @@ -23,9 +23,9 @@ */ #include "ci/ciUtilities.hpp" +#include "gc/shared/c2/cardTableBarrierSetC2.hpp" #include "gc/shared/cardTable.hpp" #include "gc/shared/cardTableBarrierSet.hpp" -#include "gc/shared/c2/cardTableBarrierSetC2.hpp" #include "gc/shared/gc_globals.hpp" #include "opto/arraycopynode.hpp" #include "opto/graphKit.hpp" diff --git a/src/hotspot/share/gc/shared/c2/modRefBarrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/modRefBarrierSetC2.cpp index cf5d3fc7e1668..ddc9caedd7165 100644 --- a/src/hotspot/share/gc/shared/c2/modRefBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/modRefBarrierSetC2.cpp @@ -22,10 +22,10 @@ * */ +#include "gc/shared/c2/modRefBarrierSetC2.hpp" #include "opto/arraycopynode.hpp" #include "opto/graphKit.hpp" #include "opto/idealKit.hpp" -#include "gc/shared/c2/modRefBarrierSetC2.hpp" Node* ModRefBarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) const { DecoratorSet decorators = access.decorators(); diff --git a/src/hotspot/share/gc/shared/cardTable.cpp b/src/hotspot/share/gc/shared/cardTable.cpp index 3236d73933c49..e5dbbcc074683 100644 --- a/src/hotspot/share/gc/shared/cardTable.cpp +++ b/src/hotspot/share/gc/shared/cardTable.cpp @@ -24,8 +24,8 @@ #include "gc/shared/cardTable.hpp" #include "gc/shared/collectedHeap.hpp" -#include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/space.hpp" #include "logging/log.hpp" #include "memory/memoryReserver.hpp" diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index 9c55a894ee702..ec9872bf40231 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -29,15 +29,15 @@ #include "gc/shared/barrierSet.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectedHeap.inline.hpp" -#include "gc/shared/gcLocker.hpp" +#include "gc/shared/gc_globals.hpp" #include "gc/shared/gcHeapSummary.hpp" -#include "gc/shared/stringdedup/stringDedup.hpp" +#include "gc/shared/gcLocker.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/gcVMOperations.hpp" #include "gc/shared/gcWhen.hpp" -#include "gc/shared/gc_globals.hpp" #include "gc/shared/memAllocator.hpp" +#include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/tlab_globals.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" diff --git a/src/hotspot/share/gc/shared/gcHeapSummary.hpp b/src/hotspot/share/gc/shared/gcHeapSummary.hpp index fb048d06a41b0..ae08f60d3a647 100644 --- a/src/hotspot/share/gc/shared/gcHeapSummary.hpp +++ b/src/hotspot/share/gc/shared/gcHeapSummary.hpp @@ -26,8 +26,8 @@ #define SHARE_GC_SHARED_GCHEAPSUMMARY_HPP #include "memory/allocation.hpp" -#include "memory/metaspaceStats.hpp" #include "memory/metaspaceChunkFreeListSummary.hpp" +#include "memory/metaspaceStats.hpp" class VirtualSpaceSummary : public StackObj { HeapWord* _start; diff --git a/src/hotspot/share/gc/shared/gcInitLogger.cpp b/src/hotspot/share/gc/shared/gcInitLogger.cpp index f2d9fffdc110a..91bebf726c12d 100644 --- a/src/hotspot/share/gc/shared/gcInitLogger.cpp +++ b/src/hotspot/share/gc/shared/gcInitLogger.cpp @@ -22,9 +22,9 @@ * */ +#include "gc/shared/gc_globals.hpp" #include "gc/shared/gcInitLogger.hpp" #include "gc/shared/gcLogPrecious.hpp" -#include "gc/shared/gc_globals.hpp" #include "logging/log.hpp" #include "oops/compressedOops.hpp" #include "runtime/globals.hpp" diff --git a/src/hotspot/share/gc/shared/gcLocker.cpp b/src/hotspot/share/gc/shared/gcLocker.cpp index caf752f70c8d9..fbc953512bb28 100644 --- a/src/hotspot/share/gc/shared/gcLocker.cpp +++ b/src/hotspot/share/gc/shared/gcLocker.cpp @@ -25,15 +25,15 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/gcLocker.hpp" #include "gc/shared/gcTrace.hpp" +#include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" -#include "logging/log.hpp" #include "runtime/atomic.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaThread.inline.hpp" #include "runtime/safepoint.hpp" -#include "utilities/spinYield.hpp" #include "runtime/threadSMR.hpp" +#include "utilities/spinYield.hpp" #include "utilities/ticks.hpp" // GCLockerTimingDebugLogger tracks specific timing information for GC lock waits. diff --git a/src/hotspot/share/gc/shared/gcLogPrecious.hpp b/src/hotspot/share/gc/shared/gcLogPrecious.hpp index ec8b1c670f321..8aa70252b3d84 100644 --- a/src/hotspot/share/gc/shared/gcLogPrecious.hpp +++ b/src/hotspot/share/gc/shared/gcLogPrecious.hpp @@ -24,10 +24,10 @@ #ifndef SHARE_GC_SHARED_GCLOGPRECIOUS_HPP #define SHARE_GC_SHARED_GCLOGPRECIOUS_HPP -#include "utilities/globalDefinitions.hpp" #include "logging/logHandle.hpp" #include "memory/allStatic.hpp" #include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" class Mutex; class stringStream; diff --git a/src/hotspot/share/gc/shared/gcOverheadChecker.hpp b/src/hotspot/share/gc/shared/gcOverheadChecker.hpp index d4a9b5cd70d72..e29ae2ab911c6 100644 --- a/src/hotspot/share/gc/shared/gcOverheadChecker.hpp +++ b/src/hotspot/share/gc/shared/gcOverheadChecker.hpp @@ -26,9 +26,9 @@ #ifndef SHARE_GC_SHARED_GCOVERHEADCHECKER_HPP #define SHARE_GC_SHARED_GCOVERHEADCHECKER_HPP -#include "memory/allocation.hpp" -#include "gc/shared/gcCause.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcCause.hpp" +#include "memory/allocation.hpp" #include "runtime/globals.hpp" class SoftRefPolicy; diff --git a/src/hotspot/share/gc/shared/gcPolicyCounters.cpp b/src/hotspot/share/gc/shared/gcPolicyCounters.cpp index d24ad745aa14d..343ad6ca41ed5 100644 --- a/src/hotspot/share/gc/shared/gcPolicyCounters.cpp +++ b/src/hotspot/share/gc/shared/gcPolicyCounters.cpp @@ -22,8 +22,8 @@ * */ -#include "gc/shared/gcPolicyCounters.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcPolicyCounters.hpp" #include "memory/resourceArea.hpp" GCPolicyCounters::GCPolicyCounters(const char* name, int collectors, diff --git a/src/hotspot/share/gc/shared/gcTimer.cpp b/src/hotspot/share/gc/shared/gcTimer.cpp index 8585975015184..a5bc7bfb02fe5 100644 --- a/src/hotspot/share/gc/shared/gcTimer.cpp +++ b/src/hotspot/share/gc/shared/gcTimer.cpp @@ -22,8 +22,8 @@ * */ -#include "gc/shared/gcTimer.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcTimer.hpp" #include "utilities/growableArray.hpp" // the "time" parameter for most functions diff --git a/src/hotspot/share/gc/shared/gcTraceTime.cpp b/src/hotspot/share/gc/shared/gcTraceTime.cpp index def8a3f3f5c0c..5839027b585a0 100644 --- a/src/hotspot/share/gc/shared/gcTraceTime.cpp +++ b/src/hotspot/share/gc/shared/gcTraceTime.cpp @@ -23,8 +23,8 @@ */ #include "gc/shared/collectedHeap.hpp" -#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/gcTrace.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" #include "memory/universe.hpp" diff --git a/src/hotspot/share/gc/shared/gcVMOperations.cpp b/src/hotspot/share/gc/shared/gcVMOperations.cpp index 8e5768ce6a98c..1632dca61d516 100644 --- a/src/hotspot/share/gc/shared/gcVMOperations.cpp +++ b/src/hotspot/share/gc/shared/gcVMOperations.cpp @@ -25,10 +25,10 @@ #include "classfile/classLoaderData.hpp" #include "classfile/javaClasses.hpp" #include "gc/shared/allocTracer.hpp" +#include "gc/shared/gc_globals.hpp" #include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.hpp" #include "gc/shared/gcVMOperations.hpp" -#include "gc/shared/gc_globals.hpp" #include "gc/shared/softRefPolicy.hpp" #include "interpreter/oopMapCache.hpp" #include "logging/log.hpp" diff --git a/src/hotspot/share/gc/shared/locationPrinter.cpp b/src/hotspot/share/gc/shared/locationPrinter.cpp index b5efb540d459a..85fdcd37524fc 100644 --- a/src/hotspot/share/gc/shared/locationPrinter.cpp +++ b/src/hotspot/share/gc/shared/locationPrinter.cpp @@ -25,9 +25,9 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/locationPrinter.hpp" #include "memory/universe.hpp" -#include "runtime/os.hpp" #include "oops/klass.hpp" #include "oops/oop.inline.hpp" +#include "runtime/os.hpp" bool LocationPrinter::is_valid_obj(void* obj) { if (!is_object_aligned(obj)) { diff --git a/src/hotspot/share/gc/shared/memAllocator.cpp b/src/hotspot/share/gc/shared/memAllocator.cpp index 64ca463571890..74ef1f66184fc 100644 --- a/src/hotspot/share/gc/shared/memAllocator.cpp +++ b/src/hotspot/share/gc/shared/memAllocator.cpp @@ -35,8 +35,8 @@ #include "prims/jvmtiExport.hpp" #include "runtime/continuationJavaClasses.inline.hpp" #include "runtime/handles.inline.hpp" -#include "runtime/sharedRuntime.hpp" #include "runtime/javaThread.hpp" +#include "runtime/sharedRuntime.hpp" #include "services/lowMemoryDetector.hpp" #include "utilities/align.hpp" #include "utilities/copy.hpp" diff --git a/src/hotspot/share/gc/shared/parallelCleaning.cpp b/src/hotspot/share/gc/shared/parallelCleaning.cpp index 1b1eaf4d79ae2..8cb09939f2260 100644 --- a/src/hotspot/share/gc/shared/parallelCleaning.cpp +++ b/src/hotspot/share/gc/shared/parallelCleaning.cpp @@ -22,13 +22,12 @@ * */ -#include "classfile/symbolTable.hpp" #include "classfile/stringTable.hpp" +#include "classfile/symbolTable.hpp" #include "code/codeCache.hpp" #include "gc/shared/parallelCleaning.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" -#include "logging/log.hpp" #include "runtime/atomic.hpp" CodeCacheUnloadingTask::CodeCacheUnloadingTask(uint num_workers, bool unloading_occurred) : diff --git a/src/hotspot/share/gc/shared/partialArrayState.cpp b/src/hotspot/share/gc/shared/partialArrayState.cpp index f79e012a36d4f..8db39281a05ec 100644 --- a/src/hotspot/share/gc/shared/partialArrayState.cpp +++ b/src/hotspot/share/gc/shared/partialArrayState.cpp @@ -32,6 +32,7 @@ #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" + #include PartialArrayState::PartialArrayState(oop src, oop dst, diff --git a/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp b/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp index 1d43578b5fea5..9d127697e5875 100644 --- a/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp +++ b/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp @@ -25,8 +25,9 @@ #ifndef SHARE_GC_SHARED_PARTIALARRAYTASKSTEPPER_INLINE_HPP #define SHARE_GC_SHARED_PARTIALARRAYTASKSTEPPER_INLINE_HPP -#include "gc/shared/partialArrayState.hpp" #include "gc/shared/partialArrayTaskStepper.hpp" + +#include "gc/shared/partialArrayState.hpp" #include "runtime/atomic.hpp" #include "utilities/checkedCast.hpp" #include "utilities/debug.hpp" diff --git a/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp b/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp index 83eaccd9813de..fd2bd8f3edc67 100644 --- a/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp +++ b/src/hotspot/share/gc/shared/referenceProcessorPhaseTimes.cpp @@ -23,8 +23,8 @@ */ #include "gc/shared/gcTimer.hpp" -#include "gc/shared/referenceProcessorPhaseTimes.hpp" #include "gc/shared/referenceProcessor.inline.hpp" +#include "gc/shared/referenceProcessorPhaseTimes.hpp" #include "gc/shared/workerDataArray.inline.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" diff --git a/src/hotspot/share/gc/shared/satbMarkQueue.cpp b/src/hotspot/share/gc/shared/satbMarkQueue.cpp index 6e33d27897ccc..915eaa116fba4 100644 --- a/src/hotspot/share/gc/shared/satbMarkQueue.cpp +++ b/src/hotspot/share/gc/shared/satbMarkQueue.cpp @@ -22,8 +22,8 @@ * */ -#include "gc/shared/satbMarkQueue.hpp" #include "gc/shared/collectedHeap.hpp" +#include "gc/shared/satbMarkQueue.hpp" #include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "oops/oop.inline.hpp" diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp b/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp index 9ad8decec7e08..b3f96da1cce47 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp @@ -25,9 +25,9 @@ #include "classfile/javaClasses.inline.hpp" #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" +#include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/oopStorage.hpp" #include "gc/shared/oopStorageSet.hpp" -#include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/stringdedup/stringDedupConfig.hpp" #include "gc/shared/stringdedup/stringDedupProcessor.hpp" diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp b/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp index 5c6628cba5cdd..83c6fea8c5b8e 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp @@ -33,10 +33,10 @@ #include "gc/shared/stringdedup/stringDedupConfig.hpp" #include "gc/shared/stringdedup/stringDedupStat.hpp" #include "gc/shared/stringdedup/stringDedupTable.hpp" -#include "memory/allocation.hpp" -#include "memory/resourceArea.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" +#include "memory/allocation.hpp" +#include "memory/resourceArea.hpp" #include "oops/access.hpp" #include "oops/oopsHierarchy.hpp" #include "oops/typeArrayOop.inline.hpp" diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.hpp b/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.hpp index 19df8184a05e8..a163319e84c09 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.hpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_GC_SHARED_STRINGDEDUP_STRINGDEDUPTABLE_HPP #define SHARE_GC_SHARED_STRINGDEDUP_STRINGDEDUPTABLE_HPP -#include "memory/allStatic.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/stringdedup/stringDedupStat.hpp" +#include "memory/allStatic.hpp" #include "oops/typeArrayOop.hpp" #include "oops/weakHandle.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/gc/shared/taskTerminator.cpp b/src/hotspot/share/gc/shared/taskTerminator.cpp index 1353c3f8c8a06..cc84665087b43 100644 --- a/src/hotspot/share/gc/shared/taskTerminator.cpp +++ b/src/hotspot/share/gc/shared/taskTerminator.cpp @@ -24,8 +24,8 @@ */ #include "gc/shared/gc_globals.hpp" -#include "gc/shared/taskTerminator.hpp" #include "gc/shared/taskqueue.hpp" +#include "gc/shared/taskTerminator.hpp" #include "logging/log.hpp" #include "runtime/globals.hpp" #include "runtime/javaThread.hpp" diff --git a/src/hotspot/share/gc/shared/taskqueue.cpp b/src/hotspot/share/gc/shared/taskqueue.cpp index a244ba454150b..162eadc3cf0d2 100644 --- a/src/hotspot/share/gc/shared/taskqueue.cpp +++ b/src/hotspot/share/gc/shared/taskqueue.cpp @@ -23,8 +23,8 @@ */ #include "gc/shared/taskqueue.hpp" -#include "oops/oop.inline.hpp" #include "logging/log.hpp" +#include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/javaThread.hpp" #include "runtime/os.hpp" diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp index 32a830a2bb138..22d19b77806c1 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp @@ -29,8 +29,8 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/tlab_globals.hpp" -#include "memory/universe.hpp" #include "logging/log.hpp" +#include "memory/universe.hpp" #include "runtime/javaThread.hpp" #include "runtime/osThread.hpp" #include "utilities/copy.hpp" diff --git a/src/hotspot/share/gc/shared/weakProcessor.cpp b/src/hotspot/share/gc/shared/weakProcessor.cpp index d7de8b5d8a88a..bc7e9ad637554 100644 --- a/src/hotspot/share/gc/shared/weakProcessor.cpp +++ b/src/hotspot/share/gc/shared/weakProcessor.cpp @@ -27,8 +27,8 @@ #include "gc/shared/oopStorage.inline.hpp" #include "gc/shared/oopStorageParState.inline.hpp" #include "gc/shared/oopStorageSet.hpp" -#include "gc/shared/weakProcessor.inline.hpp" #include "gc/shared/oopStorageSetParState.inline.hpp" +#include "gc/shared/weakProcessor.inline.hpp" #include "gc/shared/weakProcessorTimes.hpp" #include "memory/allocation.inline.hpp" #include "memory/iterator.hpp" diff --git a/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp b/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp index 9a12e0ed1a112..9f58016a6f14c 100644 --- a/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp +++ b/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp @@ -26,6 +26,7 @@ #include "c1/c1_IR.hpp" #include "gc/shared/satbMarkQueue.hpp" +#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" @@ -33,7 +34,6 @@ #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahRuntime.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #ifdef ASSERT #define __ gen->lir(__FILE__, __LINE__)-> diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index 8df4413cc2f49..d71e84d33b020 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -25,15 +25,15 @@ #include "classfile/javaClasses.hpp" #include "gc/shared/barrierSet.hpp" +#include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp" +#include "gc/shenandoah/c2/shenandoahSupport.hpp" +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahCardTable.hpp" #include "gc/shenandoah/shenandoahForwarding.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahRuntime.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -#include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp" -#include "gc/shenandoah/c2/shenandoahSupport.hpp" -#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "opto/arraycopynode.hpp" #include "opto/escape.hpp" #include "opto/graphKit.hpp" diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index 4652dbce0e36d..56d88d44d2797 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -25,8 +25,8 @@ #include "classfile/javaClasses.hpp" -#include "gc/shenandoah/c2/shenandoahSupport.hpp" #include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp" +#include "gc/shenandoah/c2/shenandoahSupport.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" #include "gc/shenandoah/shenandoahForwarding.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp index 5280e9b2ac47b..eb87a9dc4c179 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp @@ -26,9 +26,9 @@ #include "gc/shared/gcCause.hpp" +#include "gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp" #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp" -#include "gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp index a47024f3a4b87..68e540960c794 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp @@ -26,10 +26,10 @@ #ifndef SHARE_GC_SHENANDOAH_HEURISTICS_SHENANDOAHADAPTIVEHEURISTICS_HPP #define SHARE_GC_SHENANDOAH_HEURISTICS_SHENANDOAHADAPTIVEHEURISTICS_HPP -#include "memory/allocation.hpp" #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahSharedVariables.hpp" +#include "memory/allocation.hpp" #include "utilities/numberSeq.hpp" class ShenandoahAllocationRate : public CHeapObj { diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp index 9d211314474a7..403405b984da5 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp @@ -24,8 +24,8 @@ */ -#include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/heuristics/shenandoahCompactHeuristics.hpp" +#include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp index afc9abc496eb3..08fd45993462b 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp @@ -26,13 +26,12 @@ #include "gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" +#include "gc/shenandoah/shenandoahEvacInfo.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" -#include "gc/shenandoah/shenandoahEvacInfo.hpp" #include "gc/shenandoah/shenandoahTrace.hpp" - #include "logging/log.hpp" ShenandoahGenerationalHeuristics::ShenandoahGenerationalHeuristics(ShenandoahGeneration* generation) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp index 919f6c88afa9e..b8d85de04871d 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp @@ -25,10 +25,9 @@ #include "gc/shenandoah/heuristics/shenandoahGlobalHeuristics.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" -#include "gc/shenandoah/shenandoahGlobalGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" +#include "gc/shenandoah/shenandoahGlobalGeneration.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" - #include "utilities/quickSort.hpp" ShenandoahGlobalHeuristics::ShenandoahGlobalHeuristics(ShenandoahGlobalGeneration* generation) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp index 4c7ed07b2a053..b151a75e6e7e5 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp @@ -25,10 +25,10 @@ */ #include "gc/shared/gcCause.hpp" +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" -#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "logging/log.hpp" #include "logging/logTag.hpp" #include "runtime/globals_extension.hpp" diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp index 9f8c6225d23d8..ba09eeb879459 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp @@ -30,7 +30,6 @@ #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" - #include "utilities/quickSort.hpp" ShenandoahYoungHeuristics::ShenandoahYoungHeuristics(ShenandoahYoungGeneration* generation) diff --git a/src/hotspot/share/gc/shenandoah/mode/shenandoahGenerationalMode.cpp b/src/hotspot/share/gc/shenandoah/mode/shenandoahGenerationalMode.cpp index 6c8858341555d..fa784d5bb9051 100644 --- a/src/hotspot/share/gc/shenandoah/mode/shenandoahGenerationalMode.cpp +++ b/src/hotspot/share/gc/shenandoah/mode/shenandoahGenerationalMode.cpp @@ -22,8 +22,8 @@ * */ -#include "gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp" #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp" #include "gc/shenandoah/mode/shenandoahGenerationalMode.hpp" #include "logging/log.hpp" #include "logging/logTag.hpp" diff --git a/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp b/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp index 893321db1dc2f..296a1979b01b3 100644 --- a/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp +++ b/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp @@ -23,8 +23,8 @@ */ #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" -#include "gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp" #include "gc/shenandoah/heuristics/shenandoahPassiveHeuristics.hpp" +#include "gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp" #include "gc/shenandoah/mode/shenandoahPassiveMode.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "logging/log.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp index 446e19144074e..5d19a6a34e31e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp @@ -24,8 +24,8 @@ */ #include "gc/shared/barrierSetNMethod.hpp" -#include "gc/shenandoah/shenandoahBarrierSetClone.inline.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" +#include "gc/shenandoah/shenandoahBarrierSetClone.inline.hpp" #include "gc/shenandoah/shenandoahBarrierSetNMethod.hpp" #include "gc/shenandoah/shenandoahBarrierSetStackChunk.hpp" #include "gc/shenandoah/shenandoahCardTable.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp index 20937b9d08e49..b176446452a19 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp @@ -30,6 +30,7 @@ #include "gc/shared/accessBarrierSupport.inline.hpp" #include "gc/shared/cardTable.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahCardTable.hpp" #include "gc/shenandoah/shenandoahCollectionSet.inline.hpp" @@ -40,7 +41,6 @@ #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "memory/iterator.inline.hpp" #include "oops/oop.inline.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp index c08c9501201b6..725e4e6e3e9f9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp @@ -31,10 +31,10 @@ #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahEvacOOMHandler.inline.hpp" -#include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" -#include "gc/shenandoah/shenandoahNMethod.inline.hpp" #include "gc/shenandoah/shenandoahMark.inline.hpp" +#include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" +#include "gc/shenandoah/shenandoahNMethod.inline.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahTaskqueue.inline.hpp" #include "memory/iterator.inline.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp index 34db132ab83f9..d29c446f2102e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp @@ -26,9 +26,9 @@ #define SHARE_GC_SHENANDOAH_SHENANDOAHCODEROOTS_HPP #include "code/codeCache.hpp" -#include "gc/shenandoah/shenandoahSharedVariables.hpp" #include "gc/shenandoah/shenandoahLock.hpp" #include "gc/shenandoah/shenandoahPadding.hpp" +#include "gc/shenandoah/shenandoahSharedVariables.hpp" #include "memory/allStatic.hpp" #include "memory/iterator.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 7b9aafad149a0..5b5fe2c1af605 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -35,11 +35,10 @@ #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" -#include "gc/shenandoah/shenandoahOldGeneration.hpp" -#include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "gc/shenandoah/shenandoahLock.hpp" #include "gc/shenandoah/shenandoahMark.inline.hpp" #include "gc/shenandoah/shenandoahMonitoringSupport.hpp" +#include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" @@ -47,8 +46,9 @@ #include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/shenandoahVerifier.hpp" #include "gc/shenandoah/shenandoahVMOperations.hpp" -#include "gc/shenandoah/shenandoahWorkGroup.hpp" #include "gc/shenandoah/shenandoahWorkerPolicy.hpp" +#include "gc/shenandoah/shenandoahWorkGroup.hpp" +#include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "memory/allocation.hpp" #include "prims/jvmtiTagMap.hpp" #include "runtime/vmThread.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 4a0f43226d7dd..facba2236be81 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -33,13 +33,13 @@ #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahMark.inline.hpp" +#include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" -#include "gc/shenandoah/shenandoahPhaseTimings.hpp" +#include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" #include "gc/shenandoah/shenandoahStringDedup.hpp" #include "gc/shenandoah/shenandoahTaskqueue.inline.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" -#include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" #include "memory/iterator.inline.hpp" #include "memory/resourceArea.hpp" #include "runtime/continuation.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 0b20b4ddf9f61..6975bd9f3501d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -23,6 +23,8 @@ * */ +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahConcurrentGC.hpp" #include "gc/shenandoah/shenandoahControlThread.hpp" @@ -34,11 +36,9 @@ #include "gc/shenandoah/shenandoahMonitoringSupport.hpp" #include "gc/shenandoah/shenandoahPacer.inline.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" -#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "logging/log.hpp" -#include "memory/metaspaceUtils.hpp" #include "memory/metaspaceStats.hpp" +#include "memory/metaspaceUtils.hpp" ShenandoahControlThread::ShenandoahControlThread() : ShenandoahController(), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp index be99ef1d865fb..9d95b5df7ed30 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp @@ -25,10 +25,10 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHCONTROLTHREAD_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHCONTROLTHREAD_HPP -#include "gc/shared/gcCause.hpp" #include "gc/shared/concurrentGCThread.hpp" -#include "gc/shenandoah/shenandoahGC.hpp" +#include "gc/shared/gcCause.hpp" #include "gc/shenandoah/shenandoahController.hpp" +#include "gc/shenandoah/shenandoahGC.hpp" #include "gc/shenandoah/shenandoahPadding.hpp" #include "gc/shenandoah/shenandoahSharedVariables.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahController.cpp b/src/hotspot/share/gc/shenandoah/shenandoahController.cpp index c430981bfe65f..52182b092c988 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahController.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahController.cpp @@ -24,9 +24,8 @@ */ #include "gc/shared/gc_globals.hpp" +#include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahController.hpp" - -#include "shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahController.hpp b/src/hotspot/share/gc/shenandoah/shenandoahController.hpp index 83cde94f50957..d24f52cb3f177 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahController.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahController.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHCONTROLLER_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHCONTROLLER_HPP -#include "gc/shared/gcCause.hpp" #include "gc/shared/concurrentGCThread.hpp" +#include "gc/shared/gcCause.hpp" #include "gc/shenandoah/shenandoahAllocRequest.hpp" #include "gc/shenandoah/shenandoahSharedVariables.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index 8cc4e2de8ea02..7aaf7bd9f482d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp @@ -39,9 +39,9 @@ #include "gc/shenandoah/shenandoahSTWMark.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/shenandoahVerifier.hpp" -#include "gc/shenandoah/shenandoahYoungGeneration.hpp" -#include "gc/shenandoah/shenandoahWorkerPolicy.hpp" #include "gc/shenandoah/shenandoahVMOperations.hpp" +#include "gc/shenandoah/shenandoahWorkerPolicy.hpp" +#include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "runtime/vmThread.hpp" #include "utilities/events.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.cpp b/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.cpp index 3ddc8bf636e91..d393c17f64a01 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.cpp @@ -24,11 +24,11 @@ */ #include "gc/shenandoah/shenandoahAgeCensus.hpp" -#include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahEvacTracker.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -#include "runtime/threadSMR.inline.hpp" #include "runtime/thread.hpp" +#include "runtime/threadSMR.inline.hpp" ShenandoahEvacuationStats::ShenandoahEvacuationStats() : _evacuations_completed(0), _bytes_completed(0), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index e87c771dec49c..9787611d4fb93 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -31,9 +31,9 @@ #include "gc/shenandoah/shenandoahHeapRegionSet.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" -#include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "gc/shenandoah/shenandoahSimpleBitMap.hpp" #include "gc/shenandoah/shenandoahSimpleBitMap.inline.hpp" +#include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" #include "runtime/orderAccess.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index 80954af6d1a80..902e6547afd8f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -26,8 +26,8 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHFREESET_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHFREESET_HPP -#include "gc/shenandoah/shenandoahHeapRegionSet.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" +#include "gc/shenandoah/shenandoahHeapRegionSet.hpp" #include "gc/shenandoah/shenandoahSimpleBitMap.hpp" // Each ShenandoahHeapRegion is associated with a ShenandoahFreeSetPartitionId. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index 9436f09cbe050..f017b3de96287 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -34,23 +34,22 @@ #include "gc/shared/workerThread.hpp" #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" -#include "gc/shenandoah/shenandoahCollectorPolicy.hpp" -#include "gc/shenandoah/shenandoahConcurrentGC.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" +#include "gc/shenandoah/shenandoahConcurrentGC.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahFullGC.hpp" #include "gc/shenandoah/shenandoahGenerationalFullGC.hpp" #include "gc/shenandoah/shenandoahGlobalGeneration.hpp" -#include "gc/shenandoah/shenandoahPhaseTimings.hpp" -#include "gc/shenandoah/shenandoahMark.inline.hpp" -#include "gc/shenandoah/shenandoahMonitoringSupport.hpp" -#include "gc/shenandoah/shenandoahHeapRegionClosures.hpp" -#include "gc/shenandoah/shenandoahHeapRegionSet.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" +#include "gc/shenandoah/shenandoahHeapRegionClosures.hpp" +#include "gc/shenandoah/shenandoahHeapRegionSet.hpp" +#include "gc/shenandoah/shenandoahMark.inline.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahMetrics.hpp" +#include "gc/shenandoah/shenandoahMonitoringSupport.hpp" +#include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" #include "gc/shenandoah/shenandoahSTWMark.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGC.hpp index f10d5eef969da..f08bdce0a2025 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGC.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHGC_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHGC_HPP -#include "memory/allocation.hpp" #include "gc/shared/gcCause.hpp" +#include "memory/allocation.hpp" /* * Base class of three Shenandoah GC modes diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index ad91119ddad98..9a511de939ccb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -23,8 +23,9 @@ * */ -#include "gc/shenandoah/shenandoahCollectorPolicy.hpp" +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "gc/shenandoah/shenandoahCollectionSetPreselector.hpp" +#include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" @@ -37,8 +38,6 @@ #include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/shenandoahVerifier.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" -#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" - #include "utilities/quickSort.hpp" template diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp index 31c86985c6f58..242acbdea8cea 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp @@ -25,12 +25,12 @@ #ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHGENERATION_HPP #define SHARE_VM_GC_SHENANDOAH_SHENANDOAHGENERATION_HPP -#include "memory/allocation.hpp" #include "gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp" #include "gc/shenandoah/shenandoahAffiliation.hpp" #include "gc/shenandoah/shenandoahGenerationType.hpp" #include "gc/shenandoah/shenandoahLock.hpp" #include "gc/shenandoah/shenandoahMarkingContext.hpp" +#include "memory/allocation.hpp" class ShenandoahCollectionSet; class ShenandoahHeap; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationSizer.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationSizer.cpp index c6827878cd1f2..17f3d2f199f1a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationSizer.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationSizer.cpp @@ -23,13 +23,13 @@ * */ +#include "gc/shared/gc_globals.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationSizer.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" -#include "gc/shared/gc_globals.hpp" #include "logging/log.hpp" #include "runtime/globals_extension.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index 4d291ba50f792..2f2f13ca87b13 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -27,22 +27,22 @@ #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahConcurrentGC.hpp" -#include "gc/shenandoah/shenandoahGenerationalControlThread.hpp" #include "gc/shenandoah/shenandoahDegeneratedGC.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahFullGC.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" +#include "gc/shenandoah/shenandoahGenerationalControlThread.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" -#include "gc/shenandoah/shenandoahOldGC.hpp" -#include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahMonitoringSupport.hpp" +#include "gc/shenandoah/shenandoahOldGC.hpp" +#include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahPacer.inline.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "logging/log.hpp" -#include "memory/metaspaceUtils.hpp" #include "memory/metaspaceStats.hpp" +#include "memory/metaspaceUtils.hpp" #include "runtime/atomic.hpp" #include "utilities/events.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp index 6a845afa4fdff..ba9ef5979a89d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp @@ -31,8 +31,8 @@ #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahPacer.hpp" #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" -#include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" +#include "gc/shenandoah/shenandoahYoungGeneration.hpp" class ShenandoahConcurrentEvacuator : public ObjectClosure { private: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp index 3387ed9d7a846..142c2d4798948 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp @@ -25,14 +25,14 @@ #include "gc/shared/fullGCForwarding.inline.hpp" #include "gc/shared/preservedMarks.inline.hpp" +#include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationalFullGC.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" -#include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" -#include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" +#include "gc/shenandoah/shenandoahYoungGeneration.hpp" #ifdef ASSERT void assert_regions_used_not_more_than_capacity(ShenandoahGeneration* generation) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index 09b985e3b8d55..1f84feb20e8f4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -40,9 +40,9 @@ #include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahRegulatorThread.hpp" #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" +#include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/shenandoahWorkerPolicy.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" -#include "gc/shenandoah/shenandoahUtils.hpp" #include "logging/log.hpp" #include "utilities/events.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.cpp index 230fff162527b..a16a71b81759a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.cpp @@ -22,8 +22,8 @@ * */ -#include "gc/shenandoah/shenandoahAgeCensus.hpp" #include "gc/shenandoah/heuristics/shenandoahGlobalHeuristics.hpp" +#include "gc/shenandoah/shenandoahAgeCensus.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGlobalGeneration.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.hpp index d51a77fdf8f88..5857170d4ccc2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.hpp @@ -26,8 +26,8 @@ #define SHARE_VM_GC_SHENANDOAH_SHENANDOAHGLOBALGENERATION_HPP #include "gc/shenandoah/shenandoahGeneration.hpp" -#include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" +#include "gc/shenandoah/shenandoahYoungGeneration.hpp" // A "generation" that represents the whole heap. class ShenandoahGlobalGeneration : public ShenandoahGeneration { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 045f485090d2c..82c6cdb897135 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -27,7 +27,6 @@ #include "cds/archiveHeapWriter.hpp" #include "classfile/systemDictionary.hpp" - #include "gc/shared/classUnloadingContext.hpp" #include "gc/shared/fullGCForwarding.hpp" #include "gc/shared/gcArguments.hpp" @@ -37,24 +36,26 @@ #include "gc/shared/memAllocator.hpp" #include "gc/shared/plab.hpp" #include "gc/shared/tlab_globals.hpp" - #include "gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp" #include "gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp" +#include "gc/shenandoah/mode/shenandoahGenerationalMode.hpp" +#include "gc/shenandoah/mode/shenandoahPassiveMode.hpp" +#include "gc/shenandoah/mode/shenandoahSATBMode.hpp" #include "gc/shenandoah/shenandoahAllocRequest.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" +#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahCodeRoots.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahConcurrentMark.hpp" #include "gc/shenandoah/shenandoahControlThread.hpp" -#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" #include "gc/shenandoah/shenandoahGlobalGeneration.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" -#include "gc/shenandoah/shenandoahHeapRegionClosures.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" +#include "gc/shenandoah/shenandoahHeapRegionClosures.hpp" #include "gc/shenandoah/shenandoahHeapRegionSet.hpp" #include "gc/shenandoah/shenandoahInitLogger.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" @@ -73,18 +74,9 @@ #include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/shenandoahVerifier.hpp" #include "gc/shenandoah/shenandoahVMOperations.hpp" -#include "gc/shenandoah/shenandoahWorkGroup.hpp" #include "gc/shenandoah/shenandoahWorkerPolicy.hpp" +#include "gc/shenandoah/shenandoahWorkGroup.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" -#include "gc/shenandoah/mode/shenandoahGenerationalMode.hpp" -#include "gc/shenandoah/mode/shenandoahPassiveMode.hpp" -#include "gc/shenandoah/mode/shenandoahSATBMode.hpp" - -#if INCLUDE_JFR -#include "gc/shenandoah/shenandoahJfrSupport.hpp" -#endif - -#include "memory/allocation.hpp" #include "memory/allocation.hpp" #include "memory/classLoaderMetaspace.hpp" #include "memory/memoryReserver.hpp" @@ -103,9 +95,12 @@ #include "runtime/stackWatermarkSet.hpp" #include "runtime/threads.hpp" #include "runtime/vmThread.hpp" -#include "utilities/globalDefinitions.hpp" #include "utilities/events.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/powerOfTwo.hpp" +#if INCLUDE_JFR +#include "gc/shenandoah/shenandoahJfrSupport.hpp" +#endif class ShenandoahPretouchHeapTask : public WorkerTask { private: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 46f8a1340512a..4f24b9e1abd99 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -27,19 +27,19 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHHEAP_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHHEAP_HPP +#include "gc/shared/collectedHeap.hpp" #include "gc/shared/markBitMap.hpp" #include "gc/shared/softRefPolicy.hpp" -#include "gc/shared/collectedHeap.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahAllocRequest.hpp" #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahController.hpp" -#include "gc/shenandoah/shenandoahLock.hpp" #include "gc/shenandoah/shenandoahEvacOOMHandler.hpp" #include "gc/shenandoah/shenandoahEvacTracker.hpp" -#include "gc/shenandoah/shenandoahGenerationType.hpp" #include "gc/shenandoah/shenandoahGenerationSizer.hpp" +#include "gc/shenandoah/shenandoahGenerationType.hpp" +#include "gc/shenandoah/shenandoahLock.hpp" #include "gc/shenandoah/shenandoahMmuTracker.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahPadding.hpp" #include "gc/shenandoah/shenandoahSharedVariables.hpp" #include "gc/shenandoah/shenandoahUnload.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index f4ef186743cdf..cf9d808f7ce8f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -30,28 +30,28 @@ #include "gc/shenandoah/shenandoahHeap.hpp" #include "classfile/javaClasses.inline.hpp" -#include "gc/shared/markBitMap.inline.hpp" -#include "gc/shared/threadLocalAllocBuffer.inline.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" +#include "gc/shared/markBitMap.inline.hpp" #include "gc/shared/suspendibleThreadSet.hpp" +#include "gc/shared/threadLocalAllocBuffer.inline.hpp" #include "gc/shared/tlab_globals.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" #include "gc/shenandoah/shenandoahCollectionSet.inline.hpp" #include "gc/shenandoah/shenandoahForwarding.inline.hpp" -#include "gc/shenandoah/shenandoahWorkGroup.hpp" -#include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp" -#include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" +#include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" +#include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" +#include "gc/shenandoah/shenandoahWorkGroup.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/javaThread.hpp" -#include "runtime/prefetch.inline.hpp" #include "runtime/objectMonitor.inline.hpp" +#include "runtime/prefetch.inline.hpp" #include "utilities/copy.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index a25e2dfd88f67..d00a99ee7289c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -29,14 +29,14 @@ #include "gc/shared/tlab_globals.hpp" #include "gc/shenandoah/shenandoahCardTable.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" -#include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp" +#include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" +#include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" -#include "gc/shenandoah/shenandoahGeneration.hpp" -#include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" +#include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "jfr/jfrEvents.hpp" #include "memory/allocation.hpp" #include "memory/iterator.inline.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp index 7f29a8628aab5..0df482c1e2dab 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp @@ -27,8 +27,9 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHHEAPREGION_INLINE_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHHEAPREGION_INLINE_HPP -#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" + +#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahPacer.inline.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp index 360c7d2d649a5..918e6bf1be626 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp @@ -28,8 +28,8 @@ #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" -#include "gc/shenandoah/shenandoahHeapRegionSet.hpp" #include "gc/shenandoah/shenandoahHeapRegionCounters.hpp" +#include "gc/shenandoah/shenandoahHeapRegionSet.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" #include "runtime/atomic.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.hpp index c139980af4136..508b40e49a80e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.hpp @@ -26,8 +26,8 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHHEAPREGIONCOUNTERS_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHHEAPREGIONCOUNTERS_HPP -#include "memory/allocation.hpp" #include "logging/logFileStreamOutput.hpp" +#include "memory/allocation.hpp" /** * This provides the following in JVMStat: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.cpp index 46d54c70fe159..368738fe5ead7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.cpp @@ -23,9 +23,9 @@ * */ -#include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" +#include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "runtime/atomic.hpp" #include "utilities/copy.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.hpp index d933fda60b177..f81bf77d26e82 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.hpp @@ -25,10 +25,10 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHHEAPREGIONSET_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHHEAPREGIONSET_HPP -#include "memory/allocation.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahPadding.hpp" +#include "memory/allocation.hpp" #include "utilities/globalDefinitions.hpp" class ShenandoahHeapRegionSet; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.cpp b/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.cpp index b4ea327965b34..b5e5e6fd69894 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.cpp @@ -24,11 +24,11 @@ * */ +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahInitLogger.hpp" -#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "logging/log.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp index 47a144a638f0e..fcfe0d1d5d649 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp @@ -23,12 +23,11 @@ */ -#include "runtime/os.hpp" - #include "gc/shenandoah/shenandoahLock.hpp" #include "runtime/atomic.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaThread.hpp" +#include "runtime/os.hpp" #include "runtime/os.inline.hpp" void ShenandoahLock::contended_lock(bool allow_block_for_safepoint) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp index ae8d52a3d0e8f..4aef14f2c9aba 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp @@ -29,9 +29,9 @@ #include "gc/shared/ageTable.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/taskTerminator.hpp" +#include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationType.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" -#include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahTaskqueue.hpp" enum StringDedupMode { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.cpp index 9986afc6f2019..34e6af41b427c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.cpp @@ -24,8 +24,8 @@ * */ -#include "gc/shenandoah/shenandoahMarkBitMap.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahMarkBitMap.inline.hpp" #include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp index 399db525cf95c..0babeaffd3e0e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.cpp @@ -27,7 +27,6 @@ #include "gc/shared/markBitMap.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahMarkingContext.hpp" - #include "shenandoahGlobalGeneration.hpp" ShenandoahMarkingContext::ShenandoahMarkingContext(MemRegion heap_region, MemRegion bitmap_region, size_t num_regions) : diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.inline.hpp index d9bddd5fbb6b9..e3ba774283c18 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.inline.hpp @@ -28,6 +28,7 @@ #define SHARE_GC_SHENANDOAH_SHENANDOAHMARKINGCONTEXT_INLINE_HPP #include "gc/shenandoah/shenandoahMarkingContext.hpp" + #include "gc/shenandoah/shenandoahMarkBitMap.inline.hpp" #include "logging/log.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMemoryPool.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMemoryPool.cpp index e9aa69b5555c5..ebfe5267160fb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMemoryPool.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMemoryPool.cpp @@ -25,8 +25,8 @@ */ #include "gc/shenandoah/shenandoahMemoryPool.hpp" -#include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" +#include "gc/shenandoah/shenandoahYoungGeneration.hpp" ShenandoahMemoryPool::ShenandoahMemoryPool(ShenandoahHeap* heap, const char* name) : diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp index 32386e6aec052..edd4f875be4eb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp @@ -23,10 +23,10 @@ * */ -#include "gc/shenandoah/shenandoahMetrics.hpp" +#include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" -#include "gc/shenandoah/shenandoahFreeSet.hpp" +#include "gc/shenandoah/shenandoahMetrics.hpp" ShenandoahMetricsSnapshot::ShenandoahMetricsSnapshot() { _heap = ShenandoahHeap::heap(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMmuTracker.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMmuTracker.cpp index 663864b1294ce..5867478d73426 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMmuTracker.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMmuTracker.cpp @@ -24,8 +24,8 @@ */ #include "gc/shenandoah/shenandoahAsserts.hpp" -#include "gc/shenandoah/shenandoahMmuTracker.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahMmuTracker.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "logging/log.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMonitoringSupport.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMonitoringSupport.cpp index 31265addda886..6b72cbdd62bba 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMonitoringSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMonitoringSupport.cpp @@ -25,9 +25,9 @@ #include "gc/shared/collectorCounters.hpp" #include "gc/shared/generationCounters.hpp" #include "gc/shared/hSpaceCounters.hpp" -#include "gc/shenandoah/shenandoahMonitoringSupport.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegionCounters.hpp" +#include "gc/shenandoah/shenandoahMonitoringSupport.hpp" #include "memory/metaspaceCounters.hpp" #include "services/memoryService.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp index 7c28378bf2455..1724fc2849f76 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp @@ -25,11 +25,11 @@ #include "gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" +#include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahMonitoringSupport.hpp" #include "gc/shenandoah/shenandoahOldGC.hpp" -#include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "prims/jvmtiTagMap.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index b0c42c7b40feb..35d963f1801d6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -26,6 +26,7 @@ #include "gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp" #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahCardTable.hpp" +#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" @@ -35,7 +36,6 @@ #include "gc/shenandoah/shenandoahHeapRegionClosures.hpp" #include "gc/shenandoah/shenandoahMonitoringSupport.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" -#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp index e16275b480a27..62a25881b5a60 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp @@ -25,11 +25,11 @@ #include "gc/shared/workerDataArray.inline.hpp" +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" -#include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" -#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "runtime/orderAccess.hpp" #include "utilities/ostream.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp index 9100ad2b22077..0a45615131814 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp @@ -26,9 +26,9 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHPHASETIMINGS_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHPHASETIMINGS_HPP -#include "jfr/jfrEvents.hpp" -#include "gc/shenandoah/shenandoahNumberSeq.hpp" #include "gc/shared/workerDataArray.hpp" +#include "gc/shenandoah/shenandoahNumberSeq.hpp" +#include "jfr/jfrEvents.hpp" #include "memory/allocation.hpp" class ShenandoahCollectorPolicy; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp index 0e10e8c819f2e..2bbce179af8d7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp @@ -26,14 +26,14 @@ #include "classfile/javaClasses.hpp" #include "gc/shared/workerThread.hpp" -#include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" +#include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" -#include "runtime/atomic.hpp" #include "logging/log.hpp" +#include "runtime/atomic.hpp" static ReferenceType reference_type(oop reference) { return InstanceKlass::cast(reference->klass())->reference_type(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp index b3b5109f6b376..8693046297d5a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp @@ -26,9 +26,9 @@ #include "classfile/classLoaderData.hpp" #include "code/nmethod.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" -#include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" +#include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" #include "gc/shenandoah/shenandoahStackWatermark.hpp" #include "memory/iterator.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp index f1544c1762ea8..fa3fa90b2f50b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp @@ -29,11 +29,11 @@ #include "classfile/classLoaderDataGraph.hpp" #include "gc/shared/oopStorageSetParState.inline.hpp" +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" -#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "memory/resourceArea.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp index 4c7ae68fdbe02..11ff92cd9ccf3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp @@ -28,16 +28,16 @@ #include "classfile/classLoaderDataGraph.hpp" #include "code/codeCache.hpp" +#include "gc/shared/oopStorage.inline.hpp" +#include "gc/shared/oopStorageSet.hpp" #include "gc/shenandoah/shenandoahAsserts.hpp" -#include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahRootVerifier.hpp" #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" #include "gc/shenandoah/shenandoahStringDedup.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" -#include "gc/shared/oopStorage.inline.hpp" -#include "gc/shared/oopStorageSet.hpp" #include "runtime/javaThread.hpp" #include "runtime/jniHandles.hpp" #include "runtime/threads.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp index 2984debd9f861..d2a5f71bca608 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp @@ -26,8 +26,8 @@ #include "gc/shenandoah/shenandoahBarrierSetClone.inline.hpp" #include "gc/shenandoah/shenandoahRuntime.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -#include "runtime/interfaceSupport.inline.hpp" #include "oops/oop.inline.hpp" +#include "runtime/interfaceSupport.inline.hpp" #include "utilities/copy.hpp" JRT_LEAF(void, ShenandoahRuntime::arraycopy_barrier_oop(oop* src, oop* dst, size_t length)) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.inline.hpp index b0fc55631e067..68bec5c2071bc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.inline.hpp @@ -26,18 +26,19 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHSCANREMEMBEREDINLINE_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHSCANREMEMBEREDINLINE_HPP -#include "memory/iterator.hpp" -#include "oops/oop.hpp" -#include "oops/objArrayOop.hpp" +#include "gc/shenandoah/shenandoahScanRemembered.hpp" + #include "gc/shared/collectorCounters.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahCardStats.hpp" #include "gc/shenandoah/shenandoahCardTable.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" -#include "gc/shenandoah/shenandoahScanRemembered.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "logging/log.hpp" +#include "memory/iterator.hpp" +#include "oops/objArrayOop.hpp" +#include "oops/oop.hpp" // Process all objects starting within count clusters beginning with first_cluster and for which the start address is // less than end_of_range. For any non-array object whose header lies on a dirty card, scan the entire object, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp index 55d21b06e4bbd..3a4cb8cf742fc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp @@ -25,10 +25,10 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHSIMPLEBITMAP_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHSIMPLEBITMAP_HPP -#include - #include "gc/shenandoah/shenandoahAsserts.hpp" +#include + // TODO: Merge the enhanced capabilities of ShenandoahSimpleBitMap into src/hotspot/share/utilities/bitMap.hpp // and deprecate ShenandoahSimpleBitMap. The key enhanced capabilities to be integrated include: // diff --git a/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.inline.hpp index 042143254bc4c..1559dd81849eb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.inline.hpp @@ -25,9 +25,10 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHSTRINGDEDUP_INLINE_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHSTRINGDEDUP_INLINE_HPP +#include "gc/shenandoah/shenandoahStringDedup.hpp" + #include "classfile/javaClasses.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" -#include "gc/shenandoah/shenandoahStringDedup.hpp" #include "oops/markWord.hpp" bool ShenandoahStringDedup::is_string_candidate(oop obj) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp index 10887ad8c19d6..342b599caf5d7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp @@ -26,8 +26,8 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHTASKQUEUE_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHTASKQUEUE_HPP -#include "gc/shared/taskTerminator.hpp" #include "gc/shared/taskqueue.hpp" +#include "gc/shared/taskTerminator.hpp" #include "gc/shenandoah/shenandoahPadding.hpp" #include "nmt/memTag.hpp" #include "runtime/atomic.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp index 933cc501562f1..c1cebdf1ddef4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp @@ -26,16 +26,16 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHTHREADLOCALDATA_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHTHREADLOCALDATA_HPP -#include "gc/shared/plab.hpp" -#include "gc/shared/gcThreadLocalData.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcThreadLocalData.hpp" +#include "gc/shared/plab.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahCardTable.hpp" #include "gc/shenandoah/shenandoahCodeRoots.hpp" -#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" #include "gc/shenandoah/shenandoahEvacTracker.hpp" +#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" #include "gc/shenandoah/shenandoahSATBMarkQueueSet.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "runtime/javaThread.hpp" #include "utilities/debug.hpp" #include "utilities/sizes.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp index 6bd50154b4fde..83151313f7565 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp @@ -29,11 +29,11 @@ #include "code/codeBehaviours.hpp" #include "code/codeCache.hpp" #include "code/dependencyContext.hpp" -#include "gc/shared/gcBehaviours.hpp" #include "gc/shared/classUnloadingContext.hpp" +#include "gc/shared/gcBehaviours.hpp" #include "gc/shared/suspendibleThreadSet.hpp" -#include "gc/shenandoah/shenandoahNMethod.inline.hpp" #include "gc/shenandoah/shenandoahLock.hpp" +#include "gc/shenandoah/shenandoahNMethod.inline.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahRootProcessor.hpp" #include "gc/shenandoah/shenandoahUnload.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp index ecca550d5532c..176baa133c840 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp @@ -24,7 +24,6 @@ */ -#include "jfr/jfrEvents.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/gcWhen.hpp" @@ -36,6 +35,7 @@ #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" +#include "jfr/jfrEvents.hpp" #include "utilities/debug.hpp" ShenandoahPhaseTimings::Phase ShenandoahTimingsTracker::_current_phase = ShenandoahPhaseTimings::_invalid_phase; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp index fd30279d318a2..8a508c4afd84f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp @@ -37,8 +37,8 @@ #include "jfr/jfrEvents.hpp" #include "memory/allocation.hpp" #include "runtime/safepoint.hpp" -#include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" +#include "runtime/vmThread.hpp" #include "services/memoryService.hpp" class GCTimer; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index 37951c311ed99..cdf7848520765 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -27,11 +27,11 @@ #include "gc/shared/tlab_globals.hpp" #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahForwarding.inline.hpp" -#include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" +#include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahRootProcessor.hpp" #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" #include "gc/shenandoah/shenandoahTaskqueue.inline.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.cpp b/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.cpp index d6c47339f28a9..f2431a5ad0afc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.cpp @@ -25,10 +25,9 @@ #include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahTaskqueue.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" #include "gc/shenandoah/shenandoahWorkGroup.hpp" -#include "gc/shenandoah/shenandoahTaskqueue.hpp" - #include "logging/log.hpp" #include "runtime/threads.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp index 8663515d019d0..daf5d456af5ea 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp @@ -22,13 +22,13 @@ * */ +#include "gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp" #include "gc/shenandoah/shenandoahAgeCensus.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahHeapRegionClosures.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" -#include "gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp" ShenandoahYoungGeneration::ShenandoahYoungGeneration(uint max_queues, size_t max_capacity, size_t soft_max_capacity) : ShenandoahGeneration(YOUNG, max_queues, max_capacity, soft_max_capacity), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp index 1237e28c06ef8..a8ebab507b6cc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHYOUNGGENERATION_HPP #define SHARE_VM_GC_SHENANDOAH_SHENANDOAHYOUNGGENERATION_HPP -#include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp" +#include "gc/shenandoah/shenandoahGeneration.hpp" class ShenandoahYoungGeneration : public ShenandoahGeneration { private: diff --git a/src/hotspot/share/gc/shenandoah/vmStructs_shenandoah.hpp b/src/hotspot/share/gc/shenandoah/vmStructs_shenandoah.hpp index 851fa39472237..a245f91fa71e9 100644 --- a/src/hotspot/share/gc/shenandoah/vmStructs_shenandoah.hpp +++ b/src/hotspot/share/gc/shenandoah/vmStructs_shenandoah.hpp @@ -24,9 +24,9 @@ #ifndef SHARE_GC_SHENANDOAH_VMSTRUCTS_SHENANDOAH_HPP #define SHARE_GC_SHENANDOAH_VMSTRUCTS_SHENANDOAH_HPP -#include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" +#include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahMonitoringSupport.hpp" diff --git a/src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp b/src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp index f3643c0a3251d..7bd2495591091 100644 --- a/src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp +++ b/src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp @@ -21,12 +21,12 @@ * questions. */ +#include "c1/c1_CodeStubs.hpp" #include "c1/c1_FrameMap.hpp" #include "c1/c1_LIR.hpp" #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_LIRGenerator.hpp" #include "c1/c1_MacroAssembler.hpp" -#include "c1/c1_CodeStubs.hpp" #include "gc/z/c1/zBarrierSetC1.hpp" #include "gc/z/zBarrierSet.hpp" #include "gc/z/zBarrierSetAssembler.hpp" diff --git a/src/hotspot/share/gc/z/zHeapIterator.hpp b/src/hotspot/share/gc/z/zHeapIterator.hpp index fb58e3abe5fd6..2b570e98f1c71 100644 --- a/src/hotspot/share/gc/z/zHeapIterator.hpp +++ b/src/hotspot/share/gc/z/zHeapIterator.hpp @@ -25,8 +25,8 @@ #define SHARE_GC_Z_ZHEAPITERATOR_HPP #include "gc/shared/collectedHeap.hpp" -#include "gc/shared/taskTerminator.hpp" #include "gc/shared/taskqueue.hpp" +#include "gc/shared/taskTerminator.hpp" #include "gc/z/zGranuleMap.hpp" #include "gc/z/zLock.hpp" #include "gc/z/zRootsIterator.hpp" diff --git a/src/hotspot/share/gc/z/zMarkContext.hpp b/src/hotspot/share/gc/z/zMarkContext.hpp index 009252e524da6..788e17cae8f2b 100644 --- a/src/hotspot/share/gc/z/zMarkContext.hpp +++ b/src/hotspot/share/gc/z/zMarkContext.hpp @@ -24,8 +24,8 @@ #ifndef SHARE_GC_Z_ZMARKCONTEXT_HPP #define SHARE_GC_Z_ZMARKCONTEXT_HPP -#include "gc/z/zMarkCache.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" +#include "gc/z/zMarkCache.hpp" #include "memory/allocation.hpp" class ZMarkStripe; diff --git a/src/hotspot/share/gc/z/zMarkingSMR.hpp b/src/hotspot/share/gc/z/zMarkingSMR.hpp index a6c5afe76c941..26670d959598a 100644 --- a/src/hotspot/share/gc/z/zMarkingSMR.hpp +++ b/src/hotspot/share/gc/z/zMarkingSMR.hpp @@ -26,8 +26,8 @@ #include "gc/z/zArray.hpp" #include "gc/z/zValue.hpp" -#include "utilities/globalDefinitions.hpp" #include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" class ZMarkStackListNode; diff --git a/src/hotspot/share/gc/z/zNMT.cpp b/src/hotspot/share/gc/z/zNMT.cpp index 76e164308dd0c..1019bcfdd961b 100644 --- a/src/hotspot/share/gc/z/zNMT.cpp +++ b/src/hotspot/share/gc/z/zNMT.cpp @@ -24,9 +24,9 @@ #include "gc/z/zAddress.inline.hpp" #include "gc/z/zGlobals.hpp" #include "gc/z/zNMT.hpp" +#include "nmt/memoryFileTracker.hpp" #include "nmt/memTag.hpp" #include "nmt/memTracker.hpp" -#include "nmt/memoryFileTracker.hpp" #include "utilities/nativeCallStack.hpp" MemoryFileTracker::MemoryFile* ZNMT::_device = nullptr; diff --git a/src/hotspot/share/gc/z/zNMT.hpp b/src/hotspot/share/gc/z/zNMT.hpp index b5b1aa07870f3..5fea74ee8ae6b 100644 --- a/src/hotspot/share/gc/z/zNMT.hpp +++ b/src/hotspot/share/gc/z/zNMT.hpp @@ -27,8 +27,8 @@ #include "gc/z/zAddress.hpp" #include "gc/z/zGlobals.hpp" #include "memory/allStatic.hpp" -#include "nmt/memTracker.hpp" #include "nmt/memoryFileTracker.hpp" +#include "nmt/memTracker.hpp" #include "utilities/globalDefinitions.hpp" class ZNMT : public AllStatic { diff --git a/src/hotspot/share/gc/z/zNMethod.cpp b/src/hotspot/share/gc/z/zNMethod.cpp index 4ae440ea23123..bf592c20fa296 100644 --- a/src/hotspot/share/gc/z/zNMethod.cpp +++ b/src/hotspot/share/gc/z/zNMethod.cpp @@ -22,8 +22,8 @@ */ #include "code/codeCache.hpp" -#include "code/relocInfo.hpp" #include "code/nmethod.hpp" +#include "code/relocInfo.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/classUnloadingContext.hpp" diff --git a/src/hotspot/share/gc/z/zNMethodTable.cpp b/src/hotspot/share/gc/z/zNMethodTable.cpp index 0aec0d5a9c7f4..bbc8f56b654ac 100644 --- a/src/hotspot/share/gc/z/zNMethodTable.cpp +++ b/src/hotspot/share/gc/z/zNMethodTable.cpp @@ -21,8 +21,8 @@ * questions. */ -#include "code/relocInfo.hpp" #include "code/nmethod.hpp" +#include "code/relocInfo.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetNMethod.hpp" #include "gc/z/zHash.inline.hpp" diff --git a/src/hotspot/share/gc/z/zObjArrayAllocator.cpp b/src/hotspot/share/gc/z/zObjArrayAllocator.cpp index a4484ba10237b..ddb0ca4927849 100644 --- a/src/hotspot/share/gc/z/zObjArrayAllocator.cpp +++ b/src/hotspot/share/gc/z/zObjArrayAllocator.cpp @@ -21,8 +21,8 @@ * questions. */ -#include "gc/z/zThreadLocalData.hpp" #include "gc/z/zObjArrayAllocator.hpp" +#include "gc/z/zThreadLocalData.hpp" #include "gc/z/zUtils.inline.hpp" #include "oops/arrayKlass.hpp" #include "runtime/interfaceSupport.inline.hpp" diff --git a/src/hotspot/share/gc/z/zRuntimeWorkers.cpp b/src/hotspot/share/gc/z/zRuntimeWorkers.cpp index f19e5cd54697a..c8c4cde9ba0fc 100644 --- a/src/hotspot/share/gc/z/zRuntimeWorkers.cpp +++ b/src/hotspot/share/gc/z/zRuntimeWorkers.cpp @@ -21,8 +21,8 @@ * questions. */ -#include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcLogPrecious.hpp" #include "gc/z/zRuntimeWorkers.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/gc/z/zStat.cpp b/src/hotspot/share/gc/z/zStat.cpp index 558ccdf105acd..a6b2bd0930d83 100644 --- a/src/hotspot/share/gc/z/zStat.cpp +++ b/src/hotspot/share/gc/z/zStat.cpp @@ -24,9 +24,9 @@ #include "gc/shared/gc_globals.hpp" #include "gc/z/zAbort.inline.hpp" #include "gc/z/zCollectedHeap.hpp" +#include "gc/z/zCPU.inline.hpp" #include "gc/z/zDirector.hpp" #include "gc/z/zDriver.hpp" -#include "gc/z/zCPU.inline.hpp" #include "gc/z/zGeneration.inline.hpp" #include "gc/z/zGlobals.hpp" #include "gc/z/zNMethodTable.hpp" diff --git a/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp b/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp index f0b3dfcb42c76..0d9fccde87c56 100644 --- a/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp +++ b/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp @@ -27,9 +27,9 @@ #include "gc/z/zUncoloredRoot.hpp" #include "gc/z/zAddress.inline.hpp" +#include "gc/z/zBarrier.hpp" #include "gc/z/zBarrier.inline.hpp" #include "gc/z/zHeap.inline.hpp" -#include "gc/z/zBarrier.hpp" #include "oops/oop.hpp" template diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index 117d27997eed4..68290c2c009de 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -32,8 +32,8 @@ #include "gc/z/zResurrection.hpp" #include "gc/z/zRootsIterator.hpp" #include "gc/z/zStackWatermark.hpp" -#include "gc/z/zStoreBarrierBuffer.inline.hpp" #include "gc/z/zStat.hpp" +#include "gc/z/zStoreBarrierBuffer.inline.hpp" #include "gc/z/zVerify.hpp" #include "memory/allocation.hpp" #include "memory/iterator.inline.hpp" diff --git a/src/hotspot/share/gc/z/zVirtualMemoryManager.inline.hpp b/src/hotspot/share/gc/z/zVirtualMemoryManager.inline.hpp index 78f966d0f845e..27159b4eff8e5 100644 --- a/src/hotspot/share/gc/z/zVirtualMemoryManager.inline.hpp +++ b/src/hotspot/share/gc/z/zVirtualMemoryManager.inline.hpp @@ -26,8 +26,8 @@ #include "gc/z/zVirtualMemoryManager.hpp" -#include "utilities/globalDefinitions.hpp" #include "gc/z/zRangeRegistry.inline.hpp" +#include "utilities/globalDefinitions.hpp" inline bool ZVirtualMemoryManager::is_multi_partition_enabled() const { From 82c249446f2bd6f3b0e612c5ef3e6bfcab388c3b Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 23 Apr 2025 10:40:45 +0000 Subject: [PATCH 0725/1101] 8354228: Parallel: Set correct minimum of InitialSurvivorRatio Reviewed-by: tschatzl, gli --- .../share/gc/parallel/parallelArguments.cpp | 23 ++++++++++--------- src/hotspot/share/gc/shared/gc_globals.hpp | 2 +- .../TestMinAndInitialSurvivorRatioFlags.java | 2 -- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelArguments.cpp b/src/hotspot/share/gc/parallel/parallelArguments.cpp index 6309f52c82ed2..2cddbafd87181 100644 --- a/src/hotspot/share/gc/parallel/parallelArguments.cpp +++ b/src/hotspot/share/gc/parallel/parallelArguments.cpp @@ -66,6 +66,18 @@ void ParallelArguments::initialize() { } } + if (InitialSurvivorRatio < MinSurvivorRatio) { + if (FLAG_IS_CMDLINE(InitialSurvivorRatio)) { + if (FLAG_IS_CMDLINE(MinSurvivorRatio)) { + jio_fprintf(defaultStream::error_stream(), + "Inconsistent MinSurvivorRatio vs InitialSurvivorRatio: %d vs %d\n", MinSurvivorRatio, InitialSurvivorRatio); + } + FLAG_SET_DEFAULT(MinSurvivorRatio, InitialSurvivorRatio); + } else { + FLAG_SET_DEFAULT(InitialSurvivorRatio, MinSurvivorRatio); + } + } + // If InitialSurvivorRatio or MinSurvivorRatio were not specified, but the // SurvivorRatio has been set, reset their default values to SurvivorRatio + // 2. By doing this we make SurvivorRatio also work for Parallel Scavenger. @@ -101,17 +113,6 @@ void ParallelArguments::initialize_alignments() { void ParallelArguments::initialize_heap_flags_and_sizes_one_pass() { // Do basic sizing work GenArguments::initialize_heap_flags_and_sizes(); - - // The survivor ratio's are calculated "raw", unlike the - // default gc, which adds 2 to the ratio value. We need to - // make sure the values are valid before using them. - if (MinSurvivorRatio < 3) { - FLAG_SET_ERGO(MinSurvivorRatio, 3); - } - - if (InitialSurvivorRatio < 3) { - FLAG_SET_ERGO(InitialSurvivorRatio, 3); - } } void ParallelArguments::initialize_heap_flags_and_sizes() { diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index ba29daf2fe144..56b8bc4e4ffd8 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -412,7 +412,7 @@ \ product(uintx, InitialSurvivorRatio, 8, \ "Initial ratio of young generation/survivor space size") \ - range(0, max_uintx) \ + range(3, max_uintx) \ \ product(bool, UseGCOverheadLimit, true, \ "Use policy to limit of proportion of time spent in GC " \ diff --git a/test/hotspot/jtreg/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java b/test/hotspot/jtreg/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java index 0e91f7f20abac..5f585575e7a55 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java @@ -65,8 +65,6 @@ public static void main(String args[]) throws Exception { testSurvivorRatio(-1, 15, 3, options, true); testSurvivorRatio(-1, 15, 3, options, false); testSurvivorRatio(-1, 10, 10, options, true); - testSurvivorRatio(-1, 3, 15, options, true); - testSurvivorRatio(-1, 3, 15, options, false); } /** From ef0cd1823d7d57e42e66255a0e80bfa495a7102d Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Wed, 23 Apr 2025 11:48:48 +0000 Subject: [PATCH 0726/1101] 8354949: JFR: Split up the EventInstrumentation class Reviewed-by: mgronlun, liach --- .../jdk/jfr/internal/ClassInspector.java | 361 +++++++++ .../jfr/internal/EventInstrumentation.java | 759 ++++++------------ .../classes/jdk/jfr/internal/JVMUpcalls.java | 16 +- .../jdk/jfr/internal/util/Bytecode.java | 9 +- .../jdk/jfr/internal/util/ImplicitFields.java | 5 +- 5 files changed, 621 insertions(+), 529 deletions(-) create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java new file mode 100644 index 0000000000000..e7e0eac54ff60 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.internal; + +import static jdk.jfr.internal.util.Bytecode.classDesc; + +import java.lang.classfile.Annotation; +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.AnnotationValue; +import java.lang.classfile.Attribute; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassModel; +import java.lang.classfile.FieldModel; +import java.lang.classfile.MethodModel; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.lang.constant.ConstantDescs; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import jdk.jfr.Enabled; +import jdk.jfr.Name; +import jdk.jfr.Registered; +import jdk.jfr.SettingControl; +import jdk.jfr.SettingDefinition; +import jdk.jfr.internal.util.Bytecode; +import jdk.jfr.internal.util.ImplicitFields; +import jdk.jfr.internal.util.Bytecode.FieldDesc; +import jdk.jfr.internal.util.Bytecode.MethodDesc; +import jdk.jfr.internal.util.Bytecode.SettingDesc; +import jdk.jfr.internal.util.Utils; + +final class ClassInspector { + private static final ClassDesc TYPE_SETTING_DEFINITION = Bytecode.classDesc(SettingDefinition.class); + private static final ClassDesc ANNOTATION_REGISTERED = classDesc(Registered.class); + private static final ClassDesc ANNOTATION_NAME = classDesc(Name.class); + private static final ClassDesc ANNOTATION_ENABLED = classDesc(Enabled.class); + private static final ClassDesc ANNOTATION_REMOVE_FIELDS = classDesc(RemoveFields.class); + + private final ClassModel classModel; + private final Class superClass; + private final boolean isJDK; + private final ImplicitFields implicitFields; + private final List settingsDescs = new ArrayList<>(); + private final List fieldDescs = new ArrayList<>(); + private final String className; + + ClassInspector(Class superClass, byte[] bytes, boolean isJDK) { + this.superClass = superClass; + this.classModel = ClassFile.of().parse(bytes); + this.isJDK = isJDK; + this.className = classModel.thisClass().asInternalName().replace("/", "."); + this.implicitFields = determineImplicitFields(); + } + + String getClassName() { + return className; + } + + MethodDesc findStaticCommitMethod() { + if (!isJDK) { + return null; + } + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (FieldDesc field : fieldDescs) { + sb.append(field.type().descriptorString()); + } + sb.append(")V"); + MethodDesc m = MethodDesc.of("commit", sb.toString()); + for (MethodModel method : classModel.methods()) { + if (m.matches(method)) { + return m; + } + } + return null; + } + + String getEventName() { + String name = annotationValue(ANNOTATION_NAME, String.class); + return name == null ? getClassName() : name; + } + + boolean isRegistered() { + Boolean result = annotationValue(ANNOTATION_REGISTERED, Boolean.class); + if (result != null) { + return result.booleanValue(); + } + if (superClass != null) { + Registered r = superClass.getAnnotation(Registered.class); + if (r != null) { + return r.value(); + } + } + return true; + } + + boolean isEnabled() { + Boolean result = annotationValue(ANNOTATION_ENABLED, Boolean.class); + if (result != null) { + return result.booleanValue(); + } + if (superClass != null) { + Enabled e = superClass.getAnnotation(Enabled.class); + if (e != null) { + return e.value(); + } + } + return true; + } + + boolean hasStaticMethod(MethodDesc method) { + for (MethodModel m : classModel.methods()) { + if (Modifier.isStatic(m.flags().flagsMask())) { + return method.matches(m); + } + } + return false; + } + + static boolean isValidField(int access, ClassDesc classDesc) { + String className = classDesc.packageName(); + if (!className.isEmpty()) { + className = className + "."; + } + className += classDesc.displayName(); + return isValidField(access, className); + } + + static boolean isValidField(int access, String className) { + if (Modifier.isTransient(access) || Modifier.isStatic(access)) { + return false; + } + return Type.isValidJavaFieldType(className); + } + + List getSettings() { + return settingsDescs; + } + + List getFields() { + return fieldDescs; + } + + boolean hasDuration() { + return implicitFields.hasDuration(); + } + + boolean hasStackTrace() { + return implicitFields.hasStackTrace(); + } + + boolean hasEventThread() { + return implicitFields.hasEventThread(); + } + + ClassDesc getClassDesc() { + return classModel.thisClass().asSymbol(); + } + + ClassModel getClassModel() { + return classModel; + } + + boolean isJDK() { + return isJDK; + } + + private ImplicitFields determineImplicitFields() { + if (isJDK) { + Class eventClass = MirrorEvents.find(isJDK, getClassName()); + if (eventClass != null) { + return new ImplicitFields(eventClass); + } + } + ImplicitFields ifs = new ImplicitFields(superClass); + String[] value = annotationValue(ANNOTATION_REMOVE_FIELDS, String[].class); + if (value != null) { + ifs.removeFields(value); + } + return ifs; + } + + private List getAnnotationValues(ClassDesc classDesc) { + List list = new ArrayList<>(); + for (Attribute attribute: classModel.attributes()) { + if (attribute instanceof RuntimeVisibleAnnotationsAttribute rvaa) { + for (Annotation a : rvaa.annotations()) { + if (a.classSymbol().equals(classDesc) && a.elements().size() == 1) { + AnnotationElement ae = a.elements().getFirst(); + if (ae.name().equalsString("value")) { + list.add(ae.value()); + } + } + } + } + } + return list; + } + + @SuppressWarnings("unchecked") + // Only supports String, String[] and Boolean values + private T annotationValue(ClassDesc classDesc, Class type) { + for (AnnotationValue a : getAnnotationValues(classDesc)) { + if (a instanceof AnnotationValue.OfBoolean ofb && type.equals(Boolean.class)) { + Boolean b = ofb.booleanValue(); + return (T) b; + } + if (a instanceof AnnotationValue.OfString ofs && type.equals(String.class)) { + String s = ofs.stringValue(); + return (T) s; + } + if (a instanceof AnnotationValue.OfArray ofa && type.equals(String[].class)) { + List list = ofa.values(); + String[] array = new String[list.size()]; + int index = 0; + for (AnnotationValue av : list) { + var avs = (AnnotationValue.OfString) av; + array[index++] = avs.stringValue(); + } + return (T) array; + } + } + return null; + } + + void buildSettings() { + Set foundMethods = new HashSet<>(); + buildClassSettings(foundMethods); + buildSuperClassSettings(foundMethods); + } + + private void buildClassSettings(Set foundMethods) { + for (MethodModel m : classModel.methods()) { + for (Attribute attribute : m.attributes()) { + if (attribute instanceof RuntimeVisibleAnnotationsAttribute rvaa) { + for (Annotation a : rvaa.annotations()) { + // We can't really validate the method at this + // stage. We would need to check that the parameter + // is an instance of SettingControl. + if (a.classSymbol().equals(TYPE_SETTING_DEFINITION)) { + String name = m.methodName().stringValue(); + // Use @Name if it exists + for (Annotation nameCandidate : rvaa.annotations()) { + if (nameCandidate.className().equalsString(ANNOTATION_NAME.descriptorString())) { + if (nameCandidate.elements().size() == 1) { + AnnotationElement ae = nameCandidate.elements().getFirst(); + if (ae.name().equalsString("value")) { + if (ae.value() instanceof AnnotationValue.OfString s) { + name = Utils.validJavaIdentifier(s.stringValue(), name); + } + } + } + } + } + // Add setting if method returns boolean and has one parameter + MethodTypeDesc mtd = m.methodTypeSymbol(); + if (ConstantDescs.CD_boolean.equals(mtd.returnType())) { + if (mtd.parameterList().size() == 1) { + ClassDesc type = mtd.parameterList().getFirst(); + if (type.isClassOrInterface()) { + String methodName = m.methodName().stringValue(); + foundMethods.add(methodName); + settingsDescs.add(new SettingDesc(type, methodName)); + } + } + } + } + } + } + } + } + } + + private void buildSuperClassSettings(Set foundMethods) { + for (Class c = superClass; jdk.internal.event.Event.class != c; c = c.getSuperclass()) { + for (java.lang.reflect.Method method : c.getDeclaredMethods()) { + if (!foundMethods.contains(method.getName())) { + buildSettingsMethod(foundMethods, method); + } + } + } + } + + private void buildSettingsMethod(Set foundMethods, java.lang.reflect.Method method) { + // Skip private methods in base classes + if (!Modifier.isPrivate(method.getModifiers())) { + if (method.getReturnType().equals(Boolean.TYPE)) { + if (method.getParameterCount() == 1) { + Class type = method.getParameters()[0].getType(); + if (SettingControl.class.isAssignableFrom(type)) { + ClassDesc paramType = Bytecode.classDesc(type); + foundMethods.add(method.getName()); + settingsDescs.add(new SettingDesc(paramType, method.getName())); + } + } + } + } + } + + void buildFields() { + Set foundFields = new HashSet<>(); + // These two fields are added by native as 'transient' so they will be + // ignored by the loop below. + // The benefit of adding them manually is that we can + // control in which order they occur and we can add @Name, @Description + // in Java, instead of in native. It also means code for adding implicit + // fields for native can be reused by Java. + fieldDescs.add(ImplicitFields.FIELD_START_TIME); + if (implicitFields.hasDuration()) { + fieldDescs.add(ImplicitFields.FIELD_DURATION); + } + for (FieldModel field : classModel.fields()) { + if (!foundFields.contains(field.fieldName().stringValue()) && isValidField(field.flags().flagsMask(), field.fieldTypeSymbol())) { + fieldDescs.add(FieldDesc.of(field.fieldTypeSymbol(), field.fieldName().stringValue())); + foundFields.add(field.fieldName().stringValue()); + } + } + for (Class c = superClass; jdk.internal.event.Event.class != c; c = c.getSuperclass()) { + for (Field field : c.getDeclaredFields()) { + // Skip private fields in base classes + if (!Modifier.isPrivate(field.getModifiers())) { + if (isValidField(field.getModifiers(), field.getType().getName())) { + String fieldName = field.getName(); + if (!foundFields.contains(fieldName)) { + fieldDescs.add(FieldDesc.of(field.getType(), fieldName)); + foundFields.add(fieldName); + } + } + } + } + } + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java index 7567aea664cb7..96e6f36e5c849 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java @@ -25,71 +25,49 @@ package jdk.jfr.internal; -import java.lang.constant.ClassDesc; -import java.lang.constant.MethodTypeDesc; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Consumer; +import static jdk.jfr.internal.util.Bytecode.classDesc; +import static jdk.jfr.internal.util.Bytecode.getfield; +import static jdk.jfr.internal.util.Bytecode.invokestatic; +import static jdk.jfr.internal.util.Bytecode.invokevirtual; +import static jdk.jfr.internal.util.Bytecode.putfield; -import java.lang.classfile.Annotation; -import java.lang.classfile.AnnotationElement; -import java.lang.classfile.AnnotationValue; +import java.lang.classfile.ClassBuilder; import java.lang.classfile.ClassElement; -import java.lang.classfile.ClassModel; import java.lang.classfile.ClassFile; import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeBuilder.BlockCodeBuilder; import java.lang.classfile.FieldModel; import java.lang.classfile.Label; import java.lang.classfile.MethodModel; +import java.lang.classfile.MethodTransform; import java.lang.classfile.TypeKind; -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; -import jdk.jfr.internal.event.EventConfiguration; -import jdk.jfr.internal.event.EventWriter; -import jdk.jfr.Enabled; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.util.List; +import java.util.function.Consumer; + import jdk.jfr.Event; -import jdk.jfr.Name; -import jdk.jfr.Registered; import jdk.jfr.SettingControl; -import jdk.jfr.SettingDefinition; -import jdk.jfr.internal.util.Utils; +import jdk.jfr.internal.event.EventConfiguration; +import jdk.jfr.internal.event.EventWriter; import jdk.jfr.internal.util.Bytecode; -import jdk.jfr.internal.util.ImplicitFields; import jdk.jfr.internal.util.Bytecode.FieldDesc; import jdk.jfr.internal.util.Bytecode.MethodDesc; -import static jdk.jfr.internal.util.Bytecode.invokevirtual; -import static jdk.jfr.internal.util.Bytecode.invokestatic; -import static jdk.jfr.internal.util.Bytecode.getfield; -import static jdk.jfr.internal.util.Bytecode.putfield; -import static jdk.jfr.internal.util.Bytecode.classDesc; +import jdk.jfr.internal.util.Bytecode.SettingDesc; +import jdk.jfr.internal.util.ImplicitFields; /** * Class responsible for adding instrumentation to a subclass of {@link Event}. * */ final class EventInstrumentation { + private static final FieldDesc FIELD_EVENT_CONFIGURATION = FieldDesc.of(Object.class, "eventConfiguration"); - private record SettingDesc(ClassDesc paramType, String methodName) { - } - - private static final FieldDesc FIELD_DURATION = FieldDesc.of(long.class, ImplicitFields.DURATION); - private static final FieldDesc FIELD_EVENT_CONFIGURATION = FieldDesc.of(Object.class, "eventConfiguration");; - private static final FieldDesc FIELD_START_TIME = FieldDesc.of(long.class, ImplicitFields.START_TIME); - private static final ClassDesc ANNOTATION_ENABLED = classDesc(Enabled.class); - private static final ClassDesc ANNOTATION_NAME = classDesc(Name.class); - private static final ClassDesc ANNOTATION_REGISTERED = classDesc(Registered.class); - private static final ClassDesc ANNOTATION_REMOVE_FIELDS = classDesc(RemoveFields.class); private static final ClassDesc TYPE_EVENT_CONFIGURATION = classDesc(EventConfiguration.class); - private static final ClassDesc TYPE_ISE = Bytecode.classDesc(IllegalStateException.class); + private static final ClassDesc TYPE_ISE = classDesc(IllegalStateException.class); private static final ClassDesc TYPE_EVENT_WRITER = classDesc(EventWriter.class); - private static final ClassDesc TYPE_OBJECT = Bytecode.classDesc(Object.class); - private static final ClassDesc TYPE_SETTING_DEFINITION = Bytecode.classDesc(SettingDefinition.class); + private static final ClassDesc TYPE_OBJECT = classDesc(Object.class); + private static final MethodDesc METHOD_BEGIN = MethodDesc.of("begin", "()V"); private static final MethodDesc METHOD_COMMIT = MethodDesc.of("commit", "()V"); private static final MethodDesc METHOD_DURATION = MethodDesc.of("duration", "(J)J"); @@ -104,446 +82,242 @@ private record SettingDesc(ClassDesc paramType, String methodName) { private static final MethodDesc METHOD_SHOULD_COMMIT_LONG = MethodDesc.of("shouldCommit", "(J)Z"); private static final MethodDesc METHOD_TIME_STAMP = MethodDesc.of("timestamp", "()J"); - private final ClassModel classModel; - private final List settingDescs; - private final List fieldDescs;; - private final String eventName; - private final String className; - private final Class superClass; - private final boolean untypedEventConfiguration; - private final MethodDesc staticCommitMethod; + private final ClassInspector inspector; private final long eventTypeId; + private final ClassDesc eventClassDesc; + private final MethodDesc staticCommitMethod; + private final boolean untypedEventConfiguration; private final boolean guardEventConfiguration; - private final boolean isJDK; - private final Map> methodUpdates = new LinkedHashMap<>(); - private final ImplicitFields implicitFields; - EventInstrumentation(Class superClass, byte[] bytes, long id, boolean isJDK, boolean guardEventConfiguration) { + /** + * Creates an EventInstrumentation object. + * + * @param inspector class inspector + * @param id the event type ID to use + * @param guardEventConfiguration guard against event configuration being null. + * Needed when instrumentation is added before + * registration (bytesForEagerInstrumentation) + */ + EventInstrumentation(ClassInspector inspector, long id, boolean guardEventConfiguration) { + inspector.buildFields(); + if (!inspector.isJDK()) { + // Only user-defined events have custom settings. + inspector.buildSettings(); + } + this.inspector = inspector; this.eventTypeId = id; - this.superClass = superClass; - this.isJDK = isJDK; - this.classModel = createClassModel(bytes); - this.className = classModel.thisClass().asInternalName().replace("/", "."); - String name = annotationValue(classModel, ANNOTATION_NAME, String.class); - this.eventName = name == null ? className : name; - this.implicitFields = determineImplicitFields(); - this.settingDescs = buildSettingDescs(superClass, classModel); - this.fieldDescs = buildFieldDescs(superClass, classModel); - this.staticCommitMethod = isJDK ? findStaticCommitMethod(classModel, fieldDescs) : null; - this.untypedEventConfiguration = hasUntypedConfiguration(); - // Corner case when we are forced to generate bytecode - // (bytesForEagerInstrumentation) - // We can't reference EventConfiguration::isEnabled() before event class has - // been registered, - // so we add a guard against a null reference. this.guardEventConfiguration = guardEventConfiguration; + this.eventClassDesc = inspector.getClassDesc(); + this.staticCommitMethod = inspector.findStaticCommitMethod(); + this.untypedEventConfiguration = hasUntypedConfiguration(); } - private ImplicitFields determineImplicitFields() { - if (isJDK) { - Class eventClass = MirrorEvents.find(isJDK, className); - if (eventClass != null) { - return new ImplicitFields(eventClass); - } - } - ImplicitFields ifs = new ImplicitFields(superClass); - String[] value = annotationValue(classModel, ANNOTATION_REMOVE_FIELDS, String[].class); - if (value != null) { - ifs.removeFields(value); - } - return ifs; + byte[] buildInstrumented() { + return ClassFile.of().transformClass(inspector.getClassModel(), this::transform); } - static MethodDesc findStaticCommitMethod(ClassModel classModel, List fields) { - StringBuilder sb = new StringBuilder(); - sb.append("("); - for (FieldDesc field : fields) { - sb.append(field.type().descriptorString()); - } - sb.append(")V"); - MethodDesc m = MethodDesc.of("commit", sb.toString()); - for (MethodModel method : classModel.methods()) { - String d = method.methodTypeSymbol().descriptorString(); - if (method.methodName().equalsString("commit") && m.descriptor().descriptorString().equals(d)) { - return m; - } + private void transform(ClassBuilder clb, ClassElement cle) { + if (cle instanceof MethodModel method && instrumentable(method) instanceof Consumer modification) { + clb.transformMethod(method, MethodTransform.transformingCode((codeBuilder, _) -> modification.accept(codeBuilder))); + } else { + clb.with(cle); } - return null; } - private boolean hasUntypedConfiguration() { - for (FieldModel f : classModel.fields()) { - if (f.fieldName().equalsString(FIELD_EVENT_CONFIGURATION.name())) { - return f.fieldType().equalsString(TYPE_OBJECT.descriptorString()); - } + private Consumer instrumentable(MethodModel method) { + if (isMethod(method, METHOD_IS_ENABLED)) { + return this::methodIsEnabled; } - throw new InternalError("Class missing configuration field"); - } - - public String getClassName() { - return classModel.thisClass().asInternalName().replace("/", "."); - } - - private ClassModel createClassModel(byte[] bytes) { - return ClassFile.of().parse(bytes); - } - - boolean isRegistered() { - Boolean result = annotationValue(classModel, ANNOTATION_REGISTERED, Boolean.class); - if (result != null) { - return result.booleanValue(); + if (isMethod(method, METHOD_BEGIN)) { + return this::methodBegin; } - if (superClass != null) { - Registered r = superClass.getAnnotation(Registered.class); - if (r != null) { - return r.value(); - } + if (isMethod(method, METHOD_END)) { + return this::methodEnd; } - return true; - } - - boolean isEnabled() { - Boolean result = annotationValue(classModel, ANNOTATION_ENABLED, Boolean.class); - if (result != null) { - return result.booleanValue(); + if (isMethod(method, METHOD_EVENT_SHOULD_COMMIT)) { + return this::methodShouldCommit; } - if (superClass != null) { - Enabled e = superClass.getAnnotation(Enabled.class); - if (e != null) { - return e.value(); - } + if (staticCommitMethod == null && isMethod(method, METHOD_COMMIT)) { + return this::methodCommit; } - return true; - } - - @SuppressWarnings("unchecked") - // Only supports String, String[] and Boolean values - private static T annotationValue(ClassModel classModel, ClassDesc classDesc, Class type) { - String typeDescriptor = classDesc.descriptorString(); - for (ClassElement ce : classModel) { - if (ce instanceof RuntimeVisibleAnnotationsAttribute rvaa) { - for (Annotation a : rvaa.annotations()) { - if (a.className().equalsString(typeDescriptor)) { - if (a.elements().size() == 1) { - AnnotationElement ae = a.elements().getFirst(); - if (ae.name().equalsString("value")) { - if (ae.value() instanceof AnnotationValue.OfBoolean ofb && type.equals(Boolean.class)) { - Boolean b = ofb.booleanValue(); - return (T)b; - } - if (ae.value() instanceof AnnotationValue.OfString ofs && type.equals(String.class)) { - String s = ofs.stringValue(); - return (T)s; - } - if (ae.value() instanceof AnnotationValue.OfArray ofa && type.equals(String[].class)) { - List list = ofa.values(); - String[] array = new String[list.size()]; - int index = 0; - for (AnnotationValue av : list) { - var avs = (AnnotationValue.OfString)av; - array[index++] = avs.stringValue(); - } - return (T)array; - } - } - } - } - } + if (inspector.isJDK() && isStatic(method)) { + if (isMethod(method, METHOD_ENABLED)) { + return this::methodEnabledStatic; } - } - return null; - } - - private static List buildSettingDescs(Class superClass, ClassModel classModel) { - Set methodSet = new HashSet<>(); - List settingDescs = new ArrayList<>(); - for (MethodModel m : classModel.methods()) { - for (var me : m) { - if (me instanceof RuntimeVisibleAnnotationsAttribute rvaa) { - for (Annotation a : rvaa.annotations()) { - // We can't really validate the method at this - // stage. We would need to check that the parameter - // is an instance of SettingControl. - if (a.className().equalsString(TYPE_SETTING_DEFINITION.descriptorString())) { - String name = m.methodName().stringValue(); - // Use @Name if it exists - for (Annotation nameCandidate : rvaa.annotations()) { - if (nameCandidate.className().equalsString(ANNOTATION_NAME.descriptorString())) { - if (nameCandidate.elements().size() == 1) { - AnnotationElement ae = nameCandidate.elements().getFirst(); - if (ae.name().equalsString("value")) { - if (ae.value() instanceof AnnotationValue.OfString s) { - name = Utils.validJavaIdentifier(s.stringValue(), name); - } - } - } - } - } - // Add setting if method returns boolean and has one parameter - MethodTypeDesc mtd = m.methodTypeSymbol(); - if ("Z".equals(mtd.returnType().descriptorString())) { - if (mtd.parameterList().size() == 1) { - ClassDesc type = mtd.parameterList().getFirst(); - if (type.isClassOrInterface()) { - String methodName = m.methodName().stringValue(); - methodSet.add(methodName); - settingDescs.add(new SettingDesc(type, methodName)); - } - } - } - } - } - } + if (isMethod(method, METHOD_SHOULD_COMMIT_LONG)) { + return this::methodShouldCommitStatic; } - } - for (Class c = superClass; jdk.internal.event.Event.class != c; c = c.getSuperclass()) { - for (java.lang.reflect.Method method : c.getDeclaredMethods()) { - if (!methodSet.contains(method.getName())) { - // skip private method in base classes - if (!Modifier.isPrivate(method.getModifiers())) { - if (method.getReturnType().equals(Boolean.TYPE)) { - if (method.getParameterCount() == 1) { - Class type = method.getParameters()[0].getType(); - if (SettingControl.class.isAssignableFrom(type)) { - ClassDesc paramType = Bytecode.classDesc(type); - methodSet.add(method.getName()); - settingDescs.add(new SettingDesc(paramType, method.getName())); - } - } - } - } - } + if (isMethod(method, METHOD_TIME_STAMP)) { + return this::methodTimestamp; + } + if (staticCommitMethod != null && isMethod(method, staticCommitMethod)) { + return this::methodCommit; } } - return settingDescs; + return null; } - private List buildFieldDescs(Class superClass, ClassModel classModel) { - Set fieldSet = new HashSet<>(); - List fieldDescs = new ArrayList<>(classModel.fields().size()); - // These two fields are added by native as 'transient' so they will be - // ignored by the loop below. - // The benefit of adding them manually is that we can - // control in which order they occur and we can add @Name, @Description - // in Java, instead of in native. It also means code for adding implicit - // fields for native can be reused by Java. - fieldDescs.add(FIELD_START_TIME); - if (implicitFields.hasDuration()) { - fieldDescs.add(FIELD_DURATION); - } - for (FieldModel field : classModel.fields()) { - if (!fieldSet.contains(field.fieldName().stringValue()) && isValidField(field.flags().flagsMask(), field.fieldTypeSymbol())) { - FieldDesc fi = FieldDesc.of(field.fieldTypeSymbol(), field.fieldName().stringValue()); - fieldDescs.add(fi); - fieldSet.add(field.fieldName().stringValue()); - } + private void methodIsEnabled(CodeBuilder codeBuilder) { + Label nullLabel = codeBuilder.newLabel(); + if (guardEventConfiguration) { + getEventConfiguration(codeBuilder); + codeBuilder.ifnull(nullLabel); } - for (Class c = superClass; jdk.internal.event.Event.class != c; c = c.getSuperclass()) { - for (Field field : c.getDeclaredFields()) { - // skip private field in base classes - if (!Modifier.isPrivate(field.getModifiers())) { - if (isValidField(field.getModifiers(), field.getType().getName())) { - String fieldName = field.getName(); - if (!fieldSet.contains(fieldName)) { - fieldDescs.add(FieldDesc.of(field.getType(), fieldName)); - fieldSet.add(fieldName); - } - } - } - } + getEventConfiguration(codeBuilder); + invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_IS_ENABLED); + codeBuilder.ireturn(); + if (guardEventConfiguration) { + codeBuilder.labelBinding(nullLabel); + codeBuilder.iconst_0(); + codeBuilder.ireturn(); } - return fieldDescs; } - public static boolean isValidField(int access, ClassDesc classDesc) { - String className = classDesc.packageName(); - if (!className.isEmpty()) { - className = className + "."; + private void methodBegin(CodeBuilder codeBuilder) { + if (!inspector.hasDuration()) { + throwMissingDuration(codeBuilder, "begin"); + } else { + codeBuilder.aload(0); + invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_TIME_STAMP); + putfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_START_TIME); + codeBuilder.return_(); } - className += classDesc.displayName(); - return isValidField(access, className); } - public static boolean isValidField(int access, String className) { - if (Modifier.isTransient(access) || Modifier.isStatic(access)) { - return false; + private void methodEnd(CodeBuilder codeBuilder) { + if (!inspector.hasDuration()) { + throwMissingDuration(codeBuilder, "end"); + } else { + codeBuilder.aload(0); + codeBuilder.aload(0); + getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_START_TIME); + invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_DURATION); + putfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); + codeBuilder.return_(); } - return Type.isValidJavaFieldType(className); - } - - public byte[] buildInstrumented() { - makeInstrumented(); - return toByteArray(); } - byte[] toByteArray() { - return ClassFile.of().build(classModel.thisClass().asSymbol(), classBuilder -> { - for (ClassElement ce : classModel) { - boolean updated = false; - if (ce instanceof MethodModel method) { - Consumer methodUpdate = findMethodUpdate(method); - if (methodUpdate != null) { - classBuilder.withMethod(method.methodName().stringValue(), method.methodTypeSymbol(), method.flags().flagsMask(), methodBuilder -> { - methodBuilder.withCode(methodUpdate); - }); - updated = true; - } - } - if (!updated) { - classBuilder.with(ce); - } - } - }); - } - - public byte[] buildUninstrumented() { - makeUninstrumented(); - return toByteArray(); - } - - private void throwMissingDuration(CodeBuilder codeBuilder, String method) { - String message = "Cannot use method " + method + " when event lacks duration field"; - Bytecode.throwException(codeBuilder, TYPE_ISE, message); - } - - private void makeInstrumented() { - // MyEvent#isEnabled() - updateEnabledMethod(METHOD_IS_ENABLED); - - // MyEvent#begin() - updateMethod(METHOD_BEGIN, codeBuilder -> { - if (!implicitFields.hasDuration()) { - throwMissingDuration(codeBuilder, "begin"); - } else { - codeBuilder.aload(0); - invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_TIME_STAMP); - putfield(codeBuilder, getEventClassDesc(), FIELD_START_TIME); - codeBuilder.return_(); - } - }); - - // MyEvent#end() - updateMethod(METHOD_END, codeBuilder -> { - if (!implicitFields.hasDuration()) { - throwMissingDuration(codeBuilder, "end"); + private void methodShouldCommit(CodeBuilder codeBuilder) { + Label fail = codeBuilder.newLabel(); + if (guardEventConfiguration) { + getEventConfiguration(codeBuilder); + codeBuilder.ifnull(fail); + } + // if (!eventConfiguration.shouldCommit(duration) goto fail; + getEventConfiguration(codeBuilder); + codeBuilder.aload(0); + getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); + invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT); + codeBuilder.ifeq(fail); + List settingDescs = inspector.getSettings(); + for (int index = 0; index < settingDescs.size(); index++) { + SettingDesc sd = settingDescs.get(index); + // if (!settingsMethod(eventConfiguration.settingX)) goto fail; + codeBuilder.aload(0); + getEventConfiguration(codeBuilder); + codeBuilder.loadConstant(index); + invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_GET_SETTING); + MethodTypeDesc mdesc = MethodTypeDesc.ofDescriptor("(" + sd.paramType().descriptorString() + ")Z"); + codeBuilder.checkcast(sd.paramType()); + codeBuilder.invokevirtual(eventClassDesc, sd.methodName(), mdesc); + codeBuilder.ifeq(fail); + } + // return true + codeBuilder.iconst_1(); + codeBuilder.ireturn(); + // return false + codeBuilder.labelBinding(fail); + codeBuilder.iconst_0(); + codeBuilder.ireturn(); + } + + private void methodCommit(CodeBuilder codeBuilder) { + Label excluded = codeBuilder.newLabel(); + Label end = codeBuilder.newLabel(); + codeBuilder.trying(blockCodeBuilder -> { + if (staticCommitMethod != null) { + updateStaticCommit(blockCodeBuilder, excluded); } else { - codeBuilder.aload(0); - codeBuilder.aload(0); - getfield(codeBuilder, getEventClassDesc(), FIELD_START_TIME); - invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_DURATION); - putfield(codeBuilder, getEventClassDesc(), FIELD_DURATION); - codeBuilder.return_(); + updateInstanceCommit(blockCodeBuilder, end, excluded); } - }); - - // MyEvent#commit() or static MyEvent#commit(...) - MethodDesc m = staticCommitMethod == null ? METHOD_COMMIT : staticCommitMethod; - updateMethod(m, codeBuilder -> { - Label excluded = codeBuilder.newLabel(); - Label end = codeBuilder.newLabel(); - codeBuilder.trying(blockCodeBuilder -> { - if (staticCommitMethod != null) { - updateStaticCommit(blockCodeBuilder, excluded); - } else { - updateInstanceCommit(blockCodeBuilder, end, excluded); - } - // stack: [integer] - // notified -> restart event write attempt - blockCodeBuilder.ifeq(blockCodeBuilder.startLabel()); - // stack: [] - blockCodeBuilder.goto_(end); - }, catchBuilder -> { - catchBuilder.catchingAll(catchAllHandler -> { - getEventWriter(catchAllHandler); - // stack: [ex] [EW] - catchAllHandler.dup(); - // stack: [ex] [EW] [EW] - Label rethrow = catchAllHandler.newLabel(); - catchAllHandler.ifnull(rethrow); - // stack: [ex] [EW] - catchAllHandler.dup(); - // stack: [ex] [EW] [EW] - invokevirtual(catchAllHandler, TYPE_EVENT_WRITER, METHOD_RESET); - catchAllHandler.labelBinding(rethrow); - // stack:[ex] [EW] - catchAllHandler.pop(); - // stack:[ex] - catchAllHandler.athrow(); - }); - }); - codeBuilder.labelBinding(excluded); - // stack: [EW] - codeBuilder.pop(); - codeBuilder.labelBinding(end); + // stack: [integer] + // notified -> restart event write attempt + blockCodeBuilder.ifeq(blockCodeBuilder.startLabel()); // stack: [] - codeBuilder.return_(); + blockCodeBuilder.goto_(end); + }, catchBuilder -> { + catchBuilder.catchingAll(catchAllHandler -> { + getEventWriter(catchAllHandler); + // stack: [ex] [EW] + catchAllHandler.dup(); + // stack: [ex] [EW] [EW] + Label rethrow = catchAllHandler.newLabel(); + catchAllHandler.ifnull(rethrow); + // stack: [ex] [EW] + catchAllHandler.dup(); + // stack: [ex] [EW] [EW] + invokevirtual(catchAllHandler, TYPE_EVENT_WRITER, METHOD_RESET); + catchAllHandler.labelBinding(rethrow); + // stack:[ex] [EW] + catchAllHandler.pop(); + // stack:[ex] + catchAllHandler.athrow(); + }); }); + codeBuilder.labelBinding(excluded); + // stack: [EW] + codeBuilder.pop(); + codeBuilder.labelBinding(end); + // stack: [] + codeBuilder.return_(); + } - // MyEvent#shouldCommit() - updateMethod(METHOD_EVENT_SHOULD_COMMIT, codeBuilder -> { - Label fail = codeBuilder.newLabel(); - if (guardEventConfiguration) { - getEventConfiguration(codeBuilder); - codeBuilder.ifnull(fail); - } - // if (!eventConfiguration.shouldCommit(duration) goto fail; + private void methodEnabledStatic(CodeBuilder codeBuilder) { + Label nullLabel = codeBuilder.newLabel(); + if (guardEventConfiguration) { getEventConfiguration(codeBuilder); - codeBuilder.aload(0); - getfield(codeBuilder, getEventClassDesc(), FIELD_DURATION); - invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT); - codeBuilder.ifeq(fail); - for (int index = 0; index < settingDescs.size(); index++) { - SettingDesc sd = settingDescs.get(index); - // if (!settingsMethod(eventConfiguration.settingX)) goto fail; - codeBuilder.aload(0); - getEventConfiguration(codeBuilder); - codeBuilder.loadConstant(index); - invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_GET_SETTING); - MethodTypeDesc mdesc = MethodTypeDesc.ofDescriptor("(" + sd.paramType().descriptorString() + ")Z"); - codeBuilder.checkcast(sd.paramType()); - codeBuilder.invokevirtual(getEventClassDesc(), sd.methodName(), mdesc); - codeBuilder.ifeq(fail); - } - // return true - codeBuilder.iconst_1(); - codeBuilder.ireturn(); - // return false - codeBuilder.labelBinding(fail); + codeBuilder.ifnull(nullLabel); + } + getEventConfiguration(codeBuilder); + invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_IS_ENABLED); + codeBuilder.ireturn(); + if (guardEventConfiguration) { + codeBuilder.labelBinding(nullLabel); codeBuilder.iconst_0(); codeBuilder.ireturn(); - }); + } + } - if (isJDK) { - if (hasStaticMethod(METHOD_ENABLED)) { - updateEnabledMethod(METHOD_ENABLED); - } + private void methodTimestamp(CodeBuilder codeBuilder) { + invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_TIME_STAMP); + codeBuilder.lreturn(); + } - updateIfStaticMethodExists(METHOD_SHOULD_COMMIT_LONG, codeBuilder -> { - Label fail = codeBuilder.newLabel(); - if (guardEventConfiguration) { - // if (eventConfiguration == null) goto fail; - getEventConfiguration(codeBuilder); - codeBuilder.ifnull(fail); - } - // return eventConfiguration.shouldCommit(duration); - getEventConfiguration(codeBuilder); - codeBuilder.lload(0); - codeBuilder.invokevirtual(TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT.name(), METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT.descriptor()); - codeBuilder.ireturn(); - // fail: - codeBuilder.labelBinding(fail); - // return false - codeBuilder.iconst_0(); - codeBuilder.ireturn(); - }); - updateIfStaticMethodExists(METHOD_TIME_STAMP, codeBuilder -> { - invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_TIME_STAMP); - codeBuilder.lreturn(); - }); + private void methodShouldCommitStatic(CodeBuilder codeBuilder) { + Label fail = codeBuilder.newLabel(); + if (guardEventConfiguration) { + // if (eventConfiguration == null) goto fail; + getEventConfiguration(codeBuilder); + codeBuilder.ifnull(fail); } + // return eventConfiguration.shouldCommit(duration); + getEventConfiguration(codeBuilder); + codeBuilder.lload(0); + codeBuilder.invokevirtual(TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT.name(), METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT.descriptor()); + codeBuilder.ireturn(); + // fail: + codeBuilder.labelBinding(fail); + // return false + codeBuilder.iconst_0(); + codeBuilder.ireturn(); + } + + private void throwMissingDuration(CodeBuilder codeBuilder, String method) { + String message = "Cannot use method " + method + " when event lacks duration field"; + Bytecode.throwException(codeBuilder, TYPE_ISE, message); } - void updateStaticCommit(BlockCodeBuilder blockCodeBuilder, Label excluded) { + private void updateStaticCommit(BlockCodeBuilder blockCodeBuilder, Label excluded) { // indexes the argument type array, the argument type array does not include // 'this' int argIndex = 0; @@ -576,7 +350,7 @@ void updateStaticCommit(BlockCodeBuilder blockCodeBuilder, Label excluded) { invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.method()); fieldIndex++; // stack: [EW] - if (implicitFields.hasDuration()) { + if (inspector.hasDuration()) { // write duration blockCodeBuilder.dup(); // stack: [EW], [EW] @@ -588,14 +362,14 @@ void updateStaticCommit(BlockCodeBuilder blockCodeBuilder, Label excluded) { fieldIndex++; } // stack: [EW] - if (implicitFields.hasEventThread()) { + if (inspector.hasEventThread()) { // write eventThread blockCodeBuilder.dup(); // stack: [EW], [EW] invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_EVENT_THREAD.method()); } // stack: [EW] - if (implicitFields.hasStackTrace()) { + if (inspector.hasStackTrace()) { // write stackTrace blockCodeBuilder.dup(); // stack: [EW], [EW] @@ -603,6 +377,7 @@ void updateStaticCommit(BlockCodeBuilder blockCodeBuilder, Label excluded) { } // stack: [EW] // write custom fields + List fieldDescs = inspector.getFields(); while (fieldIndex < fieldDescs.size()) { blockCodeBuilder.dup(); // stack: [EW], [EW] @@ -622,19 +397,19 @@ void updateStaticCommit(BlockCodeBuilder blockCodeBuilder, Label excluded) { // stack: [int] } - void updateInstanceCommit(BlockCodeBuilder blockCodeBuilder, Label end, Label excluded) { + private void updateInstanceCommit(BlockCodeBuilder blockCodeBuilder, Label end, Label excluded) { // if (!isEnable()) { // return; // } blockCodeBuilder.aload(0); - invokevirtual(blockCodeBuilder, getEventClassDesc(), METHOD_IS_ENABLED); + invokevirtual(blockCodeBuilder, eventClassDesc, METHOD_IS_ENABLED); Label l0 = blockCodeBuilder.newLabel(); blockCodeBuilder.ifne(l0); blockCodeBuilder.return_(); blockCodeBuilder.labelBinding(l0); // long startTime = this.startTime blockCodeBuilder.aload(0); - getfield(blockCodeBuilder, getEventClassDesc(), FIELD_START_TIME); + getfield(blockCodeBuilder, eventClassDesc, ImplicitFields.FIELD_START_TIME); blockCodeBuilder.lstore(1); // if (startTime == 0) { // startTime = EventWriter.timestamp(); @@ -654,7 +429,7 @@ void updateInstanceCommit(BlockCodeBuilder blockCodeBuilder, Label end, Label ex // } blockCodeBuilder.labelBinding(durationEvent); blockCodeBuilder.aload(0); - getfield(blockCodeBuilder, getEventClassDesc(), FIELD_DURATION); + getfield(blockCodeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); blockCodeBuilder.lconst_0(); blockCodeBuilder.lcmp(); blockCodeBuilder.ifne(commit); @@ -662,11 +437,11 @@ void updateInstanceCommit(BlockCodeBuilder blockCodeBuilder, Label end, Label ex invokestatic(blockCodeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_TIME_STAMP); blockCodeBuilder.lload(1); blockCodeBuilder.lsub(); - putfield(blockCodeBuilder, getEventClassDesc(), FIELD_DURATION); + putfield(blockCodeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); blockCodeBuilder.labelBinding(commit); // if (shouldCommit()) { blockCodeBuilder.aload(0); - invokevirtual(blockCodeBuilder, getEventClassDesc(), METHOD_EVENT_SHOULD_COMMIT); + invokevirtual(blockCodeBuilder, eventClassDesc, METHOD_EVENT_SHOULD_COMMIT); blockCodeBuilder.ifeq(end); getEventWriter(blockCodeBuilder); // stack: [EW] @@ -687,39 +462,40 @@ void updateInstanceCommit(BlockCodeBuilder blockCodeBuilder, Label end, Label ex invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.method()); fieldIndex++; // stack: [EW] - if (implicitFields.hasDuration()) { + if (inspector.hasDuration()) { // write duration blockCodeBuilder.dup(); // stack: [EW] [EW] blockCodeBuilder.aload(0); // stack: [EW] [EW] [this] - getfield(blockCodeBuilder, getEventClassDesc(), FIELD_DURATION); + getfield(blockCodeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); // stack: [EW] [EW] [long] invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.method()); fieldIndex++; } // stack: [EW] - if (implicitFields.hasEventThread()) { + if (inspector.hasEventThread()) { // write eventThread blockCodeBuilder.dup(); // stack: [EW] [EW] invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_EVENT_THREAD.method()); } // stack: [EW] - if (implicitFields.hasStackTrace()) { + if (inspector.hasStackTrace()) { // write stack trace blockCodeBuilder.dup(); // stack: [EW] [EW] invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_STACK_TRACE.method()); } // stack: [EW] + List fieldDescs = inspector.getFields(); while (fieldIndex < fieldDescs.size()) { FieldDesc field = fieldDescs.get(fieldIndex); blockCodeBuilder.dup(); // stack: [EW] [EW] blockCodeBuilder.aload(0); // stack: [EW] [EW] [this] - getfield(blockCodeBuilder, getEventClassDesc(), field); + getfield(blockCodeBuilder, eventClassDesc, field); // stack: [EW] [EW] EventWriterMethod eventMethod = EventWriterMethod.lookupMethod(field); invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, eventMethod.method()); @@ -731,90 +507,33 @@ void updateInstanceCommit(BlockCodeBuilder blockCodeBuilder, Label end, Label ex // stack:[int] } - private void updateEnabledMethod(MethodDesc method) { - updateMethod(method, codeBuilder -> { - Label nullLabel = codeBuilder.newLabel(); - if (guardEventConfiguration) { - getEventConfiguration(codeBuilder); - codeBuilder.ifnull(nullLabel); - } - getEventConfiguration(codeBuilder); - invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_IS_ENABLED); - codeBuilder.ireturn(); - if (guardEventConfiguration) { - codeBuilder.labelBinding(nullLabel); - codeBuilder.iconst_0(); - codeBuilder.ireturn(); - } - }); - } - - private void updateIfStaticMethodExists(MethodDesc method, Consumer code) { - if (hasStaticMethod(method)) { - updateMethod(method, code); - } + private static boolean isStatic(MethodModel method) { + return (method.flags().flagsMask() & ClassFile.ACC_STATIC) != 0; } - private boolean hasStaticMethod(MethodDesc method) { - for (MethodModel m : classModel.methods()) { - if (m.methodName().equalsString(method.name()) && m.methodTypeSymbol().equals(method.descriptor())) { - return Modifier.isStatic(m.flags().flagsMask()); - } - } - return false; + private static boolean isMethod(MethodModel m, MethodDesc desc) { + return desc.matches(m); } - private void getEventWriter(CodeBuilder codeBuilder) { + private static void getEventWriter(CodeBuilder codeBuilder) { invokestatic(codeBuilder, TYPE_EVENT_WRITER, METHOD_GET_EVENT_WRITER); } private void getEventConfiguration(CodeBuilder codeBuilder) { if (untypedEventConfiguration) { - codeBuilder.getstatic(getEventClassDesc(), FIELD_EVENT_CONFIGURATION.name(), TYPE_OBJECT); + codeBuilder.getstatic(eventClassDesc, FIELD_EVENT_CONFIGURATION.name(), TYPE_OBJECT); codeBuilder.checkcast(TYPE_EVENT_CONFIGURATION); } else { - codeBuilder.getstatic(getEventClassDesc(), FIELD_EVENT_CONFIGURATION.name(), TYPE_EVENT_CONFIGURATION); + codeBuilder.getstatic(eventClassDesc, FIELD_EVENT_CONFIGURATION.name(), TYPE_EVENT_CONFIGURATION); } } - private void makeUninstrumented() { - updateExistingWithReturnFalse(METHOD_EVENT_SHOULD_COMMIT); - updateExistingWithReturnFalse(METHOD_IS_ENABLED); - updateExistingWithEmptyVoidMethod(METHOD_COMMIT); - if (staticCommitMethod != null) { - updateExistingWithEmptyVoidMethod(staticCommitMethod); + private boolean hasUntypedConfiguration() { + for (FieldModel f : inspector.getClassModel().fields()) { + if (f.fieldName().equalsString(FIELD_EVENT_CONFIGURATION.name())) { + return f.fieldType().equalsString(TYPE_OBJECT.descriptorString()); + } } - updateExistingWithEmptyVoidMethod(METHOD_BEGIN); - updateExistingWithEmptyVoidMethod(METHOD_END); - } - - private final void updateExistingWithEmptyVoidMethod(MethodDesc voidMethod) { - updateMethod(voidMethod, codeBuilder -> { - codeBuilder.return_(); - }); - } - - private final void updateExistingWithReturnFalse(MethodDesc voidMethod) { - updateMethod(voidMethod, codeBuilder -> { - codeBuilder.iconst_0(); - codeBuilder.ireturn(); - }); - } - - private Consumer findMethodUpdate(MethodModel mm) { - MethodDesc m = MethodDesc.of(mm.methodName().stringValue(), mm.methodType().stringValue()); - return methodUpdates.get(m); - } - - private void updateMethod(MethodDesc method, Consumer codeBuilder) { - methodUpdates.put(method, codeBuilder); - } - - private ClassDesc getEventClassDesc() { - return classModel.thisClass().asSymbol(); - } - - public String getEventName() { - return eventName; + throw new InternalError("Class missing configuration field"); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java index 36dc2259be944..18b76cc3ff9fb 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java @@ -72,7 +72,8 @@ static byte[] onRetransform(long traceId, boolean dummy1, boolean dummy2, Class< } boolean jdkClass = Utils.isJDKClass(clazz); Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding instrumentation to event class " + clazz.getName() + " using retransform"); - EventInstrumentation ei = new EventInstrumentation(clazz.getSuperclass(), oldBytes, traceId, jdkClass, false); + ClassInspector c = new ClassInspector(clazz.getSuperclass(), oldBytes, jdkClass); + EventInstrumentation ei = new EventInstrumentation(c, traceId, false); byte[] bytes = ei.buildInstrumented(); Bytecode.log(clazz.getName(), bytes); return bytes; @@ -105,9 +106,9 @@ static byte[] bytesForEagerInstrumentation(long traceId, boolean forceInstrument } String eventName = ""; try { - EventInstrumentation ei = new EventInstrumentation(superClass, oldBytes, traceId, bootClassLoader, true); - eventName = ei.getEventName(); - if (!JVMSupport.shouldInstrument(bootClassLoader, ei.getEventName())) { + ClassInspector c = new ClassInspector(superClass, oldBytes, bootClassLoader); + eventName = c.getEventName(); + if (!JVMSupport.shouldInstrument(bootClassLoader, c.getEventName())) { Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Skipping instrumentation for " + eventName + " since container support is missing"); return oldBytes; } @@ -118,14 +119,15 @@ static byte[] bytesForEagerInstrumentation(long traceId, boolean forceInstrument // No need to generate bytecode if: // 1) Event class is disabled, and there is not an external configuration that overrides. // 2) Event class has @Registered(false) - if (!mr.isEnabled(ei.getEventName()) && !ei.isEnabled() || !ei.isRegistered()) { + if (!mr.isEnabled(c.getEventName()) && !c.isEnabled() || !c.isRegistered()) { Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Skipping instrumentation for event type " + eventName + " since event was disabled on class load"); return oldBytes; } } - Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding " + (forceInstrumentation ? "forced " : "") + "instrumentation for event type " + eventName + " during initial class load"); + EventInstrumentation ei = new EventInstrumentation(c, traceId, true); byte[] bytes = ei.buildInstrumented(); - Bytecode.log(ei.getClassName() + "(" + traceId + ")", bytes); + Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding " + (forceInstrumentation ? "forced " : "") + "instrumentation for event type " + eventName + " during initial class load"); + Bytecode.log(c.getClassName() + "(" + traceId + ")", bytes); return bytes; } catch (Throwable t) { Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation for event type " + eventName + ". " + t.getMessage()); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java index 1241993e762bc..3cea5e8064388 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ import jdk.jfr.internal.LogLevel; import jdk.jfr.internal.LogTag; import java.lang.classfile.CodeBuilder; +import java.lang.classfile.MethodModel; import java.lang.classfile.ClassModel; import java.lang.classfile.ClassFile; import jdk.internal.classfile.components.ClassPrinter; @@ -74,6 +75,12 @@ public static MethodDesc of(String methodName, Class returnType, Class... MethodTypeDesc mtd = MethodTypeDesc.of(returnDesc, parameterDesc); return new MethodDesc(methodName, mtd); } + + public boolean matches(MethodModel m) { + return this.descriptor().equals(m.methodTypeSymbol()) && m.methodName().equalsString(this.name()); + } + } + public record SettingDesc(ClassDesc paramType, String methodName) { } public static ClassDesc classDesc(ValueDescriptor v) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ImplicitFields.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ImplicitFields.java index c97efe0bdb9f0..4c82569a83f8c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ImplicitFields.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ImplicitFields.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ import java.util.List; import jdk.jfr.internal.RemoveFields; +import jdk.jfr.internal.util.Bytecode.FieldDesc; /** * Class that describes fields that was not directly named * in the event definition. @@ -37,6 +38,8 @@ public final class ImplicitFields { public static final String DURATION = "duration"; public static final String EVENT_THREAD = "eventThread"; public static final String STACK_TRACE = "stackTrace"; + public static final FieldDesc FIELD_DURATION = FieldDesc.of(long.class, DURATION); + public static final FieldDesc FIELD_START_TIME = FieldDesc.of(long.class, START_TIME); private final List fields = new ArrayList<>(4); From 44c5aca54d1e0aaf0616f77845c5b3b1e2fccf5a Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Wed, 23 Apr 2025 11:53:09 +0000 Subject: [PATCH 0727/1101] 8341491: Reserve and commit memory operations should be protected by NMT lock Reviewed-by: stuefe, stefank --- src/hotspot/share/runtime/os.cpp | 10 ++++ test/hotspot/gtest/runtime/test_os.cpp | 68 ++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index e4bab3410c1a7..943f81d752c2f 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -2251,6 +2251,11 @@ void os::commit_memory_or_exit(char* addr, size_t size, size_t alignment_hint, MemTracker::record_virtual_memory_commit((address)addr, size, CALLER_PC); } +// The scope of NmtVirtualMemoryLocker covers both pd_uncommit_memory and record_virtual_memory_uncommit because +// these operations must happen atomically to avoid races causing NMT to fall out os sync with the OS reality. +// We do not have the same lock protection for pd_commit_memory and record_virtual_memory_commit. +// We assume that there is some external synchronization that prevents a region from being uncommitted +// before it is finished being committed. bool os::uncommit_memory(char* addr, size_t bytes, bool executable) { assert_nonempty_range(addr, bytes); bool res; @@ -2273,6 +2278,11 @@ bool os::uncommit_memory(char* addr, size_t bytes, bool executable) { return res; } +// The scope of NmtVirtualMemoryLocker covers both pd_release_memory and record_virtual_memory_release because +// these operations must happen atomically to avoid races causing NMT to fall out os sync with the OS reality. +// We do not have the same lock protection for pd_reserve_memory and record_virtual_memory_reserve. +// We assume that there is some external synchronization that prevents a region from being released +// before it is finished being reserved. bool os::release_memory(char* addr, size_t bytes) { assert_nonempty_range(addr, bytes); bool res; diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index ee6d1427d0b8b..04d71a55a49c4 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -28,6 +28,7 @@ #include "runtime/os.inline.hpp" #include "runtime/thread.hpp" #include "runtime/threads.hpp" +#include "testutils.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" @@ -1113,3 +1114,70 @@ TEST_VM(os, free_without_uncommit) { os::release_memory(base, size); } #endif + +TEST_VM(os, commit_memory_or_exit) { + const size_t page_sz = os::vm_page_size(); + const size_t size = 16 * page_sz; + const char* letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + char* base = os::reserve_memory(size, false, mtTest); + ASSERT_NOT_NULL(base); + os::commit_memory_or_exit(base, size, false, "Commit failed."); + strcpy(base, letters); + ASSERT_TRUE(os::uncommit_memory(base, size, false)); + os::commit_memory_or_exit(base, size, page_sz, false, "Commit with alignment hint failed."); + strcpy(base, letters); + ASSERT_TRUE(os::uncommit_memory(base, size, false)); + EXPECT_TRUE(os::release_memory(base, size)); +} + +#if !defined(_AIX) + +TEST_VM(os, map_memory_to_file) { + const char* letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const size_t size = strlen(letters) +1; + + int fd = os::open("map_memory_to_file.txt", O_RDWR | O_CREAT, 0666); + EXPECT_TRUE(fd > 0); + EXPECT_TRUE(os::write(fd, letters, size)); + + char* result = os::map_memory_to_file(size, fd, mtTest); + ASSERT_NOT_NULL(result); + EXPECT_EQ(strcmp(letters, result), 0); + EXPECT_TRUE(os::unmap_memory(result, size)); + ::close(fd); +} + +TEST_VM(os, map_unmap_memory) { + const char* letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const char* path = "map_unmap_memory.txt"; + const size_t size = strlen(letters) + 1; + int fd = os::open(path, O_RDWR | O_CREAT, 0666); + EXPECT_TRUE(fd > 0); + EXPECT_TRUE(os::write(fd, letters, size)); + ::close(fd); + + fd = os::open(path, O_RDONLY, 0666); + char* result = os::map_memory(fd, path, 0, nullptr, size, true, false, mtTest); + ASSERT_NOT_NULL(result); + EXPECT_EQ(strcmp(letters, result), 0); + EXPECT_TRUE(os::unmap_memory(result, size)); + ::close(fd); +} + +TEST_VM(os, map_memory_to_file_aligned) { + const char* letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const size_t size = strlen(letters) + 1; + + int fd = os::open("map_memory_to_file.txt", O_RDWR | O_CREAT, 0666); + EXPECT_TRUE(fd > 0); + EXPECT_TRUE(os::write(fd, letters, size)); + + char* result = os::map_memory_to_file_aligned(os::vm_allocation_granularity(), os::vm_allocation_granularity(), fd, mtTest); + ASSERT_NOT_NULL(result); + EXPECT_EQ(strcmp(letters, result), 0); + EXPECT_TRUE(os::unmap_memory(result, os::vm_allocation_granularity())); + ::close(fd); +} + +#endif // !defined(_AIX) From c873837da6e373613866f5f5c0017f0fccb97b57 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Wed, 23 Apr 2025 13:01:42 +0000 Subject: [PATCH 0728/1101] 8355300: Add final to BitSieve Reviewed-by: liach, pminborg --- src/java.base/share/classes/java/math/BitSieve.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/java/math/BitSieve.java b/src/java.base/share/classes/java/math/BitSieve.java index 8d0d370f9be44..4403d79a22ff8 100644 --- a/src/java.base/share/classes/java/math/BitSieve.java +++ b/src/java.base/share/classes/java/math/BitSieve.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,22 +44,22 @@ * @author Michael McCloskey * @since 1.3 */ -class BitSieve { +final class BitSieve { /** * Stores the bits in this bitSieve. */ - private long bits[]; + private final long[] bits; /** * Length is how many bits this sieve holds. */ - private int length; + private final int length; /** * A small sieve used to filter out multiples of small primes in a search * sieve. */ - private static BitSieve smallSieve = new BitSieve(); + private static final BitSieve smallSieve = new BitSieve(); /** * Construct a "small sieve" with a base of 0. This constructor is From a372937d8480404e69eff43682c91506997fd8ee Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Wed, 23 Apr 2025 13:22:57 +0000 Subject: [PATCH 0729/1101] 8350983: JShell LocalExecutionControl only needs stopCheck() on backward branches Reviewed-by: jlahoda, liach, asotona --- .../execution/LocalExecutionControl.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java index 1f4dae2df3819..5f547b25178ff 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,11 +29,16 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; import java.lang.classfile.ClassFile; import java.lang.classfile.ClassTransform; +import java.lang.classfile.CodeTransform; +import java.lang.classfile.Label; import java.lang.classfile.instruction.BranchInstruction; +import java.lang.classfile.instruction.LabelTarget; /** * An implementation of {@link jdk.jshell.spi.ExecutionControl} which executes @@ -90,11 +95,19 @@ public void load(ClassBytecodes[] cbcs) private static byte[] instrument(byte[] classFile) { var cc = ClassFile.of(); return cc.transformClass(cc.parse(classFile), - ClassTransform.transformingMethodBodies((cob, coe) -> { - if (coe instanceof BranchInstruction) - cob.invokestatic(CD_Cancel, "stopCheck", ConstantDescs.MTD_void); - cob.with(coe); - })); + ClassTransform.transformingMethodBodies( + CodeTransform.ofStateful(() -> { + Set